0.  前言

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

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

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

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

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


2.  异步任务和进度条

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

这里使用AsyncTask进行异步任务,不熟悉AsyncTask的可以参考Android开发——AsyncTask的使用以及源码解析,任务开始时显示了一个FragmentDialog对话框,如果不熟悉可以参考Android开发——官方推荐使用DialogFragment替换AlertDialog,这里就不赘述了。任务下载中时,我们模拟了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<String> mDatas;private KeepDataFragment dataFragment;private MyAsyncTask mMyTask;@Overridepublic 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();}}@Overrideprotected void onRestoreInstanceState(Bundle state) {super.onRestoreInstanceState(state);}@Overrideprotected void onSaveInstanceState(Bundle outState) {mMyTask.setActivity(null);super.onSaveInstanceState(outState);}@Overrideprotected void onDestroy() {super.onDestroy();}public void onTaskCompleted() {mDatas = mMyTask.getItems();mAdapter = new ArrayAdapter<String>(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

Android开发——异步任务中Activity销毁时的问题相关推荐

  1. android bitmap着色,android开发 替换bitmap中的颜色值

    /** * 将bitmap中的某种颜色值替换成新的颜色 * @param bitmap * @param oldColor * @param newColor * @return */ public ...

  2. # android开发:4-1、Activity启动方式、生命周期、不同activity的数据传递

    4.Activity活动简介 什么是Activity: 如何创建Activity: Activity启动方式: Activity的生命周期: 不同Activity之间数据的传递: 什么是Activit ...

  3. android设计一个多线程和画图的程序小球,Android开发之多线程中实现利用自定义控件绘制小球并完成小球自动下落功能实例...

    本文实例讲述了Android开发之多线程中实现利用自定义控件绘制小球并完成小球自动下落功能的方法.分享给大家供大家参考,具体如下: 1.布局界面 xmlns:tools="http://sc ...

  4. Android开发 - 解决DialogFragment在全屏时View被状态栏遮住的问题

    Android开发 - 解决DialogFragment在全屏时View被状态栏遮住的问题 参考文章: (1)Android开发 - 解决DialogFragment在全屏时View被状态栏遮住的问题 ...

  5. android开发出现No Launcher activity found!解决方案

    android开发出现No Launcher activity found!解决方案 参考文章: (1)android开发出现No Launcher activity found!解决方案 (2)ht ...

  6. Android开发艺术探索之Activity篇总结

    本文内容来自<Android开发艺术探索>第一章,个人学习提炼总结,欢迎指正. 1.1典型情况下的生命周期 onCreate():表示Activity正在被创建,初始化布局资源+Activ ...

  7. [Android开发]cocos2dx工程中接入支付宝sdk

    cocos2dx工程中接入支付宝sdk 1. 首先去支付宝官网下载开发者文档 2. 然后按着开发者文档将支付宝的sdk导入到你的工程中,并关联到工程中,步骤入下图: (1)将从支付宝官方网站获得的支付 ...

  8. android cursor关闭,android在异步任务中关闭Cursor的代码方法

    查询数据会比较耗时,所以我们想把查询数据放在一个异步任务中,查询结果获得Cursor,然后在onPostExecute (Cursor result)方法中设置Adapter,我们可能会想到使用Act ...

  9. android studio2.3安装apk,在Android Studio 2.3中安装apk时出错

    工具: > Android Studio 2.3 > Firebase 设备测试 >三星GT-I9505 >三星SM-T211 设备OS: > Android 5.0 问 ...

最新文章

  1. Python itertools库详细教程
  2. 还有更多REST技巧
  3. LeetCode 367. 有效的完全平方数(二分查找)
  4. Zookeeper数据一致性原理
  5. c# 定义委托和使用委托(事件的使用)
  6. .AsEnumerable() 和 .ToList() 的区别:
  7. 【Linux】如何在文件中写入感叹号
  8. 操作系统原理好书推荐
  9. MQ队列管理器_PMTS命令
  10. Centos禁止屏幕虚拟键盘弹出
  11. 通过CImageList加载图标 报错
  12. dss中文含义_DSS(中文译名:决策支持系统),这是什么系统?有多少个种类?...
  13. OPTEE学习笔记 - IPC
  14. SAP库存查询MB52报表如何设置为ALV格式显示?
  15. 评价页面,随手写的评价简陋模板
  16. 英语练习 Tony and Tina
  17. 面试总结 -记周六校招笔试
  18. Tomcat SSL Failed to load keystore type JKS with path 系统找不到指定文件
  19. 网易我的世界服务器看不到聊天信息,网易禁止文字?我的世界:文字消失“不可逆”的6种解决办法...
  20. 微信开放平台开发第三方授权登陆:微信扫码登录

热门文章

  1. 【问链财经-区块链基础知识系列】 第二十七课 区块链与分布式账本的异同
  2. php页面调用时间戳,php--------获取当前时间、时间戳
  3. autojs 如何获取控件的desc_Autojs Pro中,常用的几个选择器搜索接口的区别-技术类-雨后春笋...
  4. JZOJ 5400. 【NOIP2017提高A组模拟10.7】Repulsed
  5. html如何引入less,VueJS如何引入css或者less文件的一些坑
  6. androidstudio sqlite where 条件_SQL 面试题:WHERE 和 HAVING、ON 有什么区别?
  7. CVPR 2020 运行12-in-1遇到的问题及解决办法(持续更新中)
  8. 2017年10月21日普及组 排名
  9. 羊车门问题python_python编程羊车门问题代码示例
  10. git 查看修改明细_git 查看指定文件的修改历史记录