android 组件 - Service小结

Service是android4大组件之一,它主要用于处理后台的一些耗时逻辑,以及实现需要长期运行在后台的任务。


Service 分类:

1.1. 按运行地点分类:

本地服务,服务依附在主进程上

远程服务,独立进程

1.2. 按运行类型分类

前台服务

后台服务

1.3. 按启动方式分类:

startService

bindService

startService + bindService

 

Service与Thread区别

1.Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位,Thread运行在子线程上,独立于主线程。

2. Service:Service 是android的一种机制, Service 是运行在主进程的 main 线程上的。

Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。

 

Service的生命周期方法

onCreate():Service创建时调用

onStartCommand():Service启动时调用

onBind():Service绑定时调用

onRebind():Service重绑定时调用

onUnbind():Service解绑定时调用

onDestroy():Service销毁时调用

 

Service的操作方法

startService

调用startService时,如果此时Service没有启动则会调用onCreate->

onStartCommand.如果此时Service已经启动,则不会再调用onCreate,onCreate函数只在服务未启动时启动服务调用,但是会继续调用onStartCommand,调用次数与startService调用次数对应。


对于多个Activity启动Service的情况,这样的结论也适合,当Activity已经启动过该Service,在另外Activity启动该Service时,不会创建Service,但会调用onStartCommand。

当Activity使用startService启动服务时,退出未停止服务,重新进入Activity调用startService时不会调用onCreate,但会调用onStartCommand。

 

stopService

当调用stopService停止服务时,Service会调用onDestory停止服务。


对于多个Activity,当Service已经使用startService启动完成之后,如果在另外的Activity调用stopService结束该Service,会调用onDestory。如果之后返回到最初启动的Activity再调用stopService,那么此时不会再触发onDestory,因为之前启动的Service已经结束了。由此可知,调用startService启动服务,可以在另外的地方调用stopService结束服务。


其中onDestory是在另外Activity调用stopService触发的。


bindService

当一个service没有启动,直接调用bindService时,则会触发Service的onCreate和onBind方法。


对于多个Activity绑定同一个Service,如果Service已经被启动,则再次调用bindService时,Service的onCreate和onBind都不会继续调用,此时会回调ServiceConnection的onServiceConnected方法。

Activity通过调用unbindService来与一个已经绑定的Service解除绑定,该方法会触发Service的onUnbind和onDestory方法,当该Service只与当前Activity绑定时,测试效果如下:


一个Activity如果调用了bindService,那么在结束之前需要调用unbindService解除与服务的绑定,否则会抛出android.app.ServiceConnectionLeaked异常。此时仍会触发Service的onUnbind和onDestory,Service仍然会结束。


unbindService

一个Activity只能调用一次unbindService来解除与Service的绑定,多次调用则会抛出java.lang.IllegalArgumentException:Service not registered…的异常。

      

如果想Service可以绑定,并且退出当前绑定Activity时服务仍然继续运行,可以在Activity启动的时候先调用startService,之后再调用bindService进行绑定服务。如果解除绑定之后再次启动Activity进行绑定Service,那么此时onBind将不会继续调用,但是会回调ServiceConnection的onServiceConnected方法。

Service中含有一个onRebind的方法,当Service中的onUnbind方法返回true,并且Service调用unbindService之后并没有销毁,此时重新绑定时将会触发onRebind方法,该方法不会重复调用,类似于onBind,但是和onBind不一样的是,初次绑定Service时还是会调用onBind,之后才会调用onRebind。onRebind在Service未被绑定并且Sevice之前已经被解除绑定时调用onBind触发。

 

Service常见操作流程

假设有两个Activity,分别为a1和a2.

a1.StartService->a1.stopService

Service回调:onCreate->onStartCommand->onDestory

a1.StartService->a2.startService->a2.stopService

onCreate->onStartCommand->onStartCommand->onDestory

stopService先调先停止

a1.bindService->a1.unbindService

onCreate->onBind->a1.onServiceConnected->onUnbind->onDestory

同一Activity多次调用bindService效果一样

a1.bindService->a2.bindService->a2.unbindService->a1.unbindService

onCreate->onBind->a1.onServiceConnected->a2.onServiceConnected

->onUnbind->onDestory

5.a1.StartService->a1.bindService->a1.unbindService->a1.stopService

onCreate->onStartCommand->onBind->a1.onServiceConnected

->onUnbind->onDestory

6.a1.bindService->a1.StartService->a1.stopService->a1.unbindService

onCreate-> onBind->onStartCommand->a1.onServiceConnected

->onUnbind->onDestory

 

Service的启动和停止

         Service首先需要在AndroidManifest.xml里注册,然后通过startService和stopService可以实现基本启动和停止功能。

Service的绑定

Service需要在AndroidManifest.xml里注册,Service需要实现onBind方法,在onBind里返回一个Binder实例。在调用bindService方法时需要传递一个ServiceConnection对象,用来监听与Service连接和丢失连接的状态。Service 取消绑定时使用unbindService方法实现。


注意问题

1.使用 startService 启动服务之后,需要使用 stopService停止服务;

2.调用 bindService 绑定到Service的时候,应该使用unbindService 解除绑定,bindService 和unbindService 应该是成对出现的;

3.在 sdk 2.0 及其以后的版本中,应当使用 onStartCommand 而不是onStart。

4.使用 startService 与 bindService 启动服务,要使Service 的终止,unbindService与stopService都需要调用,才能停止Service;

5.当手机屏幕横竖屏的时候,使用 bindService 建立的连接便会断开,服务的生命周期与上述相同。

6.Service.onBind如果返回null,则调用 bindService 会启动 Service,但不会连接上 Service,因此 ServiceConnection.onServiceConnected不会被调用,但任然需要使用 unbindService 函数断开它,这样 Service 才会停止。

7.使用 startForeground ,如果 id 为 0 ,那么notification 将不会显示。

8.OnBind onCreate onRebind onUnbind方法不能重复被调用


测试代码

TestService.java

public class TestService extends Service {
	
	private int num = 0;
	
	@Override
	public void onCreate() {
		super.onCreate();
		System.out.println("-----------------> TestService: onCreate");
	}

	@Override
	public int onStartCommand(Intent intent, int fTAGs, int startId) {
		System.out.println("-----------------> TestService: onStartCommand");
		return super.onStartCommand(intent, fTAGs, startId);
	}

	@Override
	public IBinder onBind(Intent intent) {
		
		System.out.println("-----------------> TestService: onBind");
		return binder;
	}

	@Override
	public void onRebind(Intent intent) {
		super.onRebind(intent);
		System.out.println("-----------------> TestService: onRebind");
	}

	@Override
	public boolean onUnbind(Intent intent) {
		System.out.println("-----------------> TestService: onUnbind");
//		return super.onUnbind(intent);
		return true;
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		System.out.println("-----------------> TestService: onDestroy");
	}
	
	public int getNum() {
		int a = num ++;
		return a;
	}
	
	public IBinder binder = new TestBinder();

    public class TestBinder extends Binder{

        public TestService getService(){
            return TestService.this;
        } 
    }
}

MainActivity.java
public class MainActivity extends Activity {

	private Button btStart = null; 
	private Button btStop = null; 
	private Button btBind= null; 
	private Button btUnbind = null; 
	private Button btOther = null; 
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();
	}

	// 控件初始化
	private void initView() {
		btStart = (Button) findViewById(R.id.bt_start);
		btStart.setOnClickListener(clickListener);
		btStop = (Button) findViewById(R.id.bt_stop);
		btStop.setOnClickListener(clickListener);
		btBind = (Button) findViewById(R.id.bt_bind);
		btBind.setOnClickListener(clickListener);
		btUnbind = (Button) findViewById(R.id.bt_unbind);
		btUnbind.setOnClickListener(clickListener);
		btOther = (Button) findViewById(R.id.bt_other);
		btOther.setOnClickListener(clickListener);
	}
	
	private OnClickListener clickListener = new OnClickListener() {

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			switch (v.getId()) {
			case R.id.bt_start: // start
				startService(new Intent(MainActivity.this, TestService.class)); 
				break;
			case R.id.bt_stop: // stop
				stopService(new Intent(MainActivity.this, TestService.class));
				break;
			case R.id.bt_bind: // bind
				bindService(new Intent(MainActivity.this, TestService.class), serviceConnection, Context.BIND_AUTO_CREATE);
				break;
			case R.id.bt_unbind: // unbind
				unbindService(serviceConnection);
				break;
			case R.id.bt_other: // 
				Intent it = new Intent();
				it.setClass(MainActivity.this, MainActivity.class);
				startActivity(it);
				break;
			default:
				break;
			}
		}
	};
	
	private ServiceConnection serviceConnection = new ServiceConnection() {

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			System.out.println("----------------> onServiceConnected");
			TestBinder sBinder = (TestBinder)service;
			System.out.println("----------------> num: " + sBinder.getService().getNum());

		}

		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
			System.out.println("----------------> onServiceDisconnected");
		}
	};
}

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
  	>

    <Button
        android:id="@+id/bt_start"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="startService" />

    <Button
        android:id="@+id/bt_stop"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="stopService" />

    <Button
        android:id="@+id/bt_bind"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="bindService" />

    <Button
        android:id="@+id/bt_unbind"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:onClick="myClick"
        android:text="unbindService" />

    <Button
        android:id="@+id/bt_other"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="otherActivity" />
</LinearLayout>

AndroidMainfest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testservice"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.testservice.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name="com.example.testservice.TestService" ></service>
        
    </application>

</manifest>






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值