在机器人的WeakReference / AsyncTask的模式 [英] WeakReference/AsyncTask pattern in android

查看:184
本文介绍了在机器人的WeakReference / AsyncTask的模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于这个简单的android系统中经常发生的情况的问题。

我们有一个主要活动,我们调用的AsyncTask非常久远的mainactivity的参考,以便该AsyncTask的可更新的MainActivity的意见。

我会分解事件到步骤

  • 在MainActivity创建一个AyncTask,将它的参考吧。
  • AysncTask,开始它的工作,下载十个文件,例如
  • ,用户改变了设备的方向。这导致在AsyncTask的
  • 孤儿指针
  • 当AsyncTask的完成,并尝试访问该活动以更新状态,它崩溃,因为空指针。

对于上面的解决方案是保持在AsyncTask的一个WeakReference的所推荐的书临安卓4.0

 的WeakReference<活动> weakActivity;

在方法onPostExecute

活性活性= weakActivity.get();
如果(活动!= NULL){
   //做你的东西与活动在这里
}
 

这是如何解决的情况呢?

我的问题是,如果我的AsyncTask正在下载十个文件,以及5完成后,该活动将重新启动(因为方向变化的),然后将我的FileDownloadingTask再次被调用?

会发生在最初被调用previous AsyncTask的是什么?

感谢你,我对这个问题的长度道歉。

解决方案
  

这是如何解决的情况呢?

的WeakReference 允许活动作为垃圾进行回收,所以你不要有内存泄漏。

一个空引用意味着的AsyncTask 不能的盲目尝试更新不再连接一个用户界面,它会抛出异常(如认为没有连接到窗口管理器)。当然,你必须检查空,以避免NPE。

  

如果我的AsyncTask正在下载十个文件,以及5完成后,该活动将重新启动(因为方向变化的),然后将我的FileDownloadingTask再次被调用?

取决于具体的实现,但或许是肯定的 - 如果你不刻意做些什么,使重复下载不必要的,比如缓存结果的地方

  

将发生在previous什么的AsyncTask 的首次调用?

在早期版本的Andr​​oid将运行到完成,下载的所有文件才扔掉(或者缓存它们,这取决于你的实现)。

在较新的Andr​​oid的,我怀疑的AsyncTask 的正随着活动的开始杀害了他们,但我的基础怀疑仅仅是内存泄漏演示的为 RoboSpice (见下文),实际上并没有泄露我的软糖设备。

如果我可以提供一些建议:的AsyncTask 不适合执行可能长时间运行的任务,如网络。

IntentService 是一个更好的(和还比较简单)的方法,如果一个工作线程是可以接受你。使用(本地)服务如果你想在线程池的控制 - 并注意不要做在主线程上工作

RoboSpice 似乎不错,如果你正在寻找一种方式来可靠地执行在后台联网(免责声明:我没有试了一下,我不隶属于)。有<一个href="https://play.google.com/store/apps/details?id=com.octo.android.robospice.motivations">RoboSpice动机演示应用 Play商店这解释的为什么的你应该演示荷兰国际集团所有的事情,可以去错的AsyncTask - 包括WeakReference的解决方法

请参阅此线程:<一href="http://stackoverflow.com/questions/3357477/is-asynctask-really-conceptually-flawed-or-am-i-just-missing-something">Is AsyncTask的真正概念上的缺陷还是我只是失去了一些东西?

更新:

我创建了一个 GitHub的项目使用下载的例子 IntentService 再SO问题(<一href="http://stackoverflow.com/questions/6343166/android-os-networkonmainthreadexception">android.os.NetworkOnMainThreadException),但它也与此有关,我认为,它有额外的好处是,经由 onActivityResult 返回结果,下载即在飞行中,当你旋转设备将交付到重新启动的活动

I have a question regarding this simple frequently occurring situation in android .

We have a main activity , we invoke an AsyncTask alongwith the reference of the mainactivity , so that that the AsyncTask can update the views on the MainActivity.

I will break down the event into steps

  • MainActivity creates an AyncTask , passes its reference to it .
  • AysncTask , starts it's work , downloading ten files for example
  • The user changed the orientation of the device. This results in an orphan pointer in the AsyncTask
  • When the AsyncTask completes , and tries to access the activity to update the status , it crashes , because of the null pointer .

The solution for the above is to keep a WeakReference in the AsyncTask as recommended by the book "Pro Android 4"

WeakReference<Activity> weakActivity;

in method onPostExecute

Activity activity = weakActivity.get();
if (activity != null) {
   // do your stuff with activity here
}

How does this resolve the situation ?

My question it , if my asynctask is downloading ten files , and upon completion of 5 the activity is restarted (because of an orientation change) then would my FileDownloadingTask be invoked once again ?.

What would happen to the previous AsyncTask that was initially invoked ?

Thank you , and I apologize for the length of the question .

解决方案

How does this resolve the situation ?

The WeakReference allows the Activity to be garbage collected, so you don't have a memory leak.

A null reference means that the AsyncTask cannot blindly try to update a user-interface that is no longer attached, which would throw exceptions (e.g. view not attached to window manager). Of course you have to check for null to avoid NPE.

if my asynctask is downloading ten files , and upon completion of 5 the activity is restarted (because of an orientation change) then would my FileDownloadingTask be invoked once again ?.

Depends on your implementation, but probably yes - if you don't deliberately do something to make a repeat download unnecessary, such as caching the results somewhere.

What would happen to the previous AsyncTask that was initially invoked ?

In earlier versions of Android it would run to completion, downloading all of the files only to throw them away (or perhaps cache them, depending on your implementation).

In newer Android's I am suspicious that AsyncTask's are being killed along with the Activity that started them, but my basis for suspicion is only that the memory-leak demo's for RoboSpice (see below) do not actually leak on my JellyBean devices.

If I may offer some advice: AsyncTask is not suitable for performing potentially long running tasks such as networking.

IntentService is a better (and still relatively simple) approach, if a single worker thread is acceptable to you. Use a (local) Service if you want control over the thread-pool - and be careful not to do work on the main thread!

RoboSpice seems good if you are looking for a way to reliably perform networking in the background (disclaimer: I have not tried it; I am not affiliated). There is a RoboSpice Motivations demo app in the play store which explains why you should use it by demo-ing all the things that can go wrong with AsyncTask - including the WeakReference workaround.

See also this thread: Is AsyncTask really conceptually flawed or am I just missing something?

Update:

I created a github project with an example of downloading using IntentService for another SO question (android.os.NetworkOnMainThreadException), but it is also relevant here, I think. It has the added advantage that, by returning the result via onActivityResult, a download that is in flight when you rotate the device will deliver to the restarted Activity.

这篇关于在机器人的WeakReference / AsyncTask的模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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