欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 游戏 > Service

Service

2024/10/24 9:30:37 来源:https://blog.csdn.net/qq_33552379/article/details/140599848  浏览:    关键词:Service

Service 的启动模式

一:启动模式 startService()

通过 startService()方法启动,此服务可以在后台一直运行,不会随启动组件的消亡而消亡。

使用startService启动时是单独开一个服务,与Activity没有任何关系,

但是,此种启动模式只能执行单一操作,并且无法返回结果给调用方,主要常用于网络下载、上传文件,播放音乐等。

 通过启动模式启动的Service,如不主动关闭,Service会一直在。

当应用组件通过调用**startService()**启动服务时,服务即处于“启动”状态。一旦启动,服务即可在后台无限期运行,即使启动服务的组件已被销毁也不受影响。已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。

 Intent  mBindIntent = new Intent(ServiceMethods.this, BindServiceMethods.class);startService(mStartIntent);

首次调用完startService函数后,Service1的onCreate和onStartCommand函数会依次执行,表示服务正式启动;

服务启动后再次调用startService函数,onCreate()只执行一次不会重复的执行,而是会调用 onStart() 和onStartCommand(),onStart(),onStartCommand()也会执行多次。参数startId就是代表每次启动请求的唯一整数,参数intent就是启动服务的intent;

 startService方式启动的服务正常情况下会一直在后台运行,除非被系统杀死,建议任务执行完毕后由发起方调用stopService或者Service自身调用stopSelf来停止服务,这样Service的onDestroy方法就会被调用; 服务只会被停止一次。

页面A调用startService启动的服务,页面B调用stopService方法同样可以终止此服务。

startService方式启动Service时,如果Android面临内存匮乏,可能会销毁当前运行的 Service,待内存充足时可以重建Service。而Service被Android系统强制销毁并再次重建的行为依赖于 Service的onStartCommand()方法的返回值:

 START_STICKY: 如果service被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由 于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传 递到service,那么参数Intent将为null。

START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。

START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务

START_REDELIVER_INTENT会重建Service,重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。

StartService

通过startService()方式开启。Service的生命周期很简单,分别为onCreate、onStartCommand、onDestroy这三个。


public class StartService extends Service {private static final String TAG = "StartService";@Nullable@Overridepublic IBinder onBind(Intent intent) {Log.d(TAG , "onBind");return null;}@Overridepublic boolean onUnbind(Intent intent) {Log.d(TAG , "onUnbind");return super.onUnbind(intent);}@Overridepublic void onCreate() {super.onCreate();Log.d(TAG , "onCreate");}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG , "onDestroy");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG , "onStartCommand");return super.onStartCommand(intent, flags, startId);}
}
Intent startIntent = new Intent(this, MyService.class);  startService(startIntent);// 通过 startService() 方法启动 MyService 服务
 Intent stopIntent = new Intent(this, MyService.class);  stopService(stopIntent);// 由 Activity 来决定服务何时停止。若想服务自己停止,在 MyService 调用stopSelf()方法  

二:绑定模式 bindService()

通过绑定组件(Activity等)调用 bindService() 启动,此服务随绑定组件的消亡而解除绑定。

如果此时没有其它通过startService()启动,则此服务会随绑定组件的消亡而消亡。

bindService方式启动时,Service会和Activity进行绑定,当对应的activity销毁时,对应的Service也会销毁 。

bindService多次,onCreate()与onBind()都只会调用一次。 不执行onStart() 或者 onStartCommand() 方法

多个组件不仅可以同时绑定一个Service,而且可以通过进程间通信(IPC)执行跨进程操作等。

如果绑定服务的组件被destory,这 bind 服务会走到onUnbind()方法

启动服务和绑定服务并不是完全独立的。我们可以定义一个Service,既实现onStartCommand函数又实现onBind函数,表示咱们的Service既可以被start又可以被bind。

在startService和bindService都发生的情况下,要想收到onDestroy回调,必须stopService且unbindService,即既停止服务又解绑服务,这个也是比较符合我们的理解。

当应用组件通过调用**bindService()**绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。

多个组件可以同时绑定一个服务,服务只会在组件与其绑定时运行,一旦该服务与所有组件之间的绑定全部取消,系统便会销毁它。

bindService启动的服务和调用者之间是典型的Client-Server模式。调用者是client,Service则是Server 端。Service只有一个,但绑定到Service上面的Client可以有一个或很多个。bindService启动服务的生 命周期与其绑定的client息息相关。

 Service1

Service的生命周期很简单,分别为onCreate、onBind、onUnBind、onDestroy这四个。


public class Service1 extends Service {@Overridepublic void onCreate() {super.onCreate();Log.d(TAG, "service1 onCreate ");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG , "onStartCommand");return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG, "service1 onDestroy ");}public class MyBinder extends Binder {Service1 getService() {return Service1.this;}}@Nullable@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}@Overridepublic boolean onUnbind(Intent intent) {Log.d(TAG , "onUnbind");return super.onUnbind(intent);}// 供客户端调用  Service1的plus方法public int plus(int a, int b) {return a + b;}
}
public class MyService extends Service { private static final String TAG = "zjy"; // 第4步,实例化一个MyBinder对象 private MyBinder mBinder = new MyBinder(this); @Nullable @Override public IBinder onBind(Intent intent) { return mBinder;//第4步,返回这个mBinder对象 } public void serviceMethod(String str){ Log.d(TAG, "receive msg from activity: " + str); } 
}
public class MyService extends Service {private DownloadBinder mDownloadBinder = new DownloadBinder();public class DownloadBinder extends Binder{public void startDownload(){Log.d("MyService", "Start");}public int getProgress(){Log.d("MyService","getProgress");return 0;}public void stopDownload(){Log.d("MyService", "Stop");}}public MyService() {}@Overridepublic void onCreate() {  super.onCreate(); }@Overridepublic int onStartCommand(Intent intent, int flags, int startId) { return super.onStartCommand(intent, flags, startId);  }@Overridepublic void onDestroy() { super.onDestroy();  }@Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.return mDownloadBinder;}
}

Activity1

 
public class MainActivity extends AppCompatActivity{// 启动绑定服务处理方法public void BtnStartBindService(View view) {// 启动绑定服务处理方法bindService(mBindIntent, serviceConnection, Context.BIND_AUTO_CREATE);isBindService = true;Toast.makeText(ServiceMethod.this, "启动 " + mBindCount + " 次绑定服务",Toast.LENGTH_SHORT).show();}public void BtnSopBindService(View view) {if (isBindService) {// 解除绑定服务处理方法unbindService(serviceConnection);Toast.makeText(ServiceMethod.this, "解除 " + mUnBindCount + " 次绑定服务",Toast.LENGTH_SHORT).show();isBindService = false;}}ServiceConnection serviceConnection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {Log.d(TAG, "Activity1 bind service1 connected");Service1.MyBinder binder = (Service1.MyBinder) iBinder;Log.d(TAG, "调用service1的plus方法: " + binder.getService().plus(1,2));}@Overridepublic void onServiceDisconnected(ComponentName componentName) {Log.d(TAG, "Activity1 bind service1 disconnected");}
};}

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private MyService.DownloadBinder downloadBinder;@Overrideprotected void onCreate(Bundle savedInstanceState) {...}@Overridepublic void onClick(View v) {int id = v.getId();if (id == R.id.start_service) {...} else if (id == R.id.stop_service) {...} else if (id == R.id.bind_service) {Intent bindIntent = new Intent(this, MyService.class);// service 和 activity 绑定后自动创建服务 BIND_AUTO_CREATE,这会使得 MyService 中 OnCreate() 方法得到执行bindService(bindIntent,connection,BIND_AUTO_CREATE);} else if (id == R.id.unbind_service) {unbindService(connection);}}private ServiceConnection connection = new ServiceConnection() {// service 和 activity 绑定时调用@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// service 就是从 onBind() 方法返回的// 向下转型得到 DownloadBinder 的实例downloadBinder = (MyService.DownloadBinder) service;downloadBinder.startDownload();downloadBinder.getProgress();}@Overridepublic void onServiceDisconnected(ComponentName name) {// Service 被销毁时调用,内存不足等。}};
}

   首先Activity绑定Service得到一个MyBinder实例并注册MyBinder里面的OnTestListener回调监听,然后点击按钮的时候调用MyBinder里面的testMethod(String)方法将消息发出去,MyBinder持有一个MyService的实例,testMethod(String)里面调用MyService里面的方法就可以把Activity的消息传给Service了,

public class MainActivity extends Activity { private static final String TAG = "zjy"; public MyBinder mBinder; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { //第5步所说的在Activity里面取得Service里的binder对象 mBinder = (MyBinder)iBinder; //第6步注册自定义回调 mBinder.setOnTestListener(new MyBinder.OnTestListener() { @Override public void onTest(String str) { Log.d(TAG, "receive msg from service: "+str); } }); } @Override public void onServiceDisconnected(ComponentName componentName) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(MainActivity.this, MyService.class); bindService(intent,mConnection,BIND_AUTO_CREATE); findViewById(R.id.test_bt).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //点击按钮调用mBinder里面的方法,发送消息给Service mBinder.testMethod("hi, service."); } }); } 
}

Binder

然后testMethod(String)里面回调mListener.onTest(String)将Service的消息发给Activity。

public class MyBinder extends Binder { private static final String TAG = "zjy"; private MyService mService; private OnTestListener mListener; public MyBinder(MyService service) { this.mService = service; } public void testMethod(String str) { // Activity通过Binder来调用Service的方法将消息传给Service mService.serviceMethod(str); // 并回调mListener.onTest告诉Activity已收到消息 mListener.onTest("hi, activity."); } // MyBinder 里面提供一个注册回调的方法 public void setOnTestListener(OnTestListener listener) { this.mListener = listener; } //自定义一个回调接口 public interface OnTestListener { void onTest(String str); } 
}

为什么bindService可以跟Activity生命周期联动?

  1. bindService 方法执行时,LoadedApk 会记录 ServiceConnection 信息。

  2. Activity 执行 finish 方法时,会通过 LoadedApk 检查 Activity 是否存在未注销/解绑的 BroadcastReceiver和 ServiceConnection,如果有,那么会通知 AMS 注销/解绑对应的 BroadcastReceiver 和 Service,并打印异常信息,告诉用户应该主动执行注销/解绑的操作。

三:startService()+bindService()


context.startService()
->onCreate()- >onStartCommand()->Service running--调用context.stopService() ->onDestroy()
context.bindService()
->onCreate()->onBind()->Service running--调用>onUnbind() -> onDestroy()

启动服务和绑定服务并不是完全独立的。我们可以定义一个Service,既实现onStartCommand函数又实现onBind函数,表示咱们的Service既可以被start又可以被bind。

在startService和bindService都发生的情况下,要想收到onDestroy回调,必须stopService且unbindService,即既停止服务又解绑服务,这个也是比较符合我们的理解。

服务既可以是启动服务,也允许绑定。此时需要同时实现以下回调方法:onStartCommand()和 onBind()。

系统不会在所有客户端都取消绑定时销毁服务。为此,必须通过调用 stopSelf() 或 stopService() 显式停止服务。

注意的是:

  1. 若是 startService() 开启 Service,则无法用 unbindService() 方法关闭 Service。

  2. 若是 bindService() 开启 Service,则无法用 stopService() 关闭 Service。

3.既调用了 startService() 方法,又调用了 bindService() 方法的 Service ,这种情况下要同时调用 stopService() 和 unbindService() 方法,onDestroy() 方法才会执行。

onRebind

最后再说一下onRebind回调,之前一直没介绍,放在这里讲最合适了。在startService和bindService都发生的情况下,onRebind取决于onUnbind的返回值。下面我画一张图来说明一下:

Service解绑后回调onUnbind函数,如果返回true,下次绑定则回调onRebind。注意了,这种情况下不能调用stopService,否则既停止服务又解绑服务的话Service就销毁了,哪还有onRebind的事情,

 

Service配置属性

<application><service android:name=".utils.push.PushService"android:enabled="true"android:exported="false"android:process=":pushcore"><intent-filter><action android:name="cn.jiguang.user.service.action" /></intent-filter></service>
</application>

android:name 

属性是唯一必需的属性,用于指定服务的类名,

android:exported

属性并将其设置为 "false",确保服务仅适用于本应用。这可以有效阻止其他应用启动本应用内的服务,即便在使用显式 Intent 时也是如此

android:process=":pushcore"

用来运行服务的进程的名称。通常,应用程序的所有组件都运行在应用程序创建的默认进程中,它与应用程序包名具有相同的名称。

Service的生命周期

onCreate():

系统在service第一次创建时执行此方法,来执行只运行一次的初始化工作。如果service已经运行,这个方法不会被调用。

onStartCommand()

每次客户端调用startService()方法启动该Service都会回调该方法(多次调用)。一旦这个方法执行,service就启动并且在后台长期运行。只有通过调用stopSelf()或stopService()来停止服务。

OnBind()

当组件调用bindService()想要绑定到service时(比如想要执行进程间通讯)系统调用此方法

(一次调用,一旦绑定后,下次再调用bindService()不会回调该方法)。

 只在第一次被绑定时回调,后面的客户端又再次绑定时不会重复执行,

在你的实现中,你必须提供一个返回一个IBinder来以使客户端能够使用它与service通讯,你必须总是实现这个方法,但是如果你不允许绑定,那么你应返回null。

OnUnbind()

当前组件调用unbindService(),想要解除与service的绑定时系统调用此方法(一次调用,一旦解除绑定后,下次再调用unbindService()会抛出异常)。

OnDestory()

系统在service不再被使用并要销毁时调用此方法(一次调用)。service应在此方法中释放资源,比如线程,已注册的侦听器,接收器等等.这是service收到的最后一个调用。

当Service关闭后,如果在onDestory()方法中不关闭线程,你会发现我们的子线程进行的耗时操作是一直存在的,此时关闭该子线程的方法需要直接关闭该应用程序。因此,在onDestory()方法中要进行必要的清理工作。

Service注意事项

1.Service在主线程运行时长不能超过20s,否则会出现ANR,耗时操作一般建议在子线程或工作线程中进行操作。

2.Service如不注册 ,不会像Activity那样会导致App CrashService 不注册 不会报异常信息,但是服务会起不来,如不注意很容易迷惑。

3. Service可以被多个组件绑定,进行一些数据的交互。因此存在后台功能交互的业务也可以使用Service来完成;

4.Service默认是在应用的主线程运行,若执行时间超过20秒会导致ANR。

5. 客户端完成服务的调用后,尽量手动调用解绑操作,这样可以关闭空闲的服务;

6. onServiceDisconnected方法在服务崩溃终止时才会回调,客户端主动解绑则不会回调此方法,

7.跨应用绑定Service的时候,例如A应用想绑定B应用的Service,B应用的Service需要exported=true,此外,如果A应用的targetSDK ≥ 30,则需要在AndroidManifest文件里面声明需要查询B应用,

<queries><package android:name="com.app.B"/>
</queries>

8.Service非常适用于去执行那些不需要和用户交互而且还要求长期运行的任务。Service默认并不会运行在子线程中,它也不运行在一个独立的进程中,它同样执行在UI线程中,因此,不要在Service中执行耗时的操作,除非你在Service中创建了子线程来完成耗时操作。

9.Service默认是运行在main线程的,因此Service中如果需要执行耗时操作(大文件的操作,数据库的拷贝,网络请求,文件下载等)的话应该在子线程中完成。

10.

  • 如果只是想开个服务在后台运行的话,直接startService即可

  • 如果需要相互之间进行传值或者操作的话,就应该通过bindService。

11.exported属性设为false,那么Service仅限于应用内部使用,可以避免外部调用;

12.为了避免资源浪费,Service工作执行完毕后建议停止服务;

同进程下Activity与Service双向通信流程:

    实现步骤:

  1. 新建一个继承自Service的类MyService,然后在AndroidManifest.xml里注册这个Service

  2. Activity里面使用bindService方式启动MyService,也就是绑定了MyService(到这里实现了绑定,Activity与Service通信的话继续下面的步骤)

  3. 新建一个继承自Binder的类MyBinder

  4. 在MyService里实例化一个MyBinder对象mBinder,并在onBind回调方法里面返回这个mBinder对象

  5. 第2步bindService方法需要一个ServiceConnection类型的参数,在ServiceConnection里可以取到一个IBinder对象,就是第4步onBinder返回的mBinder对象(也就是在Activity里面拿到了Service里面的mBinder对象)

  6. 在Activity里面拿到mBinder之后就可以调用这个binder里面的方法了(也就是可以给Service发消息了),需要什么方法在MyBinder类里面定义实现就行了。如果需要Service给Activity发消息的话,通过这个binder注册一个自定义回调即可。

        代码:

         Activity

       

public class MainActivity extends Activity { private static final String TAG = "zjy"; public MyBinder mBinder; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { //第5步所说的在Activity里面取得Service里的binder对象 mBinder = (MyBinder)iBinder; //第6步注册自定义回调 mBinder.setOnTestListener(new MyBinder.OnTestListener() { @Override public void onTest(String str) { Log.d(TAG, "receive msg from service: "+str); } }); } @Override public void onServiceDisconnected(ComponentName componentName) { } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent intent = new Intent(MainActivity.this, MyService.class); bindService(intent,mConnection,BIND_AUTO_CREATE); findViewById(R.id.test_bt).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //点击按钮调用mBinder里面的方法,发送消息给Service mBinder.testMethod("hi, service."); } }); } 
}

Binder

首先Activity绑定Service得到一个MyBinder实例并注册MyBinder里面的OnTestListener回调监听,然后点击按钮的时候调用MyBinder里面的testMethod(String)方法将消息发出去,MyBinder持有一个MyService的实例,testMethod(String)里面调用MyService里面的方法就可以把Activity的消息传给Service了

 然后testMethod(String)里面回调mListener.onTest(String)将Service的消息发给Activity。

public class MyBinder extends Binder { private static final String TAG = "zjy"; private MyService mService; private OnTestListener mListener; public MyBinder(MyService service) { this.mService = service; } public void testMethod(String str) { // Activity通过Binder来调用Service的方法将消息传给Service mService.serviceMethod(str); // 并回调mListener.onTest告诉Activity已收到消息 mListener.onTest("hi, activity."); } // MyBinder 里面提供一个注册回调的方法 public void setOnTestListener(OnTestListener listener) { this.mListener = listener; } //自定义一个回调接口 public interface OnTestListener { void onTest(String str); } 
}

Service

public class MyService extends Service { private static final String TAG = "zjy"; // 第4步,实例化一个MyBinder对象 private MyBinder mBinder = new MyBinder(this); @Nullable @Override public IBinder onBind(Intent intent) { return mBinder;//第4步,返回这个mBinder对象 } public void serviceMethod(String str){ Log.d(TAG, "receive msg from activity: " + str); } 
}

Service分类说明

按运行地点分类

 按运行类型分类

按使用方式分类

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com