一、线程和Handler异步消息机制
1.1 线程与主线程
线程是一个单一的执行序列。单个线程中的代码可得到逐步执行。每个Android应用的运行都是从主线程开始的。然而,主线程并非如线程般的预定执行序列,如下图。相反,它处于一个无限循环的运行状态,等待着用户或系统触发事件的发生。事件触发后,主线程便负责执行代码,以响应这些事件。
注意:如果想要更新应用程序里的 UI 元素,则必须在主线程中进行,否则就会出现异常;而主线程不能执行网络连接等耗时行为,等待响应的时候,用户界面将会毫无反应,这可能会导致应用无响应(ANR:Application Not Responding),我们用子线程来实现耗时行为。
1.2 线程的基本用法
- 定义一个线程只需要新建一个类继承自 Thread,然后重写父类的 run()方法,并在里面编写耗时逻辑即可;
class MyThread extends Thread {
@Override
public void run() {
// 处理具体的逻辑
}
}
new MyThread().start();
2. 为了降低耦合度,我们经常使用实现Runnable()接口的方式来定义一个线程:
class MyThread implements Runnable {
@Override
public void run() {
//处理具体的逻辑
}
}
启用方法也有所调整:
MyThread myThread = new MyThread();
new Thread(myThread).start();
3. 如果不想专门再定义一个类去实现 Runnable 接口,也可以使用匿名类的方式,这种写法更为常见,如下所示:
new Thread(new Runnable() {
@Override
public void run() {
// 处理具体的逻辑
}
}).start();
1.3 异步消息处理机制
1.3.1 四个概念
1. message : 它是在线程之间传递的消息,它可以在内部携带少量的信息,用于在不同线程之间交换数据。
消息是message的一个实例,它有一下三个要素:
◆what— 用户定义的int型消息代码,用来描述消息;◆obj — 随消息发送的用户指定对象;
◆target — 处理消息的Handler。
2.message queue
MessageQueue 是消息队列的意思,它主要用于存放所有通过 Handler 发送的消息。这部分消息会一直存在于消息队列中,等待被处理。每个线程中只会有一个MessageQueue 对象。
3.looper
Looper 是每个线程中的 MessageQueue 的管家,调用 Looper 的 loop()方法后,就会进入到一个无限循环当中,然后每当发现 MessageQueue 中存在一条消息,就会将它取出,并传递到 Handler 的 handleMessage()方法中。每个线程中也只会有一个Looper 对象。
主线程也是一个消息循环,因此具有一个looper。主线程的所有工作都是由其looper完成的。
4.Handler:
Handler 顾名思义也就是处理者的意思,它主要是用于发送和处理消息的。发送消息一般是使用 Handler 的 sendMessage()方法,而发出的消息经过一系列地辗转处理后,最终会传递到 Handler 的 handleMessage()方法中。
Looper、Handler、Message和HandlerThread的关系
1.3.2 使用方法
public class MainActivity extends Activity {
public static final int MASSAGE_CODE = 00001;
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 接收message
switch (msg.what) {
case MASSAGE_CODE:
int value = (int) msg.obj;
mTextView.setText(String.valueOf(value / 1000));
msg = Message.obtain();
msg.arg1 = 0;
msg.arg2 = 1;
msg.what = MASSAGE_CODE;
msg.obj = value - 1000;
//<span style="white-space:pre"> </span>循环发送massage
if (value > 0) {
sendMessageDelayed(msg, 1000);
}
break;
}
}
};
private TextView mTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activiyt_handler);
mTextView = (TextView) findViewById(R.id.handler_textView);
Message message = mHandler.obtainMessage();
message.arg1 = 0;
message.arg2 = 1;
//what在这里是相当于一个标牌,用于区别不同的message,可转成常量
message.what = MASSAGE_CODE;
message.obj = 10000;
//发送message
mHandler.sendMessageDelayed(message, 1000);
}
}
- 首先创建一个Handler实例,实现其继承的方法 handleMessage(Message msg) ,在方法中接收并处理message,并将处理完的message发送出去,完成一个循环机制的代码;
- 在onCreate()方法中,使用Handler.obtainMessage(...)方法创建(拉取)一个消息实例,在以创建的Handler中完成Handler操作。
二、服务(Service)
2.1 定义一个服务
public class MusicService extends Service {
private MediaPlayer mMediaPlayer;
@Override
public void onCreate() {
super.onCreate();
mMediaPlayer = MediaPlayer.create(this, R.raw.shalong);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mMediaPlayer.start();
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
mMediaPlayer.stop();
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
2.2 Service和Activity之间的通信——binder
比如说目前我们希望在 MyService 里提供一个下载功能,然后在活动中可以决定何时开始下载,以及随时查看下载进度。实现这个功能的思路是创建一个专门的 Binder 对象来
对下载功能进行管理。
@Nullable
@Override
public IBinder onBind(Intent intent) {
//在这里返回新创建的LocalBinder实例
return mLocalBinder;
}
public class LocalBinder extends Binder {
//可以获取进度的Binder
public int getProgress() {
return 0;
}
}
LocalBinder mLocalBinder = new LocalBinder();
上面的代码中,我们新建了一个 DownloadBinder 类,并让它继承自 Binder,然后在它的内部提供了开始下载以及查看下载进度的方法。接着,在 MyService 中创建了 DownloadBinder 的实例,然后在 onBind()方法里返回了这个实例,这样 MyService 中的工作就全部完成了。
接下来,添加在MainActivity中的代码:
- 首先创建一个ServiceConnection的匿名类,在里面重写onServiceConnected()和onServiceDisconnected()方法。这两个方法分别会在活动与服务成功绑定以及解除绑定的时候调用。
-
在 onServiceConnected()方法中,我们又通过向下转型得到了 LocalBinder 的实例,有了这个实例,活动和服务之间的关系就变得非常紧密了。现在我们可以在活动中根据具体的场景来调用 LocalBinder 中的任何 public 方法,即实现了指挥服务干什么,服务就去干什么的功能。
-
调用bindService()方法将 MainActivity 和MusicService 进行绑定。bindService()方法接收三个参数,第一个参数就是刚刚构建出的 Intent 对象,第二个参数是前面创建出的ServiceConnection 的实例,第三个参数则是一个标志位,这里传入BIND_AUTO_CREATE 表示在活动和服务进行绑定后自动创建服务。这会使得 MyService中的 onCreate()方法得到执行,但 onStartCommand()方法不会执行。调用一下 unbindService()方法解绑。
三、BroadReceiver — 广播接收器
静态注册:注册之后是一直有效的(可用于开机启动)。
使用方法:在mainfest中注册receiver,在程序代码中触发动作发送广播,receiver接收广播,并根据类中定义的逻辑代码进行操作。
动态注册:用完之后还要销掉,要有onStart、onStop函数进行注册和反注册操作。
使用方法:在程序代码中注册receiver,并触发动作发送广播,receiver接收广播,并根据类中定义的逻辑代码进行操作。
广播类型——Normal Broadcasts(标准广播):是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。
Ordered Broadcasts(有序广播):是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。通过 mainfest中的android:priority 属性给广播接收器设置了优先级,优先级比较高的广播接收器就可以先收到广播。
广播又分为系统广播和自定义广播:系统广播 —— 是系统发出的广播,有系统默认值的广播,需要在mainfest中声明使用权限,否则程序将会直接崩溃;
自定义广播 —— 在文件中自定义一个带有一个值的广播,用来发送和接收。
本地广播 —— 使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播。
生命周期:register——> sendBroadcast ——> onReceice ——> unregister