当前位置: 首页 > 科技观察

service

时间:2023-03-22 11:39:42 科技观察

,android的四大组件之一,最近没有找到工作,所以趁着现在的时间把之前的整理一下,不然总是很容易忘记,所以今天就来讲解一下服务的使用。作为Android的四大组件之一,其重要性可想而知。在应用中,我们主要用它来执行一些后台操作,而不需要和应用UI交互,执行耗时的任务等。官方文档是这样说的:Serviceisaapplicationcomponentthatcanperformlong-runningoperationsthatcanperformlong-runningoperationswithout提供用户界面。服务可以由其他应用程序组件启动,并且即使用户切换到另一个应用程序也会继续在后台运行。此外,组件可以绑定到服务以与它们交互,甚至执行进程间通信(IPC)。例如,服务可以在后台处理网络事务、播放音乐、执行文件I/O或与内容提供者交互。Service的用途:1.在后台执行耗时操作,但不需要与用户交互。2.一个应用暴露给其他应用使用的一些功能。这里需要说明一下,Service是运行在主线程上的,所以如果需要进行耗时操作或者访问网络,需要在Service中另开一个线程来执行(不需要手动如果使用IntentService,请自行打开线程)。启动Service启动Service有两种方式:Context.startService()Context.bindService()(图片摘自官方文档:https://developer.android.com...)startService()启动Service,我们启动后就没办法控制Service了,启动后Service一直在后台运行,即使里面的一些代码执行了,如果我们想终止Service,就需要调用stopSelf()方法在他的代码中或者直接调用stopService()方法。对于通过bindService()方法启动的Service,客户端会获取到Service的持久连接,客户端会获取Service的onBind(Intent)方法返回的IBinder对象,用于客户端回调回调方法。无论使用哪种方法,我们都需要定义一个类,让它继承Service类,重写其中的几个方法。如果我们使用startService()启动,只需要重写onCreate()、onStartCommand(Intentintent,intflags,intstartId)、onDestroy()方法(其实也可以重写),如果bindService()方法用于启动,我们需要重写onCreate()、onBind(Intentintent)、onUnbind(Intentintent)方法。需要注意的是,作为四大组件之一,Service在使用前必须在manifest文件中进行配置。......Context.startService()MyService.java的代码:publicclassMyServiceextendsService{publicMyService(){}@OverridepublicvoidonCreate(){super.onCreate();Log.i("test","onCreteexecuted!");}@OverridepublicintonStartCommand(Intentintent,intflags,intstartId){Log.i("test","onStartComandexecuted!");returnsuper.onStartCommand(intent,flags,startId);}@OverridepublicvoidonDestroy(){super.onDestroy();Log.i("test","onDestroyexecuted!");}}MainActivity.java的代码如下:publicclassMainActivityextendsAppCompatActivityimplementsView.OnClickListener{ButtonbtnStart,btnStop;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);btnStart=(Button)findViewById(R.id.btn_start);btnStop=(Button)findViewById(R.id.btn_stop);btnStart.setOnClickListener(this);btnStop.setOnClickListener(this);}@OverridepublicvoidonClick(Viewview){IntentmIntent=newIntent(MainActivity.this,MyService.class);开关(view.getId()){caseR.id.btn_start:startService(mIntent);break;caseR.id.btn_stop:stopService(mIntent);break;}}}主界面有两个按钮,一个用来启动Service,一个用来停止Service:我们点击首先是START按钮,Log信息如下:是的可以看到先执行了onCreate()方法,然后马上执行了onStartCommand()方法,那我们再点开始按钮呢?结果如下:我们可以看到这次并没有再次执行onCreate()方法,而是直接执行了onStartCommand()方法。这是因为Service只有在第一次创建时才执行onCreate()方法。如果已经创建,那么再次调用startService()启动Service时,只会执行onStartCommand()方法,不会执行onCreate()方法。接下来,我们点击停止按钮,可以看到执行了onDestroy()方法:注意如果我们手动停止Service而不点击停止按钮,Service会一直在后台运行,即使代码在它的onStartCommand()方法中已经执行完毕,我们可以在下图中看到:这个时候我们的Service一直在后台运行,即使它的onStartCommand()方法中的代码已经执行过了。如果我们想让它自动停止,我们可以修改onStartCommand()方法中的代码如下:@OverridepublicintonStartCommand(Intentintent,intflags,intstartId){Log.i("test","onStartCommand()executed!");stopSelf();returnsuper.onStartCommand(intent,flags,startId);}Context.bindService()使用这个方法的代码比之前稍微多一些,因为我们需要在客户端控制Service,所以我们会在MainActivity中创建一个然后在bindService()方法和unbindService()方法中传入匿名内部类ServiceConnection。MyService.java中的代码如下:;}@OverridepublicvoidonDestroy(){super.onDestroy();Log.i("test","onDestroy()已执行!");}@OverridepublicbooleanonUnbind(Intentintent){Log.i("test","onUnbindex已执行!");returnsuper.onUnbind(intent);}@OverridepublicIBinderonBind(Intentintent){Log.i("test","onBind()已执行!");returnmyBinder;}classMyBinderextendsBinder{publicvoidstartDownload(){Log.i("test","MyBinderstartDownload()executed!");//执行具体的下载任务,需要开启一个子线程来执行具体的代码}}}MainActivity.java的代码如下:publicclassMainActivityextendsAppCompatActivityimplementsView.OnClickListener{ButtonbtnBind,btnUnBind;MyService.MyBindermyBinder;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState)nceState);setContentView(R.layout.activity_main);btnBind=(Button)findViewById(R.id.bind);btnUnBind=(Button)findViewById(R.id.btn_unBind);btnBind.setOnClickListener(this);btnUnBind.setOnClickListener(this);}ServiceConnectionmServiceConnection=newServiceConnection(){@OverridepublicvoidonServiceConnected(ComponentNamecomponentName,IBinderiBinder){//将IBinder向下转化为我们的内部类MyBindermyBinder=(MyService.MyBinder)iBinder;//执行下载任务myBinder.startDownload();}@OverridepublicvoidonServiceDisconnected(ComponentNamecomponentName){}};@OverridepublicvoidonClick(Viewview){IntentmIntent=newIntent(MainActivity.this,MyService.class);switch(view.getId()){caseR.id.bind://bindServicebindService(mIntent,mServiceConnection,BIND_AUTO_CREATE);break;caseR.id.btn_unBind://UnbindServiceunbindService(mServiceConnection);break;}}}点击绑定按钮;点击解除绑定按钮:注意,如果我们不先点击绑定如果直接点击解除绑定,程序会直接崩溃,报如下错误:java.lang.IllegalArgumentException:Servicenotregistered:com.qc.admin.myserializableparceabledemo.MainActivity$1@8860e28atandroid.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1120)atandroid.app.ContextImpl.unbindService(ContextImpl.java:1494)atandroid.content.ContextWrapper.unbindService(ContextWrapper.java:616)atcom.qc.admin.myserializableparceabledemo.MainActivity.onClick(MainActivity.java:71)细心的你可能发现了“onServiceDisconnectedexecuted!”这句话Log中没有打印,说明没有调用onServiceDisconnected()方法?从字面上看,onServiceConnected()方法在Service建立连接时被调用。服务断开时不应该调用onServiceDisconnected()吗?其实看看这个方法的文档我们就知道了:当与Service的连接丢失时调用。这通常发生在托管服务的进程崩溃或被终止时。这不会删除ServiceConnection本身——与服务的绑定将保持活动状态,并且您将在服务下次运行时收到对onServiceConnected(ComponentName,IBinder)的调用。意思是:当Service绑定的连接丢失时,会调用该方法。典型情况是持有Service的进程崩溃或被kill但这并不会移除ServiceConnection本身——它仍然会保持活动状态,下次执行Service时仍会调用onServiceConnected(ComponentName,IBinder)方法。但是注意,如果我们按照刚才说的,不是先点击bindService()方法,而是直接点击unbindService()方法,虽然程序崩溃了,但是不会调用onServiceDisconnected()方法,这样就容易明白了,毕竟没有建立连接,何必断开呢。但是如果我们已经绑定了Service,然后在后台直接终止Service呢?会发生什么?答案是仍然不会调用onServiceDisconnected()方法。这里我觉得应该是进程只有在意想不到的情况下才会结束,是由系统自动调用的,而不是我们手动停止的。我们可以查看方法里面的注释:当与服务的连接意外断开时调用——即它的进程崩溃了。因为它在我们的同一个进程中运行,所以我们永远不应该看到这种情况发生。这段文字清楚的描述了该方法执行的场景:连接异常断开。也就是说,进程崩溃了。由于它与我们的应用程序在同一进程中运行,因此我们永远不希望看到这种情况发生。Context.startService()和Context.bindService()可以同时使用,但是要注意startService()和stopService()方法是对应的,bindService()和unBind()方法是对应的,也就是说,如果我们先调用startService()再调用bindService()方法,反之亦然,那么如果我们只调用stopService()或者只调用bindService(),我们是不能停止Service的,只能同时进行.下面来看下工具代码:MainActivity.javapublicclassMainActivityextendsAppCompatActivityimplementsView.OnClickListener{ButtonbtnStart,btnStop,btnBind,btnUnBind;MyService.MyBindermyBinder;@OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savtentViewbStartactivity(R.setCon);Button)findViewById(R.id.btn_start);btnStop=(Button)findViewById(R.id.btn_stop);btnBind=(Button)findViewById(R.id.btn_bind);btnUnBind=(Button)findViewById(R.id.btn_unBind);btnStart.setOnClickListener(this);btnStop.setOnClickListener(this);btnBind.setOnClickListener(this);btnUnBind.setOnClickListener(this);}ServiceConnectionmServiceConnection=newServiceConnection(){@OverridepublicvoidonServiceConnected(ComponentNamecomponentName,IB/inderiBinder){向下变换到我们的内部类MyBindermyBinder=(MyService.MyBinder)iBinder;//执行下载任务myBinder.startDownload();}@OverridepublicvoidonServiceDisconnected(ComponentNamecomponentName){Log.i("test","onServiceDisconnectedexecuted!");}};@OverridepublicvoidonClick(Viewview){IntentmIntent=newIntent(MainActivity.this,MyService.class);switch(view.getId()){caseR.id.btn_start://启动ServicestartService(mIntent);break;caseR.id.btn_stop://终止ServicestopService(mIntent);break;caseR.id.btn_bind://绑定ServicebindService(mIntent,mServiceConnection,BIND_AUTO_CREATE);break;caseR.id.btn_unBind://取消绑定ServiceunbindService(mServiceConnection);break;}}}MyService.java的代码:publicclassMyServiceextendsService{privateMyBindermyBinder=newMyBinder();publicMyService(){}@OverridepublicvoidonCreate(){super.onCreate();Log.i("test","onCreate()执行!”);}@OverridepublicintonStartCommand(Intentintent,intflags,intstartId){Log.i(“测试”,“onStartComand()执行!”);returnsuper.onStartCommand(意图,标志,startId);}@OverridepublicvoidonDestroy(){super.onDestroy();Log.i("测试","onDestroy()已执行!");}@OverridepublicbooleanonUnbind(Intentintent){Log.i("test","onUnbindexexecuted!");returnsuper.onUnbind(intent);}@OverridepublicIBinderonBind(Intentintent){Log.i("test","onBind()已执行!");returnmyBinder;}classMyBinderextendsBinder{publicvoidstartDownload(){Log.i("test","startDownload()executedinMyBinder!");//执行具体的下载任务}}}a.下面是点击开始、绑定、停止、取消绑定按钮的输出:b.下面是依次点击开始、绑定、解除绑定、停止按钮的输出结果:在前台运行服务我们一直说Service一般是用来在后台进行耗时操作的,但是你一定要知道该服务也是可以在前台运行的后台服务。Service的优先级比较低,内存不足时可以被系统kill掉。通过将其设置为前景,可以大大降低被杀的几率。前台Service会在系统通知栏显示一个图标,我们可以在这里进行一些操作。前台Service比较常见的场景是音乐播放器和天气预报等:那么我们直接添加代码:@OverridepublicvoidonCreate(){super.onCreate();Log.i("test","onCreate()executed!");IntentmIntent=newIntent(this,SecondActivity.class);PendingIntentmPendingIntent=PendingIntent.getActivity(this,0,mIntent,0);NotificationmNotification=newNotificationCompat.Builder(this).setSmallIcon(R.mipmap.ic_launcher).setContentTitle("MyNotification").setContentText("HelloWorld!").setContentIntent(mPendingIntent).build();//注意:提供给startForeground()的整数ID不能为0。//要从前台移除一个服务,调用停止前景()。此方法采用一个布尔值,指示是否也删除状态栏通知。//但是stopForeground()不会停止服务。但是,如果您在服务在前台运行时停止该服务,通知也将被删除。startForeground(1,mNotification);}其实这里的实现很简单,就是通过startForeground(1,mNotification);传递一个Notification;将通知与服务相关联。当我们点击这个通知时,会跳转到第二个Activity(但是Notification不会消失),截图如下:

最新推荐
猜你喜欢