Android开发小记(三)

Posted by Csming on 2016-12-11

AsyncTask使用的时候遇到了一个小问题

  • 最近的软工实践项目中,在网络请求的时候使用到了AsyncTask异步的方法
  • 队友小超超在使用过程中发现, doInGround()方法中使用的HttpUtil的回调方法一直没办法结束
  • 使得在onPsotExcute()方法有时候回得不到调用,使得UI没有更改
  • 最终无法显示数据
  • 我觉得这个似乎是因为doInGround方法调用的回调函数没办法返回结果值。于是到不了该函数的终点

了解一下AsyncTask

  • 带着疑问,我去网上找了一些博客
  • 以图了解这个机制

Android之所以有Handler和AsyncTask,都是为了不阻塞主线程(UI线程),且UI的更新只能在主线程中完成,因此异步处理是不可避免的。

与Handler对比

说到AsyncTask,就要与Handler对比
1.首先AsyncTask,是android提供的轻量级的异步类,可以直接继承AsyncTask,在类中实现异步操作,并提供接口反馈当前异步执行的程度(可以通过接口实现UI进度更新),最后反馈执行的结果给UI主线程.

  • 优点:

简单快捷,并且过程可控

  • 缺点:

在使用多个异步操作和并需要进行Ui变更时,就变得复杂起来.

2.然后是Handler
在Handler 异步实现时,涉及到 Handler, Looper, Message,Thread四个对象,实现异步的流程是主线程启动Thread(子线程)àthread(子线程)运行并生成Message-àLooper获取Message并传递给HandleràHandler逐个获取Looper中的Message,并进行UI变更。

*优点:

结构清晰,功能定义明确。对于多个后台任务时,简单,清晰

*缺点:

在单个后台异步处理时,显得代码过多,结构过于复杂(相对性)

AsyncTask

AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务
AsyncTask可以使得用户避免直接使用Thread类和Handler 来处理后台操作,适用于需要异步处理数据并将数据更新到界面上的情况。AsyncTask适用于后台操作只有几秒的短时操作。

  • 1.用法

AsyncTask<Params , Progress , Result>
Params启动任务执行的输入参数的类型
Progress后台任务完成的进度
Result后台执行任务完成后返回结果的类型

步骤:
(1).创建AsyncTask子类,并为三个泛型参数指定类型
如果不需要指定则为void
(2).实现AsyncTask的方法:
Params doInBackground(Params…params)后台线程所要完成的任务调用publishProgress(Progress… values)方法更新任务的执行进度
void onProgressUpdate(Progress… Values)在doInBackground()方法中调用publishProgress(Progress… values)方法更新任务的执行进度后触发该方法

void onRreExecute()该方法将在执行后台耗时操作前被调用。通常用来完成一些初始化的准备工作,比如在界面上显示进度条等

void onPostExcute(Result result)在doInBackground(Params…params)完成后调用,并将doInBackground的返回值传给该函数

(3).调用AsyncTask子类的实例的execute(Params… params)

必须在UI线程中创建AsyncTask实例
必须在UI线程中调用execute()
AsyncTask的onPreExecute()、onPostExecute(Result result)、doInBackground(Params…params)、onProgressUpdate(Progress… Values)方法,不应该有程序员代码调用,而是由Android系统负责调用

每个AsyncTask只能被执行一次,多次调用会引发异常

(1).生命周期

很多开发者会认为一个在Activity中创建的AsyncTask会随着Activity的销毁而销毁。然而事实并非如此。AsyncTask会一直执行, 直到doInBackground()方法执行完毕。然后,如果 cancel(boolean)被调用, 那么onCancelled(Result result) 方法会被执行;否则,执行onPostExecute(Result result) 方法。如果我们的Activity销毁之前,没有取消 AsyncTask,这有可能让我们的AsyncTask崩溃(crash)。因为它想要处理的view已经不存在了。所以,我们总是必须确保在销毁活动之前取消任务。总之,我们使用AsyncTask需要确保AsyncTask正确地取消。

另外,即使我们正确地调用了cancle() 也未必能真正地取消任务。因为如果在doInBackgroud里有一个不可中断的操作,比如BitmapFactory.decodeStream(),那么这个操作会继续下去。

(2).内存泄漏

如果AsyncTask被声明为Activity的非静态的内部类,那么AsyncTask会保留一个对创建了AsyncTask的Activity的引用。如果Activity已经被销毁,AsyncTask的后台线程还在执行,它将继续在内存里保留这个引用,导致Activity无法被回收,引起内存泄露。

(3).结果丢失

屏幕旋转或Activity在后台被系统杀掉等情况会导致Activity的重新创建,之前运行的AsyncTask会持有一个之前Activity的引用,这个引用已经无效,这时调用onPostExecute()再去更新界面将不再生效。

(4).并行还是串行

在Android 1.6之前的版本,AsyncTask是串行的,在1.6至2.3的版本,改成了并行的。在2.3之后的版本又做了修改,可以支持并行和串行,当想要串行执行时,直接执行execute()方法,如果需要并行执行,则要执行executeOnExecutor(Executor)。

结语

怎么感觉问题还是没有解决
但是模糊的感觉,主要原因在于数据没获取完的情况下,线程被中断了?
Orz