0
点赞
收藏
分享

微信扫一扫

Android开发之IntentService(另类…

扬帆远航_df7c 2023-07-27 阅读 58

以前做项目的时候一直都是用Asynctask或者自己开Thead(线程)来处理后台耗时操作,却很少注意到还有个IntentService,前段时间看到了一篇关于IntentService的解释,发现了它相对于Service来说有很多更加方便之处,今天在这里稍微来总结下我的心得。


   首先IntentService是继承自Service的,那我们先看看Service的官方介绍,这里列出两点比较重要的地方:


     1.A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.


     2.A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).


     稍微翻一下


     1.Service不是一个单独的进程 ,它和应用程序在同一个进程中。


     2.Service不是一个线程,所以我们应该避免在Service里面进行耗时的操作


关于第二点我想说下,不知道很多网上的文章都把耗时的操作直接放在Service的onStart方法中,而且没有强调这样会出现Application Not Responding!希望我的文章能帮大家认清这个误区(Service不是一个线程,不能直接处理耗时的操作)。


      有人肯定会问,那么为什么我不直接用Thread而要用Service呢?关于这个,大家可以网上搜搜,这里不过多解释。有一点需要强调,如果有耗时操作在Service里,就必须开启一个单独的线程来处理!!!这点一定要铭记在心。  


      IntentService相对于Service来说,有几个非常有用的优点,首先我们看看官方文档的说明:


        IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests throughstartService(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使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker thread中处理,不会阻塞应用程序的主线程,这里就给我们提供了一个思路,如果有耗时的操作与其在Service里面开启新线程还不如使用IntentService来处理耗时操作。

下面给一个小例子:


package com.xmagicj.intentservice;  
                                
import android.app.Service;  
import android.content.Intent;  
import android.os.IBinder;  
                                
public class MyService extends Service {  
                                
    @Override
    public void onCreate() {  
        super .onCreate();  
    }  
                                    
    @Override
    public void onStart(Intent intent, int startId) {  
        super .onStart(intent, startId);  
        //经测试,Service里面是不能进行耗时的操作的,必须要手动开启一个工作线程来处理耗时操作  
        System.out.println( "onStart" );  
        try {  
            Thread.sleep( 20000 );  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println( "睡眠结束" );  
    }  
                                    
    @Override
    public IBinder onBind(Intent intent) {  
        return null ;  
    }  
}



Android SDK 中介绍IntentService,它主要负责以下几个方面:


Creates a default worker thread that executes all intents delivered to onStartCommand() separate from your application's main thread.


  生成一个默认的且与主线程互相独立的工作者线程来执行所有传送至 onStartCommand() 方法的Intetnt


Creates a work queue that passes one intent at a time to your onHandleIntent() implementation, so you never have to worry about multi-threading.


  生成一个工作队列来传送Intent对象给你的onHandleIntent()方法,同一时刻只传送一个Intent对象,这样一来,你就不必担心多线程的问题。


Stops the service after all start requests have been handled, so you never have to call stopSelf().


  在所有的请求(Intent)都被执行完以后会自动停止服务,所以,你不需要自己去调用stopSelf()方法来停止该服务


Provides default implementation of onBind() that returns null.


  提供了一个onBind()方法的默认实现,它返回null


Provides a default implementation of onStartCommand() that sends the intent to the work queue and then to your onHandleIntent() implementation


  提供了一个onStartCommand()方法的默认实现,它将Intent先传送至工作队列,然后从工作队列中每次取出一个传送至onHandleIntent()方法,在该方法中对Intent对相应的处理


从以上看来,你所需要做的就是实现 onHandleIntent() 方法,在该方法内实现你想进行的操作。另外,继承IntentService时,你必须提供一个无参构造函数,且在该构造函数内,你需要调用父类的构造函数,如下

2.IntentService:


package com.xmagicj.intentservice;  
                               
import android.app.IntentService;  
import android.content.Intent;  
                               
public class MyIntentService extends IntentService {  
                               
    public MyIntentService() {  
        super ( "yyyyyyyyyyy" );  
    }  
                               
    @Override
    protected void onHandleIntent(Intent intent) {  
        // 经测试,IntentService里面是可以进行耗时的操作的  
        //IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent  
        //对于异步的startService请求,IntentService会处理完成一个之后再处理第二个  
        System.out.println( "onStart" );  
        try {  
            Thread.sleep( 20000 );  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println( "睡眠结束" );  
    }  
}


测试主程序:



package com.xmagicj.intentservice;  
                            
import android.app.Activity;  
import android.content.Intent;  
import android.os.Bundle;  
                            
public class ServiceDemoActivity extends Activity {  
    
    @Override
    public void onCreate(Bundle savedInstanceState) {  
        super .onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        startService( new Intent( this ,MyService. class )); //主界面阻塞,最终会出现Application not responding  
        //连续两次启动IntentService,会发现应用程序不会阻塞,而且最重的是第二次的请求会再第一个请求结束之后运行(这个证实了IntentService采用单独的线程每次只从队列中拿出一个请求进行处理)  
        startService( new Intent( this ,MyIntentService. class ));  
        startService( new Intent( this ,MyIntentService. class ));  
    }  
}



再举另外一个网上看到的例子:



// activity 的onCreate()  
@Override
    public void onCreate(Bundle savedInstanceState) {  
        super .onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
                   
        startSer1 = (Button) findViewById(R.id.startSer1);  
        stopSer1 = (Button) findViewById(R.id.stopSer1);  
                   
        startSer2 = (Button) findViewById(R.id.startSer2);  
        stopSer2 = (Button) findViewById(R.id.stopSer2);  
                   
        log = (TextView) findViewById(R.id.log);  
                   
        logView = (ScrollView) findViewById(R.id.logView);  
                   
        startSer1.setOnClickListener(btnListener);  
        stopSer1.setOnClickListener(btnListener);  
                   
        startSer2.setOnClickListener(btnListener);  
        stopSer2.setOnClickListener(btnListener);  
                   
        intent = new Intent(MyServiceActivity. this , IntentServiceDemo. class );  
                   
        // 打印出主线程的ID  
        long id = Thread.currentThread().getId();  
        updateLog(TAG + " ----> onCreate() in thread id: " + id);  
    }


// service 代码  
package com.archer.rainbow;  
                  
import java.text.SimpleDateFormat;  
import java.util.Date;  
                  
import android.app.IntentService;  
import android.content.Intent;  
                  
public class IntentServiceDemo extends IntentService {  
    private static final String TAG = "IntentServiceDemo" ;  
    private static final SimpleDateFormat SDF_DATE_FORMAT = new SimpleDateFormat( "yyyy/MM/dd hh:mm:ss.SSS" );  
                  
    public IntentServiceDemo() {  
        super (TAG);  
        MyServiceActivity.updateLog(TAG + " ----> constructor" );  
    }  
                  
    @Override
    public void onCreate() {  
        super .onCreate();  
                  
        // 打印出该Service所在线程的ID  
        long id = Thread.currentThread().getId();  
        MyServiceActivity.updateLog(TAG + " ----> onCreate() in thread id: "
                + id);  
    }  
                  
    @Override
    public void onDestroy() {  
        super .onDestroy();  
        MyServiceActivity.updateLog(TAG + " ----> onDestroy()" );  
    }  
                  
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {  
        MyServiceActivity.updateLog(TAG + " ----> onStartCommand()" );  
        // 记录发送此请求的时间  
        intent.putExtra( "time" , System.currentTimeMillis());  
        return super .onStartCommand(intent, flags, startId);  
    }  
                  
    @Override
    public void setIntentRedelivery( boolean enabled) {  
        MyServiceActivity.updateLog(TAG + " ----> setIntentRedelivery()" );  
        super .setIntentRedelivery(enabled);  
    }  
                  
    @Override
    protected void onHandleIntent(Intent intent) {  
        // 打印出处理intent所用的线程的ID  
        long id = Thread.currentThread().getId();  
        MyServiceActivity.updateLog(TAG  
                + " ----> onHandleIntent() in thread id: " + id);  
        long time = intent.getLongExtra( "time" , 0 );  
        Date date = new Date(time);  
        try {  
            // 打印出每个请求对应的触发时间  
            MyServiceActivity.updateLog(TAG  
                    + " ----> onHandleIntent(): 下载文件中..." + SDF_DATE_FORMAT.format(date));  
            Thread.sleep( 3000 );  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
    }  
                  
}

应用启动时,界面如下:





从此图可以看出,主线程(UI线程)的ID是1。接,连续点击三次Start Service 1 按钮,得如下画面:






从此图中可以看出,IntentServiceDemo的onCreate()所处的线程ID仍为1,说明它是在主线程中被执行的,且只被执行一次。然后,我每点击一次按钮,它都会触发一下onStartCommand()方法。仔细看第二次与第三次的onCommand()方法以及onHandleIntent()打印出来的语句,你会发现,第二、三两次点击按钮与第一次点击按钮的时间是没有超过3秒钟的,它们是连续被执行的,这说明了什么呢?说明,在第一个intent被处理时(即onHandleIntent()处于运行中),该Service仍然可以接受新的请求,但接受到新的请求后并没有立即执行,而是将它们放入了工作队列中,等待被执行。



这就是 IntentService 的简单用法。但你若是想在Service中让多个线程并发的话,就得另想法子喽。比如,使用第一种方法,在Service内部起多个线程,但是这样的话,你可要处理好线程的同步哦~~~  

————————————————


举报

相关推荐

0 条评论