美文网首页
Service 学习

Service 学习

作者: Ucoon | 来源:发表于2016-09-07 22:12 被阅读18次

    Service 学习要点

    1.Service概述

    Service的主要作用是让系统在后台在后台做一些不与用户交互的操作(例如耗时操作:下载网络资源,长期运行的操作:播放音乐)
    Service与Thread的区别:(1)Service不是在一个独立的进程中,它与我们的应用程序在同一进程(process)中 (2)Service也不是一个线程,相反,它是运行在主线程的(即UI线程),因此若我们要在Service中进行耗时操作时,需要开启一个子线程,在其中进行耗时操作,否则很容易出现ANR错误(Application Not Responding 程序无响应)

    2.Service用法

    ServiceTest.java如下:

    public class ServiceTest extends Service {

    private MyLocalBinder myLocalBinder=new
    MyLocalBinder();

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("TAG","onCreate");
    }
    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("TAG","onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e("TAG","onBind");
        return myLocalBinder;
    }
    
    @Override
    public boolean onUnbind(Intent intent) {
        Log.e("TAG","onUnbind");
        return super.onUnbind(intent);
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("TAG","onDestroy");
    }
    
    //对外提供的访问方法
    public void downLoad(){
        Log.e("downLoad","正在下载...");
    }
    public void undownLoad(){
        Log.e("downLoad","取消下载...");
    }
    class MyLocalBinder extends Binder{
        public ServiceTest getServiceTestInstance(){
            return ServiceTest.this;
        }
        //...这里也可以继续写方法对外提供
    }
    

    }

    与Activity相似,使用Service也需要通过intent,不能忘记的是在使用Service前,需要在AndroidManifest.xml中进行声明

    启动方式一:startService()

    通过打印Service的生命周期,我们发现第一次启动Service的时候,会执行onCreate()和onStartCommand(),**
    再次启动时,只会执行onStartCommand(),也就是说onCreate()只会在第一次启动的时候进行初始化
    **点击“stopService”后,Service被销毁,进入onDestroy()方法。不管我们启动了多少次Service,只要我们在外部调用一次Context.stopService()或者在Service内部调用stopSelf(),Service就会被销毁

    上面这种启动方式的缺点:启动完Service后,这个Service就在后台运行了,同时也与启动它的Activity失去了联系,因为不能通过ServiceTest service = new ServiceTest()的方式启动Service,因而我们的Activity中不能获取到ServiceTest的实例。
    为了解决与启动Service的组件的通信能力,还有一个解决方案就是通过广播的形式。我们在Activity中发出一些想用操作广播,在Service中注册该广播,Service接收到该广播信息后,完成相应的功能。但是频繁发送广播比较消耗性能,同时,由于广播接受者中的onReceive()中,不能执行长时间的工作,时间超过后,可能就直接跳出了方法。因此,这种方案不是首选。

    启动方式二:bindService() Bound机制

    通过bindService()方式第一次启动后,会执行onCreate()和onBind()方法,当我们点击“unBindService“时,走的是onUnbind()和onDestroy()方法。如果有另一个组件对同一个Service进行bindService()操作(也就是在bindService()中传入不同的ServiceConnection,此时只会进入onBind()方法,即onCreate()只会在第一次启动的时候进行初始化

    总结:可以看到,不管是通过哪种方式启动Service,同一个Service在整个应用程序中只有一个实例存在。区别:(1)两种方式所走的生命周期是不一样的(2)何时被销毁:当我们通过startService()启动时,不管我们启动了多少次Service,只要我们在外部调用一次Context.stopService()或者在Service内部调用stopSelf(),Service就会被销毁;而当我们通过bindService()启动时,前面我们多次启动service后,当所有客户端发出unBindService(),这个Service将被系统销毁。(3)当Service即被startService()启动也被bindService()启动时,这种情况下,Service必须在既没有任何activity关联又停止的情况下,Service才会被销毁。

    3.IntentService

    我们在第一部分谈到,有时需要在service中进行耗时操作,此时就需要开启一个子线程,而对于这种需求,Android提供了IntentService给用户,intentservice内部已经帮我们开启了线程,我们只需要实现它的onHandleIntent方法,在里面实现我们的功能即可,注:intentservice不能处理多个线程的请求,但是可以处理多个service的请求(此处求解?)

    IntentService提供的功能:(1)所有请求处理完成后自动停止服务(2)提供了默认onBind()的实现,直接返回null,意味着我们只能通过startService()的方式启动IntentService

    public class MyIntentService extends IntentService

    {

    public MyIntentService()

    {
    super("MyIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Log.e("MyIntentService","Thread is"+Thread.currentThread().getId());
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("OnDestroy","OnDestroy");
    }
    

    }

    使用时需注意两点:首先要提供一个无参的构造方法,里面调用父类的有参构造方法,第二是实现onHandleIntent这个抽象方法。

    4.前台Service

    Service默认都是在后台默默运行的,用户基本察觉不到有Service在运行。此时,Service的优先级是比较低的,当系统资源不足的时候,易被销毁。因此,如果我们想让用户知道有Service在后台运行,如音乐播放器,或者想让Service一直保持运行状态,不容易被系统回收,此时,就可以考虑使用前台Service。前台Service是被认为是用户已知的正在运行的服务,当系统需要释放内存时不会优先杀掉该进程。
    用法:

    @Override

    public void onCreate() {

        super.onCreate();
        Log.e("TAG","onCreate");
        Notification notification=new Notification(R.mipmap.ic_launcher,"前台通知",System.currentTimeMillis());
        Intent intent=new Intent(this,MainActivity.class);
        PendingIntent pendingIntent=PendingIntent.getActivity(this,0,intent,0);
        notification.setLatestEventInfo(this, "通知标题", "前台Service内容", pendingIntent);
        //设置到前台运行,第一个参数为通知notification的唯一ID
        startForeground(1,notification);
    }
    (关于Notification在SDK23以后和SDK22之前用法不一样,上面是SDK22以前的,下面是SDK23以后的)
    
    Notification.Builder builder=new Notification.Builder(getApplication());
        builder.setContentInfo("补充内容");
        builder.setContentText("主内容区");
        builder.setContentTitle("通知标题");
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setTicker("新消息");
        builder.setAutoCancel(true);
        builder.setWhen(System.currentTimeMillis());
        Intent intent = new Intent(getApplication(), MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(getApplication(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        builder.setContentIntent(pendingIntent);
        Notification notification = builder.build();
    

    如果我们要移除这个前台Service,只需要调用stopService()即可

    相关文章

      网友评论

          本文标题:Service 学习

          本文链接:https://www.haomeiwen.com/subject/lhvjettx.html