Android多线程编程

October 23, 2015
JavaAndroid

学过Java的人对多线程编程一定不会陌生,多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。这篇文章将会讲解Android开发中多线程的使用。

1.什么时候会用到多线程?

在开发的过程中,难免会遇到一个耗时的操作,比如像服务器请求数据,由于不是在本地,考虑网速和服务器响应时间的原因,这个操作往往不会再一瞬间就完成。如果不去新建一个子进程来执行这个操作而直接在主进程来执行这个操作的话,主进程就会被阻塞(Blocked),这样主线程将不会去响应用户之后的操作,比如在执行联网操作时候,用户点击app界面的时候app是不会有反应的,因为主线程正在进行联网操作而不能去响应用户界面更新操作。这样会大大影响用户体验。
(不过在Android 2.3之后网络连接这类的耗时操作已经不能放在主线程中运行了,会抛出 NetworkOnMainThread 异常而无法完成编译)。

2.线程的基本用法

thread

Android的多线程编程其实和Java差不多,可以通过集成Thread类然后重写run方法来实现创建新的线程。

Life-cycle-of-a-thread

  1. public class myThread extends Thread {
  2. @Override
  3. public void run() {
  4. //Write code here
  5. super.run();
  6. }
  7. }

如果想运行那个新的子线程,可以创建那个线程的对象并且调用start方法就可以启动线程。

  1. myThread thread=new myThread();
  2. thread.start();

可是直接继承Thread类来实现的耦合性比较高所以一般更推荐使用实现Runnable接口来定义线程

  1. public class myThread implements Runnable{
  2. @Override
  3. public void run() {
  4. //Write code here
  5. super.run();
  6. }
  7. }

当然,如果觉得这样太麻烦的话也可以使用匿名类的方式来实现线程的创建于运行(这个方法比较常见)

  1. new Thread(new Runnable() {
  2. @Override
  3. public void run() {
  4. //Write code here!
  5. }
  6. }).start();

上面的线程创建方法和Java一样,接下来来谈一谈Android多线程和Java中不同的地方。

3.Android中特有的多线程方法

曾经刚学习安卓的时候写过一个指南针的软件,其中有一个功能就是把GPS坐标转换成地址然后显示在屏幕上。这个功能的原理就是GPS获取经纬度,然后发送到一个服务器,服务器会转换坐标,然后将地址发回来,然后调用TextView组件的setText方法来吧街道信息显示在主界面上。

这个过程说起来没什么难度好像使用刚才所说的创建一个子线程处理网络然后更新TextView来实现,但是实际上这样并不可以,编译的时候会抛出
CalledFromWrongThreadException

callfromwrongthread

所以这就证实了Android是不允许在子线程中更新UI。可是,有的时候我们必须在子线程里面执行耗时的任务然后根据子线程执行后返回的结果来更新相应的UI。这时,就得用上Android中提供的异步消息处理机制了。

异步消息机制有两种 Handler机制和AsyncTask机制。接下来将分别介绍这两种机制。

1.Handler

Handler
机制,它是Runnable和Activity交互的桥梁,在run方法中发送Message,在Handler里,通过不同的Message执行不同的任务。

handler_system

下面的代码将会使用Thread来更新一个TextView UI控件

  1. <pre>public class MainActivity extends Activity {
  2. private static final int UPDATE_TEXTVIEW=1;
  3. private TextView textView;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.activity_main);
  8. textView= (TextView) findViewById(R.id.TextView);
  9. //建立子线程
  10. new Thread(new Runnable() {
  11. @Override
  12. public void run() {
  13. //10后发送Message给Handler来更新TextView UI
  14. try {
  15. sleep(10000);
  16. Message message=new Message();
  17. message.what=UPDATE_TEXTVIEW;
  18. handler.sendMessage(message);
  19. } catch (InterruptedException e) {
  20. e.printStackTrace();
  21. }
  22. }
  23. }).start();
  24. }
  25. private Handler handler=new Handler() {
  26. @Override
  27. public void handleMessage(Message msg) {
  28. switch (msg.what){
  29. case UPDATE_TEXTVIEW:
  30. textView.setText("Handler updated TextView UI!");
  31. break;
  32. default:
  33. break;
  34. }
  35. super.handleMessage(msg);
  36. }
  37. };
  38. }</pre>

以上代码中启动了一个子线程,10秒后会发送一个Message出去。然后通过创建一个Handler对象然后重写父类的hanldeMessage方法来处理子线程发给Handler的Message对象。如果Handler发现what的值是UPDATE_TEXTVIEW然后TextView控件将被更细成显Handler
updated TextView UI!字样。

了解了以上的代码就掌握了Android异步消息处理的基本方法,这样就可以解决在子线程中更新UI的问题了。

不过Android提供了一种更加方便的方法来方便我们在子线程中对UI尽享操作,那就是AsyncTask类。

2.AsyncTask

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

AsyncTask是Android
API中的一个抽象类,所以要想实现我们必须去创建一个子类来继承他。继承时可以传进去3个泛型参数,分别是Parms,Progress,Result。

Parms用来承接执行AsyncTask时候的参数,用于执行的时候使用。

Progress用于后台执行任务的时候需要在界面上显示当前进度。

Result用于执行完毕后对结果的返回

所以,要想定义一个新的AsyncTask可以这么写:

  1. <pre>class demoTask extends AsyncTask<Void,Void,Boolean>{
  2. @Override
  3. protected Boolean doInBackground(Void... params) {
  4. return false;
  5. }
  6. }</pre>

不过要想让这个AsyncTask有意义,还需重写以下几个方法对任务进行定制才可以。

AsyncTask

1. onPreExcute() :这个方法会在后台任务执行前调用,用于进行UI界面上的一些初始化操作,比如去显示“正在加载”字样

2. doInBackground(Params) :
这个方法里面的代码将会在子线程中运行,处理耗时任务的代码应该写在这个方法里面。任务完成后将会把任务结果返回,如果第三个参数指定的是Void则不会返回。但是这个方法是不能执行UI更新操作的。

3.onProgressUpdate(Progress.)
:如果在后台任务中调用了publishProgress()方法,这个方法将会被调用。这个方法可以更新UI进程,可以用来更新进度条之类的。

4.onPostExcute (Result)
:当后台任务执行完成后,这个方法会被调用,可以接受返回的数据,利用书库来进行UI更新,比如显示操作结果,关闭进度条等等。

以上就是要定义一个AsyncTask需要用到的。

如果想启动他,只要写出以下代码

new demoTask( ).excute( );

以上就是AsyncTask的基本用法。是不是比Handler方便好多?

Comments

July 21, 2018 at 10:52 am

There are no comments

keyboard_arrow_up