大气的门户网站,外贸 模板网站 定制网站,给网站底部做友情链接,购物网站建设网站Service组件 Service 和Activity 一样同为Android 的四大组件之一#xff0c;并且他们都有各自的生命周期#xff0c;要想掌握Service 的用法#xff0c;那就要了解Service 的生命周期有哪些方法#xff0c;并且生命周期中各个方法回调的时机和作用 什么是service#xff…Service组件 Service 和Activity 一样同为Android 的四大组件之一并且他们都有各自的生命周期要想掌握Service 的用法那就要了解Service 的生命周期有哪些方法并且生命周期中各个方法回调的时机和作用 什么是serviceservice的基本概念 Service是Android中实现程序后台运行的解决方案非常适合用于去执行哪些不需要和用户交互而且还要求长期运行的任务。不能运行在一个独立的进程当中而是依赖与创建服务时所在的应用程序进程。只能在后台运行并且可以和其他组件进行交互。 Service可以在很多场合使用比如播放多媒体的时候用户启动了其他Activity此时要在后台继续播放比如检测SD卡上文件的变化比如在后台记录你的地理信息位置的改变等等总之服务是藏在后台的。 定义启动一个Service Service 有两种启动方式并且它的两种启动方式的生命周期是不一样的。 1.startService方式启动Service 当应用组件通过startService方法来启动Service 时Service 则会处于启动状态一旦服务启动它就会在后台无限期的运行生命周期独立于启动它的组件即使启动它的组件已经销毁了也不受任何影响由于启动的服务长期运行在后台这会大量消耗手机的电量因此我们应该在任务执行完成之后调用stopSelf()来停止服务或者通过其他应用组件调用stopService 来停止服务。 startService 启动服务后会执行如下生命周期onCreate() onStartCommand() onStart()(现在已经废弃) onDestroy() 。具体看一下它的几个生命周期方法 onCreate() :首次启动服务的时候系统会调用这个方法在onStartCommand 和 onBind 方法之前如果服务已经启动起来了再次启动时则不会调用此方法因此可以在onCreate 方法中做一些初始化的操作比如要执行耗时的操作可以在这里创建线程要播放音乐可以在这里初始化音乐播放器。 onStartCommand(): 当通过startService 方法来启动服务的时候在onCreate 方法之后就会回调这个方法此方法调用后服务就启动起来了将会在后台无限期的运行直到通过stopService 或者 stopSelf 方法来停止服务。 onDestroy():当服务不再使用且将被销毁时系统将调用此方法。服务应该实现此方法来清理所有资源如线程、注册的侦听器、接收器等。 这是服务接收的最后一个调用。 了解了这几个生命周期方法后就来写一个简单Service 。 要使用Service 就要通过继承Service类或者继承IntentService ,后文会讲来实现代码如下 package com.example.servicetest;import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;public class MyService extends Service { public static final String TAG MyService; //创建服务时调用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); } Override public IBinder onBind(Intent intent) { return null; }
} 可以看到我们只是在onCreate()、onStartCommand()和onDestroy()方法中分别打印了一句话并没有进行其它任何的操作注意代码注释中这三个方法的作用。 onBind()方法是Service中唯一的一个抽象方法所以必须要在子类里实现。我们知道Service可以有两种启动方式一种是startService()另一种是bindService()。第二种启动方式才会用到onBind()方法。我们这先用第一种方式启动Service所以暂时忽略onBind()方法。 2在清单文件中声明和Activity标签并列 service android:name.MyService /service 3修改activity_main.xml代码如下 LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:layout_widthmatch_parent android:layout_heightmatch_parent android:orientationvertical Button android:idid/button1_start_service android:layout_widthmatch_parent android:layout_heightwrap_content android:textStart Service / Button android:idid/button2_stop_service android:layout_widthmatch_parent android:layout_heightwrap_content android:textStop Service / /LinearLayout 我们在布局文件中加入了两个按钮一个用于启动Service一个用于停止Service。 4在MainActivity作为程序的主Activity在里面加入启动Service和停止Service的逻辑代码如下 package com.example.servicetest;import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;public class MainActivity extends Activity implements OnClickListener { private Button button1_start_service; private Button button2_stop_service; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button1_start_service (Button) findViewById(R.id.button1_start_service); button2_stop_service (Button) findViewById(R.id.button2_stop_service); button1_start_service.setOnClickListener(this); button2_stop_service.setOnClickListener(this); } Override public void onClick(View v) { switch (v.getId()) { case R.id.button1_start_service: Intent startIntent new Intent(this, MyService.class); startService(startIntent); break; case R.id.button2_stop_service: Intent stopIntent new Intent(this, MyService.class); stopService(stopIntent); break; default: break; } } } 代码所示在Start Service按钮的点击事件里我们构建出了一个Intent对象并调用startService()方法来启动MyService。然后在Stop Serivce按钮的点击事件里我们同样构建出了一个Intent对象并调用stopService()方法来停止MyService。代码的逻辑非常简单。 小结通过startService 方式启动的服务服务会无限期的在后台运行直到通过stopService 或 stopSelf 来终止服务。服务独立于启动它的组件也就是说当组件启动服务后组件和服务就再也没有关系了就算启动它的组件被销毁了服务照样在后台运行。通过这种方式启动的服务不好与组件之间通信。 bindService 方式启动服务 除了startService 来启动服务之外另外一种启动服务的方式就是通过bindService 方法了也就是绑定服务其实通过它的名字就容易理解绑定即将启动组件和服务绑定在一起。前面讲的通过startService 方式启动的服务是与组件相独立的即使启动服务的组件被销毁了服务仍然在后台运行不受干扰。但是通过bindSerivce 方式绑定的服务就不一样了它与绑定组件的生命周期是有关的。如下 多个组件可以绑定到同一个服务上如果只有一个组件绑定服务当绑定的组件被销毁时服务也就会停止了。如果是多个组件绑定到一个服务上当绑定到该服务的所有组件都被销毁时服务才会停止。 bindService 绑定服务 和startService 的生命周期是不一样bindServie 的生命周期如下onCreate onBind onUnbind onDestroy。其中重要的就是onBind 和onUnbind 方法。 onBind(): 当其他组件想通过bindService 与服务绑定时系统将会回调这个方法在实现中你必须返回一个IBinder接口供客户端与服务进行通信必须实现此方法这个方法是Service 的一个抽象方法但是如果你不允许绑定的话返回null 就可以了。 onUnbind(): 当所有与服务绑定的组件都解除绑定时就会调用此方法。 了解了这2个方法后我们来看一下怎么绑定一个服务。1首先添加一个类 继承 Binder ,在Binder 类中添加其他组件要与服务交互的方法并在onBind() 方法中返回IBinder 实例对象 public class SimpleService extends Service {public static final String TAG SimpleService;NullableOverridepublic IBinder onBind(Intent intent) {Log.i(TAG,call onBind...);//返回IBinder 接口对象return new MyBinder();}Overridepublic boolean onUnbind(Intent intent) {Log.i(TAG,call onUnbind...);return super.onUnbind(intent);}Overridepublic void onCreate() {Log.i(TAG,call onCreate...);}Overridepublic void onStart(Intent intent, int startId) {Log.i(TAG,call onStart...);}Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG,call onStartCommand...);return super.onStartCommand(intent, flags, startId);}Overridepublic void onDestroy() {Log.i(TAG,call onDestroy...);}// 添加一个类继承Binderpublic class MyBinder extends Binder{// 添加要与外界交互的方法public String getStringInfo(){return 调用了服务中的方法;}}} 2, 绑定服务的时候需要提供一个ServiceConnection 接口在接口回调中获取Binder 对象与服务进行通信。 private SimpleService.MyBinder mMyBinder;// 绑定/解除绑定 Service 回调接口private ServiceConnection mConnection new ServiceConnection() {Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 绑定成功后回调//1 ,获取Binder接口对象mMyBinder (SimpleService.MyBinder) service;//2, 从服务获取数据String content mMyBinder.getStringInfo();// 3,界面提示Toast.makeText(ServiceSimpleActivity.this,content,Toast.LENGTH_LONG).show();}Overridepublic void onServiceDisconnected(ComponentName name) {// 解除绑定后回调mMyBinder null;}}; 3,绑定和解除绑定服务 case R.id.bind_service:Intent intent new Intent(this,SimpleService.class);// 绑定服务bindService(intent,mConnection, Context.BIND_AUTO_CREATE);break;case R.id.unbind_service:// 解除绑定服务unbindService(mConnection);break; 可以看到绑定服务的生命周期内依次调用了onCreate ,onBind,onUnbind 和 onDestroy 方法只有中间两个生命周期方法与startService 启动服务是不同的。 两种方式的生命周期的异同 Service生命周期.png started服务与bind服务的区别 区别一生命周期 通过started方式的服务会一直运行在后台需要由组件本身或外部组件来停止服务才会以结束运行bind方式的服务生命周期就要依赖绑定的组件区别二参数传递 started服务可以给启动的服务对象传递参数但无法获取服务中方法的返回值bind服务可以给启动的服务对象传递参数也可以通过绑定的业务对象获取返回结果实际开发中的技巧 第一次先使用started方式来启动一个服务之后可以使用bind的方式绑定服务从而可以直接调用业务方法获取返回值IntentService IntentService 是Service 的子类它使用工作线程逐一处理所有启动请求果您不要求服务同时处理多个请求这是最好的选择。 您只需实现 onHandIntent方法即可该方法会接收每个启动请求的 Intent使您能够执行后台工作。 IntentService 示例 IntentService 默认为我们开启了一个工作线程在任务执行完毕后自动停止服务因此在我们大多数的工作中使用IntentService 就够了并且IntentService 比较简单只要实现一个方法OnHandleIntent接下来看一下示例 1新建一个MyIntentService类继承自IntentService并重写父类的onHandleIntent()方法代码如下 1 package com.example.servicetest;2 3 import android.app.IntentService;4 import android.content.Intent;5 import android.util.Log;6 7 public class MyIntentService extends IntentService{8 9 public MyIntentService() {
10 super(MyIntentService);//调用父类有参构造函数。这里我们手动给服务起个名字为MyIntentService
11 // TODO Auto-generated constructor stub
12 }
13
14 //该方法在会在一个单独的线程中执行来完成工作任务。任务结束后该Service自动停止
15 Override
16 protected void onHandleIntent(Intent intent) {
17 // TODO Auto-generated method stub
18 for(int i 0;i3;i) {
19 //打印当前线程的id
20 Log.d(MyIntentService,IntentService线程的id是Thread.currentThread().getId());
21 try {
22 Thread.sleep(1000);
23 } catch (InterruptedException e) {
24 // TODO Auto-generated catch block
25 e.printStackTrace();
26 }
27 }
28 }
29
30 Override
31 public void onDestroy() {
32 // TODO Auto-generated method stub
33 super.onDestroy();
34 Log.d(MyIntentService,onDestroy);
35 }
36 } 这里首先要提供一个无参的构造方法并且必须在其内部调用父类的有参构造方法9至12行我们在第10行手动将服务的名字改为“MyIntentService”。 然后在子类中实现onHandleIntent()这个抽象方法可以在这个方法里去处理一些具体的逻辑我们就用三次for循环打印当前线程的id每次延时1秒。 因为这个服务在运行结束后会自动停止所以我们在onDestroy()方法中打印日志验证一下。 2在清单文件中对服务进行注册服务 service android:name.MyIntentService /service 3在activity_main.xml中添加一个按钮button3_stop_intentservice用于启动MyIntentService服务代码略。 4在MainActivity里面加入启动IntentService的逻辑核心代码如下 1 case R.id.button3_stop_intentservice:
2 Log.d(MainActivity,主线程的id是Thread.currentThread().getId());
3 Intent intentService new Intent(this,MyIntentService.class);
4 startService(intentService);
5 default: 我们在第02行中打印主线程的id。 运行程序点击按钮button3_stop_intentservice显示如下 由此可见启动一个IntentService和启动一个普通的Service步骤是一样的。 4、Service和Thread的关系 不少Android初学者都可能会有这样的疑惑Service和Thread到底有什么关系呢什么时候应该用Service什么时候又应该用Thread答案可能会有点让你吃惊因为Service和Thread之间没有任何关系 之所以有不少人会把它们联系起来主要就是因为Service的后台概念。Thread我们大家都知道是用于开启一个子线程在这里去执行一些耗时操作就不会阻塞主线程的运行。而Service我们最初理解的时候总会觉得它是用来处理一些后台任务的一些比较耗时的操作也可以放在这里运行这就会让人产生混淆了。但是如果我告诉你Service其实是运行在主线程里的你还会觉得它和Thread有什么关系吗 其实后台和子线程是两个完全不同的概念 Android的后台就是指它的运行是完全不依赖UI的。即使Activity被销毁或者程序被关闭只要进程还在Service就可以继续运行。比如说一些应用程序始终需要与服务器之间始终保持着心跳连接就可以使用Service来实现。你可能又会问Service既然是运行在主线程里在这里一直执行着心跳连接难道就不会阻塞主线程的运行吗当然会但是我们可以在Service中再创建一个子线程然后在这里去处理耗时逻辑就没问题了。 既然在Service里也要创建一个子线程那为什么不直接在Activity里创建呢这是因为Activity很难对Thread进行控制当Activity被销毁之后就没有任何其它的办法可以再重新获取到之前创建的子线程的实例而且在一个Activity中创建的子线程另一个Activity无法对其进行操作。但是Service就不同了所有的Activity都可以与Service进行关联然后可以很方便地操作其中的方法即使Activity被销毁了之后只要重新与Service建立关联就又能够获取到原有的Service中Binder的实例。因此使用Service来处理后台任务Activity就可以放心地finish完全不需要担心无法对后台任务进行控制的情况。 所以说一个比较标准的Service就可以写成本段中第1节的样子。 IntentService总结IntentService是Service 的子类默认给我们开启了一个工作线程执行耗时任务并且执行完任务后自 动停止服务。扩展IntentService比较简单提供一个构造方法和实现onHandleIntent 方法就可了不用重写父类的其他方法。但是如果要绑定服务的话还是要重写onBind 返回一个IBinder 的。使用Service 可以同时执行多个请求而使用IntentService 只能同时执行一个请求。 Service 与应用组件通信的几种方式 1,BroadcastReceiver通过前文我们知道startService方式启动的服务在后台无限期地运行并且与启动它的组件是独立的启动Service 之后也就与启动它的组件没有任何关系了。因此它是不能与启动它的组件之间相互通信的。虽然Service 没有提供这种启动方式的通信方法我们还是可以通过其他方式来解决的这就用到了BroadcastReceiver。 场景描述通过startService 启动一个长期在后台运行的下载图片服务然后在界面上点击下载按钮通过intent 传递一个下载链接给Service在下载完成后通过BroadcastReceiver 通知Activity 界面显示图片。看一下代码实现 Service代码如下 public class DownloadService extends Service {public static final String IMAGE iamge_url;public static final String RECEIVER_ACTION com.zhouwei.simpleservice;private static final String TAG DownloadService;public static final String ACTION_START_SERVICER com.zhouwei.startservice;public static final String ACTION_DOWNLOAD com.zhouwei.startdownload;private Looper mServiceLooper;private ServiceHandler mServiceHandler;private final class ServiceHandler extends Handler {public ServiceHandler(Looper looper){super(looper);}Overridepublic void handleMessage(Message msg) {// 工作线程做耗时下载String url (String) msg.obj;Bitmap bitmap null;try {bitmap Picasso.with(getApplicationContext()).load(url).get();Intent intent new Intent();intent.putExtra(bitmap,bitmap);intent.setAction(RECEIVER_ACTION);// 通知显示LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);} catch (IOException e) {e.printStackTrace();}//工作完成之后停止服务stopSelf();}}NullableOverridepublic IBinder onBind(Intent intent) {return null;}Overridepublic void onCreate() {// 开启一个工作线程做耗时工作HandlerThread thread new HandlerThread(ServiceHandlerThread, Process.THREAD_PRIORITY_BACKGROUND);thread.start();// 获取工作线程的LoopermServiceLooper thread.getLooper();// 创建工作线程的HandlermServiceHandler new ServiceHandler(mServiceLooper);}Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.i(TAG,call onStartCommand...);if(intent.getAction().equals(ACTION_DOWNLOAD)){handleCommand(intent);}else if(intent.getAction().equals(ACTION_START_SERVICER)){//do nothing}return START_STICKY;}private void handleCommand(Intent intent){String url intent.getStringExtra(IMAGE);// 发送消息下载Message message mServiceHandler.obtainMessage();message.obj url;mServiceHandler.sendMessage(message);}
} 新建了一个DownloadService 在里面启动了一个工作线程在线程里下载图片然后通过BroadcastReceiver 通知Activity显示。 Activity的代码很简单注册BroadcastReceiver在onReceiver中显示图片就好了代码如下 private ImageView mImageView;private BroadcastReceiver mReceiver new BroadcastReceiver() {Overridepublic void onReceive(Context context, Intent intent) {// 显示图片Bitmap bitmap intent.getParcelableExtra(bitmap);mImageView.setImageBitmap(bitmap);}};/*** 启动下载*/private void startDownload(){Intent intent new Intent(this,DownloadService.class);// 启动服务intent.putExtra(DownloadService.IMAGE,http://www.8kmm.com/UploadFiles/2012/8/201208140920132659.jpg);intent.setAction(DownloadService.ACTION_DOWNLOAD);startService(intent);} 声明 https://blog.csdn.net/qq_34115898/article/details/83347882 文章来源转载于:https://www.cnblogs.com/ythzxxq/p/9978158.html