Android四大组件详解–Service篇
Android服务是一个后盾运行的组件,执行长时间运行且不须要用户交互的工作。即便利用被销毁也仍然能够工作。
一:Service根本用法
1.StartService开启服务
新建一个TestService继承Service,并重写父类的onCreate(),onStartCommand(),onDestroy()的办法
public class TestService extends Service { public static final String TAG="TestService"; /** * 继承一个Service必然要实现的onBind办法*/ @Nullable @Override public IBinder onBind(Intent intent) { Log.d(TAG,"onBind()"); return null; } @Override public void onCreate() { super.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() { super.onDestroy(); Log.d(TAG,"onDestroy()"); } }
在AndroidManifest中配置Service
<application> <service android:name=".TestService"/> </application>
点击执行Service
four_teen_btn=findViewById(R.id.four_teen_btn); four_teen_btn_service=findViewById(R.id.four_teen_btn_service); four_teen_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(FourTeenActivity.this,TestService.class); startService(intent);//开启服务 } }); four_teen_btn_service.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent=new Intent(FourTeenActivity.this,TestService.class); stopService(intent);//进行服务 } }); 后果: D/TestService: onCreate() D/TestService: onStartCommand() startService开启服务后会走onCreate()和onStartCommand()办法 屡次点击只会执行onStartCommand(),onCreate()只会调用一次 D/TestService: onStartCommand() 调用stopService办法敞开服务 D/TestService: onDestroy()
context.startService()开启服务流程:
context.startService()–>onCreate()–>onStartCommand()—>context.stopService()–>onDestroy()–>Service Stop
2.bindService绑定服务
察看发现下面发现Service和Activity之间关联不大,发现下面始终有一个onBind()办法没有用到
故Activity和Service通信,能够通过绑定一个Service
利用组件能够调用bindService()绑定一个service,Android零碎之后调用service的onBind()办法,它返回一个用来与service交互的IBinder
绑定是异步的,bindService()会立刻返回,它不会返回IBinder给客户端,要接管IBinder,客户端必须创立一个ServiceConnection的实例并传给bindService()ServiceConnection蕴含一个回调办法,零碎调用这个办法来传递要返回的IBinder.
public class TestService extends Service { public static final String TAG="TestService"; private MyBinder myBinder=new MyBinder(); /** * 继承一个Service必然要实现的onBind办法*/ @Nullable @Override public IBinder onBind(Intent intent) { Log.d(TAG,"onBind()"); return myBinder;//返回IBinder接口 } @Override public void onCreate() { super.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() { super.onDestroy(); Log.d(TAG,"onDestroy()"); } class MyBinder extends Binder{//Binder实现了IBinder接口了 public void startDownload(){ Log.d(TAG,"startDownload()"); //执行具体的工作 } } }
four_teen_btn_bind_service.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent bindIntent = new Intent(FourTeenActivity.this, TestService.class); bindService(bindIntent, connection, BIND_AUTO_CREATE); } }); four_teen_btn_unbind_service.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent bindIntent = new Intent(FourTeenActivity.this, TestService.class); unbindService(connection); } }); } ServiceConnection connection=new ServiceConnection() { //这个办法零碎调用这个来传送在Service的onBind()中返回的IBinder @Override public void onServiceConnected(ComponentName name, IBinder service) { //拿到后盾服务的代理对象 TestService.MyBinder myBinder= (TestService.MyBinder) service; //调用后盾服务的办法 myBinder.startDownload(); } //Android零碎在同service连贯意外失落调用这个 @Override public void onServiceDisconnected(ComponentName name) { } }; 通过调用bindService传递给他ServiceConnection的实现 bindService(bindIntent, connection, BIND_AUTO_CREATE); 第一个参数明确指定要绑定的ServiceIntent 第二个参数是ServiceConnection对象 第三个参数是一个标记,表明绑定中的操作,它个别是BIND_AUTO_CREATE 后果: 点击bindService后 Service走了onBind办法 D/TestService: onCreate() D/TestService: onBind() 调用Binder类自定义的办法 D/TestService: startDownload() 点击unbindService D/TestService: onUnbind() D/TestService: onDestroy()
通过bindService绑定服务
bindService()–>onCreate()–>onBind()–>unBindService()–>onUnbind()–>onDestory()
3.Service和线程Thread的区别
Thread:是程序执行的最小单元,能够用线程来执行一些异步操作。
Service:是android的一种机制,当它运行的时候如果是Local Service,那么对应的Service是运行在主线程main线程上;如果是Remote Service .那么对应的Service则运行在独立过程的main线程上。
//在Activity中 protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_four_teen); Log.d(TAG,"onCreate()"); Log.d("TestService","FourTeenActivity thread is"+Thread.currentThread().getId()); } 后果: D/FourTeenActivity: onCreate() D/TestService: FourTeenActivity thread is2 //在Service中 public void onCreate() { super.onCreate(); Log.d(TAG,"onCreate()"); Log.d("TestService","MyService thread is"+Thread.currentThread().getId()); } 后果: D/TestService: onCreate() D/TestService: MyService thread is2 发现2个线程的id雷同,阐明service运行在主线程main中
故:不要把后盾服务和子线程分割在一起,service不能做耗时操作,不然会导致ANR,要做耗时操作须要在服务中创立一个子线程。
4.前台服务
前台服务是那些被认为用户晓得且在零碎内存不足的时候不容许零碎杀死的服务。前台服务必须给状态栏提供一个告诉。
最常见的表现形式就是音乐播放服务,应用程序后盾进行时,用户能够通过告诉栏,晓得以后播放内容,并进行暂停,持续,切歌等相干操作。
创立一个前台服务Service
public class ForegroundService extends Service { private static final String TAG = "ForegroundService"; private static final int NOTIFICATION_ID=10; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); Log.d(TAG, "onCreate()"); //获取服务告诉 Notification notification=createForegroundNotification(); //将服务置于启动状态,NOTIFICATION_ID指的是创立的告诉的ID startForeground(NOTIFICATION_ID,notification); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "onStartCommand()"); // 数据获取 String data = intent.getStringExtra("Foreground"); Toast.makeText(this, data, Toast.LENGTH_SHORT).show(); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { stopForeground(true); super.onDestroy(); Log.d(TAG, "onDestroy()"); } /** * 创立服务告诉 */ private Notification createForegroundNotification() { NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); //惟一的告诉通道的id String notificationChannelId="notification_channel_id_01"; //Android8.0以上的零碎,新建音讯通道 if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){ //用户可见的通道名称 String channelName="Foreground Service Notification"; //通道的重要水平 int importance=NotificationManager.IMPORTANCE_HIGH; NotificationChannel notificationChannel=new NotificationChannel(notificationChannelId,channelName,importance); notificationChannel.setDescription("Channel description"); //LED灯 notificationChannel.enableLights(true); notificationChannel.setLightColor(Color.RED); //触动 notificationChannel.setVibrationPattern(new long[]{0,1000,500,1000}); notificationChannel.enableVibration(true); if (notificationManager!=null){ notificationManager.createNotificationChannel(notificationChannel); } } NotificationCompat.Builder builder=new NotificationCompat.Builder(this,notificationChannelId); //告诉小图标 builder.setSmallIcon(R.mipmap.ic_launcher); //告诉题目 builder.setContentTitle("ContentTitle"); //告诉内容 builder.setContentText("ContentText"); //设置告诉工夫 builder.setWhen(System.currentTimeMillis()); //设置启动内容 Intent activityIntent=new Intent(this,NotificationActivity.class); PendingIntent pendingIntent=PendingIntent.getActivity(this,1,activityIntent,PendingIntent.FLAG_UPDATE_CURRENT); builder.setContentIntent(pendingIntent); return builder.build(); } }
btn_start_service=findViewById(R.id.btn_start_service); btn_stop_service=findViewById(R.id.btn_stop_service); btn_start_service.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // Android 8.0应用startForegroundService在前台启动新服务 Intent mForegroundService = new Intent(NotificationActivity.this, ForegroundService.class); mForegroundService.putExtra("Foreground", "This is a foreground service."); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(mForegroundService); } else { //启动服务 startService(mForegroundService); } } }); btn_stop_service.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //进行服务 Intent mForegroundService = new Intent(NotificationActivity.this, ForegroundService.class); stopService(mForegroundService); } });
前台服务须要配置一个权限
<!--前台服务权限--> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
前台服务和Notification密不可分,Notification具体须要具体钻研
**总结:
前台服务Service的零碎优先级更高,不易被回收
前台服务Service会始终有一个正在运行的图标在零碎的状态栏显示,下拉状态栏后能够看到更具体的信息,十分相似于告诉的成果**
5.近程服务Remote Service
1.什么是近程服务
近程服务也被称之为独立过程,它不受其余过程影响,能够为其余利用过程提供调用的接口–实际上就是过程间通信(IPC),Android 提供了AIDL工具来帮忙过程间接口的建设。
注:在Android中,不同的利用属于不同的过程(Process),一个过程不能拜访其它过程的存储(能够通过ContentProvider实现,如:通讯录的读取)。
1.AS创立AIDL文件,创立一个MyRemote接口
新建一个MyRemote接口,创立一个getMessage()办法
注:如果服务端与客户端不在同一App上,须要在客户端、服务端两侧都建设该aidl文件。
3.新建一个Remote Service
在近程服务中通过Service的onBind(),在客户端与服务端建设连贯时,用来传递对象
public class RemoteService extends Service { private static final String TAG="RemoteService"; @Nullable @Override public IBinder onBind(Intent intent) { Log.d(TAG,"onBind"); Log.d(TAG,Thread.currentThread().getName()); return stub;// 在客户端连贯服务端时,Stub通过ServiceConnection传递到客户端 } @Override public boolean onUnbind(Intent intent) { Log.d(TAG,"onUnbind"); return super.onUnbind(intent); } @Override public void onDestroy() { Log.d(TAG,"onDestroy"); super.onDestroy(); } // 实现接口中裸露给客户端的Stub--Stub继承自Binder,它实现了IBinder接口 private MyRemote.Stub stub = new MyRemote.Stub() { //实现AIDL文件中定义的办法 @Override public String getMessage() throws RemoteException { // 在这里咱们只是用来模仿调用成果,因而轻易反馈值给客户端 return "Remote Service办法调用胜利"; } }; } //咱们在AndroidManifest文件定义Service <service android:name=".RemoteService" android:process="com.ruan.test.remote">//或者android:process=":remote" <intent-filter> <action android:name="com.soudao.test.RemoteService"/> </intent-filter> </service>
注:如果客户端与服务端在同个App中,AndroidManifest.xml中设置Remote Service的andorid:process
属性时,如果被设置的过程名是以一个冒号(:)结尾的,则这个新的过程对于这个利用来说是公有的,当它被须要或者这个服务须要在新过程中运行的时候,这个新过程将会被创立。如果这个过程的名字是以小写字符结尾的,则这个服务将运行在一个以这个名字命名的全局的过程中,当然前提是它有相应的权限。这将容许在不同利用中的各种组件能够共享一个过程,从而缩小资源的占用。
4.在Activity中去开启近程服务和敞开近程服务
public class RemoteActivity extends AppCompatActivity { private Button btn_start_service; private Button btn_stop_service; private MyRemote myRemote;//定义接口变量 @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_remote); btn_start_service = findViewById(R.id.btn_start_service); btn_stop_service = findViewById(R.id.btn_stop_service); btn_stop_service.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { unbindService(connection); } }); btn_start_service.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intentService = new Intent(); intentService.setClassName(RemoteActivity.this, "com.soudao.test.RemoteService"); bindService(intentService, connection, BIND_AUTO_CREATE); } }); } ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder iBinder) { //从连贯中获取Stub对象 myRemote = MyRemote.Stub.asInterface(iBinder); // 调用Remote Service提供的办法 try { Log.d("RemoteActivity", "获取到音讯:" + myRemote.getMessage()); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { // 断开连接 myRemote=null; } }; @Override protected void onDestroy() { super.onDestroy(); if (connection!=null){ unbindService(connection);//解除绑定 } } }
点击开启服务,近程服务会开启,过程com.soudao.test:remote
对应的RemoteActivity与Remote Service的连贯,获取Stub,而后调用Remote Service提供的办法获取对应的数据
近程服务的优缺点:
长处:
1.近程服务有本人的独立过程,不会受其余过程的影响
2.能够被其余过程复用,提供公共服务
3.具备很高的灵活性
毛病:
绝对一般服务占用系统资源较多,应用AIDL进行IPC也绝对麻烦
5.AndroidManifest.xml中Service元素常见属性
1.android:name=”.RemoteService”//服务的类名,能够是残缺的包名+类名。也能够应用.代替包名
2.android:exported=”true”//其余利用是否拜访该服务,如果不能,则只有本利用获取有雷同用户ID的利用能拜访,默认是false
3.android:enabled=”true”//标记服务是否能够被零碎实例化。true零碎默认启动,false 不启动
4.android:label=””//显示给用户的服务名称,如果没有进行服务名称的设置,默认显示服务的类名
5.android:process=”:remote”//服务所在的过程名,默认是在以后过程下运行,与包名统一。如果进行设置,警徽在包名后加上设置的集成名。
6.android:icon=””//服务的图标
7.android:permission=””//申请应用该服务的权限,如果没有配置下相干权限,服务将不执行,应用startService,和bindService办法将得不到执行
6.无障碍服务Service
无障碍服务是为了加强用户界面以帮忙残障人士,它的具体实现是通过AccessibilityService服务运行在后盾中,通过AccessibilityEvent接管指定事件的回调。这样的事件示意用户在界面中的一些状态转换,例如:焦点扭转了,一个按钮被点击,等等。这样的服务能够抉择申请流动窗口的内容的能力。简略的说AccessibilityService就是一个后盾监控服务,当你监控的内容产生扭转时,就会调用后盾服务的回调办法
1.AccessibilityService的应用
public class AutoScriptService extends AccessibilityService { public static final String ACTION_SERVICE_STATE_CHANGE = "ACTION_SERVICE_STATE_CHANGE"; //当服务启动的时候就会别调用 @Override protected void onServiceConnected() { super.onServiceConnected(); LogUtils.d("AccessibilityService onServiceConnected"); sendAction(true); } //监听窗口变动的回调 @Override public void onAccessibilityEvent(AccessibilityEvent event) { LogUtils.d("AccessibilityService onAccessibilityEvent"); } //中断服务的回调 @Override public void onInterrupt() { } private void sendAction(boolean state) { Intent intent = new Intent(ACTION_SERVICE_STATE_CHANGE); intent.putExtra("state", state); sendBroadcast(intent); } }
对应的AndroidManfest.xml文件里
<service android:name=".AutoScriptService" android:exported="true" android:enabled="true" android:label="@string/app_name" android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> <intent-filter> <action android:name="android.accessibilityservice.AccessibilityService" /> </intent-filter> <meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityconfig" /> </service>
在res文件下新建一个xml文件
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android" android:accessibilityEventTypes="typeAllMask" android:accessibilityFeedbackType="feedbackGeneric" android:accessibilityFlags="flagIncludeNotImportantViews|flagReportViewIds|flagRequestEnhancedWebAccessibility|flagRetrieveInteractiveWindows" android:canRequestEnhancedWebAccessibility="true" android:canRetrieveWindowContent="true" android:description="@string/my_accessibility_description" android:notificationTimeout="100" />
7.IntentService应用
public class MyIntentService extends IntentService { private static final String TAG="MyIntentService"; private int count=0; public MyIntentService() { super(TAG); } @Override protected void onHandleIntent(@Nullable Intent intent) { count++; Log.d(TAG,"count:"+count); } } 1.IntentService 是继承于 Service 并解决异步申请的一个类,在 IntentService 内有一个工作线程来解决耗时操作,启动 IntentService 的形式和启动传统 Service 一样 2.当工作执行完后,IntentService 会主动进行,而不须要咱们去手动管制敞开 3.能够启动 IntentService 屡次 4.而每一个耗时操作会以工作队列的形式在IntentService 的 onHandleIntent 回调办法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。就是在一个单队列 5.申请都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只解决一个申请
8.Android 零碎服务
获取零碎的网络连接服务: ConnectivityManager mConnectivityManager = (ConnectivityManager)context.getSystemService(CONNECTIVITY_SERVICE); 获取零碎的 WiFi 服务: WifiManager wifimanager = (WifiManager) this.getSystemService(WIFI_SERVICE); 获取零碎的 Auido(音响/声音)服务: AudioManager mAudioManager = (AudioManager) this.getSystemService(AUDIO_SERVICE); 获取零碎的 Activity 服务: ActivityManager mActivityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE); 别忘了增加权限: <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>//网络状态权限 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>//读取WiFi状态 <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />//扭转WiFi状态 <uses-permission android:name="android.permission.GET_TASKS"/>//容许一个程序获取信息无关以后或最近运行的工作,一个缩略的工作状态,是否流动等等
END:道虽迩,不行不至;事虽小,不为不成