gpt4 book ai didi

android - Kotlin协程:使一个线程执行代码,而另一个等待第一个完成

转载 作者:行者123 更新时间:2023-12-02 13:31:43 29 4
gpt4 key购买 nike

我从Kotlin转换后的https://github.com/blink22/react-native-html-to-pdf/blob/master/android/src/main/java/android/print/PdfConverter.java中找到以下代码:

import android.content.Context
import android.os.Build
import android.os.Handler
import android.os.ParcelFileDescriptor
import android.print.PrintAttributes.Resolution
import android.print.PrintDocumentAdapter.LayoutResultCallback
import android.print.PrintDocumentAdapter.WriteResultCallback
import android.util.Log
import android.webkit.WebView
import android.webkit.WebViewClient
import java.io.File


/**
* Converts HTML to PDF.
*
*
* Can convert only one task at a time, any requests to do more conversions before
* ending the current task are ignored.
*/
class PdfConverter private constructor() : Runnable {
private var mContext: Context? = null
private var mHtmlString: String? = null
private var mPdfFile: File? = null
private var mPdfPrintAttrs: PrintAttributes? = null
private var mIsCurrentlyConverting = false
private var mWebView: WebView? = null
private var done: Boolean = false

override fun run() {
mWebView = WebView(mContext as Context)
mWebView!!.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) throw RuntimeException(
"call requires API level 19"
) else {
val documentAdapter =
mWebView!!.createPrintDocumentAdapter()
documentAdapter.onLayout(
null,
pdfPrintAttrs,
null,
object : LayoutResultCallback() {},
null
)
documentAdapter.onWrite(
arrayOf(PageRange.ALL_PAGES),
outputFileDescriptor,
null,
object : WriteResultCallback() {
override fun onWriteFinished(pages: Array<PageRange>) {
destroy()
done = true
}
})

}
Log.d("end of onpagefinished()", "end of onpagefinished()")
}
}
mWebView!!.loadData(mHtmlString, "text/HTML", "UTF-8")
Log.d("end of run()", "end of run()")

}


var pdfPrintAttrs: PrintAttributes?
get() = if (mPdfPrintAttrs != null) mPdfPrintAttrs else defaultPrintAttrs
set(printAttrs) {
mPdfPrintAttrs = printAttrs
}

fun convert(
context: Context?,
htmlString: String?,
file: File?
) {
requireNotNull(context) { "context can't be null" }
requireNotNull(htmlString) { "htmlString can't be null" }
requireNotNull(file) { "file can't be null" }
if (mIsCurrentlyConverting) return
mContext = context
mHtmlString = htmlString
mPdfFile = file
mIsCurrentlyConverting = true
runOnUiThread(this)
Log.d("end of convert()","end of convert()")
}

private val outputFileDescriptor: ParcelFileDescriptor?
private get() {
try {
mPdfFile!!.createNewFile()
Log.d("outputfiledescriptor","the file has been created")
return ParcelFileDescriptor.open(
mPdfFile,
ParcelFileDescriptor.MODE_TRUNCATE or ParcelFileDescriptor.MODE_READ_WRITE
)
} catch (e: Exception) {
Log.d(TAG, "Failed to open ParcelFileDescriptor", e)
}
return null
}

private val defaultPrintAttrs: PrintAttributes?
private get() = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) null else PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.NA_GOVT_LETTER)
.setResolution(Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
.build()

private fun runOnUiThread(runnable: Runnable) {
val handler = Handler(mContext!!.mainLooper)
handler.post(this)
}

private fun destroy() {
mContext = null
mHtmlString = null
mPdfFile = null
mPdfPrintAttrs = null
mIsCurrentlyConverting = false
mWebView = null
Log.d("end of destroy()","end of destroy()")
}

companion object {
private const val TAG = "PdfConverter"
private var sInstance: PdfConverter? = null
@get:Synchronized
val instance: PdfConverter?
get() {
if (sInstance == null) sInstance =
PdfConverter()
return sInstance
}
}
}

我希望执行在返回 onWriteFinished之前先等待 runOnUiThread。我也希望主线程执行 run。因此,我尝试使用协程使用以下代码来实现这一目标:
package android.print

import kotlinx.coroutines.runBlocking

import android.content.Context
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.os.ParcelFileDescriptor
import android.print.PrintAttributes.Resolution
import android.print.PrintDocumentAdapter.LayoutResultCallback
import android.print.PrintDocumentAdapter.WriteResultCallback
import android.util.Log
import android.webkit.WebView
import android.webkit.WebViewClient
import java.io.File


/**
* Converts HTML to PDF.
*
*
* Can convert only one task at a time, any requests to do more conversions before
* ending the current task are ignored.
*/
class PdfConverter2 {
private var mContext: Context? = null
private var mHtmlString: String? = null
private var mPdfFile: File? = null
private var mPdfPrintAttrs: PrintAttributes? = null
private var mIsCurrentlyConverting = false
private var mWebView: WebView? = null
private var done: Boolean = false

suspend fun run() {
Log.d("run()","is this the main thread :"+(Looper.myLooper() == Looper.getMainLooper()))
mWebView = WebView(mContext as Context)
mWebView!!.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) throw RuntimeException(
"call requires API level 19"
) else {
val documentAdapter =
mWebView!!.createPrintDocumentAdapter()
documentAdapter.onLayout(
null,
pdfPrintAttrs,
null,
object : LayoutResultCallback() {},
null
)
documentAdapter.onWrite(
arrayOf(PageRange.ALL_PAGES),
outputFileDescriptor,
null,
object : WriteResultCallback() {
override fun onWriteFinished(pages: Array<PageRange>) {
destroy()
done = true
}
})

}
Log.d("end of onpagefinished()", "end of onpagefinished()")
}
}
mWebView!!.loadData(mHtmlString, "text/HTML", "UTF-8")
Log.d("end of run()", "end of run()")

}


var pdfPrintAttrs: PrintAttributes?
get() = if (mPdfPrintAttrs != null) mPdfPrintAttrs else defaultPrintAttrs
set(printAttrs) {
mPdfPrintAttrs = printAttrs
}

fun convert(
context: Context?,
htmlString: String?,
file: File?
) {
requireNotNull(context) { "context can't be null" }
requireNotNull(htmlString) { "htmlString can't be null" }
requireNotNull(file) { "file can't be null" }
if (mIsCurrentlyConverting) return
mContext = context
mHtmlString = htmlString
mPdfFile = file
mIsCurrentlyConverting = true
runOnUiThread()
Log.d("end of convert()","end of convert()")
}

private val outputFileDescriptor: ParcelFileDescriptor?
private get() {
try {
mPdfFile!!.createNewFile()
Log.d("outputfiledescriptor","the file has been created")
return ParcelFileDescriptor.open(
mPdfFile,
ParcelFileDescriptor.MODE_TRUNCATE or ParcelFileDescriptor.MODE_READ_WRITE
)
} catch (e: Exception) {
Log.d(TAG, "Failed to open ParcelFileDescriptor", e)
}
return null
}

private val defaultPrintAttrs: PrintAttributes?
private get() = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) null else PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.NA_GOVT_LETTER)
.setResolution(Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
.build()

private fun runOnUiThread() {
runBlocking {
run()
while(!done){

}
}

}

private fun destroy() {
mContext = null
mHtmlString = null
mPdfFile = null
mPdfPrintAttrs = null
mIsCurrentlyConverting = false
mWebView = null
Log.d("end of destroy()","end of destroy()")
}

companion object {
private const val TAG = "PdfConverter2"
private var sInstance: PdfConverter2? = null
@get:Synchronized
val instance: PdfConverter2?
get() {
if (sInstance == null) sInstance =
PdfConverter2()
return sInstance
}
}
}

在另一个文件中也有一个函数,该函数调用PdfConverter并调用 PdfConverter
fun createPdfFromHtml(htmlstring: String) {
val converter: PdfConverter? = PdfConverter.instance
val file = File(
Environment.getExternalStorageDirectory().getPath().toString() + "/" + name_of_directory_of_pdfs + "/",
nameofpdf
)
converter?.convert(m_context, htmlstring, file)
mFilepdf = file
}

我想要的是代码执行停止在'converter?.convert(m_context,htmlstring,file)',然后等待PdfConverter的'onWriteFinished'执行,然后继续。我认为的另一个观点是执行在“runonUiThread”处停止,并等待“onWriteFinished”再次执行。

在回答@ m0skit0之后,我更改了最后一个代码:
fun createPdfFromHtml(htmlstring: String) {
val file = File(
Environment.getExternalStorageDirectory().path.toString() + "/" + name_of_directory_of_pdfs + "/",
nameofpdf
)
var converter = PdfConverter3.from(m_context)
GlobalScope.launch(Dispatchers.IO) {// I TRY ALSO Dispatchers.Main
converter.convert(htmlstring, file)
}
mFilepdf = file
Log.d("mich/createPDfFromHtml", "at the end of createPdfFromHtml, is this the main thread ? "+ (Looper.myLooper() == Looper.getMainLooper()))
}

但是事情再次存在。

最佳答案

这是我使用协程将类翻译成Kotlin的观点

package org.m0skit0.android.testapp

import android.annotation.TargetApi
import android.content.Context
import android.os.ParcelFileDescriptor
import android.print.PageRange
import android.print.PrintAttributes
import android.print.PrintDocumentAdapter
import android.webkit.WebView
import android.webkit.WebViewClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

@TargetApi(19)
class PdfConverter private constructor(private val context: Context) {

private val defaultPrintAttributes: PrintAttributes by lazy {
PrintAttributes.Builder()
.setMediaSize(PrintAttributes.MediaSize.NA_GOVT_LETTER)
.setResolution(PrintAttributes.Resolution("RESOLUTION_ID", "RESOLUTION_ID", 600, 600))
.setMinMargins(PrintAttributes.Margins.NO_MARGINS)
.build()
}

private var printAttributes: PrintAttributes? = null

fun printAttributes(printAttributes: PrintAttributes): PdfConverter = apply {
this.printAttributes = printAttributes
}

suspend fun convert(htmlString: String, pdfFile: File) {
withContext(Dispatchers.Main) {
suspendCoroutine<Unit> { continuation ->
WebView(context).apply {
webViewClient = WebViewClientImpl(pdfFile, continuation)
}.loadData(htmlString, "text/html", "UTF-8")
}
}
}

private fun File.outputFileDescriptor(): ParcelFileDescriptor? =
try {
createNewFile()
ParcelFileDescriptor.open(this, ParcelFileDescriptor.MODE_TRUNCATE or ParcelFileDescriptor.MODE_READ_WRITE)
} catch (e: Exception) {
null
}

companion object {
fun from(context: Context): PdfConverter = PdfConverter(context)
}

private inner class WebViewClientImpl(private val file: File, private val continuation: Continuation<Unit>) : WebViewClient() {
override fun onPageFinished(webView: WebView, url: String) {
webView.createPrintDocumentAdapter()?.run {
onLayout(
null,
printAttributes ?: defaultPrintAttributes,
null,
object : PrintDocumentAdapter.LayoutResultCallback() {},
null
)
onWrite(
arrayOf(PageRange.ALL_PAGES),
file.outputFileDescriptor(),
null,
object : PrintDocumentAdapter.WriteResultCallback() {
override fun onWriteCancelled() {
super.onWriteCancelled()
continuation.resume(Unit)
}

override fun onWriteFailed(error: CharSequence?) {
super.onWriteFailed(error)
continuation.resumeWithException(Exception(error.toString()))
}

override fun onWriteFinished(pages: Array<out PageRange>?) {
super.onWriteFinished(pages)
continuation.resume(Unit)
}
}
)
}
}
}
}

关于android - Kotlin协程:使一个线程执行代码,而另一个等待第一个完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60966195/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com