IntentService使用

来源:互联网 发布:儒释道网络电视台 编辑:程序博客网 时间:2024/06/05 21:58

前言:

IntentService 是继承自 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,当任务执行完后,IntentService 会自动停止,不需要我们去手动结束。如果在短时间内(Service没有自动调用stopService)启动 IntentService 多次,那么每一个耗时操作会以工作队列的方式在 IntentService 的 onHandleIntent 回调方法中执行,依次去执行,执行完自动结束。

IntentService的介绍

public abstract class IntentService extends Service java.lang.Object   ↳android.content.Context    ↳android.content.ContextWrapper     ↳android.app.Service      ↳android.app.IntentService
API原版说明:
IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through 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.
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 onHandleIntent(Intent). IntentService will receive the Intents, launch a worker thread, and stop the service as appropriate.
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.
中文翻译:
IntentService是一个基本类,用来处理异步请求(用Intents来传递的)的服务。客户端通过调用startService(Intent)来发送请求;当需要的时候service被启动,使用一个工作者线程来依次处理每一个Intent;当任务运行完毕之后会自动关闭。
这个“工作队列处理器”模式通常用来帮助处理应用的主线程中的任务。IntentService类是为了简化这个模式和照看结构而存在的。通过继承IntentService实现onHandleIntent(Intent)方法来使用它。IntentService将会接收Intents,创建一个工作者线程,并在适当的时候(任务结束的时候)停止服务。
所有的请求都被一个单独的工作者线程处理--他们或许需要足够长的时间来处理(并且不会阻塞应用的主循环),但是同一时间只能处理一个请求
IntentService中onHandleIntent(Intent intent)方法:

当某个请求需要处理时,这个方法会在工作者线程被调用,一次仅仅会有一个请求被处理,但是处理过程会运行在工作者线程(独立于其他应用程序逻辑运行)。因此,如果某段代码需要执行很长时间,它会阻塞住其他提交到该IntentService的请求,但是不会阻塞住其他任何东西。当所有的请求被处理完成之后,IntentService会停止它自身,因此你不应该手动调用stopSelf()方法。

IntentService的使用方法

  1. 创建一个类,继承IntentService,注意的是这里需要写一个无参的构造方法,不然会报错(IntentService的构造函数一定是参数为空的构造函数,然后再在其中调用super("classname")这种形式的构造函数。因为Service的实例化是系统来完成的,而且系统是用参数为空的构造函数来实例化Service的)
  2. 重写最关键的onHandleIntent处理方法
  3. IntentService继承自Service,所以同样需要到AndroidManifest.xml中去注册
  4. 启动服务。

使用IntentService模拟一个多张图片下载的场景

模拟一个多张图片下载的场景,点击“Add Task”按钮可以增加图片下载任务,下方也会增加一条记录代表新增的下载任务,当下载任务完成时,相应的任务记录也会进行更新客户端可通过startService(Intent)来发送请求,Service会根据需要被启动,使用一个工作者线程轮流处理每个请求,并且当它处理完所有的请求后会停止它自身。
package com.example.dy.intentservicedemo;import android.app.IntentService;import android.content.Context;import android.content.Intent;import android.util.Log;/** * Created by dy on 2016/8/29. */public class MyIntentService extends IntentService {    private String TAG="dy";    public static final String EXTRA_DOWNLOAD_IMAGE="com.example.downloadimage.extra.DOWNLOAD_IMAGE";    public MyIntentService() {        super("worker thread");//name Used to name the worker thread    }    @Override    public void onCreate() {        super.onCreate();        Log.e(TAG, "onCreate: ");    }    /**     * 该方法在主线程中执行,原则上,由于是主线程,可进行UI操作,但是好的编程风格,service不处理activity的内容。     * @param intent     * @param flags     * @param startId     * @return     */    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.e(TAG, "onStartCommand: ");        return super.onStartCommand(intent, flags, startId);    }    @Override    protected void onHandleIntent(Intent intent) {        if(intent!=null){            String path = intent.getStringExtra(EXTRA_DOWNLOAD_IMAGE);            //根据下载路径模拟网络下载操作            downLoadWork(path);            Log.e(TAG, "onHandleIntent: ");        }    }    private void downLoadWork(String path) {        try {            Thread.sleep(3000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }    @Override    public void onDestroy() {        super.onDestroy();        Log.e(TAG, "onDestroy: ");    }    public static void startDownload(Context ctn,String path){        Intent intent=new Intent(ctn,MyIntentService.class);        intent.putExtra(EXTRA_DOWNLOAD_IMAGE,path);        ctn.startService(intent);    }}

package com.example.dy.intentservicedemo;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.LinearLayout;import android.widget.TextView;public class MainActivity extends AppCompatActivity {    private Button btn;    private LinearLayout container;    private int i;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        btn= (Button) findViewById(R.id.btn);        container= (LinearLayout) findViewById(R.id.container);        //点击按钮添加下载任务        btn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                TextView textView=new TextView(MainActivity.this);                String path="/sdcard/imgs"+(++i)+".png";//模拟下载路径                textView.setText(path+" is downloading");                textView.setTag(path);                container.addView(textView);                MyIntentService.startDownload(MainActivity.this,path);            }        });    }}



下面通过广播的方式更新UI:BroadcasReceivert结合IntentService其实是一种很典型高效的做法,同时也更符合OO的思想,通过广播注册与反注册的方式,对两个组件进行解耦。如果使用Handler传递到后台线程作为回调,容易带来的内存泄漏。原因是:匿名内部类对外面的Actvitiy持有引用,如果在Acitivity被销毁的时候,没有对Handler进行显式的解绑,会导致Activity无法正常销毁,这样自然就有了内存泄漏。
package com.example.dy.intentservicedemo;import android.app.IntentService;import android.content.Context;import android.content.Intent;import android.util.Log;/** * Created by dy on 2016/8/29. */public class MyIntentService extends IntentService {    private String TAG="dy";    public static final String EXTRA_DOWNLOAD_IMAGE="com.example.dy.intentservicedemo.extra.DOWNLOAD_IMAGE";    private static final String ACTION_DOWNLOAD_IMAGE="com.example.dy.intentservicedemo.action.DOWNLOAD_IMAGE";    public MyIntentService() {        super("worker thread");////name Used to name the worker thread    }    @Override    public void onCreate() {        super.onCreate();        Log.e(TAG, "onCreate: ");    }    /**     * 该方法在主线程中执行,原则上,由于是主线程,可进行UI操作,但是好的编程风格,service不处理activity的内容。     * @param intent     * @param flags     * @param startId     * @return     */    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.e(TAG, "onStartCommand: ");        return super.onStartCommand(intent, flags, startId);    }    @Override    protected void onHandleIntent(Intent intent) {        if(intent!=null){            if(intent.getAction().equals(ACTION_DOWNLOAD_IMAGE)){                String path = intent.getStringExtra(EXTRA_DOWNLOAD_IMAGE);                //根据下载路径模拟网络下载操作                downLoadWork(path);            }        }        Log.e(TAG, "onHandleIntent: ");    }    private void downLoadWork(String path) {        try {            Thread.sleep(3000);        } catch (InterruptedException e) {            e.printStackTrace();        }        Intent intent=new Intent(MainActivity.RESULT_DOWNLOAD_IMAGE);//发送指定的广播        intent.putExtra(EXTRA_DOWNLOAD_IMAGE,path);//发送广播的同时将对应path传过去        sendBroadcast(intent);    }    @Override    public void onDestroy() {        super.onDestroy();        Log.e(TAG, "onDestroy: ");    }    public static void startDownload(Context ctn,String path){        Intent intent=new Intent(ctn,MyIntentService.class);        intent.setAction(ACTION_DOWNLOAD_IMAGE);        intent.putExtra(EXTRA_DOWNLOAD_IMAGE,path);        ctn.startService(intent);    }}
package com.example.dy.intentservicedemo;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.LinearLayout;import android.widget.TextView;public class MainActivity extends AppCompatActivity {    private Button btn;    private LinearLayout container;    private int i;    private TextView textView;    public static final String RESULT_DOWNLOAD_IMAGE="com.example.dy.intentservicedemo.result.DOWNLOAD_IMAGE";    private BroadcastReceiver receiver=new BroadcastReceiver() {        @Override        public void onReceive(Context context, Intent intent) {            //更新UI            if(intent!=null){                String path = intent.getStringExtra(MyIntentService.EXTRA_DOWNLOAD_IMAGE);//接收传过来的path                //TextView text= (TextView) container.findViewWithTag(textView.getTag());写法错误                TextView text= (TextView) container.findViewWithTag(path);                text.setText(path+"is successful!!!");            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        btn= (Button) findViewById(R.id.btn);        container= (LinearLayout) findViewById(R.id.container);        //点击按钮添加下载任务        btn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                textView = new TextView(MainActivity.this);                String path="/sdcard/imgs"+(++i)+".png";//模拟下载路径                textView.setText(path + " is downloading");                textView.setTag(path);                container.addView(textView);                MyIntentService.startDownload(MainActivity.this,path);            }        });        //注册广播        IntentFilter filter=new IntentFilter(RESULT_DOWNLOAD_IMAGE);        registerReceiver(receiver,filter);    }    @Override    protected void onDestroy() {        super.onDestroy();        unregisterReceiver(receiver);    }}
log信息:
运行结果:
以上大致逻辑是每当点击“Add Task”按钮时,会去调用MyIntentService的startDownload方法,在startDownload中,会调用startService方法去启动我们的MyIntentService,startService方法的参数是一个intent,该intent中封装了我们这回要执行的任务类型(action)以及执行任务所需的参数(Extra),之后会执行到onHandleIntent方法,此时的onHandleIntent方法是运行在工作线程中的,在onHandleIntent方法中,会去执行图片下载的具体任务,下载完成后,会发送一个广播通知主界面相关任务记录进行更新。
另外,不建议通过 bindService() 启动 IntentService。IntentService 源码中的 onBind() 默认返回 null;不适合 bindService() 启动服务,如果你执意要 bindService() 来启动 IntentService,可能因为你想通过 Binder 或 Messenger 使得 IntentService 和 Activity 可以通信,这样那么 onHandleIntent() 不会被回调,相当于在你使用 Service 而不是 IntentService。

上述代码下载:源码

IntentService源码解析:

见下方参考资料

参考资料:

IntentService官方源码:https://developer.android.com/reference/android/app/IntentService.html

Android IntentService完全解析 当Service遇到Handler:http://blog.csdn.net/lmj623565791/article/details/47143563

IntentService 示例与详解:http://www.jianshu.com/p/332b6daf91f0

服务Service(上)- IntentService:http://blog.csdn.net/flowingflying/article/details/7616333

IntentService源码解析:http://www.jianshu.com/p/f7dd2cd64d11

0 0
原创粉丝点击