[Android] IntentService

IntentService是什么

  • 本质是一种特殊的Service,继承自Service并且本身是一个抽象类,优先级高于Service。
  • 它可以在后台执行耗时的异步任务,任务完成后会自动停止。
  • 它拥有较高的优先级,不易被系统杀死(因为继承Service),因此比较适合执行一些高优先级的异步任务。
  • 它背部通过HandlerThread和Handler实现异步操作。
  • 创建IntentService时,只需要实现onHandleIntent和构造方法,onHandleIntent是异步方法,可以执行耗时操作。 

IntentService源码分析

IntentService的onCreate方法:

@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);
}

当启动IntentService时,它的onCreate方法将会被调用,其内部会去创建一个HandlerThread并启动,接着创建一个ServiceHandler(继承Handler),并传入 HandlerThread的Looper对象,这样ServiceHandler就变成可以处理异步线程的执行类了(因为Looper对象与HandlerThread绑定,而HandlerThread又是一个异步线程,我们把HandlerThread持有的Looper对象传递给Handler后,ServiceHandler内部就持有异步线程的Looper,自然就可以执行异步任务)。

IntentService如何启动异步任务?IntentService启动后还会去调用onStartCommand方法,而onStartCommand方法又会去调用onStart方法。

@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;
}

onStart方法中,IntentService通过mServiceHandler的sendMessage方法发送一个消息,这个消息将会发送到HandlerThread中进行处理(因为HandlerThread持有Looper对象,所以其实是Looper从消息队列中取出消息进行处理,然后调用mServiceHandler的handleMessage方法)。

ServiceHandler:

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);
    }
}

这里说明onHandlerIntent确实是一个异步处理方法(ServiceHandler本身就是一个异步处理的handler类),在onHandleIntent方法执行结束后,IntentService会通过stopSelf(int startId)方法来尝试停止服务。采用stopSelf(int startId)而不是stopSelf()来停止服务,是因为stopSelf()会立即停止服务,而stopSelf(int startId)会等待所有消息都处理完毕后才终止服务。

@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);

@Override
public void onDestroy() {
       mServiceLooper.quit();
}

onHandlerIntent方法是一个抽象方法,所以在创建IntentService时必须实现该方法,通过分析,onHandleIntent方法也是个异步方法。注意,如果后台任务只有一个的话,onHandleIntent执行完,服务就会销毁,如果任务有多个,onHandleIntent执行完最后一个任务时,服务才会销毁。

每一次执行一个后台任务就必须启动一次IntentService,而IntentService内部则是通过消息的方式发送给HandlerThread的,由Handler中的Looper来处理消息,Looper时按顺序从消息队列中取任务,当有多个任务时,这些任务按照任务时序排队执行。

IntentService和Service的区别 

Service用于后台服务,当应用程序被挂到后台时,为了保证某些组件仍然可以工作。

Service不是独立的进程,也不是独立的线程,它依赖于应用程序的主线程。不建议在Service中进行耗时操作,否则会引起ANR,为了解决这个问题,可以使用IntentService。

IntentService时继承Service的,包含了Service的全部特性和生命周期。IntentService执行onCreate时,内部会开一个线程(HandlerThread)去执行耗时操作。 

如何使用IntentService 

Demo

public class MyIntentService extends IntentService {

    private static final String TAG = "Ekko-Service";

    public static final String DOWNLOAD_URL = "download_url";
    public static final String INDEX_FLAG = "index_flag";
    public static UpdateUI updateUI;

    public MyIntentService() {
        super("MyIntentService");
    }

    public static void setUpdateUI(UpdateUI updateUIInterface) {
        updateUI = updateUIInterface;
    }

    /**
     * 实现异步任务的方法
     *
     * @param intent Activity传递过来的Intent,数据封装在intent中
     */
    @Override
    protected void onHandleIntent(Intent intent) {

        //在子线程中进行网络请求
        Bitmap bitmap = downloadUrlBitmap(intent.getStringExtra(DOWNLOAD_URL));
        Message msg1 = new Message();
        msg1.what = intent.getIntExtra(INDEX_FLAG, 0);
        msg1.obj = bitmap;
        //通知主线程去更新UI
        if (updateUI != null) {
            updateUI.updateUI(msg1);
        }

        Log.d(TAG, "onHandleIntent");
    }

    public interface UpdateUI {
        void updateUI(Message message);
    }

    private Bitmap downloadUrlBitmap(String urlString) {
        HttpURLConnection urlConnection = null;
        BufferedInputStream in = null;
        Bitmap bitmap = null;
        try {
            final URL url = new URL(urlString);
            urlConnection = (HttpURLConnection) url.openConnection();
            in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
            bitmap = BitmapFactory.decodeStream(in);
        } catch (final IOException e) {
            e.printStackTrace();
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
            try {
                if (in != null) {
                    in.close();
                }
            } catch (final IOException e) {
                e.printStackTrace();
            }
        }
        return bitmap;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate");
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        Log.d(TAG, "onStart");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind");
        return super.onBind(intent);
    }
}

Activity

public class ServiceActivity4 extends AppCompatActivity implements MyIntentService.UpdateUI {

    /**
     * 图片地址集合
     */
    private String url[] = {
            "https://img-blog.csdn.net/20160903083245762",
            "https://img-blog.csdn.net/20160903083252184",
            "https://img-blog.csdn.net/20160903083257871",
            "https://img-blog.csdn.net/20160903083257871",
            "https://img-blog.csdn.net/20160903083311972",
            "https://img-blog.csdn.net/20160903083319668",
            "https://img-blog.csdn.net/20160903083326871"
    };

    private ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_service4);
        imageView = (ImageView) findViewById(R.id.image);

        Intent intent = new Intent(this, MyIntentService.class);
        for (int i = 0; i < 7; i++) {//循环启动任务
            intent.putExtra(MyIntentService.DOWNLOAD_URL, url[i]);
            intent.putExtra(MyIntentService.INDEX_FLAG, i);
            startService(intent);
        }
        MyIntentService.setUpdateUI(this);
    }

    //必须通过Handler去更新,该方法为异步方法,不可更新UI
    @Override
    public void updateUI(Message message) {
        mUIHandler.sendMessageDelayed(message, message.what * 1000);
    }

    private final Handler mUIHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            imageView.setImageBitmap((Bitmap) msg.obj);
        }
    };
}

参考:Android 多线程之IntentService 完全详解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值