Android多线程

Android多线程

一个Android的应用程序运行在一个独立的进程中,运行在一个独立的虚拟机(dvk)上。(进程名为包名)
Android应用程序开启后,默认开启一个主线程(UI线程)
Activity,Service,BroadcastReceive组件运行在主线程中
Android 应用程序退出后,保留空UI线程,可以加快应用程序启动速度。
用户不能再UI主线程中做耗时的操作,一旦操作超过5s,应用程序抛出一个ANR(application not respond)

如何避免ANR错误?
将耗时的操作放入到子线程中。(耗时的操作包括:长时间的休眠,计数,联网,复杂的运算)
只有主线程才能操作Widget控件。
如果在子线程中出现操作Widget控件,系统抛出CalledFromWrongThreadException异常。
系统为什么要这么做?
避免出现同步问题。

Handler机制

作用
主要为了解决非UI线程中不能更新Widget控件的问题
Handler机制剖析
子线程发送消息给底层的消息队列。
handler.sendMessage(msg)
主线程查询消息队列,处理消息对象。
handlerMessage(msg)
MessageQueue 消息队列
负责存储消息对象
Looper
给UI线程安排代码,一个UI线程只能有一个Looper对象,否则多个Looper对象都在UI线程上安排代码,解决冲突就是个大问题。
Looper对象会线性安排在UI线程上执行的代码,它通过一个队列管理各个Handler对象提交的代码。
Message消息对象
//从消息池中获取消息对象
Message msg = handler.obtainMessage();
//在消息对象上绑定int类型数据
msg.arg1 = count;
//在消息对象上绑定其它类型数据
msg.setData(Bundle); //Bundler为数据集(类似于HashMap容器)

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
/**
 * @author Administrator
 * 事件驱动的应用程序
 */
public class MainActivity extends Activity implements OnClickListener {
    Button btnStart;
    TextView tv;
    int count = 0;
    boolean isRun;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnStart = (Button) findViewById(R.id.button1);
        btnStart.setOnClickListener(this);
        findViewById(R.id.button2).setOnClickListener(this);
        tv = (TextView) findViewById(R.id.textView1);
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        if(v.getId() == R.id.button1){  
            btnStart.setEnabled(false);
            count = 0;
            isRun = true;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    // 修改Widget控件的值
                    // tv.setText(String.valueOf(count));
                    while (isRun) {
                        count++;
                        // 创建消息对象
                        Message msg = new Message();
                        msg.arg1 = count;
                        //设置消息类型
                        msg.what = 2;
                        // 发送消息 (发给底层的消息队列)
                        handler.sendMessage(msg);

                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }

                    handler.sendEmptyMessage(1);
                }
            }).start();
        }else if(v.getId() == R.id.button2){    
            isRun = false;  
        }
    }
    Handler handler = new Handler(){

        //如果消息队列中有消息,系统自动调用该方法处理消息
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            if(msg.what == 2){
                int count = msg.arg1;
                tv.setText(String.valueOf(count));
            }else if(msg.what == 1){
                //修改按钮属性
                btnStart.setEnabled(true);
            }
        }
    };
}

向消息队列发送消息,1000毫秒后执行Runnable对象中的代码。

myHandler.postDelayed(new Runnable() {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        Log.e("Test", "thread name = "+Thread.currentThread().getName());
    }
}, 1000);

异步任务(Async Task)

概念
封装多线程和Handler机制。给用户提供重写接口的方式,不需要用户手动创建子线程和Handler对象。
异步任务的优点
Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI主线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但是也有缺点,代码臃肿,在多个任务同时执行时,不易对线程进行精确的控制。为了简化操作,Android1.5提供了一个工具类AsyncTask,它是创建异步任务变的更加简单,不再需要编写任务线程和Handler实例就可完成任务。
异步任务的局限性
多个异步任务不能同时执行,在某个时间内,只能执行一个异步任务。
执行异步任务的步骤:

  • 1 execute(Params … params),执行一个异步任务,需要我们在代码中调用此方法,触发异步任务的执行。
  • 2 onPreExecute(),在execute(Params… params
    )被调用后立即执行,一般用来在执行后台任务前对UI做一些标记。
  • 3 doInBackground(Params…
    params),在onPreExecute()完成后立即执行,用于执行较为费时的操作,此方法将接受输入参数和返回计算结果在执行过程中可以调用publishProgress(Progress…values)来更新进度信息。作用在非UI线程上。
  • 4 onProgressUpdate(Progress… values),在调用publishProgress(Progress…
    values)时,此方法被执行,直接将进度信息更新到UI组件上。
  • 5 onPostExecute(Result
    result)当后台操作结束时,此方法将被调用,计算结果讲座为参数传递到方法中,直接将结果显示到UI组件上。
import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;

//Params 执行异步任务时,传入的参数
//Progress 异步任务的进度
//Result 结果
public class MyTask extends AsyncTask<Void, Integer, Void> {

    TextView tv;
    public MyTask(TextView tv) {
        // TODO Auto-generated constructor stub
        this.tv = tv;
    }

    @Override
    protected void onPreExecute() {
        // TODO Auto-generated method stub
        super.onPreExecute();
        Log.d("Test", "onPre");
    }
    //该方法运行在非UI线程中
    //该方法中放耗时操作
    @Override
    protected Void doInBackground(Void... params) {
        // TODO Auto-generated method stub
        int count = 0;
        while(!isCancelled() && count < 10){
            count++;
            //发布进度
            //触发系统自动调用onProgressUpdate
            //相当于handler.sendMessage()
            publishProgress(count);

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return null;
    }
    //相当于handlerMessage()
    //该方法运行在UI线程中
    @Override
    protected void onProgressUpdate(Integer... values) {
        // TODO Auto-generated method stub
        super.onProgressUpdate(values);

        if(isCancelled()){
            return;
        }
        //操作UI控件
        int count = values[0];
        tv.setText(String.valueOf(count));
    }

    //该放在在取消异步任务之后运行
    @Override
    protected void onCancelled() {
        // TODO Auto-generated method stub
        super.onCancelled();
    }

    @Override
    protected void onPostExecute(Void result) {
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        Log.d("Test", "onPost");
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值