如何实现从一个保留片段主办的异步任务坚持更改UI? [英] How to deliver and persist changes to the UI from an asynchronous task hosted by a retained fragment?

查看:129
本文介绍了如何实现从一个保留片段主办的异步任务坚持更改UI?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用保留的片段主办异步任务是不是一个新概念(见亚历克斯·洛克伍德的出色的博客文章的话题)

但是使用这个从AsyncTask的回调提供内容时回到我的活动,我碰到的问题后。具体来说,我发现,试图解雇一个对话框,可能会导致IllegalStateException。同样,对于这种解释可以另一篇博客通过亚历克斯·洛克伍德。具体来说,这部分解释是怎么回事:


  

避免内部异步回调方式进行交易。


  
  

这包括常用的方法,如AsyncTask的#onPostExecute()
  和LoaderManager.LoaderCallbacks#onLoadFinished()。这个问题
  在这些方法中执行交易的是,它们没有
  当它们的活动周期的当前状态的知识
  调用。例如,考虑事件的顺序如下:


  
  

      
  1. 一个活动执行的AsyncTask的。

  2.   
  3. 用户presses的Home键,
      导致活动的的onSaveInstanceState()和的onStop()方法来
      被调用。

  4.   
  5. 的AsyncTask的完成,onPostExecute()被调用,
      不知道该活动已经被停止了。

  6.   
  7. 系统FragmentTransaction是onPostExecute内提交()方法,
      引起异常被抛出。

  8.   

不过,在我看来,这是一个更广泛问题的一部分,它只是碰巧片段经理抛出一个异常,让你意识到这一点。一般情况下,任何改变您对UI后的onSaveInstanceState()将丢失。因此,建议


  

避免内部异步回调方式进行交易。


其实应该是:


  

避免内部异步回调方法进行UI更新。


问题:


  1. 如果使用这种模式,你应该因此取消任务,的onSaveInstanceState preventing回调()如果不转?

像这样:

  @覆盖
公共无效的onSaveInstanceState(捆绑outState)
{
    如果(!isChangingConfigurations())
    {
        //如果我们不旋转,我们需要在持续的任务失去兴趣,并取消
        mRetainedFragment.cancelOnGoingTask();
    }
    super.onSaveInstanceState(outState);
}

<醇开始=2>

  • 如果您甚至懒得使用保留的片段都保留正在进行的任务是什么?它会更有效,始终标志着模型关于正在进行的请求的东西吗?或者做类似RoboSpice在那里,如果它正在等待您可以重新连接到正在进行的任务。为了得到一个类似的行为给保留的片段,你必须取消,如果你停止了超过一个配置变化等原因的任务。


  • 这是第一个问题继续:即使在一个配置的变化,你不应该在的onSaveInstanceState作出任何UI更新(),所以你其实应该做这样的事情这样的:


  • 粗糙code:

      @覆盖
    公共无效的onSaveInstanceState(捆绑outState)
    {
        如果(!isChangingConfigurations())
        {
            //如果我们不旋转,我们需要在持续的任务失去兴趣,并取消
            mRetainedFragment.cancelOnGoingTask();
        }
        其他
        {
            mRetainedFragment.beginCachingAsyncResponses();
        }
        super.onSaveInstanceState(outState);
    }@覆盖
    公共无效onRestoreInstanceState(束安置)
    {
        super.onRestoreInstanceState(安置);
        如果(inState!= NULL)
        {
            mRetainedFragment.stopCachingAndDeliverAsyncResponses();
        }
    }

    beginCachingAsyncResponses()会做这样的事情看到<一的PauseHandler href=\"http://stackoverflow.com/questions/8040280/how-to-handle-handler-messages-when-activity-fragment-is-paused\">here


    在现场应用
    解决方案

    从一个开发者的角度,避免NPE的'是企业的第一顺序。像 onPostExecute方法() 的AsyncTask onResume()&安培; 的onError()在凌空请求,地址:

     活动= getActivity();
    如果(活动= NULL&放大器;!&放大器;如果(isAdded())){    //继续...}

    里面的活动应该是

     如果(这个!= NULL){    //继续...}

    这是不雅。和低效的,因为其他线程的工作依然不减。但是,这将让应用程序躲闪的NPE。除此之外,还有各种调用取消()的onPause方法()的onStop()的onDestroy()

    现在来的配置更改和应用程序退出的更一般的问题。我读过的AsyncTask 和排球请求取值应该只从服务执行 s且不活动 S,因为服务继续朝着运行,即使用户退出应用程序。

    Using a retained fragment to host asynchronous tasks is not a new idea (see Alex Lockwood's excellent blog post on the topic)

    But after using this I've come up against issues when delivering content back to my activity from the AsyncTask callbacks. Specifically, I found that trying to dismiss a dialog could result in an IllegalStateException. Again, an explanation for this can be found in another blog post by Alex Lockwood. Specifically, this section explains what is going on:

    Avoid performing transactions inside asynchronous callback methods.

    This includes commonly used methods such as AsyncTask#onPostExecute() and LoaderManager.LoaderCallbacks#onLoadFinished(). The problem with performing transactions in these methods is that they have no knowledge of the current state of the Activity lifecycle when they are called. For example, consider the following sequence of events:

    1. An activity executes an AsyncTask.
    2. The user presses the "Home" key, causing the activity's onSaveInstanceState() and onStop() methods to be called.
    3. The AsyncTask completes and onPostExecute() is called, unaware that the Activity has since been stopped.
    4. A FragmentTransaction is committed inside the onPostExecute() method, causing an exception to be thrown.

    However, it seems to me that this is part of a wider problem, it just happens that the fragment manager throws an exception to make you aware of it. In general, any change you make to the UI after onSaveInstanceState() will be lost. So the advice

    Avoid performing transactions inside asynchronous callback methods.

    Actually should be:

    Avoid performing UI updates inside asynchronous callback methods.

    Questions:

    1. If using this pattern, should you therefore cancel your task, preventing callbacks in onSaveInstanceState() if not rotating?

    Like so:

    @Override
    public void onSaveInstanceState(Bundle outState)
    {
        if (!isChangingConfigurations())
        {
            //if we aren't rotating, we need to lose interest in the ongoing task and cancel it
            mRetainedFragment.cancelOnGoingTask();
        }
        super.onSaveInstanceState(outState);
    }
    

    1. Should you even bother using retained fragments at all for retaining ongoing tasks? Will it be more effective to always mark something in your model about an ongoing request? Or do something like RoboSpice where you can re-connect to an ongoing task if it is pending. To get a similar behaviour to the retained fragment, you'd have to cancel a task if you were stopping for reasons other than a config change.

    2. Continuing from the first question: Even during a config change, you should not be making any UI updates after onSaveInstanceState() so should you actually do something like this:

    Rough code:

    @Override
    public void onSaveInstanceState(Bundle outState)
    {
        if (!isChangingConfigurations())
        {
            //if we aren't rotating, we need to lose interest in the ongoing task and cancel it
            mRetainedFragment.cancelOnGoingTask();
        }
        else
        {
            mRetainedFragment.beginCachingAsyncResponses();
        }
        super.onSaveInstanceState(outState);
    }
    
    @Override
    public void onRestoreInstanceState(Bundle inState)
    {
        super.onRestoreInstanceState(inState);
        if (inState != null)
        {
            mRetainedFragment.stopCachingAndDeliverAsyncResponses();
        }
    }
    

    The beginCachingAsyncResponses() would do something like the PauseHandler seen here

    解决方案

    From a developer's point of view, avoiding NPEs' in a live app is the first order of business. To methods like onPostExecute() of AsyncTask and onResume() & onError() in a Volley Request, add:

    Activity = getActivity();
    if(activity != null && if(isAdded())){
    
        // proceed ...
    
    }
    

    Inside an Activity it should be

    if(this != null){
    
        // proceed ...
    
    }
    

    This is inelegant. And inefficient, because the work on other thread continues unabated. But this will let the app dodge NPEs'. Besides this, there is the calling of various cancel() methods in onPause(), onStop() and onDestroy().

    Now coming to the more general problem of configuration changes and app exits. I've read that AsyncTasks and Volley Requests should only be performed from Services and not Activitys, because Services continue to run even if the user "exits" the app.

    这篇关于如何实现从一个保留片段主办的异步任务坚持更改UI?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆