(七)线程与消息处理



7.1实现多线程

在程序开发时,对于- -些比较耗时的操作,通常会为其开辟一个 单独的线程来执行,以尽可能减少用户的等待时间。在Android中,默认情况下,所有的操作都在主线程中进行,主线程负责管理与UI相关的事件,而在用户自己创建的子线程中,不能对UI组件进行操作。因此,Android 提供了消息处理传递机制来解决这一问题。
在现实生活中,很多事情都是同时进行的,例如,我们可以一边看书,一 边喝咖啡;而计算机则可以一边播放音乐,一边打印文档。对于这种可以同时进行的任务,可以用线程来表示,每个线程完成一个任务,并与其他线程同时执行,这种机制被称为多线程。下面就来介绍如何创建线程、开启线程、让线程休眠和中断线程。

7.1.1 创建线程

1.通过Thread类的构造方法创建线程

Thread(Runnable runnable)

该构造方法的参数runnable可以通过创建一个Runnable类的对象并重写其run0方法来实现,例如,要创建一个名称为thread的线程,可以使用下面的代码:

Thread thread=new Thread(new Runnable(){
   
	//重写run()方法
	@Override
	public void run() {
   
	//要执行的操作
	}
});

说明:在run0方法中,可以编写要执行的操作的代码,当线程被开启时,run()方法将被执行。

2.通过实现Runnable接口创建线程

public class ClassName extends 0bject implements Runnable

当一个类实现Runnable接口后,还需要实现其run0方法,在run0方法中,可以编写要执行的操作的代码。
例如,要创建一个实现了Runnable 接口的Activity,可以使用下面的代码:

public class MainActivity extends Activity implements Runnable {
   
@Override
public void onCreate ( Bundle savedInstanceState) {
   
	super.onCreate ( savedInstanceState);
	setContentView(R. layout .main);
	@override
	public void run() {
   
		//要执行的操作
}
7.1.2 开启线程

创建线程对象后,还需要开启线程,线程才能执行。Thread 类提供了start()方 法用于开启线程,其语法格式如下:

start()

例如,存在一个名称为thread的线程,如果想开启该线程,可以使用下面的代码:

thread.start();//开启线程
7.1.3 线程的休眠

线程的休眠就是让线程暂停一段时间后再次执行。 同Java一样,在Android中,也可以使用Thread类的sleep()方法让线程休眠指定的时间。sleep()方 法的语法格式如下:

sleep(long time) 其中参数time用于指定休眠的时间,单位为毫秒。

例如,想要线程休眠1秒钟,可以使用下面的代码:

Thread. sleep(1000);
7.1.4 中断线程

当需要中断指定的线程时,可以使用Thread类提供的iterupt()方法来实现。使用interrupt()方法可以向指定的线程发送一个中断请求,并将该线程标记为中断状态。interrupt()方 法的语法格式如下:

interrupt()

例如,存在一个名称为thread的线程,如果想中断该线程,可以使用下面的代码:

.//省略部分代码
thread. interrupt();
//省略部分代码
public void run() {
   
	while( !Thread. currentThread().isInterrupted()){
   
	...//省略部分代码
	}
|)

另外,由于当线程执行wait()、join()或 sleep0方法时,线程的中断状态将被清除并抛出InteruptedException,所以,如果想在线程中执行了waitO、join()或 sleep0方法时中断线程,就需要使用一个boolean型的标记变量来记录线程的中断状态,并通过该标记变量来控制循环的执行与停止。例如,通过名称为islnterrupt 的boolean型变量来标记线程的中断,关键代码如下:

private boolean isInterrupt=false;
	//定义标记变量
	...//省略部分代码
	...//在需要中断线程时,将isInterrupt的值设置为true
	public void run() {
   
		while(!isInterrupt){
   
		...//省略部分代码
	}
}        
7.1.5 案例 1:通过实现Runnable接口来创建线程

main.xml

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

    <Button
        android:id="@+id/startBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="启动线程"
        android:layout_gravity="center"
        />
    <Button
        android:id="@+id/stopBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="中断线程"
        android:layout_gravity="center"
        />

</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements Runnable{
   
    private Thread thread;
    private int i;
    private boolean interruptFlag;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button button1 = (Button) findViewById(R.id.startBtn);
        Button button2 = (Button) findViewById(R.id.stopBtn);

        button1.setOnClickListener(new View.OnClickListener() {
   
            @Override
            public void onClick(View v) {
   
                i=0;
                thread = new Thread(MainActivity.this);
                thread.start();
                interruptFlag=true;
            }
        });

        button2.setOnClickListener(new View.OnClickListener() {
   
            @Override
            public void onClick(View v) {
   
                if (thread!=null){
   
                    thread.interrupt();
                    interruptFlag=false;
                    thread=null;
                }
                Log.i("线程运行提示====》","线程已中断。。。");
            }
        });
    }

    @Override
    public void run() {
   
        while (interruptFlag){
   
            i++;
            Log.i("线程执行",String.valueOf(i));
            try {
   
                Thread.sleep(2000);
            } catch (InterruptedException e) {
   
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onDestroy() {
   
        if (thread!=null){
   
            thread.interrupt();
            interruptFlag=true;
            thread=null;
        }
        super.onDestroy();
    }
}

在这里插入图片描述

7.1.6 案例 2:开启一个新线程播放背景音乐

main.xml

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

    <Button
        android:id="@+id/startBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="播放"
        android:layout_gravity="center"
        />


</LinearLayout>

MainActivity.java

package com.jingyi.aboutthread;

import androidx.appcompat.app.AppCompatActivity;

import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity{
   
    private Thread thread;
    private static MediaPlayer mediaPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button button1 = (Button) findViewById(R.id.startBtn);

        button1.setOnClickListener(new View.OnClickListener() {
   
            @Override
            public void onClick(View v) {
   
                ((Button)v).setEnabled(false);//设置不可用
                thread=new  Thread(new Runnable() {
   
                    @Override
                    public void run() {
   
                        playSound();
                    }
                });
                thread.start();
            }
        });

    }

    private void playSound() {
   
        if (mediaPlayer!=null){
   
            mediaPlayer.release();//释放资源
        }
        mediaPlayer = MediaPlayer.create(MainActivity.this, R.raw.qilixiang);
        mediaPlayer.start();//开始播放
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
   
            @Override
            public void onCompletion(MediaPlayer mp) {
   
                try{
   
                    Thread.sleep(10000);//线程休眠5秒
                    playSound();//重新播放
                }catch (InterruptedException e){
   
                    e.printStackTrace();
                }
            }
        });
    }


    @Override
    protected void onDestroy() {
   //释放资源
        if (thread!=null){
   
            thread=null;
        }
        if (mediaPlayer!=null){
   
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer=null;
        }
        super.onDestroy();
    }
}
7.2 Handler 消息传递机制

直接在新创建的子线程上对UI界面上的内容进行操作会抛出异常。为此,Android 中引入了Handler 消息传递机制,来实现在新创建的线程中操作UI界面。下面将对Handler 消息传递机制进行介绍。

7.2.1 循环者(Looper)

在介绍Looper之前,需要先来了解一下MessageQueue的概念。在Android中, 一个线程对应一个Looper对象,而一个Looper对象又对应一个MessageQueue(消息队列) 。MessageQueue用于存放Message(消息),在MessageQueue中,存放的消息按照FIFO (先进先出)原则执行,由于MessageQueue被封装到Looper里面,所以这里不对
MessageQueue进行过多介绍。
Looper对象用来为一个线程开启一个消息循环,从而操作MessageQueue。默认情况下,Android 中新创建的线程是没有开启消息循环的,但是主线程除外。系统自动为主线程创建Looper 对象,开启消息循环。所以,当在主线程中应用下面的代码创建Handler对象时不会出错,而如果在新创建的非主线程中应用下面的代码创建Handler对象,将产生异常信息。

Handler handler2 = new Handler();

如果想要在非主线程中创建Handler对象,首先需要使用Looper 类的prepare()方法来初始化一个 Looper对象,然后创建该Handler对象,再使用Looper类的loop()方法启动Looper,从消息队列中获取和处理消息。

小DEMO

public class LooperThread extends Thread {
   
    public Handler handler;

    @Override
    public void run() {
   
        super.run();
        Looper.prepare();//初始化Looper对象
        handler = new Handler() {
   
            @Override
            public void handleMessage(@NonNull Message msg) {
   
                Log.i("Looper_MSG", String
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值