异步消息处理机制
说明:异步消息处理框架 Handler
、AsyncTask
、HandlerThread
和 IntentService
本质上都是对线程和线程池
的封装。
1. Handler
1.1 what is Handle
handler:handler是一个消息分发对象,进行发送和处理消息。handle通过发送和处理Message和Runnable对象来关联相对应线程的MessageQueue。让耗时操作放在子线程,更新UI放在主线程。
1.2 handle机制原理
handle机制原理.png四者关系.png
1.3 handler异步消息处理的两种方式
(1) 通过handler.post(runnable)的方式来进行消息传递
- 创建Handler对象
- 创建runnable对象并重写run()方法
- 通过handler.post(runnable)方法将runnable对象通过post()方法传到handler中:主线程会在合适的时候执行runnable对象run方法中的代码从而更新UI
(2) 通过handler.sendMessage(message)的方式来进行消息传递
- 创建Handler对象并重写handleMessage()方法
- 创建Message对象添加消息标识后通过handler.sendMessage(message)方法发送消息
- 在handleMessage()方法中根据消息标识处理消息从而更新UI
备注
:post(runnable)只是对sendMessage(message)进行了封装,底层最终调用的还是sendMessage(message)。
注意
:UI线程(主线程)才能更新UI,所以创建Handler只能在主线程而不能在内部类,从而使Handler的HandlerhandleMessage(msg)方法执行在UI线程,这样才能保证UI线程是线程安全的。
1.4 handler异步消息处理示例
(1) 常见的子线程向主线程发送消息更新UI
package comi.example.liy.mytestdemo;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
/**
* Created by liy on 2019-11-06 15:36
*/
public class HandlerWithRunnableActivity extends AppCompatActivity {
private HandlerWithRunnableActivity activity;
//(1)在成员变量中创建Handler对象:创建后Handler就会绑定到UI线程(主线程)
private Handler myHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity = this;
}
@Override
protected void onResume() {
super.onResume();
new MyThread().start();
}
private class MyThread extends Thread{
@Override
public void run() {
super.run();
try{
System.out.println("开始耗时操作");
sleep(5000);
System.out.println("耗时操作完成");
//(2)创建runnable对象并重写run方法
Runnable runnable = new Runnable() {
@Override
public void run() {
/*Toast.makeText(HandlerWithMessageActivity.this,"更新UI",Toast.LENGTH_SHORT).show();*/
Toast.makeText(activity,"更新UI",Toast.LENGTH_SHORT).show();
}
};
myHandler.post(runnable);//(3)完成耗时操作后将runnable对象通过post方法传到handler中:主线程会在合适的时候执行runnable对象run方法中的代码从而更新UI
}catch (Exception e){
e.printStackTrace();
}
}
}
}
package comi.example.liy.mytestdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
/**
* Created by liy on 2019-11-06 15:35
*/
public class HandlerWithMessageActivity extends AppCompatActivity {
private static final int MESSAGE_TEST = 1;//消息标识
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//(1)在成变量中创建Handler对象并重写handleMessage方法
private Handler myHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){//(3)根据消息标识处理消息
case MESSAGE_TEST:
Toast.makeText(HandlerWithMessageActivity.this,"更新UI",Toast.LENGTH_SHORT).show();
}
}
};
@Override
protected void onResume() {
super.onResume();
new MyThread().start();
}
private class MyThread extends Thread{
@Override
public void run() {
super.run();
try{
sleep(5000);
}catch (Exception e){
e.printStackTrace();
}
//(2)创建Message对象添加消息标识后发送消息
Message message = new Message();// Message messsag = myHandler.obtainMessage();
message.what = MESSAGE_TEST;
myHandler.sendMessage(message);
}
}
}
Bundle传参示例
Message message = new Message();
message.what = MESSAGE_TEST;
Bundle bundle = new Bundle();
bundle.putString("number",number);
bundle.putString("name",name);
message.setData(bundle);
myHandler.sendMessage(message);
(2) 不常见的的主线程向子线程发送消息
拓展
:我们平时开发时,经常是子线程向主线程发消息让主线程更新UI,但根据具体的项目需求也可能会要求主线程向子线程发消息。
package comi.example.liy.mytestdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
/**
* Created by liy on 2019-11-07 14:40
* 主线程向子线程发送消息
*/
public class HandlerTestActivity extends AppCompatActivity {
private Handler handler;
private HandlerTestActivity activity;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity = this;
textView = findViewById(R.id.text);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handler.sendEmptyMessage(2);//主线程发送消息
}
});
}
@Override
protected void onResume() {
super.onResume();
new MyThread().start();
}
//子线程接收消息
private class MyThread extends Thread{
@Override
public void run() {
super.run();
//(1)子线程创建Looper对象开启消息循环(默认情况下Android中除主线程外新建的子线程都没有开启消息循环,主线程系统会自动为其创建Looper对象并开启消息循环)
Looper.prepare();
//(2)在子线程中创建Handler
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("threadName:" + Thread.currentThread().getName() + ",messageWhat:" + msg.what);
Toast.makeText(activity,"threadName:" + Thread.currentThread().getName() + ",messageWhat:" + msg.what,Toast.LENGTH_SHORT).show();
}
};
try{
sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
//(3)取出消息对象开始消息循环
//注意:写在Looper.loop()之后的代码不会被执行,这个函数内部是一个死循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。
Looper.loop();//开始消息循环:Looper从消息队列取出消息并交给Handler处理
}
}
}
拓展
:开启子线程的三种方式
1.5 handler引起的内存泄漏及解决方法
(1) handler引起内存泄漏原因:非静态内部类持有外部类的匿名引用导致外部activity无法释放(java相关)。创建的Handler若不是静态内部类,则会隐秘地持有activity的引用,当activity被回收时,若handler内部仍在做耗时操作则handler没有被释放,所有handler所持有的activity的引用也不能被释放,导致activity无法被回收从而导致内存泄漏。
(2) 解决方法:Android常见异常与性能优化
- 静态内部类:Handler 改为
静态
内部类(static) - 弱引用:内部类Handler若调用了外部activity,可使用
弱引用
而不要直接使用activity - 资源回收:在activity的onDestory()生命周期函数中调用
handler.removeCallbacks()
方法
2. AsyncTask框架
2.1 what is AsyncTask
AsyncTask:AsyncTask本质上是封装了线程池和Handler的异步框架,主要是来执行异步任务的(适用于耗时短的操作,耗时长的任务使用线程池比较好),由于内部集成了Handler,所以能够方便地在UI线程(主线程)和工作线程(子线程)灵活切换。
- UI线程(主线程):主线程负责UI的绘制及相应用户的操作
- 工作线程(子线程):子线程负责在后台做耗时操作,避免UI线程的ANR(Application Not Responding)问题
2.2 AsyncTask内部原理
内部原理:AsyncTask框架内部封装了线程池,通过Handler发送消息在UI线程和主线程中传递
2.3 AsyncTask的使用方法(掌握3个参数和5个方法)
3个参数和5个方法.png(1) AsyncTaskTestActivity.java
package comi.example.liy.mytestdemo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* Created by liy on 2019-11-07 17:10
*/
public class AsyncTaskTestActivity extends AppCompatActivity {
private Button button;
private ProgressBar progressBar;
private TextView textView;
private AsyncTaskUpdateInfo asyncTask;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_asynctask);
button = (Button)findViewById(R.id.button03);
progressBar = (ProgressBar)findViewById(R.id.progressBar02);
textView = (TextView)findViewById(R.id.textView01);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
asyncTask = new AsyncTaskUpdateInfo(textView, progressBar);
asyncTask.execute(1000);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
asyncTask.onCancelled();//在activity的onDestroy()方法中取消asyncTask任务避免内存泄漏
}
}
(2) AsyncTaskUpdateInfo .java
package comi.example.liy.mytestdemo;
import android.os.AsyncTask;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* Created by liy on 2019-11-07 13:13
* AsyncTask是android提供的一个抽象类,需派生出子类来执行不同的异步任务
* AsyncTask的三个参数(泛型)分别代表:耗时操作需传递的参数,进度条和返回结果
* AsyncTask的五个方法:
*/
public class AsyncTaskUpdateInfo extends AsyncTask<Integer,Integer,String> {
private TextView textView;
private ProgressBar progressBar;
public AsyncTaskUpdateInfo(TextView textView, ProgressBar progressBar) {
this.textView = textView;
this.progressBar = progressBar;
}
//(1)耗时操作执行前的UI更新
@Override
protected void onPreExecute() {
super.onPreExecute();
textView.setText("开始执行异步线程");
}
//(2)在子线程中执行耗时操作
@Override
protected String doInBackground(Integer... params) {
int i;
for (i = 10; i<=100 ; i+=10) {
publishProgress(i);//publishProgress()执行完成后就会调用onProgressUpdate()来更新进度条
}
return i + params[0].intValue() + "";
}
//耗时操作时的UI实时更新
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
int value = values[0];
progressBar.setProgress(value);
}
//(3)耗时操作完成后的UI更新
@Override
protected void onPostExecute(String s) {//doInBackground()执行完毕后会执行onPostExecute(),并把返回结果传递给onPostExecute()
super.onPostExecute(s);
textView.setText("异步操作执行结束:" + result);
}
@Override
protected void onCancelled(String s) {
super.onCancelled(s);
}
@Override
protected void onCancelled() {
super.onCancelled();
}
}
(3) activity_asynctask.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/textView01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<ProgressBar
android:id="@+id/progressBar02"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
/>
<Button
android:id="@+id/button03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="更新progressbar"
/>
</LinearLayout>
2.4 AsyncTask注意事项
(1) 内存泄漏:AsyncTask引起的内存泄漏的原因和Handler一样。
说明:解决handler引起的内存泄漏可在activity的onDestory()生命周期函数中调用handler.removeCallbacks()
方法,而解决AsyncTask引起的内存泄漏调用asyncTask.onCancelled()
方法即可。
(2) 结果丢失:
- 原因和现象描述:非静态内部类AsyncTask持有外部类activity的引用,当销毁activity时若AsyncTask还在执行耗时任务,则导致activity无法被回收。此时若重新打开activity则此时AsyncTask所持有的activity的引用并非是当前activity,导致结果丢失。
- 解决:在activity的onDestory()生命周期函数中调用asyncTask.onCancelled()方法。
(3) 并行 or 串行:AsyncTask虽然可以执行并行执行耗时操作,但是会导致线程池不稳定,AsyncTask仅适合执行耗时短的操作。
3. HandlerThread框架
3.1 HandlerThread介绍
(1)产生背景:耗时任务需要通过创建子线程来执行,执行完毕会自动销毁子线程;但线程的创建和销毁很消耗系统资源,当第一个耗时任务执行完毕后又有耗时任务,那么就需要重新再创建一个子线程,如此循环地创建和销毁线程很浪费系统资源。
为了解决这个问题,我们可以创建一个循环线程,在线程中创建Looper监听器来进行消息的轮询,即当有耗时任务投放到循环线程当中,线程就开始执行耗时任务,处理完成后循环线程处于阻塞等待状态,直到下一个耗时任务被投放在循环线程(通过阻塞等待来保证性能最优,避免频繁创建销毁线程消耗系统资源)。过程如下:
package comi.example.liy.mytestdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
/**
* Created by liy on 2019-11-07 14:40
* 创建一个循环线程,在线程中创建Looper监听器来进行消息的轮询:HanderThread的原理
*/
public class HandlerTestActivity extends AppCompatActivity {
private Handler handler1;
private HandlerTestActivity activity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activity = this;
}
@Override
protected void onResume() {
super.onResume();
new MyThread().start();
}
//在子线程中调用Looper.prepare()为线程开启消息循环:默认情况下Android中除主线程外新建的子线程都没有开启消息循环,主线程系统会自动为其创建Looper对象并开启消息循环
private class MyThread extends Thread{
@Override
public void run() {
super.run();
//(1)创建Looper对象
Looper.prepare();
handler1 = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
System.out.println("threadName:" + Thread.currentThread().getName() + ",messageWhat:" + msg.what);
Toast.makeText(activity,"threadName:" + Thread.currentThread().getName() + ",messageWhat:" + msg.what,Toast.LENGTH_SHORT).show();
}
};
try{
sleep(3000);
}catch (Exception e){
e.printStackTrace();
}
handler1.sendEmptyMessage(2);
//注意:写在Looper.loop()之后的代码不会被执行,这个函数内部是一个死循环,当调用mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。
Looper.loop();//(2)开始消息循环:Looper从消息队列取出消息并交给Handler处理
}
}
}
然而以上操作可以用已经封装好的HandlerThread类来帮我们完成。
(2) what is HandlerThread:HandlerThread本质上是一个内部建立了looper的特殊线程(继承Thread)
,可以进行looper循环,在HandlerThread内部创建Handler对象来处理消息。通过获取HandlerThread的looper对象传递消息给Handler,可以在handleMessage()方法中执行异步任务。
- 优点:不会阻塞UI线程,使主界面更流畅(HandlerThread将loop转到
子线程
中处理,拥有自己的消息队列,不会干扰或阻塞UI线程) - 缺点:不能同时进行多任务的处理,需等待处理。(与线程池并发不同,HandlerThread背后只有
一个
线程,在线程内部,任务是串行
处理)
3.2 HandlerThread源码解析(内部机制)
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os;
/**
* Handy class for starting a new thread that has a looper. The looper can then be
* used to create handler classes. Note that start() must still be called.
*/
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
/**
* Constructs a HandlerThread.
* @param name
* @param priority The priority to run the thread at. The value supplied must be from
* {@link android.os.Process} and not from java.lang.Thread.
*/
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
/**
* Call back method that can be explicitly overridden if needed to execute some
* setup before Looper loops.
*/
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
/**
* This method returns the Looper associated with this thread. If this thread not been started
* or for any reason is isAlive() returns false, this method will return null. If this thread
* has been started, this method will block until the looper has been initialized.
* @return The looper.
*/
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
/**
* Quits the handler thread's looper.
* <p>
* Causes the handler thread's looper to terminate without processing any
* more messages in the message queue.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p class="note">
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*
* @see #quitSafely
*/
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
/**
* Quits the handler thread's looper safely.
* <p>
* Causes the handler thread's looper to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* Pending delayed messages with due times in the future will not be delivered.
* </p><p>
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
* </p><p>
* If the thread has not been started or has finished (that is if
* {@link #getLooper} returns null), then false is returned.
* Otherwise the looper is asked to quit and true is returned.
* </p>
*
* @return True if the looper looper has been asked to quit or false if the
* thread had not yet started running.
*/
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
/**
* Returns the identifier of this thread. See Process.myTid().
*/
public int getThreadId() {
return mTid;
}
}
3.3 HandlerThread使用
(1) HandlerThreadTestActivity .java
package comi.example.liy.mytestdemo;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
/**
* Created by liy on 2019-11-08 9:15
*/
public class HandlerThreadTestActivity extends AppCompatActivity {
private HandlerThread handlerThread;
private Handler handler;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handlerThread = new HandlerThread("handler-thread");//创建一个线程(HandlerThread是一个具有Looper对象的特殊线程),名字是handler-thread
handlerThread.start();//开启线程
handler = new Handler(handlerThread.getLooper()){//在handler-thread线程中创建Handler对象
@Override
public void handleMessage(Message msg) {//该方法运行在handler-thread线程,可进行耗时操作
super.handleMessage(msg);
Log.v( "HandlerThread: " , "线程名:" + Thread.currentThread().getName() + ",消息标识:" + msg.what) ;
}
};
handler.sendEmptyMessage(1);//在主线程给Handler发消息
new Thread(new Runnable() {
@Override
public void run() {
handler.sendEmptyMessage(2);//在子线程给Handler发消息
}
}).start();
}
@Override
protected void onDestroy() {
super.onDestroy();
handlerThread.quit();//释放资源
}
}
运行效果:
mytestdemo V/HandlerThread:线程名:handler-thread,消息标识:1
mytestdemo V/HandlerThread:线程名:handler-thread,消息标识:2
4. IntentService
4.1 what is IntentService
IntentService:IntentService本质上是一个内部封装了Handler和HandlerThread的特殊服务(继承Service)
,在 IntentService 内有一个工作线程来处理耗时操作。
4.2 IntentService源码解析(内部机制)
说明:IntentService本质上是一个封装了HandlerThread和Handler的异步框架,HandlerThread可以在线程中开启循环,利用Handler来发送消息。
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app;
import android.annotation.WorkerThread;
import android.annotation.Nullable;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
/**
* IntentService is a base class for {@link Service}s that handle asynchronous
* requests (expressed as {@link Intent}s) on demand. Clients send requests
* through {@link android.content.Context#startService(Intent)} calls; the
* service is started as needed, handles each Intent in turn using a worker
* thread, and stops itself when it runs out of work.
*
* <p>This "work queue processor" pattern is commonly used to offload tasks
* from an application's main thread. The IntentService class exists to
* simplify this pattern and take care of the mechanics. To use it, extend
* IntentService and implement {@link #onHandleIntent(Intent)}. IntentService
* will receive the Intents, launch a worker thread, and stop the service as
* appropriate.
*
* <p>All requests are handled on a single worker thread -- they may take as
* long as necessary (and will not block the application's main loop), but
* only one request will be processed at a time.
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For a detailed discussion about how to create services, read the
* <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> developer guide.</p>
* </div>
*
* @see android.os.AsyncTask
*/
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public IntentService(String name) {
super();
mName = name;
}
/**
* Sets intent redelivery preferences. Usually called from the constructor
* with your preferred semantics.
*
* <p>If enabled is true,
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_REDELIVER_INTENT}, so if this process dies before
* {@link #onHandleIntent(Intent)} returns, the process will be restarted
* and the intent redelivered. If multiple Intents have been sent, only
* the most recent one is guaranteed to be redelivered.
*
* <p>If enabled is false (the default),
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
* dies along with it.
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onDestroy() {
mServiceLooper.quit();
}
/**
* Unless you provide binding for your service, you don't need to implement this
* method, because the default implementation returns null.
* @see android.app.Service#onBind
*/
@Override
@Nullable
public IBinder onBind(Intent intent) {
return null;
}
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
* This may be null if the service is being restarted after
* its process has gone away; see
* {@link android.app.Service#onStartCommand}
* for details.
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
}
4.3 IntentService使用方法
- 自定义类MyIntentService继承自IntentService
- 实现构造方法和onHandlerIntent()方法:onHandlerIntent()为异步方法,可执行耗时操作
(1) IntentServiceTestActivity .java
package comi.example.liy.mytestdemo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* Created by liy on 2019-11-08 9:59
*/
public class IntentServiceTestActivity extends AppCompatActivity {
private Button button;
private ProgressBar progressBar;
private TextView textView;
private Intent intent;
public final static String ACTION_TYPE_THREAD = "action.type.thread";
private LocalBroadcastManager localBroadcastManager;
private MyBroadcastReceiver myBroadcastReceiver;
class MyBroadcastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction()==ACTION_TYPE_THREAD){
String status = intent.getStringExtra("status");
int progress = intent.getIntExtra("progress",0);
Log.v("IntentServiceUpdateInfo","status:" + status + ",progress:" + progress + "%");
textView.setText("status:" + status + ",progress:" + progress + "%");
progressBar.setProgress(progress);
}
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_asynctask);
button = (Button)findViewById(R.id.button03);
progressBar = (ProgressBar)findViewById(R.id.progressBar02);
textView = (TextView)findViewById(R.id.textView01);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
intent = new Intent(IntentServiceTestActivity.this,IntentServiceUpdateInfo.class);
startService(intent);
}
});
localBroadcastManager = LocalBroadcastManager.getInstance(this);
myBroadcastReceiver = new MyBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_TYPE_THREAD);
localBroadcastManager.registerReceiver(myBroadcastReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
stopService(intent);
localBroadcastManager.unregisterReceiver(myBroadcastReceiver);
}
}
(2) HandlerThreadTestActivity .java
package comi.example.liy.mytestdemo;
import android.app.IntentService;
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
/**
* Created by liy on 2019-11-08 10:10
*/
public class IntentServiceUpdateInfo extends IntentService {
private boolean isRunning;
private int count;
private LocalBroadcastManager localBroadcastManager;
public IntentServiceUpdateInfo(){
super("IntentServiceUpdateInfo");
Log.v("IntentServiceUpdateInfo","构造方法");
}
@Override
public void onCreate() {
super.onCreate();
localBroadcastManager = LocalBroadcastManager.getInstance(this);
Log.v("IntentServiceUpdateInfo","服务启动");
}
@Override
protected void onHandleIntent(Intent intent) {
Log.v("IntentServiceUpdateInfo","重写onHandleIntent()方法处理耗时任务");
try{
Thread.sleep(1000);
isRunning = true;
count = 0;
while (isRunning){
count++;
if (count>=100){
isRunning = false;
sendThreadStatus("线程结束",count);
return;
}
Thread.sleep(50);
sendThreadStatus("线程运行中",count);
}
}catch (Exception e){
e.printStackTrace();
}
}
//发送进度消息:service通过broadcast向activity传递消息
private void sendThreadStatus(String status, int progress){
Intent intent = new Intent(IntentServiceTestActivity.ACTION_TYPE_THREAD);
intent.putExtra("status",status);
intent.putExtra("progress",progress);
localBroadcastManager.sendBroadcast(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.v("IntentServiceUpdateInfo","服务结束" +count);
}
}
(3) activity_asynctask.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/textView01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<ProgressBar
android:id="@+id/progressBar02"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
/>
<Button
android:id="@+id/button03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="更新progressbar"
/>
</LinearLayout>
5. 拓展
(1) 更新UI可通过handler
,也可以在runOnUiThread
这个方法中。
//更新UI可以在runOnUiThread这个方法或通过handler
runOnUiThread(new Runnable() {
@Override
public void run() {
Bitmap bitmap = BitmapFactory.decodeByteArray(data,0,data.length);
imageView.setImageBitmap(bitmap);
}
});