导读:
1. 当我们的服务需要多线程运行时,需要使用扩展Service类,对于每一个启动请求它都用一个工作线程处理任务,并且每次只处理一个请求。
2.当我们的服务需要通过一个工作队列来处理启动请求时,可以使用扩展IntentService类。
该Service会在需要的时候创建,当完成所有的任务以后自己关闭,且请求是在工作线程处理的。这么说,我们使用了IntentService最起码有两个好处,一方面不需要自己 去new Thread了;另一方面不需要考虑在什么时候关闭该Service了。
那么扩展IntentService的执行步骤:
这是Service类的子类,它使用了工作(worker)线程来处理所有的启动请求,每次请求都会启动一个线程。 如果服务不需要同时处理多个请求的话,这是最佳的选择。 所有你要做的工作就是实现onHandleIntent()即可,它会接收每个启动请求的intent,然后就可在后台完成工作。
创建一个缺省的工作(worker)线程,它独立于应用程序主线程来执行所有发送到onStartCommand()的intent。
创建一个工作队列,每次向你的onHandleIntent()传入一个intent,这样你就永远不必担心多线程问题了。
在处理完所有的启动请求后,终止服务,因此你就永远不需调用stopSelf()了。
提供缺省的onBind()实现代码,它返回null。
提供缺省的onStartCommand()实现代码,它把intent送入工作队列,稍后会再传给你的onHandleIntent()实现代码。
以上所有步骤将汇成一个结果:你要做的全部工作就是实现onHandleIntent()的代码,来完成客户端提交的任务。(当然你还需要为服务提供一小段构造方法。)
以下是个IntentService的实现例程:
public class HelloIntentService extends IntentService { /** * 构造方法是必需的,必须用工作线程名称作为参数 * 调用父类的[http://developer.android.com/reference/android/app/IntentService.html#IntentService(java.lang.String) IntentService(String)]构造方法。 */ public HelloIntentService() { super("HelloIntentService"); } /** * IntentService从缺省的工作线程中调用本方法,并用启动服务的intent作为参数。 * 本方法返回后,IntentService将适时终止这个服务。 */ @Override protected void onHandleIntent(Intent intent) { // 通常我们会在这里执行一些工作,比如下载文件。 // 作为例子,我们只是睡5秒钟。 long endTime = System.currentTimeMillis() + 5*1000; while (System.currentTimeMillis() < endTime) { synchronized (this) { try { wait(endTime - System.currentTimeMillis()); } catch (Exception e) { } } } } }
所有你需要做的就是:一个构造方法和一个onHandleIntent()方法的实现。
如果你还决定重写其它的回调方法,比如onCreate()、onStartCommand()、onDestroy(), 请确保调用一下父类的实现代码,以便IntentService能正确处理工作线程的生命周期。
比如说,onStartCommand()必须返回缺省实现代码的结果(缺省代码实现了如何获取传给onHandleIntent()的intent):
@Override public int onStartCommand(Intent intent, int flags, int startId) { Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent,flags,startId); }
除了onHandleIntent()以外,唯一不需要调用父类实现代码的方法是onBind()(不过如果你的服务允许绑定,你还是需要实现它)。
/**********************************************************以下是一个模拟上传图片的DEMO***************************************************************************************/
出现情景:当我们上传多张图片,在上传过程中,我们可能将应用置于后台,去做别的,这时我们的Activity可能会被杀死,所以我们需要将上传图片这个操作交给Service来实现,优点还有是:当服务被杀死,我们还可以通过设置 startForeground(int,Notification)设置优先级。
Service
package com.intentservice;
import com.example.uploadimage.MainActivity;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
/**
* IntentService:会在需要时自动开启线程去操作耗时任务,但操作完成时会自动关闭:因此IntentService不需要我们自己亲自去管理,使用起来比较方便
* @author galaxy
*
*/
public class UploadImgService extends IntentService {
private static final String ACTION_UPLOAD_IMG = "com.intentservice.action.UPLOAD_IMAGE";
public static final String EXTRA_IMG_PATH = "com.intentservice.extra.IMG_PATH";
public static void startUploadImg(Context context,String path){
Intent intent = new Intent();
intent.setAction(ACTION_UPLOAD_IMG);
intent.putExtra(EXTRA_IMG_PATH, path);
context.startService(intent);
Log.e("jg", "UploadImgService-----startUploadImg");
}
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
}
/*构造方法的参数必须是工作线程名称*/
public UploadImgService() {
super("UploadImgService");
}
/*
* 缺省的onStartCommand()将intent送入到工作队列中,然后在传给onHandleIntent
*/
@Override
protected void onHandleIntent(Intent intent) {
Log.e("jg", "UploadImgService-----onHandleIntent");
if(intent != null){
final String action = intent.getAction();
if(ACTION_UPLOAD_IMG.equals(action)){
final String path = intent.getStringExtra(EXTRA_IMG_PATH);
handleUploadImg(path);
}
}
}
/**
* 书写一个方法,用来执行上传 这个动作
* @param path: 要上传到的路径
*/
public void handleUploadImg(String path){
try {
Thread.sleep(3000);//模拟上传耗时
Intent intentUpload = new Intent(MainActivity.UPLOAD_RESULT);//参数说明:给这个intent加一个标识,上传结果
intentUpload.putExtra(EXTRA_IMG_PATH, path);
System.out.println("上传的路径-handleUploadImg-->"+path);
//使用广播,通知Activity,Service的任务完成状态
sendBroadcast(intentUpload);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}
Activity
package com.example.uploadimage;
import com.intentservice.UploadImgService;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
* 实现一个使用IntentService在后台上传图片的功能 (注:Service与Activity之间的通信我们可以选择使用广播)
* @author galaxy
*
*/
public class MainActivity extends Activity{//在主线程里发送请求
public static final String UPLOAD_RESULT = "com.intentservice.UPLOAD_RESULT";
private LinearLayout mLyTaskContainer;
BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
//Intent broadCastIntent = getIntent();
if(intent.getAction()==UPLOAD_RESULT){
final String path = intent.getStringExtra(UploadImgService.EXTRA_IMG_PATH);
handleResult(path);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLyTaskContainer= (LinearLayout) findViewById(R.id.id_ll_taskcontainer);
//注册 添加标记的 广播
registReceiver();
}
private void registReceiver(){
IntentFilter filter = new IntentFilter();
filter.addAction(UPLOAD_RESULT);
registerReceiver(mBroadcastReceiver, filter);
}
int i = 0;
public void addTask(View view)
{
//模拟路径
String path = "/sdcard/imgs/" + (++i) + ".png";
UploadImgService.startUploadImg(MainActivity.this, path);
TextView tv = new TextView(this);
mLyTaskContainer.addView(tv);
tv.setText(path + " is uploading ...");
tv.setTag(path);
}
/**
* 处理
* @param path
*/
public void handleResult(String path){
TextView tv = (TextView) mLyTaskContainer.findViewWithTag(path);
tv.setText(path + " upload success ~~~ ");
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unregisterReceiver(mBroadcastReceiver);
}
}
布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:id="@+id/id_ll_taskcontainer"
android:orientation="vertical">
<Button
android:id="@+id/btn_click"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="startTask"
android:textSize="25sp"
android:background="#FF83FA"
android:onClick="addTask"
/>
</LinearLayout>
这里尤其注意的地方:
在Manifest.xml文件的<application>节点中注册Service和设置intent-filter
<service
android:name="com.intentservice.UploadImgService"
>
<intent-filter>
<action android:name="com.intentservice.action.UPLOAD_IMAGE" />
</intent-filter>
</service>
因为项目中设置了action,所以在注册的时候没有添加 <action android:name="com.intentservice.action.UPLOAD_IMAGE" />,当时真是快崩溃了~~~~
源码地址:点击打开链接
参考网址:http://blog.csdn.net/lmj623565791/article/details/47143563
http://www.android-doc.com/guide/components/services.html#.E6.89.A9.E5.B1.95IntentService.E7.B1.BB