天天看点

Android中Service的意义及用法

1、下面介绍Service和AsyncTask的用法和比较。

Service没有界面,用于执行一个需要在后台长期运行的任务。AsyncTask用于执行短时间的异步任务,并跟UI线程交互,用于替代Thread和Handler。

1) MainActivity.java

public class MainActivity extends Activity {
	private static final String TAG = MainActivity.class.getSimpleName();
	/**便于多次、多地调用,生命周期伴随Activity*/
	Intent intent;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		Log.i(TAG, "onCreate");
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
//		mAsyncTask.execute("http://www.qinuli.com:83/picture/thumb.jpg", "http://www.qinuli.com:83/picture/hand_in_hand.jpg");
		intent = new Intent(this, MyService.class);
	}
	protected void onDestroy() {
		Log.d(TAG, "onDestroy");
		super.onDestroy();
	};
	/**
	 * 定义一个AsyncTask的子类;实例化并在UI线程调用其execute方法
	 * <li>3个参数:Params、Progress、Result
	 * <li>4 steps:onPreExecute->doInBackground->onProgressUpdate->onPostExecute
	 * <li>功能:用于后台执行前台显示的任务
	 * <li>意义:代替或封装Thread和Handler,方便后台线程和UI线程交互
	 */
	AsyncTask<String, Integer, CharSequence> mAsyncTask = new AsyncTask<String, Integer, CharSequence>() {
		@Override
		protected void onPreExecute() {
			Log.d(TAG, "onPreExecute");
		};
		@Override
		protected CharSequence doInBackground(String... params) {
			//perform a computation on a background thread
			for(int i=0;i<params.length;i++){
				publishProgress(Integer.valueOf(i));
			}
			return "加油!";
		}
		@Override
		protected void onProgressUpdate(Integer... values) {
			Log.d(TAG, "onProgressUpdate-"+values[0]);
		};
		@Override
		protected void onPostExecute(CharSequence result) {
			Log.d(TAG, "onPostExecute-"+result);
		};
	};
	private ServiceConnection mServiceConnection = new ServiceConnection() {
		@Override
		public void onServiceDisconnected(ComponentName name) {
			Log.d(TAG, "onServiceDisconnected-"+name.getClassName());
		}
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			//由bindService触发,在onBind之后
			MyService myService = ((MyBinder)service).getService();
			Log.d(TAG, "onServiceConnected-"+name.getClassName()+"-"+myService.name);
		}
	};
	public void onClick(View v){
		switch (v.getId()) {
		case R.id.btn_startService:
			//调用Service的空参构造
			startService(intent);
			break;
		case R.id.btn_stopService:
			stopService(intent);
			break;
		case R.id.btn_bindService:
			bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
			break;
		case R.id.btn_unbindService:
			unbindService(mServiceConnection);
		}
	}
}
           

2) activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <Button 
        android:id="@+id/btn_startService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="startService"/>
    <Button 
        android:id="@+id/btn_stopService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="stopService"/>
    <Button 
        android:id="@+id/btn_bindService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="bindService"/>
    <Button 
        android:id="@+id/btn_unbindService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="unbindService"/>
</LinearLayout>
           

3) MyService.java,讲解startService和bindService的原理

/**
 * <li>Service的意义:perform a longer running operation
 * <li>Service和AsyncTask的区别:Service运行在主线程,不会结束
 */
public class MyService extends Service {
	private static final String TAG = MyService.class.getSimpleName();
	private MyBinder myBinder = new MyBinder();
	public String name = "ShiXin";
	
	public MyService(){
		super();
		Log.d(TAG, "MyService");
	}
	
	/**继承Binder类,Binder类实现IBinder接口。实例化该类供onBind使用*/
	public class MyBinder extends Binder{
		/**返回Service的实例,进而调用其方法和属性,实现一些数据通信和功能操作*/
		public MyService getService(){
			return MyService.this;
		}
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		Log.d(TAG, "onBind");
		//由bindService触发
		return myBinder;
	}

	@Override
	public boolean onUnbind(Intent intent) {
		Log.d(TAG, "onUnbind");
		return super.onUnbind(intent);
	}
	
	@Override
	public void onCreate() {
		Log.d(TAG, "onCreate");
		//重新实例化新的Service
		super.onCreate();
	}
	
	public void onDestroy() {
		Log.d(TAG, "onDestroy");
		super.onDestroy();
	};
	
	@Override
	public void onStart(Intent intent, int startId) {
		//deprecated 被onStartCommand代替
		super.onStart(intent, startId);
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		//每次startService都会触发,bindService不会触发
		//startId:unique integer token,标记每次startService,Service创建后从1开始计数
		//START_STICKY_COMPATIBILITY 0;Service.START_STICKY 1
		stopSelfResult(3);//onStartCommand执行3次
		int state = super.onStartCommand(intent, flags, startId);
		Log.d(TAG, "onStartCommand-"+intent.getComponent().getClassName()+"-"+flags+"-"+startId+"-"+state);
		return state;//1
	}
}
           

4) MyIntentService.java,IntentService用于在后台线程执行异步任务,执行完Service自动destroy

/**
 * handle asynchronous requests
 */
public class MyIntentService extends IntentService {

	private static final String TAG = MyIntentService.class.getSimpleName();
	
	public MyIntentService() {
		//name worker thread
		super("worker thread");
	}
	@Override
	protected void onHandleIntent(Intent intent) {
		//代替onStartCommand;执行完调用stopSelf()
		Log.d(TAG, Thread.currentThread().getName()+"-onHandleIntent");
	}
	@Override
	public void onCreate() {
		Log.d(TAG, "onCreate");
		super.onCreate();
	}
	@Override
	public void onDestroy() {
		Log.d(TAG, "onDestroy");
		super.onDestroy();
	}
}
           

5) AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.qinuli.testproject"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity android:name="com.qinuli.testproject.MainActivity">
            <intent-filter >
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <service android:name="com.qinuli.testproject.MyService"></service>
        <service android:name="com.qinuli.testproject.MyIntentService"></service>
    </application>

</manifest>
           

2、如何让服务永久运行

本示例介绍了TIME_TICK和BOOT_COMPLETED广播的用法

public class MainActivity extends Activity {
	private static final String TAG = MainActivity.class.getSimpleName();
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		Log.d(TAG, "onCreate");
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
	@Override
	protected void onDestroy() {
		Log.d(TAG, "onDestroy");
		super.onDestroy();
	}
	public void onClick(View v){
		switch(v.getId()){
		case R.id.btn_killProcess:
			Process.killProcess(Process.myPid());
		}
	}
}
           

MyService.java

public class MyService extends Service {

	private static final String TAG = MyService.class.getSimpleName();
	private MyBinder myBinder = new MyBinder();
	public class MyBinder extends Binder{
		public MyService getService(){
			return MyService.this;
		}
	}
	@Override
	public IBinder onBind(Intent intent) {
		return myBinder;
	}
	@Override
	public void onCreate() {
		Log.d(TAG, "onCreate");
		super.onCreate();
	}
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d(TAG, "onStartCommand");
		//进程被杀死,服务会重建
		return Service.START_STICKY;
	}
	@Override
	public void onDestroy() {
		Log.d(TAG, "onDestroy");
		super.onDestroy();
	}
}
           

MyApplication.java

public class MyApplication extends Application {
	private static final String TAG = MyApplication.class.getSimpleName();
	MyService myService;
	Intent intent;
	@Override
	public void onCreate() {
		Log.d(TAG, "onCreate");
		super.onCreate();
		
		intent = new Intent(this, MyService.class);
		startService(intent);
		bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
		
		registerReceiver(new TimeTickReceiver(), new IntentFilter(Intent.ACTION_TIME_TICK));
	}
	@Override
	public void onTerminate() {
		Log.d(TAG, "onTerminate");
		super.onTerminate();
		stopService(intent);
		//禁用一个manifest receiver,可禁用清单文件里注册的四大组件
		ComponentName componentName = new ComponentName(this, BootCompletedReceiver.class);
		PackageManager pm = getPackageManager();
		pm.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 
				PackageManager.DONT_KILL_APP);
	}
	private ServiceConnection mServiceConnection = new ServiceConnection() {
		@Override
		public void onServiceDisconnected(ComponentName name) {
			myService = null;
		}
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			Log.d(TAG, "onServiceConnected");
			myService = ((MyBinder)service).getService();
		}
	};
}
           

BootCompleteReceiver.java

public class BootCompletedReceiver extends BroadcastReceiver {
	private static final String TAG = BootCompletedReceiver.class.getSimpleName();

	public BootCompletedReceiver(){
		super();
		Log.d(TAG, "BootCompletedReceiver");
	}
	
	public void onReceive(Context context, Intent intent) {
		String action = intent.getAction();
		Log.d(TAG, action);
		if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
			//清单文件注册,开机可收到广播
			boolean isServiceRunning = false;
			ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
			for(RunningServiceInfo runningServiceInfo:activityManager.getRunningServices(Integer.MAX_VALUE)){
				if(MyService.class.getName().equals(runningServiceInfo.service.getClassName())){
					isServiceRunning = true;
				}
			}
			if(!isServiceRunning){
				ComponentName comp = new ComponentName(context.getPackageName(), MyService.class.getName());
				context.startService(new Intent().setComponent(comp));
			}
		}else if(ConnectivityManager.CONNECTIVITY_ACTION.equals(action)){
			//在清单文件注册,退出APP或杀死进程依然能收到广播,但清掉内存就收不到了
			ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
			NetworkInfo networkInfo = cm.getActiveNetworkInfo();
			if(networkInfo!=null)
				Log.d(TAG, "networkstate:"+networkInfo.isConnectedOrConnecting()+"-"+(networkInfo.getType()==ConnectivityManager.TYPE_MOBILE));
		}
	}
}
           

TimeTickReceiver.java

public class TimeTickReceiver extends BroadcastReceiver {
	private static final String TAG = TimeTickReceiver.class.getSimpleName();

	public TimeTickReceiver(){
		super();
		Log.d(TAG, "TimeTickReceiver");
	}
	
	@Override
	public void onReceive(Context context, Intent intent) {
		String action = intent.getAction();
		Log.d(TAG, action);
		if (Intent.ACTION_TIME_TICK.equals(action)) {
			boolean isServiceRunning = false;
			//拿到所有正在运行的服务
			ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
			for(RunningServiceInfo runningServiceInfo:activityManager.getRunningServices(Integer.MAX_VALUE)){
				if(MyService.class.getName().equals(runningServiceInfo.service.getClassName())){
					isServiceRunning = true;
				}
			}
			Log.d(TAG, "isServiceRunning="+isServiceRunning);
			if(!isServiceRunning){
				ComponentName comp = new ComponentName(context.getPackageName(), MyService.class.getName());
				context.startService(new Intent().setComponent(comp));
			}
		}
	}
}
           

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.qinuli.servicetest"
    android:versionCode="1"
    android:versionName="1.0" >

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

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    
    <application
        android:name="com.qinuli.servicetest.MyApplication"
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity android:name="com.qinuli.servicetest.MainActivity">
            <intent-filter >
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <service android:name="com.qinuli.servicetest.MyService"
            android:enabled="true"
            android:exported="false"/>
        <receiver
            android:name="com.qinuli.servicetest.BootCompletedReceiver"
            android:permission="android.permission.RECEIVE_BOOT_COMPLETED"
            android:enabled="true" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>