Android多线程编程、异步机制(AsyncTask)
2015-09-09 22:13
567 查看
线程间的通信模型
为什么要使用线程呢
下面有一个关于Thread的应用
60秒倒计时
布局
第一种写法
第二种写法
布局
线程的基本用法
如何在子线程中更新UI
处理耗时操作怎么办呢
解析异步消息处理机制
AsyncTask的使用
重写AsyncTask中的一些方法
MainActivity
布局
上面的程序是子线程给主线程发送消息
下面的程序是主线程给子线程发送消息
2、如何启动这个线程呢?
只需要new出一个MyThread的实例,然后调用它的start()方法,这样run()方法中的代码就会在子线程当中运行了。如下所示:
3、使用继承的方式耦合性有点高,更多的时候我们都会选择使用实现Runnable 接口的方式来定义一个线程。如下所示:
启动该线程的方法:
4、当然,如果不想专门在定义一个类去实现Runnable接口,也可以使用匿名内部类的方式,我个人更喜欢这种方式。
对于这种情况,Android提供了一套异步消息处理机制,完美的解决了在子线程中进行进行UI操作的问题。
案例可参考前面的60秒倒计时代码
总结:在案例中先定义一个整形常量TIME_DESC=0X23;用于表示更新mButton这个动作,然后新增一个Handler对象,并重写父类的handlerMessage()方法,在这里对具体的Message进行处理,如果发现Message的what字段的值等于TIME_DESC,就将TextView显示的内容进行处理,即减去1秒。
mButton按钮的点击事件中的代码,可以看到这次我们并没有在子线程里直接进行UI操作,而是创建一个Message对象,并将它的what字段的值指定为TIME_DESC;然后调用Handler的sendMessage()方法将这条Message发送出去,很快,Handler就会收到这条Message,并在handlerMessage()方法中对它进行处理。此时handlerMessage()方法中代码就是在主线程当中运行的,接下来对Message携带的what字段的值进行判断,如果等于TIME_DESC,就会改变时间数。
1、Message
Message是在线程之间传递的消息,它可以在内部携带少量信息,用于在不同的线程之间交换数据。比如Message的what字段、arg1和arg2字段(携带一些整形数据)、使用obj字段携带一个Object对象。
2、Handler
主要用于发送和处理消息,发送消息一般是使用Handler的sendMessage()方法,而发出的消息经过一系列的处理后,最终会传到Handler的handlerMessage()方法中。
3、MessageQueue
MessageQueue是消息队列的意思,它主要用于存放所有通过Handler发送的消息。这部分消息会一直存在于消息队列中,等待被处理,每个线程中只会有一个MessageQueue对象。
4、Looper
Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无线循环当中,然后每当发现MessageQueue中存在一条消息,就会将a它提出来,并传递到Handler的handlerMessage()方法中。每个线程中也只会有一个Looper对象。
1、Params
在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
2、Progress
后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
3、Result
当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
为什么要使用线程呢
下面有一个关于Thread的应用
60秒倒计时
布局
第一种写法
第二种写法
布局
线程的基本用法
如何在子线程中更新UI
处理耗时操作怎么办呢
解析异步消息处理机制
AsyncTask的使用
重写AsyncTask中的一些方法
MainActivity
布局
线程间的通信模型
使用Handler来传递消息。为什么要使用线程呢?
比如说发出一条网络请求时,考虑到网速等其他原因,服务器未必会立刻相应我们的请求,如果不将这类操作放在子线程里去运行,就会导致主线程被阻塞住,从而影响用户对软件的正常使用。下面有一个关于Thread的应用
60秒倒计时
[code]public class MainActivity extends Activity { private Button mButton; private int count=60; private static final int TIME_DESC=0X23; // 下面是一个匿名内部类,作用和下面那个内部类是一样的 private Handler handler=new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case TIME_DESC: String time = (String) msg.obj; mButton.setText(time); break; } } }; // private MyHandler handler=new MyHandler();//初始化handler // // class MyHandler extends Handler {//这是一个内部类 // @Override // public void handleMessage(Message msg) { // switch (msg.what){ // case TIME_DESC: // String time= (String) msg.obj; // mButton.setText(time); // break; // } // } // } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = (Button) findViewById(R.id.button); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { count = 60; new Thread(new Runnable() { @Override public void run() { while (count>0){ count--; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Message msg=handler.obtainMessage();不用每次都重新生成一个Message对象,可以直接用这个方法代替下面这条语句 Message msg=new Message(); msg.obj=count+"秒"; msg.what=TIME_DESC; handler.sendMessage(msg); } } }).start(); handler.sendEmptyMessage(TIME_DESC); } }); } }
布局
[code]<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="倒计时"/> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="60秒"/> </LinearLayout>
上面的程序是子线程给主线程发送消息
下面的程序是主线程给子线程发送消息
第一种写法
[code]public class MainActivity extends Activity { private Button mButton; private int count=60; private static final int TIME_DESC=0X23; private Handler handler=new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case TIME_DESC: count--; mButton.setText(count + "秒"); if (count > 0) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } handler.sendEmptyMessage(TIME_DESC); break; } } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = (Button) findViewById(R.id.button); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { count = 60; handler.sendEmptyMessage(TIME_DESC); } }); } }
第二种写法
[code]public class MainActivity extends Activity { private Button mButton1; private Button mButton2; private int count = 60; private static final int TIME_DESC = 0X23; private Handler handler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton1 = (Button) findViewById(R.id.button1); mButton2 = (Button) findViewById(R.id.button2); mButton1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { count = 60; MyThread thread = new MyThread(); thread.start(); thread. handler.sendEmptyMessage(TIME_DESC); } }); mButton2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { handler.sendEmptyMessage(TIME_DESC); } }); } class MyThread extends Thread { private Handler handler; @Override public void run() { Looper.prepare();//创建一个Looper循环 handler = new Handler() { @Override public void handleMessage(Message msg) { Log.d("handler", "接收到主线程发过来的消息"); } }; Looper.loop(); } } }
布局
[code] <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="发送消息给子线程"/>
线程的基本用法
1、定义一个线程只需要新建一个类继承自Thread,然后重写父类的run()方法,并在里面编写耗时逻辑即可。如下所示:[code]class MyThread extends Thread{ @Override public void run(){ //处理具体的逻辑 }
2、如何启动这个线程呢?
只需要new出一个MyThread的实例,然后调用它的start()方法,这样run()方法中的代码就会在子线程当中运行了。如下所示:
[code]new MyThread().start或者是:MyThread myThread=new MyThread(); myThread.start();
3、使用继承的方式耦合性有点高,更多的时候我们都会选择使用实现Runnable 接口的方式来定义一个线程。如下所示:
[code]class MyThread implements Runnable{ @Override public void run(){ //处理具体的逻辑 }
启动该线程的方法:
[code]MyThread myThread=new MyThread(); new Thread(myThread).start();
4、当然,如果不想专门在定义一个类去实现Runnable接口,也可以使用匿名内部类的方式,我个人更喜欢这种方式。
[code]new Thread (new Runnable(){ @Override public void run(){ //处理具体的逻辑 } }).start();
如何在子线程中更新UI
和许多其他的GUI库一样,Android的UI也是线程不安全的,也就是说,如果想要更新应用程序里的UI元素,则必须在主线程中运行,否则就会出现异常。处理耗时操作怎么办呢?
如果要执行一些耗时操作的时候,我们就必须会用到子线程——在子线程里去执行这些耗时操作,然后根据任务的执行结果来更新相应的UI控件。对于这种情况,Android提供了一套异步消息处理机制,完美的解决了在子线程中进行进行UI操作的问题。
案例可参考前面的60秒倒计时代码
总结:在案例中先定义一个整形常量TIME_DESC=0X23;用于表示更新mButton这个动作,然后新增一个Handler对象,并重写父类的handlerMessage()方法,在这里对具体的Message进行处理,如果发现Message的what字段的值等于TIME_DESC,就将TextView显示的内容进行处理,即减去1秒。
mButton按钮的点击事件中的代码,可以看到这次我们并没有在子线程里直接进行UI操作,而是创建一个Message对象,并将它的what字段的值指定为TIME_DESC;然后调用Handler的sendMessage()方法将这条Message发送出去,很快,Handler就会收到这条Message,并在handlerMessage()方法中对它进行处理。此时handlerMessage()方法中代码就是在主线程当中运行的,接下来对Message携带的what字段的值进行判断,如果等于TIME_DESC,就会改变时间数。
[code]public class MainActivity extends Activity { private Button mButton; private int count=60; private static final int TIME_DESC=0X23; // 下面是一个匿名内部类, private Handler handler=new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case TIME_DESC: String time = (String) msg.obj; mButton.setText(time); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = (Button) findViewById(R.id.button); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { count = 60; new Thread(new Runnable() { @Override public void run() { while (count>0){ count--; try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Message msg=handler.obtainMessage();不用每次都重新生成一个Message对象,可以直接用这个方法代替下面这条语句 Message msg=new Message(); msg.obj=count+"秒"; msg.what=TIME_DESC; handler.sendMessage(msg); } } }).start(); handler.sendEmptyMessage(TIME_DESC); } }); } }
解析异步消息处理机制
Android中的异步消息处理主要由四个部分组成,Message、Handler、MessageQueue和Looper。1、Message
Message是在线程之间传递的消息,它可以在内部携带少量信息,用于在不同的线程之间交换数据。比如Message的what字段、arg1和arg2字段(携带一些整形数据)、使用obj字段携带一个Object对象。
2、Handler
主要用于发送和处理消息,发送消息一般是使用Handler的sendMessage()方法,而发出的消息经过一系列的处理后,最终会传到Handler的handlerMessage()方法中。
3、MessageQueue
MessageQueue是消息队列的意思,它主要用于存放所有通过Handler发送的消息。这部分消息会一直存在于消息队列中,等待被处理,每个线程中只会有一个MessageQueue对象。
4、Looper
Looper是每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无线循环当中,然后每当发现MessageQueue中存在一条消息,就会将a它提出来,并传递到Handler的handlerMessage()方法中。每个线程中也只会有一个Looper对象。
AsyncTask的使用
AsyncTask是一个抽象类,所以我们在使用它的时候,必须要创建一个子类去继承它,在继承时我们可以为AsyncTask类指定三个泛型参数。三个参数的用途如下:1、Params
在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
2、Progress
后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
3、Result
当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
[code]class DownloadTask extends AsyncTask<Void,Integer,Boolean>{ ......... }
重写AsyncTask中的一些方法
MainActivity
[code]package com.example.administrator.asynctaskdemo; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.ProgressBar; public class MainActivity extends AppCompatActivity { private Button mButton; private ProgressBar mprogressBar; private int count = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mButton = (Button) findViewById(R.id.button); mprogressBar = (ProgressBar) findViewById(R.id.progressbar); mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { MyTask task = new MyTask(); task.execute("去执行吧!");//execute只能在主线程中调用 } }); } class MyTask extends AsyncTask<String, String, String> { //AsyncTask(异步任务)是一个抽象类,实现异步任务的基本步骤:继承抽象类AsyncTask实现抽象类中的几个基本方法。 @Override protected void onProgressUpdate(String... values) {//更新进度条 super.onProgressUpdate(values); int count = Integer.parseInt(values[0]); mprogressBar.setProgress(count); } @Override protected void onPostExecute(String s) {//执行完成 super.onPostExecute(s); mButton.setText(s); } @Override protected String doInBackground(String... params) {//后台执行中 while (count < 101) { count++; publishProgress("" + count);//publishProgress用来把数据传入到onProgressUpdate中 try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } return "已经加载完成"; } } }
布局
[code]<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="开始"/> <ProgressBar android:id="@+id/progressbar" android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/Widget.AppCompat.ProgressBar.Horizontal"/> </LinearLayout>
相关文章推荐
- Android第七讲——Android中的线程与进程
- Android下的数据存储与访问
- android button点击事件的4种写法
- Android实例-操作sqlite数据库之Grid显示图片(XE8+小米2)
- Android—软键盘弹出时关于布局的问题
- Android(java)学习笔记219:开发一个多界面的应用程序之两种意图
- Service和IntentService
- android获取设备屏幕大小的方法
- Android NDK 开发入门例子
- Android Fragment 真正解析(下)
- android static达到Service与Activity于Handler沟通
- Android版本支付宝集成获取私钥与公钥
- Android高效加载大图、多图解决方案,有效避免程序OOM
- Android进程线程---Handler(常用)
- Android 异步任务:AsyncTask
- Android中常用adb命令及Log使用
- Android—获取控件的高度
- Android实例-操作sqlite数据之自建导航(XE8+小米2)
- Android菜鸟的启航
- Android绘制的一些总结onMeasure,onLayout,onDraw