文章目录
1. 线程的作用
Android用户界面是与用户交互的接口,对于用户的操作,Android迅速响应用户输入(200ms内)是一个重要目标。
如果Activity中的应用程序在5s之内未做出响应,
可能会出现"应用程序无响应,是否关闭?"的对话框。
对于这类耗时比较多的工作,一般是使用多线程的方法来解决的
网络操作必须放到子线程(规定)
子线程不允许修改UI (视图,主线程)
ANR提示: Application Not Responding 应用程序无响应
一种错误的提示框
Android应用中的主线程(UI线程):
Android应用刚启动时,
会在当前应用所对应的进程中启动一个主线程(也叫UI线程);
该UI线程处理与UI相关的事件,如:用户的按键事件,
把相关的事件分派到对应的组件进行处理等 (模块化)。
对于UI线程中比较耗时的工作,开启一个子线程来处理这些工作:
首先创建一个Thread对象,然后调用start( )方法启动新的子线程
# 两种方式实现创建线程
# 方法一:继承Thread类
new MyThread().start(); //在主线程启动子线
----------------------------------------------------
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e("number",Thread.currentThread().getName());
new MyThread().start(); //在主线程启动子线程
}//------------------------------------------------------------------onCreate
//-------------------------------------------------耗时操作,计算斐波那契数列第n项的数值
private long fib(int n){
if (n == 1){
return 1;
}else if (n == 2){
return 1;
}else {
return fib(n - 2) + fib(n -1);
}
}
//----------------------------------------------------继承Thread类实现多线程
private class MyThread extends Thread{
@Override
public void run() { //这是子线程,要想被使需要在主线程启动。
Log.e("name",fib(10)+"");
Log.e("number",Thread.currentThread().getName());
}
}
//-----------------------------------------------------实现Ruannable接口实现多线程
# 方法二:实现Ruinable接口
new Thread(new MyRunnable()).start();//在主线程启动子线
--------------------------
代码块替换上面的MyThread块即可
private class MyRunnable implements Runnable{
@Override
public void run() {
Log.e("1111111111111111111111",Thread.currentThread().getName());
Message myMessage=new Message();//创建消息对象
myMessage.what=100;//区分消息的来源/对象,参数是整数。必填
myMessage.obj=Thread.currentThread().getName();//携带发送的数据,数据写入obj属性
mainHandler.sendMessage(myMessage);
}
}
在Android中,只有UI线程(即主线程)才可以更新主UI界面,而其子线程不能更新UI视图。
对于这类既需要异步执行,又需要更新UI界面的问题,Android提供了多种解决方案:
1. 使用多线程实现:Thread+Handler
http://www.cnblogs.com/playing/archive/2011/03/24/1993583.html
2. 使用AsyncTask实现。(异步任务)
# 打印当前线程名称
Thread.currentThread().getName()
举例: Log.e("number",Thread.currentThread().getName());
在主线程中用结果为 main
在子线程中用结果为 Thread-2,数字依次增加
2. 线程的实现 ( Handler )
Handler:接受子线程发送的数据,并用此数据配合主线程更新UI。
Handler定义在主线程中(UI线程中);
Handler充当主线程和子线程之间交互的中介:
Handler在新启动的子线程中发送消息;
Handler在主线程中获取并处理子线程所发送的消息。
# 流程简图
1. 主线程创建子线程并启动,
2. 子线程开始工作,发送消息到handler(Handler在主线程中创建的)
3. handler把消息放到主线程的消息队列
4. 主线程接受消息队列中的信息并处理
5. Looper实现了循环,实现了多个线程的处理与请求
# 重要的类
• UI线程:创建UI线程时,初始化一个Looper对象以及与其关联的MessageQueue;
• Handler:发送与处理信息,在当前线程中有一个Looper 对象;
• Message:Handler接收与处理的消息对象;
• MessageQueue:消息队列,管理Message;
• Looper:管理MessageQueue, 取出Message分发给对应 的Handler处理,
每个线程有且只有一个Looper。
# Handler的使用方法
使用Handler实现主线程与子线程的通信主要使用如下三个类:
1. Message类:发送带有附加参数的消息,
其处理方法由handlerMessage()方法处理。
2. Handler:MQ上添加消息和处理消息,通知MQ它要执行一个任务(sendMessage),
并在loop到自己的时候执行该任务(handleMessage),整个过程是异步的。
3. Looper:循环工作的线程。
Message Queue
# 注意:
1. 主线程不能执行耗时操作
2. 子线程不能修改UI
3. post 用法 在主线程中使用,线程名称为mainActivity
mainHandler.post(new MyRunnable);,可以直接启动线程对象
4. 主线程与子线程是同时运行的
细信息请参考:
http://developer.android.com/reference/android/os/Handler.html#pubmethods
# 基本流程
- 创建Handler,并添加handleMessage方法。
使用自定义的匿名子类的方法创建Handler对象,并重写handleMessage方法实现消息的处理。
Handler handler = new Handler() {
public void handleMessage (Message msg) {
switch (msg.what) {
case MSG_CURRENT: // TODO
break;
}
}
};
- 创建Thread对象,在Thread对象的run方法中发送消息。
使用自定义的匿名子类的方法创建Thread对象,并重写run方法实现消息的参数设置和添加到消息队列中等操作。
Thread backgroundThread = new Thread() {
public void run() {
Message msg = handler.obtainMessage();
msg.what = MSG_CURRENT;
handler.sendMessage(msg);
}
};
- 启动Thread对象:
backgroundThread.start();
--------------------------------------------------------------
Message对象的常用方法和属性参考:
http://developer.android.com/reference/android/os/Message.html
继承Thread类实现子线程数据返回到主线程并改变主线程界面
子线程给主线程发送数据
public class MainActivity extends AppCompatActivity {
private Button button1;
private EditText edittext1;
//线程中创建Handler匿名子类对象,子类定义简化了,正常写法也没有问题----------------------------步骤1
private Handler mainHandler=new Handler(){
@Override
//处理Message,必须重写(子类重写)------------------------------------------------------步骤3
public void handleMessage(@NonNull Message msg) {
switch(msg.what){
case 100:
edittext1.setText(msg.obj+"");
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//--------------------------------------------实现按钮点击效果(主线程)
button1=findViewById(R.id.button1);
edittext1=findViewById(R.id.edittext1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new MyThread().start(); //在主线程启动子线程
}
});
}//------------------------------------------------------------------onCreate
//-------------------------------------------------耗时操作,计算斐波那契数列第n项的数值
private long fib(int n){
if (n == 1){
return 1;
}else if (n == 2){
return 1;
}else {
return fib(n - 2) + fib(n -1);
}
}//耗时操作
//----------------------------------------------------继承Thread类实现多线程
private class MyThread extends Thread{
@Override
public void run() { //这是子线程,要想被使需要在主线程启动。
//消息包装一下(Message),用handler的senfMessage()方法传入主线程
Message myMessage=new Message();//创建消息对象
myMessage.what=100;//区分消息的来源/对象,参数是整数。必填
myMessage.obj=fib(25);//携带发送的数据,数据写入obj属性
mainHandler.sendMessage(myMessage);//进入消息队列-----------------------------------步骤2
}
}
//-----------------------------------------------------实现Ruannable接口实现多线程
}//-------------------------------------------------------------------MainActivity
Xueli-Homework-5
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/aim"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android" >
</LinearLayout>
--------------------------------------------------------
--------------------------------------------------------
--------------------------------------------------------
--------------------------------------------------------
public class MainActivity extends AppCompatActivity {
private int number;
private LinearLayout aim;
//主线程创建handle匿名子类对象对象
private Handler mainHandler = new Handler() {
@Override
//处理Message
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case 1:
aim.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_light));
Log.e("blue______number==", msg.obj+"");
break;
case 2:
aim.setBackgroundColor(getResources().getColor(android.R.color.holo_green_light));
Log.e("green______number==", msg.obj+"");
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
aim = findViewById(R.id.aim);
number = 0;
new MyThread().start();
}
//--------------------------------------------------------------------------------------------------
private class MyThread extends Thread {
@Override
public void run() {
if (number<100&&number % 2 == 1) {
Message message = new Message();//message对象
message.what = 1;//区分消息对象
message.obj=number;
mainHandler.sendMessageDelayed(message, 2000 * number);//发送消息,进入主线程消息队列
++number;
new MyThread().start();
} else if (number<100&&number % 2 == 0) {
Message message = new Message();//message对象
message.what = 2;//区分消息对象
message.obj=number;
mainHandler.sendMessageDelayed(message, 2000 * number);
++number;
new MyThread().start();
}
}
}
}
主线程给子线程发送数据与消息
public class MainActivity extends AppCompatActivity {
private Button button1;
private EditText edittext1;
private Handler workHandler;//----------------------------主线程给子线程发送消息
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//--------------------------------------------实现按钮点击效果(主线程)
button1=findViewById(R.id.button1);
edittext1=findViewById(R.id.edittext1);
new MyThread().start(); //在主线程启动子线
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//----------------------------------------主线程开始发送消息给子线程
Message myMessage=new Message();
myMessage.what=200;//区分消息的来源/对象,参数是整数。必填
myMessage.obj=fib(25);//携带发送的数据,数据写入obj属性
workHandler.sendMessage(myMessage);
}
});
}//onCreate
//-------------------------------------------------耗时操作,计算斐波那契数列第n项的数值
private long fib(int n){
if (n == 1){
return 1;
}else if (n == 2){
return 1;
}else {
return fib(n - 2) + fib(n -1);
}
}//耗时操作
//----------------------------------------------------继承Thread类实现多线程
private class MyThread extends Thread{
@Override
public void run() { //这是子线程,要想被使需要在主线程启动。
//初始化looper
Looper.prepare();//静态化初始方法
workHandler=new Handler(){//匿名子类
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 200:
Log.e("子线程收到了主线程的数据",msg.obj.toString());
break;
}
}
};
//执行looper循环消息队列
Looper.loop();
}
}
}//-------------------------------------------------------------------MainActivity