Service與Activity通訊 回調方式***

  要實現service與activity的高強度通訊用什麼方法?android

  service與activity以前的通訊方式有不少,回調接口方式、觀察者模式、廣播、還有handler等,方法有不少,但要高強度地通訊,我的以爲仍是用回調接口的方式比較穩當(雖然本人開始也是用的傳入的handler。。。哈哈,用handler的話,若是涉及到service要向多個activity傳送數據就變得麻煩了)。因此在這裏記錄下回調接口的方式進行通訊:app

一、怎樣在啓動一個Service時向它傳遞數據ide

  關鍵點:Intent傳值,onStartCommand()接收。函數

  二、怎樣向運行的Service中同步數據佈局

  關鍵點:經過onBind()獲取Service實例,而後再調用Binder中的相關方法。測試

  三、怎樣偵聽Service中數據變化this

  關鍵點:經過回調函數達到目的。spa

 

1、準備Service線程

  先貼出Service的詳細代碼,而後再慢慢分析3d

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

public
class MyService extends Service { private String data = "默認消息"; private boolean serviceRunning = false; // 必須實現的方法,用於返回Binder對象 @Override public IBinder onBind(Intent intent) { System.out.println("--onBind()--"); return new MyBinder(); } public class MyBinder extends Binder { MyService getService() { return MyService.this; } public void setData(String data) { MyService.this.data = data; } } // 建立Service時調用該方法,只調用一次 @Override public void onCreate() { super.onCreate(); System.out.println("--onCreate()--"); serviceRunning = true; new Thread() { @Override public void run() { int n = 0; while (serviceRunning) { n++; String str = n + data; System.out.println(str); if (dataCallback != null) { dataCallback.dataChanged(str); } try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } }; }.start(); } // 每次啓動Servcie時都會調用該方法 @Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("--onStartCommand()--"); data = intent.getStringExtra("data"); return super.onStartCommand(intent, flags, startId); } // 解綁Servcie調用該方法 @Override public boolean onUnbind(Intent intent) { System.out.println("--onUnbind()--"); return super.onUnbind(intent); } // 退出或者銷燬時調用該方法 @Override public void onDestroy() { serviceRunning = false; System.out.println("--onDestroy()--"); super.onDestroy(); } DataCallback dataCallback = null; public DataCallback getDataCallback() { return dataCallback; } public void setDataCallback(DataCallback dataCallback) {//注意這裏以單個回調爲例  若是是向多個activity傳送數據 能夠定義一個回調集合 在此處進行集合的添加 this.dataCallback = dataCallback; } // 經過回調機制,將Service內部的變化傳遞到外部 public interface DataCallback { void dataChanged(String str); } }

 代碼分析:咱們都知道,經過startService啓動一個Service時,Service會調用生命週期函數onStartCommand(),在代碼中建立一個Service,在onStartCommand()方法中獲取從Activity傳遞過來的數據,並在Service的onCreate()方法中開啓一個新的線程,使其循環調用回調函數,以達到通知外界信息改變的目的。並在Service中經過Binder類,將Service與Activity連接起來,以實現信息同步。

2、準備佈局文件

  佈局文件比較簡單,直接貼出,就不分析了,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">

    <TextView
        android:id="@+id/tv_out"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="顯示區域" />
    
    <EditText
        android:id="@+id/et_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10" >

        <requestFocus />
    </EditText>
    
    <Button
        android:id="@+id/btn_start_service"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="startService" />
    
    <Button
        android:id="@+id/btn_stop_service"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="stopService" />
    
    <Button
        android:id="@+id/btn_bind_service"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="bindService" />
    
    <Button
        android:id="@+id/btn_unbind_service"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="unbindService" />
    
    <Button
        android:id="@+id/btn_sync_data"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="同步數據" />

</LinearLayout>

3、準備Activity

   MainActivity代碼以下:


public
class MainActivity extends Activity implements OnClickListener { private Intent intent = null; private Button btn_start_service; private Button btn_stop_service; private Button btn_bind_service; private Button btn_unbind_service; private Button btn_sync_data; private EditText et_data; private TextView tv_out; MyServiceConn myServiceConn; MyService.MyBinder binder = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); intent = new Intent(this, MyService.class); myServiceConn = new MyServiceConn(); setOnClick(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_start_service: //用intent啓動Service並傳值 intent.putExtra("data", et_data.getText().toString()); startService(intent); break; case R.id.btn_stop_service: //中止Service stopService(intent); break; case R.id.btn_bind_service: //綁定Service bindService(intent, myServiceConn, Context.BIND_AUTO_CREATE); break; case R.id.btn_unbind_service: //解綁Service if (binder != null) { unbindService(myServiceConn); } break; case R.id.btn_sync_data: //注意:須要先綁定,才能同步數據 if (binder != null) { binder.setData(et_data.getText().toString()); } break; default: break; } } class MyServiceConn implements ServiceConnection { // 服務被綁定成功以後執行 @Override public void onServiceConnected(ComponentName name, IBinder service) { // IBinder service爲onBind方法返回的Service實例 binder = (MyService.MyBinder) service; binder.getService().setDataCallback(new MyService.DataCallback() { //執行回調函數 @Override public void dataChanged(String str) { Message msg = new Message(); Bundle bundle = new Bundle(); bundle.putString("str", str); msg.setData(bundle); //發送通知 handler.sendMessage(msg); } }); } @SuppressLint("HandlerLeak") Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { //在handler中更新UI tv_out.setText(msg.getData().getString("str")); }; }; // 服務奔潰或者被殺掉執行 @Override public void onServiceDisconnected(ComponentName name) { binder = null; } } private void loadUI() { btn_start_service = (Button) findViewById(R.id.btn_start_service); btn_stop_service = (Button) findViewById(R.id.btn_stop_service); btn_bind_service = (Button) findViewById(R.id.btn_bind_service); btn_unbind_service = (Button) findViewById(R.id.btn_unbind_service); btn_sync_data = (Button) findViewById(R.id.btn_sync_data); et_data = (EditText) findViewById(R.id.et_data); tv_out = (TextView) findViewById(R.id.tv_out); } private void setOnClick() { loadUI(); btn_start_service.setOnClickListener(this); btn_stop_service.setOnClickListener(this); btn_bind_service.setOnClickListener(this); btn_unbind_service.setOnClickListener(this); btn_sync_data.setOnClickListener(this); } }

代碼分析:

  一、加載UI,初始化變量啥的跳過了,主要說一下關鍵代碼,在第28代碼中,與啓動一個Activity相似,經過Intent想要啓動的Service傳遞參數。

  二、在37行經過bindService綁定Service,而後在ServiceConnection中獲取Service類中onBind方法返回的實例,獲取實例Service實例後,咱們就能夠經過調用Service中MyBinder的setData()方法對Service進行同步數據,如48行所示。

  三、整個過程,在Service的onCreate方法中都會循環調用回調函數,同時咱們在MainActivity中重寫回調方法以實現更新UI。

4、測試

  一、啓動示例後,在輸入框輸入你好,而後點擊startService,界面和對應的日誌以下:

    

  看了下面的代碼後就會知道,此時由於沒有綁定service,因此辦法執行回調函數更新UI,因此顯示區域沒有更新。

  二、點擊bindService後,界面以下:

   

  當執行bindService後,在ServiceConnection方法中就會執行執行回調函數更新UI,此時顯示區域開始更新。

  三、改變輸入框內容,點擊同步數據,界面和對應的日誌以下:

   

相關文章
相關標籤/搜索