Android开发-多线程

目录

1.概述

1.1 定义

1.2 创建

1.2.1 方式一

1.2.2 方式二

1.2 在子线程中更新UI

2.案例

2.1 说明

2.2 创建布局

2.3 使用异步消息处理机制解决子线程更新UI

2.4 分析

           由于Handler是在主线程中创建的,因此handleMessage()方法里面的代码也会在主线程中运行。

3.同步与异步

3.1 同步

3.2 异步

4.解析异步消息处理机制

4.1 Message

4.2 Handler

4.3 MessageQueue

4.4 Looper

4.5 异步消息流程

4.5 思想

5.使用AsyncTask

 


1.概述

1.1 定义

         Android多线程跟Java多线程类似

1.2 创建

1.2.1 方式一

        新建一个类继承自Thread,然后重写其父类的run()方法,并在里面编写逻辑代码即可。如下所示:

public class MainActivity_5 extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_4);

        //创建MyThread对象
        MyThread myThread = new MyThread();
        //开启线程
        myThread.start();
    }
    class MyThread extends Thread{
        @Override
        public void run() {
            //处理逻辑代码
        }
    }
}

1.2.2 方式二

            方式一使用的耦合性比较高,更多的时候都会选择使用实现Runnable接口的方式来定义一个线程。如下所示:

public class MainActivity_5 extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_4);

        //创建MyThread对象
        MyThread myThread = new MyThread();
        //开启线程:传入一个Runnable对象参数
        new Thread(myThread).start();
    }
    class MyThread implements Runnable{
        @Override
        public void run() {
            //处理逻辑代码
        }
    }
}

          还可以通过匿名内部类的方式,如下所示:

new Thread(new Runnable() {
    @Override
    public void run() {
        //处理逻辑代码
    }
}).start();

1.2 在子线程中更新UI

       和许多其他GUI库一样,Android的UI也是线程不安全的。也就是说想要更新应用程序里面的UI元素,就必须在主线程中进行,否则就会出现异常

     

2.案例

2.1 说明

      比较在子线程与主线程中更新UI

2.2 创建布局

        activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/change_text_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="Change Text"/>
    <TextView
        android:id="@+id/texts"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Hello World"
        android:textSize="20sp"
        android:textColor="#ed0404"/>

</RelativeLayout>

        MainActivity.java:

public class MainActivity extends AppCompatActivity {
    private Button button;
    private TextView text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity);
        button = findViewById(R.id.change_text_btn);
        text =findViewById(R.id.texts);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //开启子线程
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //在子线程中更新控件
                        text.setText("改变内容!");
                    }
                }).start();
            }
        });
    }

}

         效果:点击Change Text按钮,TextView控件值更新后,程序崩溃

         程序报错信息如下所示:

E/AndroidRuntime: FATAL EXCEPTION: Thread-1669
                  Process: com.luckyliuqs.materialdesign, PID: 16751
                  android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
                      at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6357)
                      at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:874)

2.3 使用异步消息处理机制解决子线程更新UI

          在MainActivity.java中修改代码如下所示:

public class MainActivity extends AppCompatActivity {
    private static final int UPDATE_TEXT = 1;
    private Button button;
    private TextView text;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity);
        button = findViewById(R.id.change_text_btn);
        text =findViewById(R.id.texts);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //开启子线程
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //创建Message对象
                        Message message = new Message();
                        //设置Message的what字段
                        message.what = UPDATE_TEXT;
                        //将Message对象发送出去
                        handler.sendMessage(message);
                    }
                }).start();
            }
        });
    }
    
    private Handler handler = new Handler(){
        //处理收到的Message对象方法:里面的代码就是在主线程中运行
        public void handleMessage(Message msg){
            //匹配Message的what字段
            switch (msg.what){
                case UPDATE_TEXT:
                    //在这里进行UI操作
                    text.setText("内容改变!");
                    break;
                default:
                    break;
            }
        }
    };

}

2.4 分析

          原理是:在子线程里面,Handler发送一个Message对象,然后再Handler接收到Message对象后在主线程里面更新UI。

           由于Handler是在主线程中创建的,因此handleMessage()方法里面的代码也会在主线程中运行。

 

3.阻塞与非阻塞

 

 

4.同步与异步

4.1 同步

 

4.2 异步

         顾名思义,异步就是UI主线程运行的时候,异步的完成一些操作。执行一个异步的任务在后台。我们可以将耗时的操作放在异步任务当中来执行,并随时将任务执行的结果返回给我们的UI线程来更新我们的UI控件。通过异步我们可以轻松的解决多线程之间的通信问题

        如果有多个任务执行的话,异步任务是按照顺序一个个执行的。

        在Android中实现异步任务机制有两种方式,HandlerAsyncTask

Handler

Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息

完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿

在多个任务同时执行时,不易对线程进行精确的控制

AsyncTask使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。

 

          

5.解析异步消息处理机制

          Android中的异步消息处理主要由4个部分组成:Message、Handler、MessageQueue和Looper

5.1 Message

         Message是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。前面使用了what字段,除此之外,还可以使用arg1和arg2字段来携带一些整形数据;使用obj字段携带一个object对象。

5.2 Handler

        Handler顾名思义就是处理者的意思,主要用于发送和处理消息。发送消息使用sendMessage()方法;发出的消息经过辗转处理后,会传递到handleMessage()方法中。

5.3 MessageQueue

        MessageQueue就是消息队列的意思,主要用于存放所有通过Handler发送的消息,这部分消息会一直存在与消息队列中,等待被处理。每个线程只会有一个MessageQueue对象

5.4 Looper

        Looper相当于每个线程中的MessageQueue的管家,调用Looper的loop()方法后,就会进入到一个无限循环中,每当发现MessageQueue中存在一条消息,就会将消息取出,并传递到Handler的handleMessage()方法中。同样,每个线程中,只有一个Looper对象

5.5 异步消息流程

       流程如下所示:

1.在主线程中创建一个Handler对象,并重写其handleMessage()方法。
2.当子线程需要进行UI操作时,就创建一个Message对象,并通过Handler的sendMessage(Message msg)将消息发送出去。
3.发送出去的消息会被添加到MessageQueue的队列中等待被处理。
4.Looper在期间会一直尝试从MessageQueue中取出待处理的消息,然后分发回Handler的hanleMessage()方法中
5.由于Handler是在主线程中创建的,因此handleMessage()方法里面的代码也会在主线程中运行。

        图示如下:

5.5 思想

        一个Message经过上面图示的流程辗转调用之后,就从子线程进入到了主线程,从不能更新的UI变成了可更新的UI。

 

6.使用AsyncTask

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luckyliuqs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值