温馨提示:请带着批判眼光阅读此文!
我们知道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()中进行数据更新也是可以,但我觉的加个回调方法会更灵活一些。。。
好了差不多就这些吧,说的不好,还望各位方家多多指教,不胜感激!!!
View
Code
<?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>