溫馨提示:請帶着批判眼光閱讀此文!
我們知道Android的程序架構本身即是遵循MVC模式設計的,將顯示和邏輯操作進行了很好的分離。xml文件進行view的添加和布局,Activity來實現各種View的展示,而service實現將數據按一定邏輯在View中顯示。基於這樣的原則我們設計程序時,就需要做到讓他們各司其職,合理搭配,如此才能使我們設計的Android程序更高效,更安全以及易於維護,當然這是一個很大很大很大的話題,此處我只對service和Activity的職責進行簡單闡述,希望能起到拋磚引玉的作用,當然若內容如有雷同不勝榮幸.
Service是在Android程序后台運行的組件,比如音樂播放,網絡下載等,這些操作的確都可以在service中完成,但並不是說我們只可以再service中完成,在Activity中一樣可以實現,那為什么我們還要一個service呢,曾經我也疑惑過,后來我知道了在Android中又五個進程等級(1.Foreground Process: 2.Visible Process 3.ServiceProcess 4.Background Process 5.Empty Procecc)在系統內存資源不夠的時候,系統會首先將等級較低的進程殺死來滿足其他高等級的進程正常運行,而service正處於第三等級,而被覆蓋住的Activiy處於第四等級,這樣當我們在運行程序時因為某種原因而將當前Activity覆蓋,那我們在該Activity中的很多操作尤其需要網絡交互的很可能會因為系統內存資源不足,而將其殺掉。這樣就會導致數據的不完成,使程序的魯棒性不夠強,而如果將他們都放在service中實現那就穩妥多了,程序也相對穩定多了。當然程序的穩定性是由很多因素構成的,這只是其中之一而已。那好,既然說放在service中操作,那就在那兒操作吧,這不就完了嗎,可是就在我們准備這樣做時,總會意識到一個問題,當我們把這些操作統統放到service中實現時,那Activity的中控件的更新怎么辦,比如因為播放總會有進度條的,文件下載也是要時時更新下載量的,不知道各位怎么處理這個問題的,我在網上查了查,看到的方法都是通過廣播,即在 Activity中注冊一個廣播,然后通過廣播進行service和Activity間的數據傳遞,同時以達到更新UI的目的,雖然我沒這么做過,但我知道這是可以的,但我總覺的,這樣有點勞師動眾了,而且我曾經用了一次廣播,根據我的使用的效果來說覺得廣播不適合做一些時時更新的操作(具體原因我沒有深入研究過,不敢過多評論),反應不夠及時。所以我自己就試着用別的方法進行UI更新,最后我覺得通過Binder對象實現,怎么實現我就不用文字說明了,下面我就隨便寫了個例子簡單說明。拋磚引玉吧
用來更新UI的service
1 package com.gqs.service; 2 3 import android.app.Service; 4 import android.content.Intent; 5 import android.os.Binder; 6 import android.os.Handler; 7 import android.os.IBinder; 8 import android.os.Message; 9 import android.widget.TextView; 10 11 public class UpdateService extends Service { 12 private int data; 13 private Handler handler; 14 private boolean isStart;
prrivate boolean startUpdate; 15 @Override 16 public IBinder onBind(Intent intent) {
isStart = true; 17 new Thread(new MyThread()).start; 18 return new MyBinder(); 19 } 20 21 public class MyBinder extends Binder { 22 public void setDate(final TextView tv, final UpdateData updata) { 23 startUpdate = true;24 handler = new Handler() { 25 public void handleMessage(Message msg) { 26 updata.update(tv, data); 27 } 28 }; 29 } 30 } 31 32 public class MyThread implements Runnable { 33 34 @Override 35 public void run() { 36 while (isStart) {
if(startUpdate)
{ 37 data++; 38 Message msg = handler.obtainMessage(); 39 msg.arg1 = data; 40 handler.sendMessage(msg);
} 41 try { 42 Thread.sleep(1000); 43 } catch (InterruptedException e) { 44 // TODO Auto-generated catch block 45 e.printStackTrace(); 46 } 47 } 48 } 49 50 } 51 52 public interface UpdateData { 53 public void update(TextView tv, int data); 54 55 } 56 }
用來顯示的Activity
package com.gqs.activity; 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; import android.widget.TextView; import android.widget.Toast; import com.gqs.service.UpdateService; import com.gqs.service.UpdateService.MyBinder; import com.gqs.service.UpdateService.UpdateData; public class ServiceToActivityActivity extends Activity { /** Called when the activity is first created. */ private TextView tv; private UpdateService.MyBinder binder; private Button btnStart; private ServiceConnection conn=new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub } @Override public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub binder=(MyBinder) service; tv.setText("已連接"); } }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btnStart=(Button)findViewById(R.id.btnStart); tv=(TextView)findViewById(R.id.textView); Intent intent=new Intent(this,UpdateService.class); bindService(intent, conn, Context.BIND_AUTO_CREATE); btnStart.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub if(binder!=null) { binder.setDate(tv, new UpdateData() { @Override public void update(TextView tv, int data) { // TODO Auto-generated method stub tv.setText(data+""); } }); } else { Toast.makeText(getApplicationContext(), "連接失敗", 1).show(); } } }); } @Override protected void onDestroy() { // TODO Auto-generated method stub unbindService(conn); super.onDestroy(); } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/textView" android:text="@string/hello" /> <Button android:text="開始" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnStart" /> </LinearLayout>
大致就是這樣 代碼很簡單,通過繼承Binder類和一個回調方法實現對view的更新。當然如果不要回調方法也可以,那就直接在handleMessage()中進行數據更新也是可以,但我覺的加個回調方法會更靈活一些。。。
好了差不多就這些吧,說的不好,還望各位方家多多指教,不勝感激!!!

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/textView" android:text="@string/hello" /> <Button android:text="開始" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/btnStart" /> </LinearLayout>