【问题标题】:Views not updated from callback of asynctask after orientation change方向更改后未从异步任务的回调中更新视图
【发布时间】:2019-02-03 15:56:21
【问题描述】:

我有一个带有retainedInstance = true 的片段的活动,在其onCreate() 方法中定义,片段将进行一些网络连接,然后将数据发送回活动。

这是我的回调函数

override fun updateUi(result: ArrayList<Person>?) {
    progressBar.visibility = View.GONE
    window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
    if (result != null) {
        setAdapter(result)
    }
    else {
        finishNetworking()
        val snackBar = Snackbar.make(findViewById(R.id.root_layout),
            "Network failure", Snackbar.LENGTH_INDEFINITE)
        snackBar.setAction("Try again") {
            startDownload()
        }
        snackBar.show()
    }
}

这是我的活动 onCreate()

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    viewManager = LinearLayoutManager(this)
    progressBar = findViewById(R.id.progress_bar)
    recyclerView = findViewById<RecyclerView>(R.id.recycler_view).apply {
        setHasFixedSize(true)
        layoutManager = viewManager
    }

    if (savedInstanceState == null) {
        hasArgs = false
        networkFragment = NetworkFragment.getInstance(supportFragmentManager, SWAPI_URL_PEOPLE, null)
    }
    else {
        hasArgs = true
        networking = savedInstanceState.getBoolean("networking", false)
        if (networking) {
            window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
            progressBar.visibility = View.VISIBLE

        }
        if (savedInstanceState.getParcelableArrayList<Person>("persons") != null) {
            setAdapter(savedInstanceState.getParcelableArrayList<Person>("persons") as ArrayList<Person>)
        }
    }

}

这是我的异步任务

private class NetworkTask(
    callback: NetworkCallback<ArrayList<Person>>,
    person: Person?
)
    : AsyncTask<String, Int, NetworkTask.Result>() {

    private val mCallback: NetworkCallback<ArrayList<Person>>? = callback
    private val mPerson: Person? = person

    internal class Result {
        var mResultValue: ArrayList<Person>? = null
        var mException: Exception? = null

        constructor(resultValue: ArrayList<Person>?) {
            mResultValue = resultValue
        }

        constructor(exception: Exception) {
            mException = exception
        }
    }

    override fun onPreExecute() {

        if (mCallback != null) {

            if (Build.VERSION.SDK_INT < 23) {
                val networkInfo = mCallback.getConnectivityManager().activeNetworkInfo
                if (networkInfo?.isConnected == false
                    || networkInfo?.type != ConnectivityManager.TYPE_WIFI
                    && networkInfo?.type != ConnectivityManager.TYPE_MOBILE) {
                    mCallback.updateUi(null)
                    cancel(true)
                }
            }
            else {
                val network = mCallback.getConnectivityManager().activeNetwork
                val networkCapabilities = mCallback.getConnectivityManager().getNetworkCapabilities(network)
                if (networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == false &&
                    !networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                    mCallback.updateUi(null)
                    cancel(true)
                }
            }
        }
    }

    override fun doInBackground(vararg urls: String): Result? {
        var result: Result? = null
        if (!isCancelled && urls.isNotEmpty()) {
            val urlString = urls[0]
            result = try {
                val resultString = downloadUrl(urlString)
                if (resultString != null) {
                    val persons = ArrayList<Person>()
                    if (mPerson == null) {
                        Result(getAllPersons(urlString, persons))
                    }
                    else {
                        persons.add(getPersonHomeworldAndVehicles(urlString, mPerson))
                        Result(persons)
                    }
                } else {
                    throw IOException("No response received.")
                }
            } catch (e: Exception) {
                Result(e)
            }

        }
        return result
    }


    override fun onPostExecute(result: Result?) {
        mCallback?.apply {
            result?.mException?.also { exception ->
                updateUi(null)
                return
            }
            result?.mResultValue?.also { resultValue ->
                updateUi(resultValue)
                return
            }
            finishNetworking()
        }
    }

问题是在我旋转设备后,当我收到来自 asynctask 的回调时,我的视图没有更新,因为当我设置 progressBar.visibility = View.GONE 时进度条仍然可见

【问题讨论】:

  • 你的异步任务代码在哪里?
  • 我用 asynctask 编辑了我的问题

标签: android android-fragments kotlin android-asynctask


【解决方案1】:

好的,现在我看到您从 asyncTask 函数中调用 callback.updateUi()。 这会导致问题,因为当您在异步任务中执行操作时,您处于非 UI 线程中。 为避免此问题,您需要在函数override fun updateUi(result: ArrayList&lt;Person&gt;?)() 中调用 runOnUiThread() 并用 runOnUiThread 块包围所有与 UI 相关的代码。

示例:

override fun updateUi(result: ArrayList<Person>?) {

        runOnUiThread {
            progressBar.visibility = View.GONE
            window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
            if (result != null) {
                setAdapter(result)
            } else {
                finishNetworking()
                val snackBar = Snackbar.make(findViewById(R.id.root_layout),
                        "Network failure", Snackbar.LENGTH_INDEFINITE)
                snackBar.setAction("Try again") {
                    startDownload()
                }
                snackBar.show()
            }
        }

    } 

【讨论】:

  • 已经尝试过runOnUiThread,当我不旋转屏幕时,视图会在回调中更新,但是如果我在异步任务仍在运行时旋转屏幕,当调用回调函数时,视图不会更新甚至在 runOnUiThread 内运行
  • 哦,好吧,这是因为当你旋转屏幕时,你实际上“杀死”了你的回调,后来当结果来自异步任务时,回调并不存在。
猜你喜欢
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 2017-03-14
  • 2021-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多