Android 组件Service(二)之Handler、AsyncTask异步消息

Android 组件Service(二)之Handler、AsyncTask异步消息


Handler消息机制

Android 不允许子线程中进行UI操作的,但有时必须在子线程里去执行一些耗时的任务,根据任务执行结果来更新相应的UI控件。

Android提供了一套异步消息处理机制,完美解决了在子线程中进行的UI操作问题。Handler机制设计目的是要解决多线程的问题,比如多个线程去更新UI,或造成混乱,性能低下。Handler通过消息队列,保证消息处理的有序进行。这所有的更新UI操作都是在主线程中依次处理的。

关于Handler 类中的一些方法的使用

Android中异步消息处理主要有四部分组成:Message、 Handler、 MessageQueue和Looper。

  1. Message
    是在线程之间传递的消息,可在内部携带少量的信息,用于在不同线程之间交换数据。
  2. Handler
    用于发送和处理消息的。发送消息一般使用Handler的sendMessage()方法,发出的消息经过一系列处理后会传递到 Handler的handlerMessage()方法中
  3. MessageQueue
    这是消息队列的意思,用于存放所有通过Handler发送的信息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue对象。
  4. Looper
    是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无线循环当中,然后每当发现MessageQueue中存在一条信息,就会将它取出并传递到Handler的handleMessage()方法中。每个线程只会有一个Looper对象。

现在来看handler消息处理的流程:
1. 在主线程中创建Handler对象,并重写handlerMessage()方法;
2. 当子线程需要操作UI时,就在子线程中创建Message对象,并通过Handler发出这消息;
3. 这消息添加到MessageQueue队列中,Looper可以取出这队列中的消息,分回给handlerMessage()中,这时handlerMessage方法中的代码就在主线程(UI线程)中了。

package com.example.androidthreadtest;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

class MainActivity extends AppCompatActivity {

    private TextView tv;
    private Button btn;
    public static final int UPDATE_TEXT = 0;

    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv = (TextView) findViewById(R.id.tv);
        btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                switch (v.getId()) {
                    case R.id.btn:
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                Message message = new Message();
                                message.what = UPDATE_TEXT;
                                handler.sendMessage(message);
                            }
                        }).start();
                        break;
                    default:
                        break;
                }
            }
        });

        handler = new Handler() {
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case UPDATE_TEXT:
                        tv.setText("It`s changed.");
                        break;
                    default:
                        break;
                }
            }
        };
    }
}

AsyncTask

这个工具更加方便在子线程里对UI进行操作,可以十分简单的从子线程切换到主线程。实际上是实现了 异步消息处理机制 ,这个只是做好了封装。
UI所在的线程一般被称为主线程,这里进行的操作越短越快越好,让用户感受到界面的流畅。所以要把费时的任务放到子线程中去,AsyncTask这些异步消息处理机制,为了让子线程切换到主线程上,可以进行UI操作。
AsyncTask<Params, Progress, Result>是一个抽象类,必须创建一个子类去继承它,指定三个泛型参数:
1. Params、执行时需要传入的参数
2. Progress、后台执行任务时,如果需要在界面上显示当前的进度,这里用指定的泛型为进度单位
3. Result、当任务执行完毕后,如果需要对结果进行返回,则用指定的泛型作为返回值类型

经常需要重写以下四个方法
1. onPreExecute() 后台任务执行前,界面初始化的工作;
2. doInBackground(Params…) 方法中所有代码都会在子线程中运行,不过应该在这里去处理耗时的任务。这个方法不可以进行UI操作的,如果需要更新UI元素,如当前任务执行进度,可以在后台任务中调用publishProgress(Progress..)方法之后onProgressupdate()便会调用;
3. onProgressupdate(Progress…) 这个方法中可以对UI进行操作,利用参数中的数值对UI界面元素进行相应地更新;
4. onPostExecute(Result…) 后台任务执行完毕并通过return语句进行返回时,这个方法就会被调用。返回的数据作为参数传递到此方法中,进行一些UI操作。

简单来说,使用AsyncTask 的诀窍就是,在doInBackground()方法中去执行具体的耗时任务,在onProgressUpdate()方法中进行UI 操作,在onPostExecute()方法中执行一些任务的收尾工作。

public class MyAsyncTask extends AsyncTask<Void,String,String> {

   public ProgressDialog dialog;

    @Override
    protected void onPreExecute(){
        Log.d("MyAsyncTask", "onPreExecute...");


    }
    @Override
    protected String doInBackground(Void...params) {
        Log.d("MyAsyncTask", "doInBackground...");
        //在这子线程任务中调用publishProgress()更新数据到UI上。
        publishProgress("aaa");
        return null;

    }
    @Override
    protected void onProgressUpdate(String... params){
        Log.d("MyAsyncTask", "onProgressUpdate..."+params);
    }
    @Override
    protected void onPostExecute(String s){
        super.onPostExecute(s);
        Log.d("MyAsyncTask", "onPostExecute...");

    }
}
package com.example.downloadservicetest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {
    private Button btn;
    private Button btn_update;
    private MyAsyncTask myAsyncTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myAsyncTask = new MyAsyncTask();

        btn = (Button) findViewById(R.id.btn);
        btn_update = (Button) findViewById(R.id.btn_update);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            //执行后台任务
                myAsyncTask.execute();
            }
        });
    }
}

上面的例子比较简单,仅供实验参考

发布了30 篇原创文章 · 获赞 5 · 访问量 7681

猜你喜欢

转载自blog.csdn.net/c0586/article/details/56495823