Service的理解 Service是什么? Service是一种可以在后台运行相关任务的组件。没有界面。其存在的线程是主线程,一般会通过启动子线程来执行耗时操作。 Service有什么用? 可用于在后台执行下载任务。从而不影响用户界面操作。 Service分启动型服务、绑定型服务两种。 绑定服务中的创建Binder的扩展类的目的是什么? 该类主要用于获取Service的实例,以及执行相关的方法。 额外知识 1.不绑定服务,直接点击取消绑定服务会报错。因此需要通过判断Binder对象是否为空来处理。 2.服务可以不定义Action,通过Intent指定要跳转的Service即可。 3.Service的有效范围是所有满足条件的Activity。 4.在Service里执行耗时操作会导致ANR,启动新的线程执行耗时操作可有效避免。
两种服务的区别 Service类型 说明 使用步骤 启动型服务 1.生命周期为onCreate->onStartCommand->onDestroy 2.服务一旦启动后,需要调用stopService方法或stopSelf方法才能停止。 3.可常驻系统。 1.通过调用startService启动服务 2.通过stopService停止服务 绑定型服务 1.生命周期为onCreate->onBind->onUnbind->onDestory 2.需要返回Binder对象,即定义Binder的子类。 3.通过Binder子类的方法来获取Service对象,用于与Activity交互。 4.在Activity中需要通过创建ServiceConnection对象来获取service实例。从而调用service里的方法。 1.通过bindService绑定服务 2.通过unbindService取消绑定服务
Service生命周期
Service的类型及其示例 启动型服务 - StartService 使用 1.创建java类继承Service 2.重写onStart、onCreate等方法。 3.在onCreate中新开子线程,用于执行任务。
示例 - 启动型服务 Service作用 打印0-2000的数字,完毕后停止服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 public class CalcService extends Service { private int total; private boolean openService; public CalcService () { } @Override public IBinder onBind (Intent intent) { throw new UnsupportedOperationException("Not yet implemented" ); } @Override public void onCreate () { super .onCreate(); LogTool.e("CalcService" , "onCreate" ); } @Override public int onStartCommand (final Intent intent, int flags, final int startId) { LogTool.e("CalcService" , "onStartCommand" ); Functions.toast("Service已启动,请查看LOG" ); new Thread(new Runnable() { @Override public void run () { while (!openService) { try { Thread.sleep(100 ); } catch (InterruptedException e) { e.printStackTrace(); } LogTool.e("CalcService" , total); total++; builder.setSubText("total:" + total); if (total == 2000 ) { stopSelf(); } } } }).start(); return super .onStartCommand(intent, flags, startId); } @Override public void onDestroy () { super .onDestroy(); LogTool.e("CalcService" , "onDestroy" ); Functions.toast("CalcService已停止,请查看LOG" ); openService = true ; } }
1 2 3 4 5 public void startService (View v) { Intent intent = new Intent(this ,CalcService.class); startService(intent); }
绑定型服务 - BindService BindService(Intent,ServiceConnection,Context.BIND_AUTO_CREATE) 参数分别为Intent,ServiceConnection,标识号。通常为BIND_AUTO_CREATE。 使用 1.创建java类继承Service 2.创建Java类继承Binder类。用于返回Service实例。 3.重写onBind、onUnBind等方法。 4.在Activity中创建ServiceConnection对象,并获取Binder实例。 ps:为防止未绑定服务,用户点击取消绑定而导致的崩溃。需要对unbindService进行边缘性处理。
示例 - 普通绑定型服务 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 public class BindService extends Service { private BindService service; private TestBinder binder = new TestBinder(); private int count = 0 ; public class TestBinder extends Binder { public BindService getService () { if (service == null ) { service = new BindService(); } return service; } } private boolean closeThread; public BindService () { } @Override public void onCreate () { super .onCreate(); new Thread(new Runnable() { @Override public void run () { while (!closeThread) { LogTool.e("BindService" , "count:" + count); count++; } } }).start(); } @Override public TestBinder onBind (Intent intent) { LogTool.e("BindService" , "onBind" ); return binder; } @Override public void onDestroy () { super .onDestroy(); this .closeThread = true ; LogTool.e("BindService" , "onDestroy" ); Functions.toast("BindService已停止" ); } @Override public boolean onUnbind (Intent intent) { LogTool.e("BindService" , "onUnbind" ); return true ; } public void startDownload () { Functions.toast("开始执行耗时任务,点击UnbindService按钮或返回按钮可取消任务" ); } }
Activity中的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { binder = (BindService.TestBinder) service; binder.getService().startDownload(); } @Override public void onServiceDisconnected(ComponentName name) { Functions.toast("断开连接"); LogTool.e("BindService", "serviceDisconnected"); } }; //启动服务 public void BindService(View v) { Intent intent = new Intent(this, BindService.class); bindService(intent, connection, Service.BIND_AUTO_CREATE); } // 取消绑定服务,边缘性处理 public void UnbindService(View v) { if (binder != null) { unbindService(connection); } }
示例 - 绑定型远程服务 理解 如何定义远程服务? 在配置文件中添加代码android:progress=”:remote”即可 为什么设置了Service为远程Service就不会导致ANR了? 远程服务是指将服务放到另一个进程中执行,所以就不会导致程序的ANR现象。 如何跨进程与Activity进行通信? 见示例 如何实现跨程序通信?
示例 - 实现跨进程与Activity交互 步骤 1.创建aidl文件,定义接口(TestInterface)及相关方法。点击make project,自动生成Stub相关的接口。 2.创建Service类,并在ManiFest文件设置远程属性。android:process=”:remote” 3.在Service中创建接口TestInterface.Stub 对象,重写接口方法。 4.在Activity中通过AIDL接口的asInterface方法来获取AIDL对象。 5.利用接口对象调用相关方法。
1 2 3 4 5 package io.tanjundang.study.test.service;interface RemoteAidlInterface { void calcMsg () ; }
1 2 3 4 // 配置服务远程属性 <service android:name =".test.service.RemoteService" android:process =":remote" />
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class RemoteService extends Service { RemoteAidlInterface.Stub mBinder = new RemoteAidlInterface.Stub() { @Override public void calcMsg () throws RemoteException { LogTool.e("RemoteService" , "66666" ); } }; @Override public Binder onBind (Intent intent) { return mBinder; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public class RemoteActivity extends AppCompatActivity { private RemoteAidlInterface mBinder; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected (ComponentName componentName, IBinder iBinder) { mBinder = RemoteAidlInterface.Stub.asInterface(iBinder); try { mBinder.calcMsg(); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected (ComponentName componentName) { } }; @Override protected void onCreate (Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.activity_remote); } public void StartRemoteService (View v) { Intent intent = new Intent(this , RemoteService.class); bindService(intent, connection, BIND_AUTO_CREATE); } public void UnbindRemoteService (View v) { if (mBinder != null ) { unbindService(connection); } } }
示例 - 实现跨程序与Activity交互 步骤 实现步骤跟上面类似。只是需要为Service定义Action,以及将AIDL接口及其包名复制到另一程序中。即可实现跨程序交互。
IntentService 理解 为什么有这个类? 该类是Service的子类,主要是简化了异步操作繁琐复杂的代码。 有什么特点? 1.不需要自己创建子线程。 2.不需要考虑何时关闭服务。 使用情景是什么? 多次调用startService。 使用 1.Service继承IntentService。 2.以类名为参数调用父类构造方法。 3.重写onHandleIntent核心方法以及其他方法。
前台服务 什么是前台服务? 普通服务在内存不足的情况下会被系统杀掉,而前台服务不会因为内存不足而被杀掉。 前台服务有什么特点? 前台服务有通知栏提示,可设定相关的标题、提示灯。例如天气、播放器等。 前台服务的使用 1.构建Notification对象。 2.通过startForeground方法启动通知栏。 3.通过stopForeground方法关闭通知栏。 注意 Notification的构建中,若不调用setSmallIcon方法设置Icon,其他相关设置(标题、提示)均无效。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Override public int onStartCommand (final Intent intent, int flags, final int startId) { final NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext()); builder.setContentIntent(PendingIntent.getActivity(this , 0 , new Intent(getApplicationContext(), MainActivity.class), 0 )); builder.setContentTitle("前台服务" ); builder.setSmallIcon(R.drawable.ic_menu_camera); builder.setContentText("二级子标题" ); builder.setSubText("三级子标题" ); Notification notification = builder.build(); startForeground(startId, notification); LogTool.e("CalcService" , "onStartCommand" ); Functions.toast("Service已启动,请查看LOG" ); total = intent.getIntExtra("msg" , 100 ); return super .onStartCommand(intent, flags, startId); }
Service官方文档 郭林大神ADIL服务 绑定服务