Android开发Service

Service

生命周期

1、通过startService()方式,onCreate()–>onStartCommand()–>onDestroy()
注:

  1. 若一个Service被startService()多次启动,那么onCreate()也只会调用一次,即Service实例只有1个
  2. 整个生命周期的方法中,只有onStartCommand()可多次调用,其他只能调用一次
  3. onStartCommand调用次数=startService调用次数

特点:调用者退出后Service仍然存在

应用场景:服务不需与Activity和Service通信

示例代码:

tv_content.setOnClickListener {
        val intent = Intent(this@BActivity,StartServiceDemo::class.java)
        intent.putExtra("content","nihao")
        startService(Intent(intent))
    }

    tv_content_stop.setOnClickListener {
        val intent = Intent(this@BActivity,StartServiceDemo::class.java)
        stopService(Intent(intent))
    }

定时循环任务示例代码:

public class VersionCheckServices extends Service {
private static String TAG = VersionCheckServices.class.getName();
/**
 * 定时器对象
 */
private AlarmManager manager;
private PendingIntent pendingIntent;
private final int LOOP_TIME = 60;

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

@Override
public void onCreate() {
    super.onCreate();
    manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
}

@Override
public void onDestroy() {
    if (pendingIntent != null) {
        manager.cancel(pendingIntent);
    }
    super.onDestroy();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if ((ModifySetUtils.isCodeCheckVersion() || ModifySetUtils.isCheckVersion() || ModifySetUtils.isFourCheckVersion()) && !SPUtils.isCheckUser()) {
        if (!AppUtils.isAppForeground()) {
            new CheckVersionPassPresenter().dealCheckVersion(this,checkVersionCallBack);
        } else {
            next(LOOP_TIME);
        }
    } else {
        //非审核版本就不需要继续调用服务了
        stopSelf();
    }
    return super.onStartCommand(intent, flags, startId);
}


/**
 * 检查审核版本的回调
 */
private HttpOnNextListener checkVersionCallBack = new HttpOnNextListener() {


    @Override
    public void onError(ApiException e) {
        next(LOOP_TIME);
    }

    @Override
    public void onNext(CheckPassVersionResult checkPassVersionResult) {
        if(checkPassVersionResult.getData() != null && checkPassVersionResult.getData().isPass()){
            SPNoCleanUtil.saveCheckVersion(true);
            IntentUtils.startGuideActivity(VersionCheckServices.this);
        } else {
            next(LOOP_TIME);
            SPNoCleanUtil.saveCheckVersion(false);
        }
    }

    @Override
    public void onDealCodeNext(CheckPassVersionResult baseResult) {
        next(LOOP_TIME);
        SPNoCleanUtil.saveCheckVersion(false);
    }


};


/**
 * 设置定时器,准备下次调用
 *
 * @param time 调用时间,秒
 */
private void next(int time) {
    Intent intent = new Intent(this, VersionCheckServices.class);
    pendingIntent = PendingIntent.getService(this, 0, intent, 0);
    manager.set(AlarmManager.RTC, System.currentTimeMillis() + time * 1000, pendingIntent);
}}

2、通过bindService()方式,onCreate()–>onBind()–>onUnbind()–>onDestroy()
注:

  1. 客户端通过一个IBinder接口与服务进行通信
  2. 若一个Service被BindService()多次启动,那么onCreate()也只会调用一次,即Service实例只有1个
  3. 多个客户端可绑定到同一个服务上,当所有客户端都解绑后,系统会销毁服务

特点:调用者退出后,随着调用者销毁

应用场景:服务需与Activity和Service通信、需控制服务开始时刻

bindService()方式的示例代码
先定义Service子类:

public class BindServiceDemo extends Service {

private String TAG = BindServiceDemo.class.getSimpleName();

private MyBinder mBinder = new MyBinder();

@Override
public void onCreate() {
    super.onCreate();
    Log.i(TAG,"onCreate");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.i(TAG,"onStartCommand");
    return super.onStartCommand(intent, flags, startId);
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    Log.i(TAG,"onBind");

    return mBinder;
}

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

@Override
public void onDestroy() {
    super.onDestroy();
    Log.i(TAG,"onDestroy");
}

public class MyBinder extends Binder{
    public void service_connect_Activity() {
        Log.i(TAG,"Service关联了Activity,并在Activity执行了Service的方法");


    }
}}

在AndroidManifest.xml中注册
使用:

private var myBinder:BindServiceDemo.MyBinder?= null

//创建ServiceConnection的匿名类
private val connection = object : ServiceConnection {

    //重写onServiceConnected()方法和onServiceDisconnected()方法
    //在Activity与Service解除关联的时候调用
    override fun onServiceDisconnected(name: ComponentName) {}

    //在Activity与Service关联的时候调用
    override fun onServiceConnected(name: ComponentName, service: IBinder) {
        //实例化Service的内部类myBinder
        //通过向下转型得到了MyBinder的实例
        myBinder = service as BindServiceDemo.MyBinder
        //在Activity调用Service类的方法
        myBinder?.service_connect_Activity()
    }
}

tv_bind_service.setOnClickListener {
    val intent = Intent(this@BActivity,BindServiceDemo::class.java)
    bindService(intent,connection, Context.BIND_AUTO_CREATE)
}

tv_unbind_service.setOnClickListener {
    //仅此示例,正常要判是否已经绑定成功
    unbindService(connection)
}

IntentService

多线程IntentService
本质:Handler + HandlerThread
为什么要使用IntentService呢,
因为1、普通的Service不是一个单独的进程,它和它的应用程序在同一个进程中
2、Service不是一个线程,就意味着应该避免在Service中进行耗时操作

工作流程:客户端通过startService(Intent)来启动IntentService; 我们并不需要手动地区控制IntentService,当任务执行完后,IntentService会自动停止; 可以启动IntentService多次,每个耗时操作会以工作队列的方式在IntentService的 onHandleIntent回调方法中执行,并且每次只会执行一个工作线程,执行完一,再到二这样!

生命周期: onCreate() –> onStartCommand() –> onHandleIntent() –> onDestroy()

多次调用 startService(Intent)会多次调用onStartCommand()和onHandleIntent()

注意:
一. 工作任务队列 = 顺序执行
由于onCreate()只会调用一次 = 只会创建1个工作线程
二、不建议通过 bindService() 启动 IntentService
因为bindService()的生命周期是onCreate() –> onBind() –> onunBind() –> onDestory(),并不会调onStartCommand(),因此不会将消息发送到消息队列,那么onHandleIntent()将不会回调,即无法实现多线程操作

远程服务Service

远程服务与本地服务最大的区别:远程Service与调用者不在同一个进程里,而本地服务则是与调用者在同一个进程里

使用场景:
多个应用程序共享同一个后台服务(远程服务)
具体使用:
为了让远程Service与多个应用程序的组件(四大组件)进行跨进程通信(IPC),需要使用AIDL。
AIDL:Android接口定义语言
操作步骤:
一:先定义后台服务(服务器端
步骤1:新建AIDL文件,创建提供给客户端的接口,定义好接口方法
步骤2:在Service子类中实现AIDL中定义的接口方法,即回调给客户端接口和客户端通信
关键通过AIDL_Service1.Stub mBinder = new AIDL_Service1.Stub()。生成binder,然后binder在客户端绑定成功后onServiceConnected传入改binder,然后在客户端通过AIDL_Service1.Stub.asInterface(binder)反转成AIDL_Service1实例,就可以拿到服务器端传过来的信息
示例代码:

@Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        aidl_service1 = AIDL_Service1.Stub.asInterface(service);

        try {
            aidl_service1.toDoService();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

步骤3:在AndroidManifest.xml中注册为android:exported=”true”的,还有加上,可以隐式intent绑定远程Service
:客户端
步骤1:拷贝服务器端的aidl文件到main目录下,是整个aidl目录拷贝过来,不要做任何改动
步骤2:使用Stub.asInterface接口获取服务器的Binder,根据需要调用服务提供的接口方法
步骤3:通过bindService()方法启动,intent指定服务器端的服务名称和包名,绑定远程Service

示例代码:
服务器
定义aidl接口(鼠标右键new里面有AIDL,创建完Rebuild Project):

service_aidl.png

定义Service子类:

public class AIDLServiceDemo extends Service {

private String TAG = AIDLServiceDemo.class.getSimpleName();

AIDL_Service1.Stub mBinder = new AIDL_Service1.Stub() {

    @Override
    public void toDoService() throws RemoteException {
        Log.i(TAG,"客户端通过AIDL与远程后台成功通信");

    }
};

@Override
public void onCreate() {
    super.onCreate();
    Log.i(TAG,"onCreate");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.i(TAG,"onStartCommand");
    return super.onStartCommand(intent, flags, startId);
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    Log.i(TAG,"onBind");

    return mBinder;
}

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

@Override
public void onDestroy() {
    super.onDestroy();
    Log.i(TAG,"onDestroy");
}}

在AndroidManifest.xml中注册:


        
            
        
    

客户端:
完全拷贝aidl文件过来:

service_client.png

绑定和使用:

public class MainActivity extends AppCompatActivity {

private TextView tvBindService;

private AIDL_Service1 aidl_service1;

private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        aidl_service1 = AIDL_Service1.Stub.asInterface(service);

        try {
            aidl_service1.toDoService();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    tvBindService = findViewById(R.id.tv_bind_remote_service);

    tvBindService.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent("com.cong.myapplication.service.AIDL_Service1");
            intent.setPackage("com.cong.myapplication.service");
            bindService(intent,connection,BIND_AUTO_CREATE);
        }
    });
}}

Androidmanifest里Service的常见属性说明

android:name:Service的类名
android:permission:申明此Service的权限。注:有提供了该权限的应用才能控制或连接此服务
android:process:表示该服务是否在另一个进程中运行(远程服务)。注:不设置默认为本地服务;remote则设置成远程服务
android:exported:该服务是否能够被其他应用程序所控制或连接
注:不设置默认为false

参考:https://www.jianshu.com/p/d963c55c3ab9