博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android开发——异步任务中Activity销毁时的问题
阅读量:5278 次
发布时间:2019-06-14

本文共 5004 字,大约阅读时间需要 16 分钟。

0.  前言

在Android开发中经常会发生Activity的销毁重建,比如用户长时间接听一个电话后回到APP。在我们提到了使用Fragment大量保存Activity销毁重建数据的方法,但是有一个问题是,在异步任务时旋转屏幕,如何处理异步任务呢?如果单纯的在Activity销毁之前关闭上一个异步任务,onPostExecute()中的关闭对话框就不会走了,会出现对话框无法关闭的现象;如果不关闭,可能会更新已经不存在的控件,造成错误,不仅如此最主要的是Activity的销毁会造成对话框dismiss空指针异常,因为与当前对话框绑定的FragmentManager已经是null

因此我们的目标是在异步加载数据时旋转屏幕,不会对加载任务进行中断重启,并且对话框正常显示

1.  继承Fragment并在其中声明引用

public class KeepDataFragment extends Fragment {    // 保存一个异步的任务    private MyAsyncTask data;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setRetainInstance(true);    }    public void setData(MyAsyncTask data) {        this.data = data;    }    public MyAsyncTask getData() {        return data;    }}

这里我们创建KeepDataFragment并继承Fragment,并在其中声明需要保存的数据对象,这里是保存了一个异步的任务,然后提供gettersetter。最后一定要在onCreate调用setRetainInstance(true)

2.  异步任务和进度条

public class MyAsyncTask extends AsyncTask
{ private MainActivity activity; private boolean isCompleted; private LoadingDialog mLoadingDialog; private List
items; public MyAsyncTask(MainActivity activity) { this.activity = activity; } @Override protected void onPreExecute() { mLoadingDialog = new LoadingDialog(); mLoadingDialog.show(activity.getFragmentManager(), "LOADING"); } @Override protected Void doInBackground(Void... params) { items = loadingData(); return null; } private List
loadingData() { try { Thread.sleep(5000); } catch (InterruptedException e) {} return new ArrayList
(Arrays.asList("东南大学", "信息科学与工程学院", "信息安全学科")); } @Override protected void onPostExecute(Void unused) { isCompleted = true; notifyActivityTaskCompleted(); if (mLoadingDialog != null) mLoadingDialog.dismiss(); } public List
getItems() { return items; } public void setActivity(MainActivity activity) { // 如果上一个Activity销毁,将与上一个Activity绑定的DialogFragment销毁 if (activity == null) { mLoadingDialog.dismiss(); } // 设置为当前的Activity this.activity = activity; // 开启一个与当前Activity绑定的等待框 if (activity != null && !isCompleted) { mLoadingDialog = new LoadingDialog(); mLoadingDialog.show(activity.getFragmentManager(), "LOADING"); } // 如果完成,通知Activity if (isCompleted) { notifyActivityTaskCompleted(); } } private void notifyActivityTaskCompleted() { if (null != activity) { activity.onTaskCompleted(); } }}

这里使用AsyncTask进行异步任务,不熟悉AsyncTask的可以参考任务开始时显示了一个FragmentDialog对话框,如果不熟悉可以参考,这里就不赘述了。任务下载中时,我们模拟了5秒耗时任务并返回了一个字符串List。下载任务结束时让进度框消失,并为Activity提供回调,因为这里持有了Activity的引用。这里我们也提供了setActivity方法,在Activity被销毁时在onSaveInstanceState()中设置setActivity(null)取消之前的对话框,同时也防止了内存泄漏;当Activity重建时在onCreate()中设置setActivity(this)传入新的Activity,从而再次显示一个加载框,这里需要注意的是Activity的销毁重建并不影响加载的数据,所有后台的数据一直继续在加载

3.  MainActivity中的实现

public class MainActivity extends ListActivity {    private ListAdapter mAdapter;    private List
mDatas; private KeepDataFragment dataFragment; private MyAsyncTask mMyTask; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); FragmentManager fm = getFragmentManager(); dataFragment = (KeepDataFragment) fm.findFragmentByTag("data"); if (dataFragment == null) { dataFragment = new KeepDataFragment(); fm.beginTransaction().add(dataFragment, "data").commit(); } mMyTask = dataFragment.getData(); if (mMyTask != null) { //使AsyncTask持有Activity的引用 mMyTask.setActivity(this); } else { mMyTask = new MyAsyncTask(this); dataFragment.setData(mMyTask); mMyTask.execute(); } } @Override protected void onRestoreInstanceState(Bundle state) { super.onRestoreInstanceState(state); } @Override protected void onSaveInstanceState(Bundle outState) { mMyTask.setActivity(null); super.onSaveInstanceState(outState); } @Override protected void onDestroy() { super.onDestroy(); } public void onTaskCompleted() { mDatas = mMyTask.getItems(); mAdapter = new ArrayAdapter
(MainActivity.this, android.R.layout.simple_list_item_1, mDatas); setListAdapter(mAdapter); }}

onCreate中,如果是第一次进入,则Activity引用传给AsyncTask、开启任务mMyTask并把它交给KeepDataFragment来维护,正常情况下AsyncTask正常进行,完成后回调Activity中的onTaskCompleted()。注意要考虑不正常的情况,即加载过程中屏幕的旋转Activity销毁时设置setActivity(null)取消之前的对话框,并在Activity重建时KeepDataFragment 实例因为未被销毁直接通过dataFragment.getData() 取出加载任务mTask并设置setActivity(this)从而再次显示一个新的加载框,直到任务完成正常进行Activity的回调显示数据方法。

看一下如下效果,加载数据的5秒钟内无论如何旋转屏幕都不会出现问题,这样就完成了进行异步任务时Activity的销毁重建不会发生中断并开启新的下载任务,而且对话框也会正常显示。

源码下载地址。

转载于:https://www.cnblogs.com/qitian1/p/6461454.html

你可能感兴趣的文章
div或者p标签单行和多行超出显示省略号
查看>>
Elasticsearch 滚动重启 必读
查看>>
Hadoop基本概念
查看>>
java.util.zip压缩打包文件总结一:压缩文件及文件下面的文件夹
查看>>
浅说 apache setenvif_module模块
查看>>
MySQL--数据插入
查看>>
重新学习python系列(二)? WTF?
查看>>
shell脚本统计文件中单词的个数
查看>>
SPCE061A学习笔记
查看>>
sql 函数
查看>>
hdu 2807 The Shortest Path 矩阵
查看>>
熟悉项目需求,要知道产品增删修改了哪些内容,才会更快更准确的在该项目入手。...
查看>>
JavaScript 变量
查看>>
java实用类
查看>>
smarty模板自定义变量
查看>>
研究称90%的癌症由非健康生活习惯导致
查看>>
命令行启动Win7系统操作部分功能
查看>>
排序sort (一)
查看>>
Parrot虚拟机
查看>>
Teamcenter10 step-by-step installation in Linux env-Oracle Server Patch
查看>>