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"); }}
- Android 多线程
- Android多线程
- Android 多线程
- Android 多线程
- Android 多线程
- Android多线程
- android 多线程
- android多线程
- android 多线程
- Android多线程
- android 多线程
- android多线程
- Android多线程
- android 多线程
- Android多线程
- Android 多线程
- android 多线程
- Android多线程
- 浅谈java集成中的final方法重写和重载问题
- python3.5爬虫完成笔趣阁小说的爬取
- Bellman-Ford算法,解决负权回路。
- app推广螺旋管理
- C++ POD 类型
- Android多线程
- c#数组使用复习
- 阅读器(慕客学习)之JS设计模式分解
- 【web前端开发技术】深入理解JavaScript异步编程--JavaScript异步编程的终极演变
- sendRedirect和forward区别
- java初级之25对象类型的参数传递
- servlet的数据库操作风格
- Android 图片Drawable类型之Level List
- AsyncTask的使用