700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Android 四大组件 之 服务(Service)

Android 四大组件 之 服务(Service)

时间:2022-09-02 21:11:44

相关推荐

Android 四大组件 之 服务(Service)

Android 服务(Service)

服务是一个后台运行的组件,执行长时间运行且不需要用户交互的任务,即使应用被销毁也依然可以工作,服务基本上包含两种状态服务拥有生命周期方法,可以实现监控服务状态的变化,可以在合适的阶段执行相应的工作,下面的左图展示了当服务通过startService() 被创建时的声明周期,右图则显示了当服务通过 bindService() 被创建时的生命周期:要创建服务,需要创建一个继承自 android.app.Service 基类或者它的已知子类的 Java 类。Service 基类定义了不同的回调方法和多数重要方法,虽然不需要实现所有的回调方法,但理解所有的方法还是非常重要的,实现这些回调能确保应用以用户期望的方式实现。

生命周期解析

从上图的生命周期可以知道,Android 中使用 Service 的方式有两种:

1)StartService() 启动Service

2)BindService() 启动Service

PS: 还有一种,就是启动 Service 后,绑定 Service!

StartService 启动 Service

首次启动会创建一个 Service 实例,依次调用 onCreate() 和 onStartCommand()/onStart() 方法,此时 Service 进入运行状态,如果再次调用 StartService 启动 Service,将不会再创建新的 Service 对象, 系统会直接复用前面创建的 Service 对象,调用它的 onStartCommand()/onStart() 方法!

但这样的 Service 与它的调用者无必然的联系,就是说当调用者结束了自己的生命周期,但是只要不调用 stopService,那么 Service 还是会继续运行的!

无论启动了多少次 Service,只需调用一次 StopService 即可停掉 Service

BindService 启动 Service

当首次使用 bindService 绑定一个 Service 时,系统会实例化一个 Service 实例,并调用其 onCreate() 和 onBind() 方法,然后调用者就可以通过 IBinder 和 Service 进行交互了,此后如果再次使用 bindService 绑定 Service,系统不会创建新的Sevice 实例,也不会再调用 onBind() 方法,只会直接把 IBinder 对象传递给其他后来增加的客户端!

如果解除与服务的绑定,只需调用 unbindService(),此时 onUnbind 和 onDestory 方法将会被调用,这是一个客户端的情况。假如多个客户端绑定同一个Service的话,情况是当一个客户完成和 service 之间的互动后,它调用 unbindService() 方法来解除绑定,当所有的客户端都和 service 解除绑定后,系统会销毁 service。

bindService 模式下的 Service 是与调用者相互关联的,可以理解为 "一条绳子上的蚂蚱",要死一起死,在 bindService后,一旦调用者销毁,那么 Service 也立即终止!

4)bindService(Intent service, ServiceConnection conn,int flags)

4.1)service:通过该 intent 指定要启动的 Service

4.2)conn:ServiceConnection对象,用户监听访问者与Service间的连接情况, 连接成功回调该对象中的onServiceConnected(ComponentName,IBinder)方法,如果 Service 所在的宿主由于异常终止或者其他原因终止,导致Service 与访问者间断开连接时调用onServiceDisconnected(CompanentName)方法,主动通过unBindService()方法断开并不会调用上述方法!

4.3)flags:指定绑定时是否自动创建Service(如果Service还未创建), 参数可以是0(不自动创建)、BIND_AUTO_CREATE(自动创建)

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也不会被销毁!

生命周期验证

StartService 启动 Service

新建一个 服务继承 Service

package com.example.administrator.helloworld.service;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.util.Log;import android.widget.Toast;/*** 应用主服务*/public class MainService extends Service {/*** LAG 用于做* android.util.Log#i(java.lang.String, java.lang.String) 消息前缀* Log.i 消息会在 run 窗口输出*/private final String TAG = "MainService";//必须要实现的方法,服务被绑定时调用@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG, "onBind(Intent intent)方法被调用!");return null;}//Service被创建时调用@Overridepublic void onCreate() {Log.i(TAG, "onCreate()方法被调用!");super.onCreate();}//Service 被启动时调用@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG, "onStartCommand(Intent intent, int flags, int startId)方法被调用!");return super.onStartCommand(intent, flags, startId);}//Service被关闭之前回调@Overridepublic void onDestroy() {Log.i(TAG, "onDestroy()方法被调用!");super.onDestroy();}}

AndroidManifest.xml 完成 Service注册

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="/apk/res/android"package="com.example.administrator.helloworld"><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><!-- 配置Service组件 --><service android:name=".service.MainService" /></application></manifest>

布局文件内容,将放两个按钮用于开启服务与关闭服务:

<GridLayout xmlns:android="/apk/res/android"android:id="@+id/GridLayout1"android:layout_width="fill_parent"android:layout_height="wrap_content"android:columnCount="1"android:orientation="horizontal"android:rowCount="2"><Buttonandroid:id="@+id/btnStart"android:layout_width="match_parent"android:layout_height="64dp"android:text="开始服务" /><Buttonandroid:id="@+id/btnStop"android:layout_width="match_parent"android:layout_height="64dp"android:text="停止服务" /></GridLayout>

MainActivity 活动类:

package com.example.administrator.helloworld;import android.content.Intent;import android.graphics.Bitmap;import .Uri;import android.os.Bundle;import android.provider.Contacts;import android.provider.MediaStore;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;import com.example.administrator.helloworld.service.MainService;import java.util.Date;/*** 一个应用程序可以有1个或多个活动,而没有任何限制。* 每个为应用程序所定义的活动都需要在 AndroidManifest.xml 中声明,应用的主活动的意图过滤器标签中需要包含 MAIN 动作和 LAUNCHER 类别* 如果 MAIN 动作还是 LAUNCHER 类别没有在活动中声明,那么应用程序的图标将不会出现在主屏幕的应用列表中。*/public class MainActivity extends AppCompatActivity {String msg = "MainActivity : ";private Button start;private Button stop;/*** 当活动第一次被创建时调用*/@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);/*** 从项目的 res/layout 中的XML文件加载 UI 组件* android.util.Log#d(java.lang.String, java.lang.String) 方法用于在 Logcat 窗口中打印日志*/setContentView(R.layout.activity_main);Log.i(msg, "The onCreate(Bundle savedInstanceState) .....");start = findViewById(R.id.btnStart);stop = findViewById(R.id.btnStop);/*** Intent(Context packageContext, Class<?> cls)* packageContext:包上下文* cls:调用的服务类* 创建启动 Service 的 Intent*/final Intent intent = new Intent(this, MainService.class);/**为两个按钮设置点击事件,分别是启动与停止 service*/start.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {startService(intent);}});stop.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {stopService(intent);}});}}

依次点击:“开始服务”-》“停止服务”-》“开始服务”-》“停止服务”,控制台输出消息如下:

I/MainService: onCreate()方法被调用!

onStartCommand(Intent intent, int flags, int startId)方法被调用!

I/MainService: onDestroy()方法被调用!

I/MainService: onCreate()方法被调用!

I/MainService: onStartCommand(Intent intent, int flags, int startId)方法被调用!

I/MainService: onStartCommand(Intent intent, int flags, int startId)方法被调用!

发现 onBind() 方法并没有被调用,多次点击启动 Service,只会重复地调用 onStartCommand 方法,无论启动多少次Service,一个stopService 就会停止 Service!

BindService() 启动 Service

bindService(Intent service, ServiceConnection conn, int flags)

ServiceConnection 对象:监听访问者与 Service 间的连接情况,如果成功连接,回调 onServiceConnected(),如果异常终止或者其他原因终止导致 Service 与访问者断开连接,则回调 onServiceDisconnected 方法,调用unBindService() 不会调用该方法!

onServiceConnected(ComponentName name, IBinder service) 方法中的IBinder 对象,可实现与被绑定 Service 之间的数据通信,在开发 Service 类时,默认需要实现 Service 的 onBind() 方法,该方法返回的 IBinder对象会传到 ServiceConnection 对象中的 onServiceConnected 的参数,可以在这里通过这个 IBinder 与 Service进行通信!

开发步骤:

Step 1: 自定义类继承Service,然后内部类继承 Binder,实现自己的 IBinder 对象

Step 2:通过 onBind( ) 方法返回自己的 IBinder 对象

Step 3:在绑定该 Service 的类中定义一个 ServiceConnection 对象,重写两个方法, onServiceConnected 和onDisconnected,然后直接读取 IBinder 传递过来的参数即可!

布局文件内容如下:

<GridLayout xmlns:android="/apk/res/android"android:id="@+id/GridLayout1"android:layout_width="fill_parent"android:layout_height="wrap_content"android:columnCount="1"android:orientation="horizontal"android:rowCount="2"><Buttonandroid:id="@+id/btnStart"android:layout_width="match_parent"android:layout_height="64dp"android:text="开始服务" /><Buttonandroid:id="@+id/btnStop"android:layout_width="match_parent"android:layout_height="64dp"android:text="停止服务" /><Buttonandroid:id="@+id/btnStatus"android:layout_width="match_parent"android:layout_height="64dp"android:text="服务状态" /></GridLayout>

自定义 Service 类如下:

package com.example.administrator.helloworld.service;import android.app.Service;import android.content.Intent;import android.os.Binder;import android.os.IBinder;import android.util.Log;/*** 服务类*/public class MyService extends Service {private final String TAG = "Wmx Log::";private int count;private boolean quit;//定义 onBinder 方法所返回的对象private MyBinder binder = new MyBinder();public class MyBinder extends Binder {public int getCount() {return count;}}//必须实现的方法,绑定本类的 Service 时回调该方法@Overridepublic IBinder onBind(Intent intent) {Log.i(TAG, "onBind(Intent intent) 方法被调用......" + Thread.currentThread().getName());return binder;}//Service 被创建时回调@Overridepublic void onCreate() {super.onCreate();Log.i(TAG, "onCreate() 方法被调用......" + Thread.currentThread().getName());//创建一个线程动态地修改count的值new Thread() {public void run() {while (!quit) {try {Thread.sleep(1000);Log.i(TAG, "new Thread run...." + Thread.currentThread().getName());} catch (InterruptedException e) {e.printStackTrace();}count++;}};}.start();}//Service 断开连接时回调@Overridepublic boolean onUnbind(Intent intent) {Log.i(TAG, "onUnbind(Intent intent) 方法被调用......" + Thread.currentThread().getName());return true;}//Service被关闭前回调@Overridepublic void onDestroy() {super.onDestroy();this.quit = true;Log.i(TAG, "onDestroy() 方法被调用....." + Thread.currentThread().getName());}//Service 重新绑定时调用@Overridepublic void onRebind(Intent intent) {Log.i(TAG, "onRebind(Intent intent) 方法被调用....." + Thread.currentThread().getName());super.onRebind(intent);}}

主活动 MainActivity.java 文件内容如下:

package com.example.administrator.helloworld;import android.app.Service;import ponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.Toast;import com.example.administrator.helloworld.service.MyService;/*** 一个应用程序可以有1个或多个活动,而没有任何限制。* 每个为应用程序所定义的活动都需要在 AndroidManifest.xml 中声明,应用的主活动的意图过滤器标签中需要包含 MAIN 动作和 LAUNCHER 类别* 如果 MAIN 动作还是 LAUNCHER 类别没有在活动中声明,那么应用程序的图标将不会出现在主屏幕的应用列表中。*/public class MainActivity extends AppCompatActivity {/*** btnBind:服务绑定操作按钮* btnCancel:服务取消绑定操作按钮* btnStatus:获取服务中的数据*/private Button btnBind;private Button btnCancel;private Button btnStatus;//获取启动的 Service 中的 IBinder 对象,同时定义一个 ServiceConnection 对象MyService.MyBinder binder = null;private ServiceConnection serviceConnection = new ServiceConnection() {// Activity 与 Service 断开连接时回调该方法@Overridepublic void onServiceDisconnected(ComponentName name) {Log.i("Wmx log::", "onServiceDisconnected(ComponentName name) 与服务断开连接...........");}//Activity 与 Service 连接成功时回调该方法@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {/*** 参数 IBinder service 就是 onBind(Intent intent) 方法返回的 return binder;* 数据就是靠它传递*/binder = (MyService.MyBinder) service;Log.i("Wmx log::", "onServiceConnected(ComponentName name, IBinder service) 与服务连接成功...........");}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);/*** 为 三个按钮绑定点击事件*/btnBind = findViewById(R.id.btnStart);btnCancel = findViewById(R.id.btnStop);btnStatus = findViewById(R.id.btnStatus);final Intent intent = new Intent(this, MyService.class);btnBind.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.i("Wmx log::", "开始绑定 Service.....");//绑定servicebindService(intent, serviceConnection, Service.BIND_AUTO_CREATE);}});btnCancel.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.i("Wmx log::", "开始解除绑定 Service.....");//解除service绑定unbindService(serviceConnection);}});btnStatus.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Log.i("Wmx log::", "获取 Service 中的数据.....");if (binder != null && binder.isBinderAlive()) {Toast.makeText(getApplicationContext(), "Service的count的值为:" + binder.getCount(), Toast.LENGTH_SHORT).show();} else {Toast.makeText(getApplicationContext(), "Service 未绑定", Toast.LENGTH_SHORT).show();}}});}}

在 AndroidManifest.xml 中对 Service 组件进行注册:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="/apk/res/android"package="com.example.administrator.helloworld"><!--添加外部存储的读/写权限 --><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><!--添加网络访问权限--><uses-permission android:name="android.permission.INTERNET" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><service android:name=".service.MyService" /></application></manifest>

控制台输出:

I/Wmxlog::: 开始绑定 Service.....

I/WmxLog::: onCreate() 方法被调用......main

onBind(Intent intent) 方法被调用......main

I/Wmxlog::: onServiceConnected(ComponentName name, IBinder service) 与服务连接成功...........

I/WmxLog::: new Thread run....Thread-7699

I/WmxLog::: new Thread run....Thread-7699

I/WmxLog::: new Thread run....Thread-7699

I/WmxLog::: new Thread run....Thread-7699

I/WmxLog::: new Thread run....Thread-7699

I/WmxLog::: new Thread run....Thread-7699

I/Wmxlog::: 获取 Service 中的数据.....

I/art: Background sticky concurrent mark sweep GC freed 3915(225KB) AllocSpace objects, 0(0B) LOS objects, 4% free, 3MB/3MB, paused 8.353ms total 40.832ms

I/ViewRootImpl: CPU Rendering VSync enable = true

V/RenderScript: Application requested CPU execution

V/RenderScript: 0x55b18c1170 Launching thread(s), CPUs 8

I/WmxLog::: new Thread run....Thread-7699

I/WmxLog::: new Thread run....Thread-7699

I/Wmxlog::: 开始解除绑定 Service.....

I/WmxLog::: onUnbind(Intent intent) 方法被调用......main

onDestroy() 方法被调用.....main

I/WmxLog::: new Thread run....Thread-7699

I/Wmxlog::: 获取 Service 中的数据.....

I/ViewRootImpl: CPU Rendering VSync enable = true

I/Wmxlog::: 获取 Service 中的数据.....

I/ViewRootImpl: CPU Rendering VSync enable = true

I/Wmxlog::: 获取 Service 中的数据.....

I/Wmxlog::: 获取 Service 中的数据.....

I/ViewRootImpl: CPU Rendering VSync enable = true

I/Wmxlog::: 获取 Service 中的数据.....

I/Wmxlog::: 开始绑定 Service.....

I/WmxLog::: onCreate() 方法被调用......main

I/WmxLog::: onBind(Intent intent) 方法被调用......main

I/Wmxlog::: onServiceConnected(ComponentName name, IBinder service) 与服务连接成功...........

I/ViewRootImpl: CPU Rendering VSync enable = true

I/Wmxlog::: 获取 Service 中的数据.....

I/WmxLog::: new Thread run....Thread-7700

I/Wmxlog::: 获取 Service 中的数据.....

I/WmxLog::: new Thread run....Thread-7700

I/ViewRootImpl: CPU Rendering VSync enable = true

I/WmxLog::: new Thread run....Thread-7700

I/Wmxlog::: 开始绑定 Service.....

I/WmxLog::: new Thread run....Thread-7700

I/ViewRootImpl: CPU Rendering VSync enable = true

I/WmxLog::: new Thread run....Thread-7700

I/WmxLog::: new Thread run....Thread-7700

I/ViewRootImpl: CPU Rendering VSync enable = true

I/WmxLog::: new Thread run....Thread-7700

I/Wmxlog::: 获取 Service 中的数据.....

I/WmxLog::: new Thread run....Thread-7700

I/ViewRootImpl: CPU Rendering VSync enable = true

I/Wmxlog::: 获取 Service 中的数据.....

I/WmxLog::: new Thread run....Thread-7700

I/WmxLog::: new Thread run....Thread-7700

I/ViewRootImpl: CPU Rendering VSync enable = true

I/WmxLog::: new Thread run....Thread-7700

I/Wmxlog::: 开始解除绑定 Service.....

I/WmxLog::: onUnbind(Intent intent) 方法被调用......main

onDestroy() 方法被调用.....main

I/WmxLog::: new Thread run....Thread-7700

I/Wmxlog::: 获取 Service 中的数据.....

I/ViewRootImpl: CPU Rendering VSync enable = true

I/Wmxlog::: 获取 Service 中的数据.....

I/ViewRootImpl: CPU Rendering VSync enable = true

I/Wmxlog::: 获取 Service 中的数据.....

I/ViewRootImpl: CPU Rendering VSync enable = true

I/Wmxlog::: 开始绑定 Service.....

I/WmxLog::: onCreate() 方法被调用......main

onBind(Intent intent) 方法被调用......main

I/Wmxlog::: onServiceConnected(ComponentName name, IBinder service) 与服务连接成功...........

I/WmxLog::: new Thread run....Thread-7702

I/WmxLog::: new Thread run....Thread-7702

I/WmxLog::: new Thread run....Thread-7702

I/WmxLog::: new Thread run....Thread-7702

I/Wmxlog::: 获取 Service 中的数据.....

I/ViewRootImpl: CPU Rendering VSync enable = true

I/WmxLog::: new Thread run....Thread-7702

I/WmxLog::: new Thread run....Thread-7702

I/Wmxlog::: 获取 Service 中的数据.....

I/ViewRootImpl: CPU Rendering VSync enable = true

I/WmxLog::: new Thread run....Thread-7702

I/WmxLog::: new Thread run....Thread-7702

I/Wmxlog::: 获取 Service 中的数据.....

I/ViewRootImpl: CPU Rendering VSync enable = true

I/WmxLog::: new Thread run....Thread-7702

I/WmxLog::: new Thread run....Thread-7702

I/WmxLog::: new Thread run....Thread-7702

Application terminated.

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。