Android多线程

来源:互联网 发布:php数组打印 编辑:程序博客网 时间:2024/06/18 05:34

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 0
原创粉丝点击