posts - 21,comments - 0,views - 3879

Service是一种可以长期在后台运行而不提供界面的应用组件。服务又可以分为前台服务和后台服务

  • 前台服务前台服务是指是能让用户感知到服务正在运行,因此服务必须显示通知。比如QQ音乐的播放,如果打开了播放控制里的状态栏显示,当你播放音乐时,状态栏里会显示你正在播放的音乐,再比如下载软件,也同样会在状态栏里显示下载进度
  • 后台服务后台服务与前台服务相反,用户通常感知不到后台服务正在运行

前台服务的优先级很高,因此出现系统内存不足时系统也不会将前台服务回收,而后台服务在系统内存不足时有可能会被系统回收

Service启动方式

  • startService,Intent指明了启动的Service所在类为StartService。通过该方式启动Service,访问者与Service之间没有关联,即使访问者退出了,Service也仍然运行显式启动通过类名称来启动,需要在Intent中指明Service所在的类,并调用startService (lntent)启动service。显式启动停止Service,需要将启动Service的Intent传递给stopService (Intent)函数。使用unbindService()方法取消绑定

        //启动服务
        startService(new Intent(this, MyService.class));
    
        //停止服务
        stopService(new Intent(this, MyService.class));
    
  • bindService
    使用bindService()方法启动Service,当调用者通过bindService()函数绑定Service时,onCreate()函数和onBinde ( )函数将被先后调用。通过该方式启动Service,访问者与Service绑定在一起,访问者一旦退出了,Service也就终止了。
    绑定模式使用bindService()方法启动Service

    //绑定服务
    bindService(Intent service,ServiceConnection conn,int flags);
    //解绑服务
    unbindService(ServiceConnection conn)
    
    • service:该参数通过Intent指定需要启动的service
    • conn:该参数是ServiceConnnection对象,当绑定成功后,系统将调用serviceConnnection的onServiceConnected ()方法,当绑定意外断开后,系统将调用ServiceConnnection中的onServiceDisconnected方法
    • flags:该参数指定绑定时是否自动创建Service。如果指定为BIND_AUTO_CREATE,则自动创建,指定为0,则不自动创建

    unbindService()方法成功后,系统并不会调用onServiceConnected(),因为onServiceConnected()仅在意外断开绑定时才被调用。当调用者通过unbindService()函数取消绑定Service时,onUnbind()函数将被调用。如果onUnbind()函数返回true,则表示重新绑定服务时,onRebind ()函数将被调用。

  • 启动实例

    • Activity代码

      package com.xiaozhi.myservice;
      
      import androidx.appcompat.app.AppCompatActivity;
      
      import android.content.ComponentName;
      import android.content.Context;
      import android.content.Intent;
      import android.content.ServiceConnection;
      import android.os.Bundle;
      import android.os.IBinder;
      import android.util.Log;
      import android.view.View;
      
      public class MainActivity extends AppCompatActivity {
      
          boolean flag = true;
          private static final String TAG = "xiaozhi";
          private MyService.MyBinder mBinder;
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              Log.e(TAG, "MainActivity-----" + Thread.currentThread().getName() + "--" + Thread.currentThread().getId());
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
          }
      
          //启动服务
          public void startService(View view) {
              startService(new Intent(this, MyService.class));
          }
      
          //停止服务
          public void stopService(View view) {
              stopService(new Intent(this, MyService.class));
          }
      
          //MainActivity与MyService的桥梁
          private ServiceConnection connection = new ServiceConnection() {
              @Override
              public void onServiceConnected(ComponentName name, IBinder service) {
                  Log.e(TAG, name.toString());
                  mBinder = (MyService.MyBinder) service;
                  mBinder.doTask();
              }
      
              @Override
              public void onServiceDisconnected(ComponentName name) {
                  Log.e(TAG, name.toString());
              }
          };
      
          //绑定服务
          public void bindService(View view) {
              bindService(new Intent(this, MyService.class), connection, Context.BIND_AUTO_CREATE);
          }
      
          //解绑服务
          public void unbindService(View view) {
              if (flag) {
                  unbindService(connection);
                  flag = false;
              }
          }
      
          //解绑服务的常规写法,在Activity被摧毁时执行
          @Override
          public void onDestroy() {
              super.onDestroy();
              if (flag) {
                  unbindService(connection);
                  flag = false;
              }
          }
      }
      
    • Service代码

      package com.xiaozhi.myservice;
      
      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 static final String TAG = "xiaozhi";
          private MyBinder mBinder;
      
          @Override
          public void onCreate() {
              super.onCreate();
              Log.e(TAG, "onCreate");
              Log.e(TAG, "MyService-----" + Thread.currentThread().getName() + "--" + Thread.currentThread().getId());
              mBinder = new MyBinder();
          }
      
          @Override
          public int onStartCommand(Intent intent, int flags, int startId) {
              Log.e(TAG, "onStartCommand");
              new Thread(new Runnable() {
                  @Override
                  public void run() {
                      // 任务逻辑
                      Log.e(TAG, "onStartCommand开启子线程执行耗时操作");
                  }
              }).start();
              return super.onStartCommand(intent, flags, startId);
          }
      
      
          @Override
          public void onDestroy() {
              super.onDestroy();
              Log.e(TAG, "onDestroy");
          }
      
      	//onBind()是Service必须实现的方法,返回的IBinder对象相当于Service组件的代理对象,Service允许其他程序组件通过IBinder对象来访问Service内部数据,这样即可实现其他程序组件与Service之间的通信。
          @Override
          public IBinder onBind(Intent intent) {
              if (mBinder != null) {
                  Log.e(TAG, "onBind");
                  return mBinder;
              }
              return null;
          }
      
          @Override
          public boolean onUnbind(Intent intent) {
              Log.e(TAG, "onUnbind");
              return super.onUnbind(intent);
          }
      
          class MyBinder extends Binder {
      
              public void doTask() {
                  Log.e(TAG, "doTask");
                  new Thread(new Runnable() {
                      @Override
                      public void run() {
                          // 任务逻辑
                          Log.e(TAG, "doTask开启子线程执行耗时操作");
                      }
                  }).start();
              }
          }
      }
      
    • 布局代码

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical">
      
          <Button
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="startService"
              android:onClick="startService" />
      
          <Button
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="stopService"
              android:onClick="stopService" />
      
          <Button
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="bindService"
              android:onClick="bindService" />
      
          <Button
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="unbindService"
              android:onClick="unbindService" />
      
      </LinearLayout>
      
    • 在AndroidManifest.xml文件中声明一个Service组件

          <application
              android: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=".MyService" />
          </application>
      
  • 其他启动方式

    • 使用startService()启动服务之后,再使用bindService()绑定上该服务,此时调用stopSelf()或stopService()并不能结束服务,还需要调用unbindService(),服务才会真的被关闭
    • 可以使用startForegroundService()开启前台服务,startForegroundService()与startService()相似,只不过使用startForegroundService()后,5s内必须调用startForeground(),否则会在logcat中报错。如果android设备9.0及以上,需要在AndroidMAnifest.xml中添加FOREGROUND_SERVICE权限

Service生命周期

  • startService启动的生命周期
    • onCreate()当Service第一次被创建时,由系统调用
    • onStartCommand() 当startService方法启动Service时,该方法被调用
    • onDestroy() 当Service不再使用时,由系统调用
    • 一个startService只会创建一次,销毁一次,但可以开始多次,因此,onCreate()和onDestroy()方法只会被调用一次,而onStart()方法会被调用多次
  • bindService启动的生命周期
    • onCreate() 当Service被创建时,由系统调用
    • onBind() 当bindService方法启动Service时,该方法被调用
    • onUnbind() 当unbindService方法解除绑定时,该方法被调用
    • onDestroy() 当Service不再使用时,由系统调用
    • 一个bindService可以创建多次,销毁多次,重复使用

Service和Thread的区别

  • Service是安卓中系统的组件,它运行在独立进程的主线程中,不可以执行耗时操作
  • Thread是程序执行的最小单元,分配CPU的基本单位,可以开启子线程执行耗时操作
  • Service在不同Activity中可以获取自身实例,可以方便的对Service进行操作
  • Thread在不同的Activity中难以获取自身实例,如果Activity被销毁,Thread实例就很难再获取得到

IntentService

  • IntentService是 Scrvice 的子类,因此它不是普通的Service,它比普通的Service增加了额外的功能。先看Service本身存在的两个问题

    • Service不会专门启动一个单独的进程,Service与它所在应用位于同一个进程中
    • Service不是一条新的线程,因此不应该在Service中直接处理耗时的任务
  • IntentService正好弥补了Service的不足。IntentService的特点:

    • IntentService会创建单独的worker线程来处理所有的Intent请求
    • IntentService会创建单独的worker线程来处理onHandleIntent()方法实现的代码,因此开发者无须处理多线程问题
  • IntentService实例

    package com.xiaozhi.myservice;
    
    import android.app.IntentService;
    import android.content.Intent;
    import android.util.Log;
    
    import androidx.annotation.Nullable;
    
    public class MyIntentService extends IntentService {
        private static final String TAG = "MyIntentService";
        public MyIntentService() {
            super("MyIntentService");
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            Log.e(getClass().getName(), "onHandleWork");
            for (int i = 0; i < 3; i++) {
                try {
                    Log.e(getClass().getName(), "Number:开始"+i);
                    Thread.sleep(10000);
                    Log.e(getClass().getName(), "Number:结束"+i);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.e(getClass().getName(), "onDestroy");
        }
    }
    

    启动

    startService(new Intent(this, MyIntentService.class));
    

    log打印

    11:10:13.217 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: onHandleWork
    11:10:13.217 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: Number:开始0
    11:10:23.218 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: Number:结束0
    11:10:23.219 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: Number:开始1
    11:10:33.221 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: Number:结束1
    11:10:33.221 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: Number:开始2
    11:10:43.223 4591-4624/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: Number:结束2
    11:10:43.229 4591-4591/com.xiaozhi.myservice E/com.xiaozhi.myservice.MyIntentService: onDestroy
    
  • 总结

    • IntentService 是继承于 Service 并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个

    • 普通Service直接执行20S的的耗时操作,会阻塞主线程,造成ANR(程序无响应)异常,而IntentService执行30S的耗时操作,不会阻塞主线程,更不会产生ANR

    • 执行完onHandleIntent()方法里面的耗时操作后,会自行调用onDestroy()方法,进行关闭

    • IntentService本质是采用Handler & HandlerThread方式:

      • 通过HandlerThread单独开启一个名为IntentService的线程

      • 创建一个名叫ServiceHandler的内部Handler

      • 把内部Handler与HandlerThread所对应的子线程进行绑定

      • 通过onStartCommand()传递给服务intent,依次插入到工作队列中,并逐个发送给onHandleIntent()

      • 通过onHandleIntent()来依次处理所有Intent请求对象所对应的任务

posted on   幺幺零零  阅读(309)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
< 2025年3月 >
23 24 25 26 27 28 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 1 2 3 4 5

点击右上角即可分享
微信分享提示