本文源码:https://github.com/gitEkko/MyApplication.git
Service简介
Service是android 系统中的四大组件之一(Activity、Service、BroadcastReceiver、ContentProvider),它跟 Activity的级别差不多,但不能自己运行只能后台运行,并且可以和其他组件进行交互。service可以在很多场合的应用中使用,比如播放多媒体的 时候用户启动了其他Activity这个时候程序要在后台继续播放,比如检测SD卡上文件的变化,再或者在后台记录你地理信息位置的改变等等,总之服务总是藏在后台的。
这里主要总结Service和Activity进行互相通信的两种方式:
- 通过Binder对象,绑定服务的方式,实现ServiceConnection接口。
- 通过广播
一、绑定服务的方式,实现ServiceConnection接口
bindService() - unbindService()
1.进行数据传递
- Service中声明一个Binder类,类中声明用来传递数据的方法。比如向Activity返回Service实例/接受或返回数据。
- Activity实现ServiceConnection接口,Activity绑定Service调用bindService()方法。此时onServiceConnected()方法就会被调用。此方法中利用获取的Binder实例,可以调用Service中各个用来传递数据的方法。
这就实现了Activity向Service传递数据,Service接收数据进行数据操作后,再返回给Activity。
2.Activity监听Service数据变化
- Service自定义Callback接口,声明监听数据的抽象函数onDataChange(String data),参数data用来向外部暴露data数据,并设置callback实例的setter方法。再onCreat()方法中,Service利用接收来的data数据,进行耗时操作后(例如开启线程进行data的循环递增),用callback.onDataChange(data + "")暴露data数据。
- Activity在onServiceConnected()方法中,利用获取的Service实例调用setCallback()方法,同时实例化Callback接口,进行接口回调实现onDataChange()函数,此时就监听到了Service中data数据的状态,并利用Handler进行更新UI操作。
myService2.java
public class MyService2 extends Service {
private static final String TAG = "xxxx";
private boolean connecting = false;
private Callback callback;
public int data = 0;
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
class MyBinder extends Binder {
//向Activity返回MyService2实例
MyService2 getService() {
return MyService2.this;
}
//获取从Activity传来的数据
void TransferData(int mData) {
data = mData;
}
//将data数值传递给Activity
int getData() {
return data;
}
}
@Override
public void onCreate() {
super.onCreate();
connecting = true;
//开启一个线程,对数据进行处理
new Thread(new Runnable() {
@Override
public void run() {
while (connecting) {
if (callback != null) {
callback.onDataChange(data + "");
}
data++;
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
public void setCallback(Callback callback) {
this.callback = callback;
}
public Callback getCallback() {
return callback;
}
public interface Callback {
void onDataChange(String data);
}
@Override
public void onDestroy() {
super.onDestroy();
connecting = false;
}
}
ServiceActivity2.java
public class ServiceActivity2 extends AppCompatActivity implements View.OnClickListener, ServiceConnection {
private static final String TAG = "xxxx";
private TextView textView;
private boolean bind = false;
private int TransforData;
MyService2.MyBinder binder = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service2);
TransforData = 0;
textView = (TextView) findViewById(R.id.textView);
Button bindBtn = (Button) findViewById(R.id.bind_service2);
Button unBindBtn = (Button) findViewById(R.id.unbind_service2);
Button clearBt = (Button) findViewById(R.id.clear);
bindBtn.setOnClickListener(this);
unBindBtn.setOnClickListener(this);
clearBt.setOnClickListener(this);
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//获取binder对象
binder = (MyService2.MyBinder) service;
//向Service传递数据 TransforData
binder.TransferData(TransforData);
//获取从Service传递的MyService对象
MyService2 myService2 = binder.getService();
//接口回调 监控Service中的数据变化 并在handler中更新UI
myService2.setCallback(new MyService2.Callback() {
@Override
public void onDataChange(String data) {
Message msg = new Message();
msg.obj = data;
handler.sendMessage(msg);
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bind_service2:
if (!bind) {
bind = true;
//服务绑定后,会调用 onServiceConnected
Intent bindIntent = new Intent(this, MyService2.class);
bindService(bindIntent, this, BIND_AUTO_CREATE);
Toast.makeText(this, "Bind Service Success!", Toast.LENGTH_SHORT).show();
}
break;
case R.id.unbind_service2:
if (bind) {
//从Service中获取data数值
TransforData = binder.getData();
unbindService(this);
bind = false;
Toast.makeText(this, "unBind Service Success!", Toast.LENGTH_SHORT).show();
}
break;
case R.id.clear:
if (!bind) {
TransforData = 0;
textView.setText("0");
}
break;
default:
break;
}
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//在此处更新UI
textView.setText(msg.obj.toString());
}
};
}
二、利用广播方式
startService() - stopService()
- Activity:动态注册广播 。将data存储到intent中,调用startService(intent)开启服务。
- Service:重写onStartCommand()方法,利用intent.getXXExtra()获取Activity传来的数据。对数据进行操作后,将data存到intent中并发送广播。
- Activity:接收广播,重写onReceive()函数,开启主线程并从intent中取出data数据,进行更新UI操作。
利用广播和intent实现了数据通信和监听服务数据状态。
MyService3.java
public class MyService3 extends Service {
private boolean connecting = false;
public static final String COUNTER = "data";
public static final String ACTION_NAME = "com.example.myinterview.service3.COUNTER_ACTION";
private int data;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//从Activity获取data
data = intent.getIntExtra(COUNTER, 0);
final Intent mIntent = new Intent();
mIntent.setAction(ACTION_NAME);
connecting = true;
//开启一个线程,对数据进行处理
new Thread(new Runnable() {
@Override
public void run() {
try {
while (connecting) {
//耗时操作:数据处理并保存,向Activity发送广播
mIntent.putExtra(COUNTER, data);
sendBroadcast(mIntent);
data++;
Thread.sleep(300);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
connecting = false;
}
}
ServiceActivity3.java
public class ServiceActivity3 extends AppCompatActivity implements View.OnClickListener {
private int TransforData;
private TextView textView;
private Intent mIntent;
private MyReceiver myReceiver;
private boolean bind = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service3);
TransforData = 0;
textView = (TextView) findViewById(R.id.textView);
Button startBtn = (Button) findViewById(R.id.mstart);
Button pauseBtn = (Button) findViewById(R.id.pause);
Button clearBt = (Button) findViewById(R.id.clear);
startBtn.setOnClickListener(this);
pauseBtn.setOnClickListener(this);
clearBt.setOnClickListener(this);
mIntent = new Intent(this, MyService3.class);
myReceiver = new MyReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(MyService3.ACTION_NAME);
//注册广播
registerReceiver(myReceiver, intentFilter);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.mstart:
if (!bind) {
bind = true;
//向Service传递data
mIntent.putExtra(MyService3.COUNTER, TransforData);
startService(mIntent);
Toast.makeText(this, "Start!", Toast.LENGTH_SHORT).show();
}
break;
case R.id.pause:
//停止服务
stopService(mIntent);
bind = false;
break;
case R.id.clear:
if (!bind) {
TransforData = 0;
textView.setText("0");
Toast.makeText(this, "Pause!", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, final Intent intent) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//获取从Service中传来的data
TransforData = intent.getIntExtra(MyService3.COUNTER, 0);
//更新UI
textView.setText(String.valueOf(TransforData));
}
});
}
}
@Override
protected void onDestroy() {
stopService(mIntent);
unregisterReceiver(myReceiver);
super.onDestroy();
}
}
两种方式共同实现了秒表的开始、暂停、清零。
- Service和Activity互相传递data数据
- Activity监控Service中的数据变化状态