Android线程异步机制Handler与AsyncTask详解

一、线程异步简介
基于移动客户端的软件特别强调实时性,Android程序更是如此,任何一个程序超过5s没有响应,都会被系统强制杀掉。而且Android也不允许在UI线程中进行任何网络操作,否则就会产生NetworkOnMainThreadException异常。因此,凡是耗时的操作,都不应该直接出现在UI线程中。今天,我通过最简单直观地示例总结下Android开发中最常用的两种处理耗时操作的方法:一个是Handler,另一个是AsyncTask,进行详细的讲解android中异步的方式。

二、Handler方法

Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制。本篇将通过两种方式实现Handler消息传递,实现异步方式更新操作。

1.在主线程中操作

在Android Handler中提供了几种方法通过异步的方式访问UI线程

Handler.post():把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,立即执行

        /**
         * Post方法
         * 把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,立即执行
         */
        mBtnPost.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        /**
                         * 此处直接写setmText无用
                         * 无法在子线程中访问更新UI操作,必须在主线程中更新UI
                         * 使用post方法修改UI主键属性
                         */
                        //mText.setText("Handler.post");
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                mText.setText("Handler.post-->" + Thread.currentThread().getName());
                            }
                        });
                    }
                }).start();
            }
        });


Handler.postDelayed():把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,延迟后执行。

/**
         * PostDelayed方法
         * 把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,延迟后执行。
         */
        mBtnPostDelayTime.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        handler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                mText.setText("Handler.pistDelayed,3s-->" + Thread.currentThread().getName());
                            }
                        },3000);
                    }
                }).start();
            }
        });


Handler.postAtTime():把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,在特定的时间执行。uptimeMillis参数首先需要获取当前的时间才与计算。

/**
         * PostAtTime
         * 把一个Runnable入队到消息队列中,UI线程从消息队列中取出这个对象后,在特定的时间执行。
         * uptimeMillis参数首先需要获取当前的时间才与计算
         * 事件:延迟3s显示Text
         */
        mBtnAtTime.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        handler.postAtTime(new Runnable() {
                            @Override
                            public void run() {
                                for(int count = 1; count < 3; count++){
                                    mText.setText("PostAtTime" + count);
                                }
                            }
                        },android.os.SystemClock.uptimeMillis() + 3000);
                    }
                }).start();

            }
        });


Handler.removeCallbacks():removeCallbacks移除在队列中的消息

/**
         * removeCallbacks移除在队列中的消息
         * 参数为线程名
         */
        mBtnRemoveCallbacks.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //handler.removeCallbacks(runnable);
            }
        });


Android的线程异步处理机制:Handler对象维护一个线程队列,有新的Runnable送来(post())的时候,把它放在队尾,而处理 Runnable的时候,从队头取出Runnable执行。当向队列发送一个Runnable后,立即就返回,并不理会Runnable是否被执行,执行是否成功等。而具体的执行则是当排队排到该Runnable后系统拿来执行的。这样,就实现了Android的异步处理机制。

 

注意:该方式并没有另开线程,而是在主线程中运行。因为该种方法并没有实现真正的异步,只是用post的方法实现了消息的传递。下面讲解另外开线程实现异步方法。

 

2.另开线程操作

使用new Thread()创建新线程,Handler和Looper方法进行消息传递及接收信息。

package example.com.handlertest;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.widget.TextView;

/**
 * author Jimmy.li
 * Date: 2016-07-11
 * Time: 11:11
 * version V1.0
 */
public class HandlerTest extends Activity {
    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.handlertest);

        mTextView = (TextView) this.findViewById(R.id.textview);


        //开启另一个线程
        HandlerThread mHandlerThread = new HandlerThread("HandlerThread");
        mHandlerThread.start();

        //进行消息传递
        myHandlerTest myHandlerTest = new myHandlerTest(mHandlerThread.getLooper());

        Message msg = myHandlerTest.obtainMessage();
        msg.sendToTarget();
    }

    //Handler方法接收消息
    class myHandlerTest extends Handler{

        public myHandlerTest(){
        }
        public myHandlerTest(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mTextView.setText("线程名:" + Thread.currentThread().getName());
        }
    }

}


 三、AsyncTask方法

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

AsyncTask的执行分为四个步骤,每一步都对应一个回调方法,开发者需要实现一个或几个方法。在任务的执行过程中,这些方法被自动调用。

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

protected Integer doInBackground(Void... params) {
            int i = 0;
            while (i<100){
                SystemClock.sleep(250);
                i++;
                if(i % 5 == 0){
                    publishProgress(i);
                }
            }
            return i;
        }

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

//完成更新UI操作
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            textView.setText(values[0] + "%已完成");
        }


3.onPostExecute(Result),在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread.

 //结束时调用
        @Override
        protected void onPostExecute(Integer integer) {
            super.onPostExecute(integer);
            textView.setText(integer + "%,全部完成");
        }



Good luck!

Write by Jimmy.li




 
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值