Android MultiThread & Handler & AsyncTask

Thread 是一个并发的执行单元,在java中实现线程一是通过继承Thread类,二是实现Ruunable接口,当开始一个新线程的时候必须call start(),但是线程并不是马上就run起来,而是注册到JVM的线程调度器中准备run。

涉及对象:主线程和新启动的线程。

Handler的做要作用,主要接受子线程发送的数据,然后用这个数据去更新主线程的UI

解析:

每个Android应用程序都运行在一个dalvik虚拟机进程中,进程开始的时候会启动一个主线程,由于android采用的是UI单线程模型,所以只能在UI主线程中来管理界面中的UI控件,进行时间分发,如点击一个Button的时候将分发一个事件响应函数来操作,这个过程将很短暂不是长时间的操作。但是如果是一些耗时的操作比如读取网页数据,不能在主线程中实现,不然的话就因为长时间不能响应而出现假死现象,如果5秒钟还没有完成的话,Android系统就将发出一个”强制关闭“的错误提示。

所以我们将耗时操作放在一个子线程中,因为子线程涉及到更新UI。Android 的主线程不是线程安全的,也就是说要实现更新UI只能在主线程中更新,在子线程中操作时危险的,所以Android中就定义了一个Handler类来处理该问题。

Handler对象定义在UI主线程中,子线程和主线程要通信就需要发送Message,然后处理Message中带有的数据,这个时候Handler就承担接受子线程传递过来的Meaasge对象,然后把message放入主线程队列中,来更新主线程的UI。

说的通俗一点就是Handler就是在各个线程之间的一个中转数据处理站的作用。

编程模型:

public class myActivity extends Activity {

//定义其他UI控件

    private Handler myHandler = new Handler() {

public void handlerMessage(Message msg) {

//实现消息处理函数

}

};


//定义一个子线程, 在子线程中进行计算处理或者逻辑处理

//将处理的结果封装成Message实例然后传递给主线程,在handlerMessage()

函数中主要处理就是接受子线程发送过来的Message,然后进行功能处理。

}


过程详解:

非UI线程发送Message到UI线程分量两个步骤:

UI线程-----------------------------------------------------------------UI线程

1)定义Handler对象----------------------------------------------------1)创建线程

2)实现handlerMessage()处理函数---------------------------------2)在run()方法中实现要实现的功能

......................------------------------------------------------------------3)处理结果封装成Message

3)handler对象获取Message,也就是将message发送到了handler的消息队列中了


Message:消息,包含消息ID,消息处理对象以及处理的数据等,有MessageQueue统一列队,然后最终每个Message消息有Handler来处理。

Handler:发送消息,接受消息,然后重写handleMessage(Message msg)消息来处理Message。

MessageQueue:消息队列,用来存放Handler发送过来的消息,将Message添加到队列的末尾,然后这些消息被Looper抽取出来,然后由Handler来处理。

Looper:不断的从MessageQueue中抽取出来Message来执行,所以一个MessageQueue需要有一个Looper。

Looper和MessageQueue是一一对应的关系,而多个Handler可以共享MessageQueue和Looper,当然这些Handler也就运行在同一个线程里面。

Looper.prepare():函数用来封装android线程中的消息循环,默认情况下一个线程是不存在消息循环的,需要调用Loop.prepare()来给线程创建一个消息循环,调用Looper.loop()来让MessageQueue中的消息循环起来,取出消息,交给handler处理。常用的方法是:

public class myThread extends Thread {

@Override
public void run() {
// TODO Auto-generated method stub
Looper.prepare();
handler = new Handler() {
//消息处理函数
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
//获取消息然后处理
switch(msg.what) {
case MSG : System.out.println("the message is:" + msg.obj);
//Log.d("the recived message is :", (String) msg.obj);
}
}
};
Looper.loop();
}

Note: 在Looper.loop()后的代码不会被立即执行,当调用mHandler.getLooper().quit()方法后,loop才会中止,然后之后的代码才会运行。一个线程只能对应一个Looper。


AsyncTask

AsyncTask是在Android SDK 1.5之后推出的一个方便编写后台线程和UI线程交互的辅助类。它的实现是通过一个内部的线程池,每个后台任务装载到线程池中的一个线程,然后在执行该线程。AsyncTask抽象出后台线程运行的五个状态:1,准备运行。2,正在后台运行。3,进度更新。4,完成后台任务。5,取消任务。

AsyncTask是一个一个泛型类,原型为:android.os.AsyncTask<Params, Progress, Result>

Params:启动任务执行的输入参数,比如Http请求的URL。

Progress:后台任务执行的百分比。

Result:后台执行任务的最终返回结果,不如String。

要实现的方法:

onPreExecute()------->准备阶段:该方法将在执行实际的后台操作前被UI thread调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条。

doInBackground(Params...)------>正在后台运行:该回调函数由后台线程在onPreExecute()方法执行结束后立即调用。通常在这里执行耗时的后台计算。计算的结果必须由该函数返回,并被传递到onPostExecute()中。在该函数内也可以使用publishProgress(Progress...)来发布一个或多个进度单位(unitsof progress)。这些值将会在onProgressUpdate(Progress...)中被发布到UI线程。

onProgressUpdate(Progress...)--------->进度更新:该函数由UI线程在publishProgress(Progress...)方法调用完后被调用。一般用于动态地显示一个进度条。

onPostExcute(Result)-------->完成后台任务:当后台计算结束后调用。后台计算的结果会被作为参数传递给这一函数。

onCancelled()-------------->取消任务:在调用AsyncTask的cancel()方法时调用

为了正确的使用AsyncTask类,以下是几条必须遵守的准则: 
  1) Task的实例必须在UI thread中创建 
  2) execute方法必须在UI thread中调用 
  3) 不要手动的调用onPreExecute(), onPostExecute(Result),doInBackground(Params...), onProgressUpdate(Progress...)这几个方法 
  4) 该task只能被执行一次,否则多次调用时将会出现异常 
      doInBackground方法和onPostExecute的参数必须对应,这两个参数在AsyncTask声明的泛型参数列表中指定,第一个为doInBackground接受的参数,第二个为显示进度的参数,第第三个为doInBackground返回和onPostExecute传入的参数。

AsyncTask的本质是一个线程池,然后提交的异步任务将装载在一个线程中然后执行,当工作的线程需要更UI线程交互时,

总结:Handler和AsyncTask都是为了主线程不被阻塞UI线程,但是UI的更新只能在UI主线程这个完成这是因为Android的单线程模型,所以要异步的完成。

AsyncTask 的优势体现在:
•线程的开销较大,如果每个任务都要创建一个线程,那么应用程 序的效率要低很多; 
•线程无法管理,匿名线程创建并启动后就不受程序的控制了,如果有很多个请求发送,那么就会启动非常多的线程,系统将不堪重负。 
•另外,前面已经看到,在新线程中更新UI还必须要引入handler,这让代码看上去非常臃肿。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一个android平台上的 扩展任务库,在AsyncTask基础上进行扩展。 用法 1.继承 com.github.snowdream.android.util.concurrent.AsyncTask //inherit a class from com.github.snowdream.android.util.concurrent.AsyncTask public class DownloadFilesTask extends AsyncTask { public DownloadFilesTask(TaskListener listener) { //explicit inherit the construction from the super class. super(listener); } /** * TODO * if error occurs,carry it out. * * if (listener != null) { * listener.onError(new Throwable()); * } */ protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i ) { totalSize = 10; publishProgress((int) ((i / (float) count) * 100)); // Escape early if cancel() is called if (isCancelled()) break; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } return totalSize; } } 2.定义一个 TaskListener.其中的第一个泛型参数是返回结果类型,第二个泛型参数是任务进度的类型。 private TaskListener listener = new TaskListener(){ @Override public void onStart() { super.onStart(); Log.i("onStart()"); } @Override public void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); Log.i("onProgressUpdate(values)" values[0] ); } @Override public void onSuccess(Long result) { super.onSuccess(result); Log.i("onSuccess(result)" result); } @Override public void onCancelled() { super.onCancelled(); Log.i("onCancelled()"); } @Override public void onError(Throwable thr) { super.onError(thr); Log.i("onError()"); } @Override public void onFinish() { super.onFinish(); Log.i("onFinish()"); } }; 3.创建一个AsyncTask任务,并且执行。 URL url = null; try { url = new URL("http://www.baidu.com/"); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } new DownloadFilesTask(listener).execute(url,url,url); 标签:android
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值