Android 第三章 第二节 多线程(handler)




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

# 基本流程

  1. 创建Handler,并添加handleMessage方法。
    使用自定义的匿名子类的方法创建Handler对象,并重写handleMessage方法实现消息的处理。
Handler handler = new Handler() {
	public void handleMessage (Message msg) {
		switch (msg.what) {
			case MSG_CURRENT: // TODO
			break;
		}
	}
};
  1. 创建Thread对象,在Thread对象的run方法中发送消息。
    使用自定义的匿名子类的方法创建Thread对象,并重写run方法实现消息的参数设置和添加到消息队列中等操作。
Thread backgroundThread = new Thread() {
	public void run() {	
		Message msg = handler.obtainMessage();
		msg.what = MSG_CURRENT;
		handler.sendMessage(msg);
	}
};
  1. 启动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

猜你喜欢

转载自blog.csdn.net/qq_44627608/article/details/106011707