文章目录
-
- 程序、程序、线程
-
- 概念
- 线程的生命周期
- 线程的创建
- 初识service
-
- Service概念
- Service生命周期
- Service种类
- Service重要的方法
- Service 的声明
- Service的启动
-
- StartService启动Service
- BindService启动Service
- StartService启动Service后bindService绑定
- Service 进阶
-
- IntentService的使用
- Activity与Service通信
- 实现前台服务
- 实现定时后台线程
- Service 再进阶
-
- Binder机制
-
- IBinder和Binder
- Binder机制和工作流程
- 为何Android使用Binder实现过程间通信的机制
- AIDL(重要)
-
- AIDL定义
- AIDL实现两个过程之间的简单通信
- 复杂数据的传输AIDL Service
- 通过Binder的onTransact完成跨过程通信
- 记录使用高版本的记录AIDL大坑
程序、程序、线程
在了解service在了解相关知识之前,先了解多线程知识。际开发中,Service它通常与多线程相关。
概念
- 程序:用某种语言编写的一组指令集(一组静态代码),以完成特定任务
- 过程:操作系统将是运行中的程序、系统调度和资源分配的独立单位 为每个过程分配一个内存空间!依次动态执行程序,加载和执行代码, 完成完完整过程!
- 线程:比进程更小的执行单元,每个进程可能有多条线程,线程需要放在一个 线程由程序管理,过程由系统调度!
- 多线程理解:并行执行多个指令,将CPU按照调度算法分配时间片 线程实际上是分时执行的,但切换时间很短,用户感觉到"同时"而已
唠叨两句,有很多学生会混淆过程和线程的概念,这里教你一种方法,过程作为火车;线程作为火车,然后我们看看线程和过程的概念是否非常符合这个概念?
流程是最小的资源分配单位;线程是最小的程序执行单位
线程的生命周期
共五个阶段 新建、就绪、运行、阻塞、死亡
线程的创建
- 继承Thread类
- 实现Runnable接口
//创建并启动 new Thread(myThread).start();
//使用匿名内部类 new Thread(new Runnable(){
public void run(); }).start();
- 实现Callable接口
初识service
Service概念
什么是Servie?
Service (服务)是一个应用程序组件,可以在后台长时间运行,不提供用户界面。即使用户切换到另一个应用程序,服务也可以在后台运行。此外,组件可以绑定到服务并与之互动,甚至在执行过程中进行通信(IPC) 。例如,服务可以在后台处理网络事务、播放音乐和执行文件IO或者与ContentProvider通信。
Service生命周期
Service种类
从上图可以看出,Service主要分为两种
- Started:当应用程序组件(如Activity )通过调用startService()方法启动服务时,服务处于started状态。 即使启动的组件已经被销毁,服务也可以在后台无限期运行。通常,启动服务执行单个操作并且不会向调用者返回结果。例如,它可以通过网络下载或上传文件。如果操作完成,服务需要停止。
- Bound :应用程序组件通过调用bindService()方法绑定到服务时,服务在bound状态。绑定服务提供客户端-服务器接口,允许组件与服务互动,发送请求,甚至在使用过程中获得结果(IPC) 跨过程完成这些操作。只有当其他应用程序组件被绑定时,绑定服务才能运行。多个组件可以使用一次绑定到 一个服务上,当它们都解绑定时,服务被销毁。
其实还有一种就是启动Service后,绑定Service,也就是两种兼有的
不管应用程序是否为启动状态、绑定状态或者两者兼有,都能通过Intent使用服务,就像使用Activity那样。然而,开发人员可以在配置文件中将服务声明为私有的,从而阻止其他应用程序访问。 服务运行于管理它的进程的主线程,服务不会创建自己的线程,也不会运行于独立的进程(除非开发人员定义)。这意味着,如果服务要完成CPU密集工作或者阻塞操作(如MP3回放或者联网),开发人员需要在服务中创建新线程来完成这些工作。通过使用独立的线程,能减少应用程序不响应(ANR)错误的风险,并且应用程序主线程仍然能用于用户与Activity的交互。
Service中重要的方法
为了创建服务,开发人员需要创建Service类(或其子类)的子类。在实现类中,需要重写一些处理服务生命周期重要方面的回调方法,并根据需要提供组件绑定到服务的机制。
回调 | 描述 |
---|---|
onCreate() | 当服务通过onStartCommand()和onBind()被第一次创建的时候,系统调用该方法。该方法在整个生命周期 中只会调用一次,如果服务已经运行,该方法不被调用 |
onDestory() | 当服务不再有用或者被销毁时,系统调用该方法。你的服务需要实现该方法来清理任何资源,如线程,已注册的监听器,接收器等。该方法只会回调一次! |
onStartCommand() | 其他组件(如活动)通过调用startService()来请求启动服务时,系统调用该方法。如果你实现该方法,你有责任在工作完成时通过stopSelf()或者stopService()方法来停止服务。当客户端调用startService(Intent)方法时会回调,可多次调用StartService方法, 但不会再创建新的Service对象,而是继续复用前面产生的Service对象,但会继续回调 onStartCommand()方法 |
IBinder onOnbind() | 该方法是Service都必须实现的方法,当其他组件想要通过bindService()来绑定服务时,系统调用该方法。如果你实现该方法,你需要返回IBinder对象来提供一个接口,以便客户来与服务通信。你必须实现该方法,如果你不允许绑定,则直接返回null。 |
onUnbind() | 当该Service上绑定的所有客户端都断开时会回调该方法 |
onRebind() | 当新的客户端与服务连接,且此前它已经通过onUnbind(Intent)通知断开连接时,系统调用该方法。 |
需要重写的重要回调方法有onStartCommand()
、onBind()
、onCreate()
、onDestroy()
Service 的声明
<service android: enabled= ["true" | " false"]
android:exported= ["true" |"false"]
android:icon="drawable resource'
android:label= "string resource'
android:name= "string "
android:permission="string"
android:process="string" >
</service>
android:enabled
服务能否被系统实例化,true表示可以,false 表示不可以,默认值是true。标签也有自己的enabled属性,用于包括服务的全部应用程序组件。 和enabled属性必须同时设置成true (两者的默认值都是true)才能让服务可用。如果任何一个是false,服务被禁用并且不能实例化。android:exported
其他应用程序组件能否调用服务或者与其交互,true 表示可以,false 表示不可以。当该值是false时,只有同一个应用程序的组件或者具有相同用户ID的应用程序能启动或者绑定到服务。 默认值依赖于服务是否包含Intent 过滤器。若没有过滤器,说明服务仅能通过精确类名调用,这意味着服务仅用于应用程序内部( 因为其他程序可能不知道类名)。此时,默认值是false;若存在至少一个过滤器,暗示服务可以用于外部,因此默认值是true.该属性不是限制其他应用程序使用服务的唯一方式。 还可以使用permission屈性限制外部实体与服务交互。android:icon
表示服务的图标。该属性必须设置成包含图片定义的可绘制资源引用。如果没有设置,使用应用程序图标取代。服务图标不管在此设置还是在标签设置,都是所有服务的Intent过滤器默认图标。android:label
显示给用户的服务名称。如果没有设置,使用应用程序标签取代。服务标签不管在此设置还是在标签设置,都是所有服务的Intent过滤器默认标签。标签应该设置为字符串资源引用,这样可以像用户界面的其他字符串那样本地化。然而,为了开发时方便,也可以设置成原始字符串。android:name
实现服务的Service子类名称,应该是-一个完整的类名,如com.googl.RoomService.然而,为了简便,如果名称的第一个符号是点号(如.RoomService) ,则会增加在标签中定义的包名。一旦发布了应用程序,不应该再修改子类名称。该属性没有默认值并且必须指定。android:permission
实体必须包含的权限名称,以便启动或者绑定到服务。如果startService()、bindService()或 stopService()方法调用者没有被授权,方法调用无效,并且Intent对象也不会发送给服务。 如果没有设置该属性,使用标签的permission 属性设置给服务。如果 和标签的permission属性都未设置,服务不受权限保护.android:process
服务运行的进程名称。通常,应用程序的全部组件运行于为应用程序创建的默认进程。进程名称与应用程序包名相同。标签 的process 属性能为全部组件设置一个相同的默认值。但是组件能用自己的process属性重写默认值,从而允许应用程序跨越多个进程。如果分配给该属性的名称以冒号(:)开头,仅属于应用程序的新进程会在需要时创建,服务能在该进程中运行; 如果进程名称以小写字母开头,服务会运行在以此为名的全局进程,但需要提供相应的权限。这允许不同应用程序组件共享进程,减少资源使用。
Service的启动
要想声明并启动Service,开发人员需要创建Service类(或其子类)的子类 Android提供了两个类供开发人员继承以创建启动服务。
Service
: 这是所有服务的基类。当继承该类时,创建新线程来执行服务的全部工作是非常重要的。因为服务默认使用应用程序主线程,这可能降低应用程序Activity的运行性能。IntentService
: 这是Service类的子类,它每次使用一个工作线程来处理全部启动请求。在不必同时处理多个请求时,这是最佳选择。开发人员仅需要实现onHandleIntent()方法,该方法接收每次启动请求的Intent 以便完成后台任务。
StartService启动Service
①首次启动会创建一个Service实例,依次调用onCreate()和onStartCommand()方法,此时Service 进入运行状态,如果再次调用StartService启动Service,将不会再创建新的Service对象, 系统会直接复用前面创建的Service对象,调用它的onStartCommand()方法! ②但这样的Service与它的调用者无必然的联系,就是说当调用者结束了自己的生命周期, 但是只要不调用stopService,那么Service还是会继续运行的! ③无论启动了多少次Service,只需调用一次StopService即可停掉Service
FirstService.java
package com.thundersoft.myblogdemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
/** * @ClassName FirstService * @Description TODO * @Author Yu * @Date 2022/6/30 17:19 * @Version 1.0 **/
public class FirstService extends Service {
private final static String TAG="Service1";
//必须要实现的方法
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG,"onBind()被调用");
return null;
}
//Service被启动时调用
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG,"onStartCommand()被调用");
return super.onStartCommand(intent, flags, startId);
}
//Service被创建时调用
@Override
public void onCreate() {
Log.i(TAG,"onCreate()被调用");
super.onCreate();
}
//Service被关闭之前回调
@Override
public void onDestroy() {
Log.i(TAG,"onDestroy()被调用");
super.onDestroy();
}
}
AndroidManifest.xml
<service android:name=".FirstService" android:enabled="true" >
</service>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Button btn1,btn2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = findViewById(R.id.btn1);
btn2 = findViewById(R.id.btn2);
Intent intent = new Intent(MainActivity.this, FirstService.class);
btn1.setOnClickListener(v->{
startService(intent);
});
btn2.setOnClickListener(v->{
stopService(intent);
});
}
}
点击开始服务 再次点击 点击关闭服务
这里补充一些知识点 onStartCommand()方法必须返回一个 整数。该值用来描述系统停止服务后如何继续服务onStartCommand()方法返回值必 须是下列常量之一。
START_ NOT STICKY
如果系统在onStartCommand()方法返回后停止服务,不重新创建服务,除非有PendingIntent要发送。为避免不在不需要的时候运行服务,这是最佳选择。
START_ STICKY
如果系统在onStartCommand()方法返回后停止服务,重新创建服务并调用onStartCommand()方法,但是不重新发送最后的Intent;相反,系统使用空Intent调用onStartCommand0方法,除非有PendingIntent来启动服务,此时,这些Intent会被发送。这适合多媒体播放器(或者类似服务),它们不执行命令但是无限期运行并等待工作。
START_REDELIVER_ INTENT
如果系统在onStartCommand0方法返回后停止服务,重新创建服务并使用发送给服务的最后Intent调用onStrtCommand0方法,全部PendingIntent依次发送。这适合积极执行应该立即恢复工作的服务,如下载文件。
说明:这些常 量都定义在Service类中。
BindService启动Service
①当首次使用bindService绑定一个Service时,系统会实例化一个Service实例,并调用其onCreate()和onBind()方法,然后调用者就可以通过IBinder和Service进行交互了,此后如果再次使用bindService绑定Service,系统不会创建新的Sevice实例,也不会再调用onBind()方法,只会直接把IBinder对象传递给其他后来增加的客户端! ②如果我们解除与服务的绑定,只需调用unbindService(),此时onUnbind和onDestory方法将会被调用!这是一个客户端的情况,假如是多个客户端绑定同一个Service的话,情况如下 当一个客户完成和service之间的互动后,它调用 unbindService() 方法来解除绑定。当所有的客户端都和service解除绑定后,系统会销毁service。(除非service也被startService()方法开启) ③另外,和上面那张情况不同,bindService模式下的Service是与调用者相互关联的,可以理解为 “一条绳子上的蚂蚱”,要死一起死,在bindService后,一旦调用者销毁,那么Service也立即终止!
通过BindService调用Service时调用的Context的bindService的解析 bindService(Intent Service,ServiceConnection conn,int flags)
service:通过该intent指定要启动的Service conn:ServiceConnection对象,用户监听访问者与Service间的连接情况, 连接成功回调该对象中的onServiceConnected(ComponentName,IBinder)方法; 如果Service所在的宿主由于异常终止或者其他原因终止,导致Service与访问者间断开 连接时调用onServiceDisconnected(CompanentName)方法,主动通过unBindService() 方法断开并不会调用上述方法! flags:指定绑定时是否自动创建Service(如果Service还未创建), 参数可以是0(不自动创建),BIND_AUTO_CREATE(自动创建)
Context中的bindService方法:
ServiceConnection
对象:监听访问者与Service间的连接情况,如果成功连接,回调 onServiceConnected(),如果异常终止或者其他原因终止导致Service与访问者断开 连接则回调onServiceDisconnected方法,调用unBindService()不会调用该方法!onServiceConnected
方法中有一个IBinder对象,该对象即可实现与被绑定Service 之间的通信!我们再开发Service类时,默认需要实现IBinder onBind()方法,该方法返回的 IBinder对象会传到ServiceConnection对象中的onServiceConnected的参数,我们就可以 在这里通过这个IBinder与Service进行通信!
SecondService.java
package com.thundersoft.myblogdemo;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
/** * @ClassName SecondService * @Description TODO * @Author Yu * @Date 2022/6/30 18:04 * @Version 1.0 **/
public class SecondService extends Service {
private static final String TAG="Service2";
private boolean quit;
private int count;
//onBind()返回的对象
private MyBinder binder=new MyBinder();
public class MyBinder extends Binder{
SecondService getService(){
return SecondService.this;
}
}
//必须实现的方法,绑定改Service时回调该方法
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG,"onBind()被调用");
return binder;
}
//Service被创建时回调
@Override
public void onCreate() {
Log.i(TAG,"onCreate()被调用");
new Thread(new Runnable() {
@Override
public void run() {
//当服务还在就一直累加
while (!quit){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
}
}).start();
super.onCreate();
}
//Service断开连接时回调
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind方法被调用!");
return true;
}
//Service被关闭前回调
@Override
public void onDestroy() {
super.onDestroy();
this.quit = true;
Log.i(TAG, "onDestroyed方法被调用!");
}
@Override
public void onRebind(Intent intent) {
Log.i(TAG, "onRebind方法被调用!");
super.onRebind(intent);
}
public int getCount(){
return count;
}
}
AndroidManifest.xml
<service android:name=".SecondService" android:enabled="true" android:exported="true" >
</service>
MainActivity.java
package com.thundersoft.myblogdemo;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.PersistableBundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private Button btn1,btn2,btn3;
SecondService second_service;
ServiceConnection connection = new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
SecondService.MyBinder binder=( SecondService.MyBinder) service;
second_service=binder.getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = findViewById(R.id.btn1);
btn2 = findViewById(R.id.btn2);
btn3= findViewById(R.id.btn3);
Intent intent = new Intent(this,SecondService.class);
btn1.setOnClickListener(v->{
bindService(intent,connection, Service.BIND_AUTO_CREATE);
});
btn2.setOnClickListener(v->{
unbindService(connection);
});
btn3.setOnClickListener(v->{
Toast.makeText(this,second_service.getCount()+"",Toast.LENGTH_SHORT).show();
});
}
}
点击绑定服务 点击服务状态 点击解绑服务
StartService启动Service后bindService绑定
如果Service已经由某个客户端通过StartService()启动,接下来由其他客户端 再调用bindService()绑定到该Service后调用unbindService()解除绑定最后在 调用bindService()绑定到Service的话,此时所触发的生命周期方法如下: onCreate( )->onStartCommand( )->onBind( )->onUnbind( )->onRebind( ) PS:前提是:onUnbind()方法返回true!!! 这里或许部分读者有疑惑了,调用了unbindService后Service不是应该调用 onDistory()方法么!其实这是因为这个Service是由我们的StartService来启动的 ,所以你调用onUnbind()方法取消绑定,Service也是不会终止的! 得出的结论: 假如我们使用bindService来绑定一个启动的Service,注意是已经启动的Service!!! 系统只是将Service的内部IBinder对象传递给Activity,并不会将Service的生命周期 与Activity绑定,因此调用unBindService( )方法取消绑定时,Service也不会被销毁!
Service 进阶
IntentService的使用
在前面我们提到了可以继承Service或者IntentService来创建并启动自己的Service,前面只对继承Service类的方式做了介绍,下面来详细介绍一下IntentService
既然继承Service类就可以实现自己的Service,为什么还需要IntentService类呢?
事实上,如果我们直接把耗时线程放到Service中的onStart()方法中,很容易 会引起ANR异常(Application Not Responding),虽然可以这样做,但是官方不推荐在Service中进行一些耗时操作。
1.Service不是一个单独的进程,它和它的应用程序在同一个进程中 2.Service不是一个线程,这样就意味着我们应该避免在Service中进行耗时操作
于是,Android给我们提供了解决上述问题的替代品——IntentService; IntentService是继承与Service并处理异步请求的一个类,在IntentService中有 一个工作线程来处理耗时操作,请求的Intent记录会加入队列 IntentService工作流程为:
客户端通过startService(Intent)来启动IntentService; 我们并不需要手动地去控制IntentService,当任务执行完后,IntentService会自动停止; 可以启动IntentService多次,每个耗时操作会以工作队列的方式在IntentService的 onHandleIntent回调方法中执行,并且每次只会执行一个工作线程,执行完一,再到二这样
ThirdService.java
/** * @ClassName ThirdService * @Description TODO * @Author Yu * @Date 2022/7/1 11:18 * @Version 1.0 **/ public class ThirdService extends IntentService { private static final String TAG="ThirdService"; //必须实现父类的构造方法 public ThirdService() { super("ThirdService"); } //必须重写的核心方法 @Override protected void onHandleIntent(@Nullable Intent intent) { String param = intent.getExtras().getString("PARAM"); if (param.equals("s1")) Log.i(TAG,"service1启动"); else if (param.equals("s2")) Log.i(TAG,"service2启动"); else if (param.equals("s3")) Log.i(TAG,"service3启动"); try { 标签:
exact传感器991b传感器