Android Service两种启动方式详解(总结版)

2023-11-12

1. 概念

开始,先稍稍讲一点android中Service的概念和用途吧~

Service分为本地服务(LocalService)和远程服务(RemoteService):

1、地服务依附在主进程上而不是独立的进程,这样在一定程度上节约了资源,另外Local服务因为是在同一进程因此不需要IPC,

也不需要AIDL。相应bindService会方便很多。主进程被Kill后,服务便会终止。

2、程服务为独立的进程,对应进程名格式为所在包名加上你指定的android:process字符串。由于是独立的进程,因此在Activity所在进程被Kill的时候,该服务依然在运行,

不受其他进程影响,有利于为多个进程提供服务具有较高的灵活性。该服务是独立的进程,会占用一定资源,并且使用AIDL进行IPC稍微麻烦一点。

按使用方式可以分为以下三种:

1、startService 启动的服务:主要用于启动一个服务执行后台任务,不进行通信。停止服务使用stopService;

2、bindService 启动的服务:该方法启动的服务可以进行通信。停止服务使用unbindService;

3、startService 同时也 bindService 启动的服务:停止服务应同时使用stepService与unbindService

 

 

2. Service 与 Thread 的区别

很多时候,你可能会问,为什么要用 Service,而不用 Thread 呢,因为用 Thread 是很方便的,比起 Service 也方便多了,下面我详细的来解释一下。

1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。

2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是RemoteService,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!

既然这样,那么我们为什么要用 Service 呢?其实这跟 android 的系统机制有关,我们先拿 Thread 来说。Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。

举个例子:如果你的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该 Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何 Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。

 

因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。

3.  Service和Activity通信

       需要用到bindService,通过onBind()方法来实现,看下面bindService的例子



4. Service的生命周期


Service生命周期.png

第一种方式:通过StartService启动Service

通过startService启动后,service会一直无限期运行下去,只有外部调用了stopService()或stopSelf()方法时,该Service才会停止运行并销毁。

要创建一个这样的Service,你需要让该类继承Service类,然后重写以下方法:

  • onCreate()
    1.如果service没被创建过,调用startService()后会执行onCreate()回调;
    2.如果service已处于运行中,调用startService()不会执行onCreate()方法。
    也就是说,onCreate()只会在第一次创建service时候调用,多次执行startService()不会重复调用onCreate(),此方法适合完成一些初始化工作。

  • onStartCommand()
    如果多次执行了Context的startService()方法,那么Service的onStartCommand()方法也会相应的多次调用。onStartCommand()方法很重要,我们在该方法中根据传入的Intent参数进行实际的操作,比如会在此处创建一个线程用于下载数据或播放音乐等。

  • onBind()
    Service中的onBind()方法是抽象方法,Service类本身就是抽象类,所以onBind()方法是必须重写的,即使我们用不到。

  • onDestory()
    在销毁的时候会执行Service该方法。

这几个方法都是回调方法,且在主线程中执行,由android操作系统在合适的时机调用。

startService代码实例

创建TestOneService,并在manifest里注册。

需要注意,项目中的每一个Service都必须在AndroidManifest.xml中注册才行,所以还需要编辑AndroidManifest.xml文件,代码如下所示:

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.example.servicetest"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk  
  8.         android:minSdkVersion="14"  
  9.         android:targetSdkVersion="17" />  
  10.   
  11.     <application  
  12.         android:allowBackup="true"  
  13.         android:icon="@drawable/ic_launcher"  
  14.         android:label="@string/app_name"  
  15.         android:theme="@style/AppTheme" >  
  16.           
  17.     ……  
  18.   
  19.         <service android:name="com.example.servicetest.TestOneService" >  
  20.         </service>  
  21.     </application>  
  22.   
  23. </manifest>  




在MainActivty中操作TestOneService,code如下:

 

/**
 * Created by Kathy on 17-2-6.
 */

public class TestOneService extends Service{

    @Override
    public void onCreate() {
        Log.i("Kathy","onCreate - Thread ID = " + Thread.currentThread().getId());
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("Kathy", "onStartCommand - startId = " + startId + ", Thread ID = " + Thread.currentThread().getId());
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("Kathy", "onBind - Thread ID = " + Thread.currentThread().getId());
        return null;
    }

    @Override
    public void onDestroy() {
        Log.i("Kathy", "onDestroy - Thread ID = " + Thread.currentThread().getId());
        super.onDestroy();
    }
}


在MainActivity中三次startService,之后stopService。

 

/**
 * Created by Kathy on 17-2-6.
 */

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i("Kathy", "Thread ID = " + Thread.currentThread().getId());
        Log.i("Kathy", "before StartService");

        //连续启动Service
        Intent intentOne = new Intent(this, TestOneService.class);
        startService(intentOne);
        Intent intentTwo = new Intent(this, TestOneService.class);
        startService(intentTwo);
        Intent intentThree = new Intent(this, TestOneService.class);
        startService(intentThree);

        //停止Service
        Intent intentFour = new Intent(this, TestOneService.class);
        stopService(intentFour);

        //再次启动Service
        Intent intentFive = new Intent(this, TestOneService.class);
        startService(intentFive);

        Log.i("Kathy", "after StartService");
    }
}


打印出的Log如下:

 

        02-06 15:19:45.090 8938-8938/? I/Kathy: Thread ID = 1
        02-06 15:19:45.090 8938-8938/? I/Kathy: before StartService
        02-06 15:19:45.233 8938-8938/? I/Kathy: onCreate - Thread ID = 1
        02-06 15:19:45.234 8938-8938/? I/Kathy: onStartCommand - startId = 1, Thread ID = 1
        02-06 15:19:45.234 8938-8938/? I/Kathy: onStartCommand - startId = 2, Thread ID = 1
        02-06 15:19:45.235 8938-8938/? I/Kathy: onStartCommand - startId = 3, Thread ID = 1
        02-06 15:19:45.236 8938-8938/? I/Kathy: onDestroy - Thread ID = 1
        02-06 15:19:45.237 8938-8938/? I/Kathy: onCreate - Thread ID = 1
        02-06 15:19:45.237 8938-8938/? I/Kathy: onStartCommand - startId = 1, Thread ID = 1
        02-06 15:19:45.238 8938-8938/? I/Kathy: after StartService


分析:
1.主线程打印出是1,所有回调方法中打印出的执行线程ID都是1,证明回调方法都是在主线程中执行的
2.三次调用startService,只触发一次onCreate回调,触发了三次onStartCommand回调,且startId分别为1,2,3。证明 多次startService不会重复执行onCreate回调,但每次都会执行onStartCommand回调

第二种方式:通过bindService启动Service

bindService启动服务特点:
1.bindService启动的服务和调用者之间是典型的client-server模式。调用者是client,service则是server端。service只有一个,但绑定到service上面的client可以有一个或很多个。这里所提到的client指的是组件,比如某个Activity。
2.client可以通过IBinder接口获取Service实例,从而实现在client端直接调用Service中的方法以实现灵活交互,这在通过startService方法启动中是无法实现的。
3.bindService启动服务的生命周期与其绑定的client息息相关。当client销毁时,client会自动与Service解除绑定。当然,client也可以明确调用Context的unbindService()方法与Service解除绑定。当没有任何client与Service绑定时,Service会自行销毁

bindService代码实例

交互界面设计如下:


ActivityA界面布局.png

ActivityB界面布局.png

1.创建一个TestTwoService继承Service(Server)
2.创建ActivityA,可以通过bindService绑定服务(client)
3.创建ActivityB,可以通过bindService绑定服务(client)
4.ActivityA可以跳转到ActivityB

TestTwoService创建如下:
要想让Service支持bindService调用方式,需要做以下事情:
1.在Service的onBind()方法中返回IBinder类型的实例。
2.onBInd()方法返回的IBinder的实例需要能够返回Service实例本身。通常,最简单的方法就是在service中创建binder的内部类,加入类似getService()的方法返回Service,这样绑定的client就可以通过getService()方法获得Service实例了。

/**
 * Created by Kathy on 17-2-6.
 */

public class TestTwoService extends Service{

    //client 可以通过Binder获取Service实例
    public class MyBinder extends Binder {
        public TestTwoService getService() {
            return TestTwoService.this;
        }
    }

    //通过binder实现调用者client与Service之间的通信
    private MyBinder binder = new MyBinder();

    private final Random generator = new Random();

    @Override
    public void onCreate() {
        Log.i("Kathy","TestTwoService - onCreate - Thread = " + Thread.currentThread().getName());
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i("Kathy", "TestTwoService - onStartCommand - startId = " + startId + ", Thread = " + Thread.currentThread().getName());
        return START_NOT_STICKY;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.i("Kathy", "TestTwoService - onBind - Thread = " + Thread.currentThread().getName());
        return binder;
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i("Kathy", "TestTwoService - onUnbind - from = " + intent.getStringExtra("from"));
        return false;
    }

    @Override
    public void onDestroy() {
        Log.i("Kathy", "TestTwoService - onDestroy - Thread = " + Thread.currentThread().getName());
        super.onDestroy();
    }

    //getRandomNumber是Service暴露出去供client调用的公共方法
    public int getRandomNumber() {
        return generator.nextInt();
    }
}


client端要做的事情:
1.创建ServiceConnection类型实例,并重写onServiceConnected()方法和onServiceDisconnected()方法。
2.当执行到onServiceConnected回调时,可通过IBinder实例得到Service实例对象,这样可实现client与Service的连接。
3.onServiceDisconnected回调被执行时,表示client与Service断开连接,在此可以写一些断开连接后需要做的处理。

创建ActivityA,代码如下:

/**
 * Created by Kathy on 17-2-6.
 */
public class ActivityA extends Activity implements Button.OnClickListener {
    private TestTwoService service = null;
    private boolean isBind = false;

    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            isBind = true;
            TestTwoService.MyBinder myBinder = (TestTwoService.MyBinder) binder;
            service = myBinder.getService();
            Log.i("Kathy", "ActivityA - onServiceConnected");
            int num = service.getRandomNumber();
            Log.i("Kathy", "ActivityA - getRandomNumber = " + num);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isBind = false;
            Log.i("Kathy", "ActivityA - onServiceDisconnected");
        }
    };

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_a);
        Log.i("Kathy", "ActivityA - onCreate - Thread = " + Thread.currentThread().getName());

        findViewById(R.id.btnBindService).setOnClickListener(this);
        findViewById(R.id.btnUnbindService).setOnClickListener(this);
        findViewById(R.id.btnStartActivityB).setOnClickListener(this);
        findViewById(R.id.btnFinish).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btnBindService) {
            //单击了“bindService”按钮
            Intent intent = new Intent(this, TestTwoService.class);
            intent.putExtra("from", "ActivityA");
            Log.i("Kathy", "----------------------------------------------------------------------");
            Log.i("Kathy", "ActivityA 执行 bindService");
            bindService(intent, conn, BIND_AUTO_CREATE);
        } else if (v.getId() == R.id.btnUnbindService) {
            //单击了“unbindService”按钮
            if (isBind) {
                Log.i("Kathy",
                        "----------------------------------------------------------------------");
                Log.i("Kathy", "ActivityA 执行 unbindService");
                unbindService(conn);
            }
        } else if (v.getId() == R.id.btnStartActivityB) {
            //单击了“start ActivityB”按钮
            Intent intent = new Intent(this, ActivityB.class);
            Log.i("Kathy",
                    "----------------------------------------------------------------------");
            Log.i("Kathy", "ActivityA 启动 ActivityB");
            startActivity(intent);
        } else if (v.getId() == R.id.btnFinish) {
            //单击了“Finish”按钮
            Log.i("Kathy",
                    "----------------------------------------------------------------------");
            Log.i("Kathy", "ActivityA 执行 finish");
            this.finish();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i("Kathy", "ActivityA - onDestroy");
    }
}


创建ActivityB,代码如下:

/**
 * Created by Kathy on 17-2-6.
 */
public class ActivityB extends Activity implements Button.OnClickListener {

    private TestTwoService service = null;

    private boolean isBind = false;

    private ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder binder) {
            isBind = true;
            TestTwoService.MyBinder myBinder = (TestTwoService.MyBinder)binder;
            service = myBinder.getService();
            Log.i("Kathy", "ActivityB - onServiceConnected");
            int num = service.getRandomNumber();
            Log.i("Kathy", "ActivityB - getRandomNumber = " + num);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            isBind = false;
            Log.i("Kathy", "ActivityB - onServiceDisconnected");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b);

        findViewById(R.id.btnBindService).setOnClickListener(this);
        findViewById(R.id.btnUnbindService).setOnClickListener(this);
        findViewById(R.id.btnFinish).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if(v.getId() == R.id.btnBindService){
            //单击了“bindService”按钮
            Intent intent = new Intent(this, TestTwoService.class);
            intent.putExtra("from", "ActivityB");
            Log.i("Kathy", "----------------------------------------------------------------------");
            Log.i("Kathy", "ActivityB 执行 bindService");
            bindService(intent, conn, BIND_AUTO_CREATE);
        }else if(v.getId() == R.id.btnUnbindService){
            //单击了“unbindService”按钮
            if(isBind){
                Log.i("Kathy", "----------------------------------------------------------------------");
                Log.i("Kathy", "ActivityB 执行 unbindService");
                unbindService(conn);
            }
        }else if(v.getId() == R.id.btnFinish){
            //单击了“Finish”按钮
            Log.i("Kathy", "----------------------------------------------------------------------");
            Log.i("Kathy", "ActivityB 执行 finish");
            this.finish();
        }
    }
    @Override
    public void onDestroy(){
        super.onDestroy();
        Log.i("Kathy", "ActivityB - onDestroy");
    }
}


测试步骤1

step1: 点击ActivityA的bindService按钮
step2: 再点击ActivityA的unbindService按钮
Log输出:

 

02-07 14:09:38.031 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA - onCreate - Thread = main
02-07 14:09:39.488 1738-1738/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:09:39.488 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA 执行 bindService
02-07 14:09:39.496 1738-1738/com.demo.kathy.demo I/Kathy: TestTwoService - onCreate - Thread = main
02-07 14:09:39.497 1738-1738/com.demo.kathy.demo I/Kathy: TestTwoService - onBind - Thread = main
02-07 14:09:39.500 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA - onServiceConnected
02-07 14:09:39.500 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA - getRandomNumber = -1046987376
02-07 14:09:50.866 1738-1738/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:09:50.866 1738-1738/com.demo.kathy.demo I/Kathy: ActivityA 执行 unbindService
02-07 14:09:50.870 1738-1738/com.demo.kathy.demo I/Kathy: TestTwoService - onUnbind - from = ActivityA
02-07 14:09:50.871 1738-1738/com.demo.kathy.demo I/Kathy: TestTwoService - onDestroy - Thread = main


总结调用bindService之后发生的事情:
1.client执行bindService()
2.如果Service不存在,则Service执行onCreate(),onBind()
3.client实例ServiceConnection执行onServiceConnected()方法

总结调用unbindService之后发生的事情:
1.client执行unbindService()
2.client与Service解除绑定连接状态
3.Service检测是否还有其他client与其连接,如果没有Service执行onUnbind()和onDestroy()

测试步骤2

step1: 点击ActivityA的bindService按钮
step2: 再点击ActivityA的Finish按钮
Log 输出:

 

02-07 14:49:16.626 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onCreate - Thread = main
02-07 14:49:18.102 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:49:18.102 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 执行 bindService
02-07 14:49:18.105 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onCreate - Thread = main
02-07 14:49:18.110 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onBind - Thread = main
02-07 14:49:18.112 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onServiceConnected
02-07 14:49:18.112 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - getRandomNumber = -318399886
02-07 14:49:19.540 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:49:19.540 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 执行 finish
02-07 14:49:19.789 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onDestroy
02-07 14:49:19.798 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onUnbind - from = ActivityA
02-07 14:49:19.798 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onDestroy - Thread = main


总结:如果client销毁,那么client会自动与Service解除绑定。

测试步骤3

step1: 点击ActivityA的bindService按钮
step2: 点击ActivityA的startActivity B按钮,切换到ActivityB
step3: 点击ActivityB中的bindService按钮
step4: 点击ActivityB中的unbindService按钮
step5: 点击ActivityB中的Finish按钮
step6: 点击ActivityA中的unbindService按钮
得到Log:

 

02-07 14:55:04.390 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onCreate - Thread = main
02-07 14:55:08.191 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:08.191 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 执行 bindService
02-07 14:55:08.197 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onCreate - Thread = main
02-07 14:55:08.198 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onBind - Thread = main
02-07 14:55:08.205 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - onServiceConnected
02-07 14:55:08.205 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA - getRandomNumber = -706215542
02-07 14:55:23.261 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:23.261 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 启动 ActivityB
02-07 14:55:29.239 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:29.239 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB 执行 bindService
02-07 14:55:29.241 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB - onServiceConnected
02-07 14:55:29.241 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB - getRandomNumber = 1827572726
02-07 14:55:33.951 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:33.951 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB 执行 unbindService
02-07 14:55:36.645 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:36.645 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB 执行 finish
02-07 14:55:36.852 12566-12566/com.demo.kathy.demo I/Kathy: ActivityB - onDestroy
02-07 14:55:43.137 12566-12566/com.demo.kathy.demo I/Kathy: ----------------------------------------------------------------------
02-07 14:55:43.137 12566-12566/com.demo.kathy.demo I/Kathy: ActivityA 执行 unbindService
02-07 14:55:43.143 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onUnbind - from = ActivityA
02-07 14:55:43.143 12566-12566/com.demo.kathy.demo I/Kathy: TestTwoService - onDestroy - Thread = main


总结bindService的生命周期:
1.点击ActivityA的bindService按钮
第一次调用bindService会实例化TestTwoService,然后执行其onBind()方法,得到IBinder类型的实例,将其作为参数传入ActivityA的ServiceConnection的onServiceConnected方法中,标志着ActivityA与TestTwoService建立了绑定

2.点击ActivityB中的bindService按钮
由于TestTwoService已处于运行状态,所以再次调用bindService不会重新创建它的实例,所以也不会执行TestTwoService的onCreate()方法和onBind()方法。ActivityB与ActivityA共享IBinder实例。此时有两个client与TestTwoService绑定

3.点击ActivityB中的unbindService按钮
ActivityB与TestTwoService解除了绑定,当没有任何client与Service绑定时,才会执行Service的onUnbind()方法。此时,ActivityA还在绑定连接中,所以不会执行Service的解绑方法

4.点击ActivityA中的unbindService按钮
ActivityA执行unbindService之后,ActivityA与TestTwoService就解除绑定了,这样就没有client与TestTwoService绑定,这时候Android会销毁TestTwoService,在销毁前会先执行TestTwoService的onUnbind()方法,然后才会执行其onDestroy()方法,这样TestService就销毁了。

如何保证Service不被杀死?

1. onStartCommand方式中,返回START_STICKY

首先我们来看看onStartCommand都可以返回哪些值:

调用Context.startService方式启动Service时,如果Android面临内存匮乏,可能会销毁当前运行的Service,待内存充足时可以重建Service。而Service被Android系统强制销毁并再次重建的行为依赖于Service的onStartCommand()方法的返回值。

  • START_NOT_STICKY
    如果返回START_NOT_STICKY,表示当Service运行的进程被Android系统强制杀掉之后,不会重新创建该Service
    。当然如果在其被杀掉之后一段时间又调用了startService,那么该Service又将被实例化。那什么情境下返回该值比较恰当呢?
    如果我们某个Service执行的工作被中断几次无关紧要或者对Android内存紧张的情况下需要被杀掉且不会立即重新创建这种行为也可接受,那么我们便可将 onStartCommand的返回值设置为START_NOT_STICKY。
    举个例子,某个Service需要定时从服务器获取最新数据:通过一个定时器每隔指定的N分钟让定时器启动Service去获取服务端的最新数据。当执行到Service的onStartCommand时,在该方法内再规划一个N分钟后的定时器用于再次启动该Service并开辟一个新的线程去执行网络操作。假设Service在从服务器获取最新数据的过程中被Android系统强制杀掉,Service不会再重新创建,这也没关系,因为再过N分钟定时器就会再次启动该Service并重新获取数据。

  • START_STICKY
    如果返回START_STICKY,表示Service运行的进程被Android系统强制杀掉之后,Android系统会将该Service依然设置为started状态(即运行状态),但是不再保存onStartCommand方法传入的intent对象,然后Android系统会尝试再次重新创建该Service,并执行onStartCommand回调方法,但是onStartCommand回调方法的Intent参数为null,也就是onStartCommand方法虽然会执行但是获取不到intent信息。如果你的Service可以在任意时刻运行或结束都没什么问题,而且不需要intent信息,那么就可以在onStartCommand方法中返回START_STICKY,比如一个用来播放背景音乐功能的Service就适合返回该值。

  • START_REDELIVER_INTENT
    如果返回START_REDELIVER_INTENT,表示Service运行的进程被Android系统强制杀掉之后,与返回START_STICKY的情况类似,Android系统会将再次重新创建该Service,并执行onStartCommand回调方法,但是不同的是,Android系统会再次将Service在被杀掉之前最后一次传入onStartCommand方法中的Intent再次保留下来并再次传入到重新创建后的Service的onStartCommand方法中,这样我们就能读取到intent参数。只要返回START_REDELIVER_INTENT,那么onStartCommand重的intent一定不是null。如果我们的Service需要依赖具体的Intent才能运行(需要从Intent中读取相关数据信息等),并且在强制销毁后有必要重新创建运行,那么这样的Service就适合返回START_REDELIVER_INTENT。

2.提高Service的优先级
在AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级,1000是最高值,如果数字越小则优先级越低,同时适用于广播。

3.提升Service进程的优先级

当系统进程空间紧张时,会依照优先级自动进行进程的回收。
Android将进程分为6个等级,按照优先级由高到低依次为:

  • 前台进程foreground_app
  • 可视进程visible_app
  • 次要服务进程secondary_server
  • 后台进程hiddena_app
  • 内容供应节点content_provider
  • 空进程empty_app
    可以使用startForeground将service放到前台状态,这样低内存时,被杀死的概率会低一些。

4.在onDestroy方法里重启Service
当service走到onDestroy()时,发送一个自定义广播,当收到广播时,重新启动service。

5.系统广播监听Service状态
6.将APK安装到/system/app,变身为系统级应用




FROM: 

Android Service两种启动方式详解(总结版)

http://www.jianshu.com/p/4c798c91a613


Android Service完全解析,关于服务你所需知道的一切(上)

http://blog.csdn.net/guolin_blog/article/details/11952435/


Android中Service的使用详解和注意点(LocalService)

http://www.cnblogs.com/linlf03/p/3296323.html


Android四大组件:Service服务史上最全面解析

http://www.jianshu.com/p/d963c55c3ab9

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Service两种启动方式详解(总结版) 的相关文章

随机推荐

  • 2022.06.26 华为od机试真题

    华为od机试真题 1 最长连续子串 2 正方形数量 3 二叉树层次遍历 不会做 1 最长连续子串 有N个正整数组成的一个序列 给定一个整数sum 求长度最长的的连续子序列使他们的和等于sum 返回次子序列的长度 如果没有满足要求的序列 返回
  • 2019年广东工业智能机器人产量约占全国29%

    日前发布的 广东省制造业高质量发展 十四五 规划 下称 规划 中 智能机器人是我省 十四五 谋划发展的十大战略性新兴产业之一 战略性新兴产业是科技创新和产业发展的深度融合 规划针对智能机器人的发展提出 重点发展机器人减速器 控制器等关键部件
  • 【计算机视觉

    文章目录 一 PROMISE12 二 BraTS 2015 三 LIP Look into Person 四 BigEarthNet 五 Stanford Background Standford Background Dataset 六
  • win10 powershell无法激活conda v4.9环境

    1 PATH环境变量 把condabin目录添加到环境变量中 2 初始化powershell 2 1 管理员身份运行powershell win x 弹出选项 选中 Windows PowerShell 管理员 2 2 conda init
  • python 替换_Python 实现将numpy中的nan和inf,nan替换成对应的均值

    nan not a number inf infinity 正无穷 numpy中的nan和inf都是float类型 t t 返回bool类型的数组 矩阵 np count nonzero 返回的是数组中的非0元素个数 true的个数 np
  • (python)Hex文件解析和校验

    目录 前言 Hex文件结构分析 1 利用notepad 打开hex文件 2 hex行格式 行开始 数据长度 地址 数据类型 数据 校验和 3 校验和 完整代码 总结 前言 Intel HEX文件是由一行行符合Intel HEX文件格式的文本
  • 数据赋能企服增长,构建“以客户为中心”的数字化经营体系

    目前 中国企服市场数字化需求爆发 主要表现在传统行业数字化转型加速 企服企业的服务能力得到认可 新冠疫情加速数字化进程等方面 神策数据作为大数据分析与营销科技优质服务商 结合自身数字化实践经验 总结出企服数据驱动增长的解决方案 从市场营销
  • mysql查询like多个值

    有个需求是要查询字段中code前缀是H M 81 82开头的 方法一 使用like和or select from zhy where code like H or code like M or code like 81 or code li
  • Java并发包中那些值得学习的并发工具类(空谈误国,实干兴邦,代码示范,抛砖引玉)

    首先我们通常说的并发包就是java util concurrent包及其子包 集中了Java并发的各种基础工具类 一 这个并发包在哪 上面的包就是传说中的并发包 为什么这个并发包就比较流弊呢 原因主要有以下几点 提供了几个比synchron
  • 什么叫临界资源和临界区?

    临界资源是指每次仅允许一个进程访问的资源 属于临界资源的硬件有打印机 磁带机等 软件有消息缓冲队列 变量 数组 缓冲区等 诸进程间应采取互斥方式 实现对这种资源的共享 每个进程中访问临界资源的那段代码称为临界区 显然 若能保证诸进程互斥地进
  • 机器学习源代码_机器学习中程序源代码的静态分析

    机器学习源代码 Machine learning has firmly entrenched in a variety of human fields from speech recognition to medical diagnosin
  • Qt自定义委托

    Qt中的委托通常都是继承自QStyledItemDelegate或者QItemDelegate 二者的区别主要在于绘制方式 QStyledItemDelegate会使用当前样式绘制 并且能够使用qss 因此在在自定义委托时 一般使用 QSt
  • 详解Python视频剪辑第三方库Moviepy的使用

    一 简介 Moviepy是一个用于处理视频的Python第三方库 它提供了简单易用的接口 可以进行视频剪辑 合并 转码以及添加各种效果等操作 本文将介绍如何使用Moviepy库来进行视频剪辑的基本操作 二 安装Moviepy 在开始之前 我
  • 【状态估计】基于FOMIAUKF、分数阶模块、模型估计、多新息系数的电池SOC估计研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 数据 讲解 1 概述 准确估计电池的荷电状态 SOC 是
  • 前端Js框架汇总

    前端Js框架汇总 概述 有些日子没有正襟危坐写博客了 互联网飞速发展的时代 技术更新迭代的速度也在加快 看着Java Js Swift在各领域心花路放 也是煞是羡慕 寻了寻 net的消息 也是振奋人心 net core 1 mono xam
  • 通过机器学习识别鸟类_将机器学习带到鸟类

    通过机器学习识别鸟类 Cacophony Project的广阔愿景是使用最新技术来监视新西兰鸟类的数量 并人道地消除危害其的捕食者 该项目始于我们创始人的后院 以评估他保护鸟类财产的努力的有效性 从这个简单的开始 该项目便Swift发展成为
  • MySQL存储引擎MyISAM和InnoDB底层索引结构

    目录 一 存储引擎作用于什么对象 二 MyISAM和InnoDB对索引和数据的存储在磁盘上是如何体现的 三 MyISAM主键索引与辅助索引的结构 1 主键索引 2 辅助 非主键 索引 四 InnoDB主键索引与辅助索引的结构 1 主键索引
  • struts-config.xml的dtd文件的声明方式

    struts config xml 的 dtd 文件的声明方式 第一种 第二种 第一种是 PU
  • 【C++】stack容器

    1 stack基本概念 英st k 美st k n 整齐的 一堆 lt 英 gt 垛 堆 大量 许多 尤指工厂的 大烟囱 图书馆的 藏书架 双面书架 the stacks 定高分层盘旋 等待降落 的机群 计算机 存储 栈 竖着置放的高保真音
  • Android Service两种启动方式详解(总结版)

    1 概念 开始 先稍稍讲一点android中Service的概念和用途吧 Service分为本地服务 LocalService 和远程服务 RemoteService 1 本地服务依附在主进程上而不是独立的进程 这样在一定程度上节约了资源