格式化

廣告

廣告2

2013年3月13日 星期三

[Android SDK特色教學] Service服務的原理及使用

[Android SDK特色教學] Service服務的原理及使用

[Android SDK特色教學] Service服務的原理及使用



Serviceandroid系統中的四大組件之一。與一般充斥著各種UI元件的Activity最大區別就是「服務Service完全沒有UI」,Android系統中服務(Service)是在背景執行的東西,就類似定時或週期性的任務。假設你可以利用一個Activity去啟動一個服務(Service)來播放音樂;或者定時記錄你地理訊息位置(GPS)的改變;或者需要下載網路資料時,都可以好好利用服務來幫助你達成任務。Service的啟動有兩種方式:context.startService() context.bindService() 

Android Service的生命週期並不像Activity那麼複雜,它只繼承其中的onCreate()、onStart()、onDestroy()三種方法而已,當我們第一次啟動Service時,先後呼叫了onCreate()、onStartCommand()這兩個方法,需要特別注意的是Android 2.0版之前是呼叫onStart();但是在android 2.0之後已經改成呼叫onStartCommand()了!當停止Service時,則執行onDestroy()方法,這裡需要注意的是,如果Service已經啟動了,當我們再次啟動Service時,不會在執行onCreate()方法,而是直接執行onStartCommand()方法。

使用執行緒還是服務?
即使使用者沒和應用程式互動,服務仍然可以在背景執行。因此,你應該在需要時才使用它「Service」。如果你不想在主執行緒另外執行一個任務,而是僅當使用者和應用互動時執行該任務,你應該建立新執行緒而不是服務。例如,你只想activity執行時才播放音樂,就可以在onCreate()方法裡建立一個執行緒,在onStart()方法裡啟動該執行緒,在onStop()方法裡關閉它。也可以考慮用AsyncTask或者HandlerThread,代替傳統的Thread類別。記住如果你使用了一個服務,它仍然會在主執行緒裡執行,所以,遇到耗時或非同步操作,可以建立一個新執行緒,然後再啟動該服務。

可透過底下兩種方式來開啟Service:

  1. context.startService()
  2. context.bindService() 

context.startService()啟動服務流程
context.startService()啟動服務流程
  1. 直接呼叫Context內的startService()表示已明確開啟Service
  2. 系統開啟Service後會自動呼叫該Service的onCreate()
  3. 再來呼叫該Service的onStartCommand()
  4. 如果呼叫Context的stopService(),會終止該Service;此時系統會呼叫該Service的onDestroy()並且關閉該Service
實作必須注意的是:
context.startService()一旦啟動,服務就直接在背景無限執行,即使啟動它的Activity被銷毀。通常startService()服務啟動後並不返回結果給使用者。例如,它會通過網絡下載、上傳文件,當一個任務執行完成,就會等著讓其他組件通過呼叫stopService()方法停止該服務,Android系統並不會自動銷毀該服務。
  • 一定要extends Service
  • 一定要Override onBind()方法,不過現在用不到,return值可以設為null
  • 一定要在AndroidManifest.xml註冊
<service android:name=".ExampleService"></service>
MyService類別程式碼:
import java.util.Date;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {

 private Handler handler = new Handler();
 
 private Runnable showTime = new Runnable() {
  public void run() {
   // log目前時間
   Log.i("time:", new Date().toString());
   handler.postDelayed(this, 1000);
  }
 };

 @Override
 public IBinder onBind(Intent arg0) {
  // TODO Auto-generated method stub
  return null;
 }

 @Override
 public void onCreate() {
  // TODO Auto-generated method stub
  super.onCreate();
  Log.i("服務", "建立");
 }

 @Override
 public void onDestroy() {
  // TODO Auto-generated method stub
  super.onDestroy();
  Log.i("服務", "銷毀");
  handler.removeCallbacks(showTime);
 }

 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
  // TODO Auto-generated method stub
  Log.i("服務", "執行");
  handler.postDelayed(showTime, 1000);
  return super.onStartCommand(intent, flags, startId);
 }
}

MainActivity類別程式碼
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ToggleButton;

public class MainActivity extends Activity {

 ToggleButton tbu;

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

  tbu = (ToggleButton) findViewById(R.id.toggleButton1);
  tbu.setOnCheckedChangeListener(new OnCheckedChangeListener() {

   @Override
   public void onCheckedChanged(CompoundButton buttonView,
     boolean isChecked) {
    // TODO Auto-generated method stub
    if (buttonView == tbu && isChecked == true) {
     Intent intent = new Intent(MainActivity.this,MyService.class);
     startService(intent);
    }
    if (buttonView == tbu && isChecked == false) {
     Intent intent = new Intent(MainActivity.this,MyService.class);
     stopService(intent);
    }
   }
  });
 }
}
 
context.bindService()啟動服務流程
context.bindService()啟動服務流程
  1. 呼叫Context的bindService()會連結Service,若Service未開啟就會自動開啟。
  2. 開啟Service後會呼叫onCreate()但是不會呼叫onStartCommand()
  3. 呼叫onBind()並傳回IBinder物件
  4. 呼叫ServiceConnection類別中的onServiceConnected()方法,並將步驟3的IBinder物件當作參數傳遞給onServiceConnected(),透過IBinder可以取得跟Service的聯繫。例如直接呼叫該Service內的公用方法。
  5. 呼叫Context的unbindService()方法,則系統會呼叫該Service的onUnbind()以解除Context與Service的聯繫;隨後會自動呼叫Service的onDestroy()銷毀服務。
實作必須注意的是:
context.bindService()運用來綁定服務提供使用者允許Activity與Sevice互動;發送請求;獲得結果,甚至多行程互相執行這些操作。服務和另一個與之綁定的組件執行時間一樣長;若有多個組件也只能和同一個服務綁定一次。但所有組件取消綁定之後,服務就會自動銷毀(這點跟context.startService()很不一樣!)但其實服務可以同時用以上兩種方式工作:startService()bindService(),所以可以啟動之後無限期執行而且允許綁定Activity。這只取決你有沒有實現這兩種服務的回調介面: 「onBind()」。

MyService類別程式碼:
import java.util.Date;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service {
 
 public class ServiceBinder extends Binder {
  MyService getService() {
   return MyService.this;
  }
 }

 private final IBinder mBinder = new ServiceBinder();
 private Handler handler = new Handler();

 private Runnable showTime = new Runnable() {
  public void run() {
   // log目前時間
   Log.i("time:", new Date().toString());
   handler.postDelayed(this, 1000);
  }
 };
 
 public void custom()
 {
  handler.postDelayed(showTime, 1000);
 }

 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
  // TODO Auto-generated method stub
  Log.i("服務", "呼叫onStartCommand方法");
  return super.onStartCommand(intent, flags, startId);
 }

 @Override
 public IBinder onBind(Intent arg0) {
  // TODO Auto-generated method stub
  Log.i("服務", "呼叫onBind方法");
  return mBinder;
 }

 @Override
 public void onCreate() {
  // TODO Auto-generated method stub
  super.onCreate();
  Log.i("服務", "建立");
 }

 @Override
 public void onDestroy() {
  // TODO Auto-generated method stub
  super.onDestroy();
  Log.i("服務", "銷毀");
  handler.removeCallbacks(showTime);
 }
}


MainActivity類別程式碼
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

 Button open,stop;
 MyService myService;

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

  open = (Button) findViewById(R.id.button1);
  open.setOnClickListener(new OnClickListener () {

   @Override
   public void onClick(View arg0) {
    // TODO Auto-generated method stub
    Intent intent = new Intent(MainActivity.this, MyService.class);
    bindService(intent, connc, Context.BIND_AUTO_CREATE);
   }});
  
  stop = (Button) findViewById(R.id.button2);
  stop.setOnClickListener(new OnClickListener () {

   @Override
   public void onClick(View arg0) {
    // TODO Auto-generated method stub
    unbindService(connc);
   }});
 }

 private ServiceConnection connc = new ServiceConnection() {

  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   // TODO Auto-generated method stub
   myService=((MyService.ServiceBinder)service).getService();      
   myService.custom();
  }

  @Override
  public void onServiceDisconnected(ComponentName name) {
   // TODO Auto-generated method stub
   myService=null;
  }

 };
}

沒有留言 :