Android中的Service

在手机管理中经常看到进程和服务,进程指的就是App应用在运行,服务就是Android四大组件之一的Service。

Service是一个具有较长生命周期但没有用户界面的组件,说它生命周期长并不是它运行中回调的方法多,而是它可以存在很长时间,如果必要可以一直运行,没有用户界面就是看不到,无法与用户进行交互,如果不以特殊的方式表现它的状态是无法获知它的存在的。Android手机中诸如后台下载、音乐后台播放、GPS定位服务等等都是服务的,正因为它的特性我们通常在Service中执行相对耗时的操作。

创建一个Service就不如Activity那样方便了,自定义Service需要手动继承Service类,配置文件也需要手动配置。对于一些系统级的Service可以直接通过getResource()方法来获取(这是因为Activity和Service都是Context的派生类)。

Service的配置与Activity类似,在<service>标签内必须配置name属性,同时也可以配置<intent-filter>为Service设定<action>等标记元素来完成隐式Intent的调用。

Service的启动需要依赖其他组件,可以使用Activity或者Receiver等作为调用者,启动方式分为startService启动和bindService绑定两种,这两种方法启动的Service拥有不同的生命周期。

 

startService启动的Service生命周期与Activity没有关联,即使Activity被销毁Service依然运行

onCreate()创建Service实例时的回调函数

onStartCommand()启动Service时的回调函数

onDestory()销毁Service时回调,Service一旦启动无法自动终止,除非手动停止stopService或者卸载应用程序

关于onStartCommand()返回参数onStartCommand(intent, flags,startId),startId可以获取Service被启动的次数,flags是用来指定Service的系统在用户为手动关闭Service前自动回收Service资源了Service资源情况下的重启行为,它有以下值

START_STICKY   

“粘性的”。如果Service进程被kill掉,保留Service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建Service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。

START_NOT_STICKY

“非粘性的”。如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。

START_REDELIVER_INTENT

如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。

START_STICKY_COMPATIBILITY:

START_STICKY的兼容版本,但不保证服务被kill后一定能重启。

bindService启动的Service生命周期受到调用者的影响,如果调用者被销毁,Service也会被销毁。

bindService(Intent service,ServiceConnection conn, int flags)

service要绑定Service信息的Intent对象

conn监听访问者与Service之间的连接情况。当访问者与Service之间链接成功时将回调该ServiceConnection对象的onServiceConnected(ComponentName,IBinder)方法;当Service所在的宿主进程由于异常中止或由于其他原因终止,导致该Service与访问者之间断开连接时回调该ServiceConnection对象的onServiceDisconnected(ComponentName)方法。其中onServiceConnected方法中的IBinder对象,可实现与被绑定Service之间的通信。在开发Service类时,该Service类必须提供一个IBinder onBind()方法,该方法所返回的IBinder对象将会传给ServiceConnection对象里onServiceConnected方法的参数中。这样访问者就

可以通过该IBinder对象与Service进行通信。实际开发时通常会采用继承Binder(IBinder的实现类)的方式实现自己的IBinder对象。

flags指定绑定时是否自动创建Service (如果Service还未创建),该参数可指定为0(不自动创建)或BIND_AUTO_CREATE(自动创建)。

onCreate()同startService

onBind()在Service与调用者建立关联关系时使用,该方法会返回一个IBinder类型的实例给调用者,作为Service在调用者的代理

onUnbind() Service与调用者解除绑定

onDestory()同startService

以下针对Service的使用和生命周期做一个简单的测试,首先,我们分别通过两种方式启动Service,其次在两个Service中都进行线程计数,做一些简单的实验,布局文件如下

<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"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.briup.service.MainActivity" >

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="startService"
        android:text="StartService" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="stopService"
        android:text="StopService" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="bindService"
        android:text="BindService" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="unBindService"
        android:text="UnBindService" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="getcount"
        android:text="getCount" />

</LinearLayout>

MainActivity类文件如下

import com.briup.service.SecondService.MyBinder;

import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {
	private ServiceConnection conn;
	private final static String TAG = "briup";
	private MyBinder binder;//在SecondService服务中自定义的Binder类

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		conn = new ServiceConnection() {
			// 在Activity与Service异常解除绑定时回调
			@Override
			public void onServiceDisconnected(ComponentName name) {
				Log.i(TAG, "MainActivity-onServiceDisconnected");
			}

			// 在Activity与Service进行绑定成功时回调
			@Override
			public void onServiceConnected(ComponentName name, IBinder service) {
				Log.i(TAG, "MainActivity-onServiceConnected");
				binder = (MyBinder) service;//通过IBinder对象和自定义的Binder类实现数据传递
			}
		};
	}

	public void startService(View v) {
		Intent intent = new Intent(this, FirstService.class);
		// 通过start启动的服务,该服务的生命周期与Activity没有任何关联
		startService(intent);// 启动服务
	}

	public void stopService(View v) {
		Intent intent = new Intent(this, FirstService.class);
		stopService(intent);// 终止服务
	}

	public void bindService(View v) {
		Intent intent = new Intent(this, SecondService.class);
		// 通过绑定方式启动服务,调用者的生命周期会影响服务的生命周期
		bindService(intent, conn, Service.BIND_AUTO_CREATE);// 绑定服务
	}

	public void unBindService(View v) {
		unbindService(conn);// 解绑服务
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		if(conn!=null)
			unbindService(conn);// 需要在调用者的Destroy方法中进行解绑,否则强退出错(当然前提是绑定了服务,否则会因为找不到服务而无法退出Activity终止程序)
	}

	public void getcount(View v) {//获取服务数据
		Toast.makeText(this, binder.getCount() + "", Toast.LENGTH_LONG).show();//调用自定义的Binder类中的方法完成数据传递
	}

	public void startIntentService(View v) {
		Intent intent = new Intent(this, MyIntentService.class);
		startService(intent);
	}
}

FirstService类文件如下

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class FirstService extends Service{
	private int count = 1;
	private final static String TAG = "briup";
	@Override
	public IBinder onBind(Intent intent) {
		return null;
	}
	
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		Log.i(TAG, "FirstService onCreate");
	}
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		Log.i(TAG, "FirstService onStartCommand");
		new Thread(){
			public void run(){//通过创建子线程做计数
				while(count<101){
					Log.i(TAG, "count:"+count);
					try {
						sleep(500);
						count++;
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
		return super.onStartCommand(intent, flags, startId);
	}
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
		count=200;//手动设置计数为200跳过循环即可终止线程
		Log.i(TAG, "FirstService onDestroy");
	}
}

SecondService类文件如下

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class SecondService extends Service {
	private final static String TAG = "briup";
	private int count = 1;

	// 通常自己写一个类继承Binder,也就间接的实现了IBinder接口
	public class MyBinder extends Binder {
		public int getCount() {
			return count;
		}
	}

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		Log.i(TAG, "SecondService onBind");

		new Thread() {
			public void run() {
				while (count < 101) {
					Log.i(TAG, "count:" + count);
					try {
						sleep(500);
						count++;
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}.start();
		return new MyBinder();
	}

	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		Log.i(TAG, "SecondService onCreate");
	}

	@Override
	public boolean onUnbind(Intent intent) {
		// TODO Auto-generated method stub
		Log.i(TAG, "SecondService onUnbind");
		count = 200;
		return super.onUnbind(intent);
	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		Log.i(TAG, "SecondService onDestroy");
		super.onDestroy();
	}
}
配置文件如下

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

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="19" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".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=".FirstService"
            ></service>
        <service 
            android:name=".SecondService"
            ></service>
        <service 
            android:name=".MyIntentService"
            ></service>
    </application>

</manifest>

效果如下

 

startService后不论按HOME键还是退出Activity都在计数运行

 

stopService后计数即停止

 

bindService

 

unbindService和退出Activity的情况相同,至于那种异常解绑需要异常时出现

 

getCount

 

Android中的Service是用于后台服务的,当应用程序被挂到后台的时候,问了保证应用某些组件仍然可以工作而引入了Service这个概念,那么这里面要强调的是Service不是独立的进程,也不是独立的线程,它是依赖于应用程序的主线程的,那么如果主线程被终止或阻塞,就会引起ANR(Application Not Responding,程序无响应)。我们推荐编写耗时程序时使用IntentService,IntentService是继承Service的,那么它包含了Service的全部特性,当然也包含service的生命周期,那么与service不同的是,IntentService在执行onCreate操作的时候,内部自己开了一个线程,可以用来执行耗时操作。该线程保证同一时刻只处理一个Intent,这样IntentService不会阻塞主线程。

IntentService的使用和Service是类似,需要重写onHandleIntent(Intent intent)方法,以下代码实现与上面功能相同的Service,不需要创建依赖于主线程的子线程。

import android.app.IntentService;
import android.content.Intent;
import android.util.Log;

public class MyIntentService extends IntentService {
	private int count = 1;
	private final static String TAG = "briup";

	public MyIntentService(String name) {
		super(name);
		// TODO Auto-generated constructor stub
	}

	public MyIntentService() {// 要求创建一个无参构造器,并且必须传一个名字,否则报错
		super("MyIntentService");
	}

	@Override
	// 重写该方法不需要创建子线程,该方法提供新开的线程供耗时操作
	protected void onHandleIntent(Intent intent) {
		while (count < 101) {
			Log.i(TAG, "count:" + count);
			try {
				Thread.sleep(500);
				count++;
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值