作者:李若昆

在Android平台中多线程应用很广泛,在UI更新、游戏开发和耗时处理(网络通信等)等方面都需要多线程技术。

当一个程序第一次启动的时候,Android会启动一个主线程。主线程(Main Thread)主要负责处理与UI相关的事件,如:用户的按键事件,用户接触屏幕的事件以及屏幕绘图事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。

为了提供良好的用户体验,必须保证程序有高响应性,所以不能在UI线程中进行耗时的计算或IO操作。

当主线程正在做比较耗时的操作时,如正从网络上下载一个大图片,或者访问数据库,由于主线程被这些耗时的操作阻,无法及时的响应用户的事件,从用户的角度看会觉得程序已经死掉。

所以我们要创建单独的子线程,一些较费时的对象操作需交给独立的线程去执行。

(但如果子线程来执行UI对象,Android就会发出错误信息CalledFromWrongThreadException。)

这里介绍两种方式用多线程操作UI:

第一种是创建新线程Thread,用handler负责线程间的通信和消息。

线程间通信模型如下:



Thread:处理耗时操作的子线程,在需要时通过Handler发送消息(Message);

在Java中有两种方法实现线程体:一是继承线程类Thread,二是实现接口Runnable。

如果采用第1种方式,它继承线程类Thread并重写其中的方法run(),由于Java只支持单重继承,用这种方法定义的类不能再继承其他父类。之后在主线程中实例化该线程,通过start()方法启动子线程,子线程启动之后就开始调用run()方法,run()是一个线程体,我们在子线程中处理事情就是在这里编写代码实现的。

第2种方式可以提供一个实现接口Runnable的类作为一个线程的目标对象,在构造Thread类时候把目标对象(实现Runnable的类)传递给这个线程实例,由该目标对象(实现Runnable的类)提供线程体run()方法。这时候实现接口Runnable的类仍然可以继承其他父类。

Handler:

Handler在android里负责发送和处理消息。它的主要用途有:


1)按计划发送消息或执行某个Runnable(使用POST方法);


2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程)

MessageQueue: 负责给消息排队

Looper:负责不断的从MessageQueue中取出消息,分发给UI处理线程中的Handler来接收。主线程默认有一个Looper对象。

  

默认情况下,Handler接受的是当前线程下的消息循环实例(使用Handler(Looper looper)、Handler(Looper looper, Handler.Callback callback)可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以sendMessage。Handler对于Message的处理不是并发的。一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。

进度条程序:

主线程控制Button响应和更新UI,子线程负责计算进度条进度,程序代码如下:

main.xml:


<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <TextView        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="@string/hello" />    <ProgressBar        android:id="@+id/progressBar1"        style="?android:attr/progressBarStyleHorizontal"        android:layout_width="fill_parent"        android:layout_height="wrap_content" />    <Button        android:id="@+id/button1"        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="Start" /></LinearLayout>


HandlerAcitvity.java:public class HandlerActivity extends Activity implements OnClickListener{private ProgressBar progressBar;Handler handler =new Handler(){//Handler处理收到的子线程消息,更新UI@Overridepublic void handleMessage(android.os.Message msg) {progressBar.setProgress(msg.arg1);handler.post(updateThread);};};//子线程计算进度,这里Thread.sleep(1000)表示休眠1秒,达到每1秒进度跳增加10Runnable updateThread= new Runnable() {int i = 0;public void run() {// TODO Auto-generated method stubSystem.out.println("Begin Thread");i+=10;if(i>=100)i=100;Message msg=handler.obtainMessage();msg.arg1=i;try{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}handler.sendMessage(msg);if(i>=100)handler.removeCallbacks(updateThread);}};//Runnable     /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);                Button btn=(Button)findViewById(R.id.button1);        btn.setOnClickListener(this);        progressBar=(ProgressBar)findViewById(R.id.progressBar1);    }public void onClick(View arg0) {// TODO Auto-generated method stubprogressBar.setVisibility(View.VISIBLE);handler.post(updateThread);}}


运行结果:




下面介绍多线程的第二种方式AsyncTask:

用Handler类来在子线程中更新UI线程虽然避免了在主线程进行耗时计算,但费时的任务操作总会启动一些匿名的子线程,太多的子线程给系统带来巨大的负担,随之带来一些性能问题。

因此android提供了一个工具类AsyncTask,顾名思义异步执行任务。这个AsyncTask生来就是处理一些后台的比较耗时的任务,给用户带来良好用户体验的,从编程的语法上显得优雅了许多,不再需要子线程和Handler就可以完成异步操作并且刷新用户界面。

AsyncTask的执行步骤:

1)继承AsyncTask

2)实现AsyncTask中定义的下面一个或几个方法


onPreExecute(), 该方法将在执行实际的后台操作前被UI 线程调用。可以在该方法中做一些准备工作,如在界面上显示一个进度条,或者一些控件的实例化,这个方法可以不用实现。


doInBackground(Params...), 将在onPreExecute方法执行后马上执行,该方法运行在后台线程中。这里将主要负责执行那些很耗时的后台处理工作。可以调用 publishProgress方法来更新实时的任务进度。该方法是抽象方法,子类必须实现。


onProgressUpdate(Progress...),在publishProgress方法被调用后,UI 线程将调用这个方法从而在界面上展示任务的进展情况,例如通过一个进度条进行展示。

onPostExecute(Result), 在doInBackground 执行完成后,onPostExecute方法将被UI 线程调用,后台的计算结果将通过该方法传递到UI 线程,并且在界面上展示给用户。


onCancelled(),在用户取消线程操作的时候调用。在主线程中调用onCancelled()的时候调用。

为了正确的使用AsyncTask类,以下是几条必须遵守的准则:

1)Task的实例必须在UI 线程中创建

2)execute方法必须在UI 线程中调用

3)不要手动的调用onPreExecute(),onPostExecute(Result),doInBackground(Params...),onProgressUpdate(Progress...)这几个方法,需要在UI线程中实例化这个task来调用。

4)该task只能被执行一次,否则多次调用时将会出现异常


后台计数程序示例:


main.xml:<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <TextView        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:text="@string/hello" />    <TextView        android:id="@+id/textView1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="TextView" />    <Button        android:id="@+id/button1"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="Button" /></LinearLayout>


AsyncTaskActivity.java:


public class AsyncTaskActivity extends Activity implements OnClickListener{private Button Btn;private TextView txt;private int count=0;private boolean isRunning=false;    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        Btn=(Button)findViewById(R.id.button1);        txt=(TextView)findViewById(R.id.textView1);        Btn.setOnClickListener(this);    }public void onClick(View arg0) {// TODO Auto-generated method stubisRunning=true;TimeTickLoad timetick=new TimeTickLoad();timetick.execute();}private class TimeTickLoad extends AsyncTask<Void, Integer, Void> {@Overrideprotected void onPreExecute() {super.onPreExecute();}@Overrideprotected Void doInBackground(Void... arg0) {while (isRunning) {try {Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}count++;publishProgress(null);}return null;}@Overrideprotected void onProgressUpdate(Integer... values) {// TODO Auto-generated method stubtxt.setText("时间已经过去了" + String.valueOf(count) + "S");super.onProgressUpdate(values);}@Overrideprotected void onPostExecute(Void result) {super.onPostExecute(result);}}}


运行结果:




更多相关文章

  1. Android(安卓)中 AsyncTask 的使用
  2. android ANR处理方法
  3. Android(安卓)Service 两种编写及应用
  4. Android面试题整理-3
  5. android 消息传递机制进阶EventBus的深入探究
  6. Android(安卓)方法数 65k 问题
  7. Android(安卓)壁纸设置代码 详解
  8. Android中FTP服务器、客户端搭建以及SwiFTP、ftp4j介绍
  9. android 一个小例子说明handler和AlertDialog的简单使用

随机推荐

  1. Android——Activity跳转
  2. [Build+Android+Development+Environment
  3. Android几种强大的下拉刷新库
  4. android 手机号码归属地查询
  5. Android(安卓)ADT 11.0.0
  6. Android传感器之磁场传感器
  7. android 圆形 ImageView
  8. Appium的一点一滴:UiSelector
  9. linux
  10. android键盘弹出头部上移处理