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>