使用Handler来传递消息。
比如说发出一条网络请求时,考虑到网速等其他原因,服务器未必会立刻相应我们的请求,如果不将这类操作放在子线程里去运行,就会导致主线程被阻塞住,从而影响用户对软件的正常使用。
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);
}
});
}
}
<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>
上面的程序是子线程给主线程发送消息
下面的程序是主线程给子线程发送消息
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);
}
});
}
}
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();
}
}
}
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送消息给子线程"/>
1、定义一个线程只需要新建一个类继承自Thread,然后重写父类的run()方法,并在里面编写耗时逻辑即可。如下所示:
class MyThread extends Thread{
@Override
public void run(){
//处理具体的逻辑
}
2、如何启动这个线程呢?
只需要new出一个MyThread的实例,然后调用它的start()方法,这样run()方法中的代码就会在子线程当中运行了。如下所示:
new MyThread().start或者是:MyThread myThread=new MyThread();
myThread.start();
3、使用继承的方式耦合性有点高,更多的时候我们都会选择使用实现Runnable 接口的方式来定义一个线程。如下所示:
class MyThread implements Runnable{
@Override
public void run(){
//处理具体的逻辑
}
启动该线程的方法:
MyThread myThread=new MyThread();
new Thread(myThread).start();
4、当然,如果不想专门在定义一个类去实现Runnable接口,也可以使用匿名内部类的方式,我个人更喜欢这种方式。
new Thread (new Runnable(){
@Override
public void run(){
//处理具体的逻辑
}
}).start();
和许多其他的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,就会改变时间数。
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类指定三个泛型参数。三个参数的用途如下:
1、Params
在执行AsyncTask时需要传入的参数,可用于在后台任务中使用。
2、Progress
后台任务执行时,如果需要在界面上显示当前的进度,则使用这里指定的泛型作为进度单位。
3、Result
当任务执行完毕后,如果需要对结果进行返回,则使用这里指定的泛型作为返回值类型。
class DownloadTask extends AsyncTask<Void,Integer,Boolean>{
.........
}
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 "已经加载完成";
}
}
}
<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>