Service的知识

Service看过很多遍,今天尝试着自己实践和总结一下。主要总结Service的启动方式(同一个进程和不同进程)以及特点,交互(包括AIDL)

一:Service的启动方式有两种,一种是startService,另一种是bindService 

          1.创建一个Service

public class MyStartService1 extends Service {
    int count=0;

    Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 100:
                    count+=1;
                    Log.e("TAG","MyStartService1正在执行:"+count);
                    sendEmptyMessageDelayed(100,3000);
                    break;
                case 200:
                    break;
            }
        }
    };

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("TAG", "MyStartSerice1--onCreate--当前进程:"+getCurProcessName(this) );
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.e("TAG", "MyStartSerice1--onStartCommand-starttId:" + startId);
        if (intent != null) {
            String extra = intent.getStringExtra("extra");
            Log.e("TAG", "MyStartSerice1--intent参数:" + extra);

        } else {
            Log.e("TAG", "MyStartSerice1--intent参数:null!!!");
        }
        handler.removeCallbacksAndMessages(null);
        Message obtain = Message.obtain();
        obtain.what=100;
        handler.sendMessage(obtain);
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        handler.removeCallbacksAndMessages(null);
        Log.e("TAG", "MyStartSerice1--onDestroy");
    }

    public String getCurProcessName(Context context) {
        int pid = android.os.Process.myPid();
        ActivityManager mActivityManager = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningAppProcessInfo appProcess : mActivityManager
                .getRunningAppProcesses()) {
            if (appProcess.pid == pid) {
                return appProcess.processName;
            }
        }
        return "";
    }
}

2.启动和停止方式

     同一个进程中:直接startService

intentService = new Intent(TestActivity1.this, MyStartService1.class);
intentService.putExtra("extra","我是参数,test1");
startService(intentService);

   不同进程中:需要通过包名,类名进行开启setComponent(new ComponentName(包名,类名))

intentService = new Intent();
intentService.putExtra("extra","test2参数");
intentService.setComponent(new ComponentName("com.example.liukang.mykuajincheng",MyStartService2.class.getName()));
startService(intentService);

3.两个APP之间,如果一个A应用去启动B应用的Service,而此时B应用已经被杀死了。那如何启动:

a. B应用的Service 需要做的是 :

android:exported="true"
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

b. A应用需要开启一个Servivce,然后在此Service里面用

startForegroundService(intent1);

方式去启动B应用的Service。

c. 在B应用的这个Service中需要开启一下消息通知,否则会抛异常。(android O 开始已经不允许开一个后台服务了)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    setForeground();
}
@TargetApi(26)
private void setForeground(){
    NotificationManager manager=(NotificationManager)getSystemService (NOTIFICATION_SERVICE);
    NotificationChannel channel=new NotificationChannel (ID,NAME,NotificationManager.IMPORTANCE_HIGH);
    manager.createNotificationChannel (channel);
    Notification notification=new Notification.Builder (this,ID)
            .setContentTitle ("收到一条重要通知")
            .setContentText ("这是重要通知")
            .setSmallIcon (R.mipmap.ic_launcher)
            .setLargeIcon (BitmapFactory.decodeResource (getResources (),R.mipmap.ic_launcher))
            .build ();
    startForeground (1,notification);
}

 

关闭Service: stopService(intentService)和stopSelf(startId)

stopService(intentService);

 

二:startService周期:

 

onCreate-->onStartCommand-->onDestroy  如果是已经开启的startservice,无论startService多少次,都不会再去oncre,而是一直调用onStartCommand方法

可以被很多个Activity开启,也可以在任意一个Acivity里通过stopService(intent)进行结

在startCommand中返回的三种Int类型的返回值意义:

1.START_NOT_STICKY = 2  被杀后不重启。服务被启动之后,当服务所在进程被杀死,并且当前没有新的Intents等待发送给它,那么不再新建服务,并被标记为非启动状态,直至下一个明确启动调用—startService()。

2.START_STICKY = 1  被杀后自动重启,保持启动状态,不保持Intent,重新调用onStartCommand,无新Intent则为空Intent—杀死重启后,不继续执行先前任务,能接受新任务

3.START_REDELIVER_INTENT =3  如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。

startService的特点:

1.他开启的是一个服务,他的优先级,前台进程>可见进程>服务进程>后台进程>空进程,所以在资源不足的情况下会尽量存活。

2.当资源不足,服务被杀死之后,当资源充裕的时候又可以重新启动,根据startCommmand()返回类型决定。

3.多次启动,只会执行一次onCreate(),多次执行startCommand()     

4. 当启动服务的界面,类Destroy()的时候,他仍然会继续运行,另外可以在任意其他界面通过调用stopService(intent)结束它

,对于一些长时间运行的任务可以放在服务里面,比如心跳之类的网络请求。

 

二 BindService绑定服务,这是一个重头戏,因为他涉及到交互包括跨进程的AIDL,由浅入深的说到说到。

简述:生命周期 onCreate()--> onBind()-->onUnbind()-->onDestroy()

1.在同一个进程中,先创建Service1: onBind()返回一个Binder对象并重写了几个方法

package com.example.liukang.mykuajincheng.bindservice;

import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.Log;

public class MyBindService1 extends Service {
    int  count=0;
    Handler  handler=new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what){
                case 1000:
                    Log.e("TAG","MyBindService1服务开启了:"+count);
                    count+=1;
                    handler.sendEmptyMessageDelayed(1000,3000);
                    break;
            }
            return true;
        }
    });

    MyBinder1 myBinder1 = new MyBinder1();

    class MyBinder1 extends Binder implements Iterface {

        public MyBindService1 getService() {
            return MyBindService1.this;
        }


        @Override
        public void start() {
            handler.sendEmptyMessage(1000);

        }

        @Override
        public void stop() {
            handler.removeCallbacksAndMessages(null);

        }

        @Override
        public String open(String ss) {
            return "result=" + ss;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("TAG", "MyBindService1:onCre");
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e("TAG", "MyBindService1:onBind");
        return myBinder1;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e("TAG", "MyBindService1:onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void unbindService(ServiceConnection conn) {
        super.unbindService(conn);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("TAG", "MyBindService1:onDestroy");
        handler.removeCallbacksAndMessages(null);
    }


    interface Iterface {
        void start();

        void stop();

        String open(String ss);
    }
}

2.启动

先创建一个ServiceConnection对象,这个对象里面可以获取Binder对象,拿到他就可以操作服务里面的方法了,让服务去执行我们控制的命令

通过bindService(intent, myConnection, BIND_AUTO_CREATE);去启动服务,如下:

这样便绑定了服务,并在onServiceConnected()方法中持有服务的Binder代理对象从而实现了对服务中任务的控制。

 

  结束服务:当启动此服务的宿主Activity销毁的时候,或者调用unbindService(myConnection),便可以结束改服务。

注意:

 

 

2.上面的只是实现了单向的通信,即是Activity-->Service发出指令。 要想实现交互的通信就需要借助Messenger,另外他还可以应用在跨进程中使用,同一个应用中的不同进程,或者不同的应用之间的进程都可以进行相互通信。

创建一个Service的主要步骤:

先创建handler对象并构造生成Messenge对象

然后在onBind()中去返回一个代理,和之前的代理不同,这个代理是从messenger中拿到的

然后看如何启动它

首先创建ServiceConnection对象,然后通过IBinder对象去获取服务中的Messenger对象

 

bindService(intent, myConnection, BIND_AUTO_CREATE)  绑定该服务

 

Activity中调用服务的方法:创建一个message消息,然后通过获取到的Service中的Messenge对象将其发送给服务,Messenger.send(msg)

 

此时服务中的Messenger中的handler会收到刚才Activity中发送来的消息,就可以根据参数或者标识进行处理实现了Activity-->Service的通信。

那如何让Service对Activity进行通信呢?我们可以猜想一下:如果Activity也有一个Messenge对象,并且让Service去持有它那么不是一样可以通过Messende.send(msg)给Activity发送消息实现通讯么?  

首先,Activity中创建handler对象,并且用它去构造一个Messenge对象,如下:

 

然后,将上面的cMessenger对象放到msg消息包中,这样发送给Service服务的Message中就包含有Activity的Messenge对象了,如下:

 

最后在Service中接到消息后,取出Activity中的Messenge,此时便持有Activity中的cMessenge对象了,便也可以给Activity发送消息了,如下:

   到此BindService也整理完了

 

三.下面再聊聊AIDL远程服务的调用,直观点说,就是我们通过aidl文件去绑定一个远程的服务,成功之后我们可以得到一个代理对象  IMyAidlInterface,然后通过这个对象去调用远程服务的方法,处理任务。

服务端

1.首先在服务端创建一个aidl文件:

  

2.然后编译一下:

3.在服务端创建Service,实现aidl的接口,如下:

客户端

1.我们将aidl文件复制过来放到客户端,包名要一样,如下:

2.最后创建ServiceConnection对象并绑定该服务,绑定成功的时候会获取IMyAidlInterface对象,便可以远程操作服务端的方法了。

 

3.调用如下:

对于一些大的APP 有些操作需要AIDL调用服务的  登录,校验之类的可能会用到。

 

到这里也就基本结束了,比较肤浅,但是了解一点 在读一些大型的项目的时候可能会遇到。哈哈

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值