启动service的启动两种方式
1. 通过StartService启动Service
通过startService启动后,service会一直无限期运行下去,启动
- 当外部调用了stopService()或stopSelf()方法时,启动该Service才会停止运行并销毁
- 当系统资源不足时,启动 会回收一些不重要的启动service,service被系统回收也会停止运行并被销毁
生命周期
onCreate()
1.如果service没被创建过,启动调用startService()后会执行onCreate()回调;
2.如果service已处于运行中,启动调用startService()不会执行onCreate()方法。启动
此方法适合完成一些初始化工作。启动onStartCommand()
如果多次执行了Context的启动startService()方法,那么Service的启动onStartCommand()方法也会相应的多次调用。onBind()
Service中的启动onBind()方法是抽象方法,Service类本身就是启动抽象类,所以onBind()方法是启动必须重写的,即使我们用不到。启动onDestory()
在销毁的时候会执行Service该方法。
代码实例
MyActivity.java
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 启动service Intent mIntent=new Intent(MainActivity.this,MyService.class) ; startService(mIntent); }}
MyServvice.java
public class MyService extends Service { private static final String TAG = "MyService"; private NotificationManager notificationManager; private String notificationId = "channel_Id"; private String notificationName = "channel_Name"; public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } @Override public void onCreate() { Log.d(TAG, "onCreate: ..."); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: ..."); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { Log.d(TAG, "onDestroy: ...."); super.onDestroy(); }
AndroidManifest.xml
2. 通过bindService启动Service
bindService启动服务特点:
- bindService启动的服务和调用者之间是典型的client-server模式。调用者是client,service则是server端。service只有一个,但绑定到service上面的client可以有一个或很多个。这里所提到的client指的是组件,比如某个Activity。
- client可以通过IBinder接口获取Service实例,从而实现在client端直接调用Service中的方法以实现灵活交互,这在通过startService方法启动中是无法实现的。
- bindService启动服务的生命周期与其绑定的client息息相关。当client销毁时,client会自动与Service解除绑定。当然,client也可以明确调用Context的unbindService()方法与Service解除绑定。当没有任何client与Service绑定时,Service会自行销毁
生命周期
onCreate()
当服务通过onStartCommand()和onBind()被第一次创建的时候,系统调用该方法。该调用要求执行一次性安装。onBind()
当其他组件想要通过bindService()来绑定服务时,系统调用该方法。如果你实现该方法,你需要返回IBinder对象来提供一个接口,以便客户来与服务通信。你必须实现该方法,如果你不允许绑定,则直接返回null。onUnbind()
当客户中断所有服务发布的特殊接口时,系统调用该方法。onRebind()
当新的客户端与服务连接,且此前它已经通过onUnbind(Intent)通知断开连接时,系统调用该方法。onDestroy()
当服务不再有用或者被销毁时,系统调用该方法。你的服务需要实现该方法来清理任何资源,如线程,已注册的监听器,接收器等。
代码实例
MainAcivity.java
public class MainAcivity extends Activity{ private Myservice = null; private boolean isBind = false; private ServiceConnection conn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder binder) { isBind = true; TestTwoService.MyBinder myBinder = (TestTwoService.MyBinder) binder; service = myBinder.getService(); int num = service.getRandomNumber(); } @Override public void onServiceDisconnected(ComponentName name) { isBind = false; } }; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_a); Intent intent = new Intent(this, TestTwoService.class); intent.putExtra("from", "MainAcivity"); bindService(intent, conn, BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); unbindService(conn); }}
MyService.java
public class MyService extends Service{ //client 可以通过Binder获取Service实例 public class MyBinder extends Binder { public MyService getService() { return MyService .this; } } //通过binder实现调用者client与Service之间的通信 private MyBinder binder = new MyBinder(); @Override public void onCreate() { super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { return START_NOT_STICKY; } @Nullable @Override public IBinder onBind(Intent intent) { return binder; } @Override public boolean onUnbind(Intent intent) { return false; } @Override public void onDestroy() { super.onDestroy(); } //getRandomNumber是Service暴露出去供client调用的公共方法 public int getRandomNumber() { return generator.nextInt(); }}
如何保证service不被杀死
之前说过:当系统资源不足时, 会回收一些不重要的service,service被系统回收也会停止运行并被销毁,那么如何保证service不被杀死呢
1. onStartCommand方式中,返回START_STICKY
表示Service运行的进程被Android系统强制杀掉之后,Android系统会将该Service依然设置为started状态(即运行状态),但是不再保存onStartCommand方法传入的intent对象,然后Android系统会尝试再次重新创建该Service,并执行onStartCommand回调方法,但是onStartCommand回调方法的Intent参数为null,也就是onStartCommand方法虽然会执行但是获取不到intent信息。如果你的Service可以在任意时刻运行或结束都没什么问题,而且不需要intent信息,那么就可以在onStartCommand方法中返回START_STICKY
2. 提高Service的优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低
*: 但是我在service中设置intent-filter,设置优先级build报错,有兴趣的可以另行查证
3. 提升Service进程的优先级
前台进程foreground_app优先级相对较高,可以将service设置为前台进程
代码实例:
MainActivity.java
package com.iauto.helloword;import androidx.appcompat.app.AppCompatActivity;import android.app.Activity;import android.content.Intent;import android.os.Bundle;import android.util.Log;public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 启动service Intent mIntent=new Intent(MainActivity.this,MyService.class) ; Log.d("activity", "onCreate: to start service"); startForegroundService(mIntent); Log.d("activity", "onCreate: start service end"); finish(); }}
MyService.java
package com.iauto.helloword;import android.app.Notification;import android.app.NotificationChannel;import android.app.NotificationManager;import android.app.PendingIntent;import android.app.Service;import android.content.Context;import android.content.Intent;import android.graphics.BitmapFactory;import android.os.Build;import android.os.IBinder;import android.util.Log;import androidx.core.app.NotificationCompat;public class MyService extends Service { private static final String TAG = "MyService"; private NotificationManager notificationManager; private String notificationId = "channel_Id"; private String notificationName = "channel_Name"; public MyService() { } @Override public IBinder onBind(Intent intent) { // TODO: Return the communication channel to the service. throw new UnsupportedOperationException("Not yet implemented"); } @Override public void onCreate() { Log.d(TAG, "onCreate: ..."); notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); //创建NotificationChannel if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel(notificationId, notificationName, NotificationManager.IMPORTANCE_HIGH); // 必须创建notifychannel, 不然会抛异常Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notificationManager.createNotificationChannel(channel); } startForeground(1, getNotification()); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand: ..."); return START_STICKY; } @Override public void onDestroy() { Log.d(TAG, "onDestroy: ...."); super.onDestroy(); } private Notification getNotification() { Notification.Builder builder = new Notification.Builder(this) .setContentTitle("ScenarioEngineLite正在后台运行") .setContentText(""); //设置Notification的ChannelID,否则不能正常显示 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { builder.setChannelId(notificationId); } Notification notification = builder.build(); return notification; }}
AndroidManifest.xml
4.在onDestroy方法里重启Service
当service走到onDestroy()时,发送一个自定义广播,当收到广播时,重新启动service。