(由于对java的回调机制和线程理解的不够透彻,所以这块内容我理解了好久,尤其是绑定服务传递数据,一句一句写一句一句看,对我来说挺难理解的。以后还要多看几遍--!)
既然单纯的启动或跳转activity没有意义,那么同样的,单纯的启动或绑定service也是无意义的,实际应用中常常要携带数据启动service或绑定service。
1.启动service并传递数据
(1)新建一个Service:MyService
(2)在布局中添加两个按钮,启动服务和停止服务,和一个EditText,用户传递数据
(3)给两个按钮添加监听器,分别执行startService方法和stopService方法
(4)在MyService类中onCreate方法添加一个控制台输出语句,便于我们看到服务的状态和数据的传递效果。
(5)在开始按钮的onClick方法中添加intent.putExtra("data",etData.getText().toString()),用于在activity中初始化和传递数据。
(6)在MyService类中重写onStartCommand方法,其中的intent参数用于接收activity传来的数据。intent.getStringExtra("data");
此时运行程序,点击启动服务,会在控制台输出界面输入框中的数据,更改数据再次点击启动服务,控制台输出的数据也随之改变。点击停止服务,控制台停止输出。
代码如下:
MyService.java:
public class MyService extendsService {private boolean running = false;private String data = "这是默认信息";publicMyService() {
}
@OverridepublicIBinder onBind(Intent intent) {//TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Overridepublic int onStartCommand(Intent intent, int flags, intstartId) {
data= intent.getStringExtra("data");return super.onStartCommand(intent, flags, startId);
}
@Overridepublic voidonCreate() {super.onCreate();
running= true;newThread() {
@Overridepublic voidrun() {super.run();while(running){
System.out.println(data);try{
sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
@Overridepublic voidonDestroy() {super.onDestroy();
running= false;
}
}
MainActivity.java:
importandroid.os.Bundle;importandroid.support.v7.widget.SwitchCompat;importandroid.view.View;importandroid.widget.EditText;importlayout.MyService;public class MainActivity extends AppCompatActivity implementsView.OnClickListener{privateEditText etData;
@Overrideprotected voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btnStartSevice).setOnClickListener(this);
findViewById(R.id.btnStopSevice).setOnClickListener(this);
etData=(EditText) findViewById(R.id.etData);
}
@Overridepublic voidonClick(View view) {switch(view.getId()) {caseR.id.btnStartSevice:
Intent i= new Intent(this, MyService.class);
i.putExtra("data",etData.getText().toString());
startService(i);break;caseR.id.btnStopSevice:
stopService(new Intent(this,MyService.class));break;
}
}
}
activity_main.xml:
2.绑定服务并传递数据(执行服务的内部代码)
(1)在布局中添加三个按钮,绑定服务、解除绑定服务、同步数据,同步数据按钮是用来同步activity传到service的数据。
(2)给绑定服务和解除绑定服务按钮添加监听器,执行以下代码
绑定服务:bindService(new Intent(this,MyService.class),this, Context.BIND_AUTO_CREATE);
解除绑定服务:unbindService(this);
(3)同时实现两个方法onServiceConnected()和onServiceDisconnectid();
(4)在MyService类中添加一个Binder 类,该类内添加一个成员方方法setData()用来实时更改数据。
public class Binder extendsandroid.os.Binder{public voidsetData(String data){
MyService.this.data =data;
}
}
(5)在MyService类中的onBind方法中添加return new Binder();返回上一步新建的类的一个对象作为一个activity与service绑定的纽带。
(6)回到MainActivity.java,创建一个binder:MyService.Binder binder = null;
(7)在onServiceConnected()方法中添加 binder = (MyService.Binder) iBinder;
(8)在同步数据按钮的onClick()方法中执行以下代码:
if(binder!=null){
binder.setData(etData.getText().toString());
}
至此完成绑定服务并传递数据。这样的用法好处是不用每次同步数据时都发送一个intent,而是直接通过调用方法来同步数据,保证了代码的高效性,也很快捷。
3.绑定服务并传递数据(侦听服务内部状态)
利用java的回调机制,从activity传递数据到service,service接到数据或数据改变时回调回来呈现在activity中
(1)在MyService类中添加一个CallBack接口,添加抽象方法onDataChange()。
(2)在MyService类中创建CallBack的对象,并添加get和set方法。
(3)在binder类中添加一个getService()方法,返回MyService.this.
(4)回到外部的MainActivity,布局添加一个TextView用于显示服务的状态。
(5)在onServiceConnected方法中添加binder.getService().setCallback(),给service添加回调函数,并且实现onDataChange方法,把数据通过Message传给Handler。
(6)在MainActivity中添加一个Handler(由于安全机制,安卓的UI线程不允许随意被调用。所以只能用Handler来改变UI),在Handler中改变TextView的值。
所有的代码如下:
MyService.java:
importandroid.app.Service;importandroid.content.Intent;importandroid.os.Binder;importandroid.os.IBinder;public class MyService extendsService {private boolean running = false;private String data = "这是默认信息";publicMyService() {
}
@OverridepublicIBinder onBind(Intent intent) {return newBinder();
}public class Binder extendsandroid.os.Binder{public voidsetData(String data){
MyService.this.data =data;
}publicMyService getService(){return MyService.this;
}
}
@Overridepublic int onStartCommand(Intent intent, int flags, intstartId) {
data= intent.getStringExtra("data");return super.onStartCommand(intent, flags, startId);
}
@Overridepublic voidonCreate() {super.onCreate();
running= true;newThread() {
@Overridepublic voidrun() {super.run();int i = 0;while(running){
i++;
String str= i+":"+data;
System.out.println(i+":"+data);if(callback!=null){
callback.onDataChange(str);
}try{
sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
@Overridepublic voidonDestroy() {super.onDestroy();
running= false;
}private CallBack callback = null;public voidsetCallback(CallBack callback) {this.callback =callback;
}publicCallBack getCallback() {returncallback;
}public static interfaceCallBack{voidonDataChange(String data);
}
}
activity_main.xml和MainActivity:
importandroid.content.ComponentName;importandroid.content.Context;importandroid.content.Intent;importandroid.content.ServiceConnection;importandroid.os.Handler;importandroid.os.IBinder;importandroid.os.Message;importandroid.support.v7.app.AppCompatActivity;importandroid.os.Bundle;importandroid.support.v7.widget.SwitchCompat;importandroid.view.View;importandroid.widget.EditText;importandroid.widget.TextView;importlayout.MyService;public class MainActivity extends AppCompatActivity implementsView.OnClickListener, ServiceConnection {privateEditText etData;privateTextView tvOut;private MyService.Binder binder = null;
@Overrideprotected voidonCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etData=(EditText) findViewById(R.id.etData);
findViewById(R.id.btnStartSevice).setOnClickListener(this);
findViewById(R.id.btnStopSevice).setOnClickListener(this);
findViewById(R.id.btnBindService).setOnClickListener(this);
findViewById(R.id.btnUnbindService).setOnClickListener(this);
findViewById(R.id.btnSyncData).setOnClickListener(this);
tvOut=(TextView) findViewById(R.id.tvOut);
}
@Overridepublic voidonClick(View view) {switch(view.getId()) {caseR.id.btnStartSevice:
Intent i= new Intent(this, MyService.class);
i.putExtra("data",etData.getText().toString());
startService(i);break;caseR.id.btnStopSevice:
stopService(new Intent(this,MyService.class));break;caseR.id.btnBindService:
bindService(new Intent(this,MyService.class),this, Context.BIND_AUTO_CREATE);break;caseR.id.btnUnbindService:
unbindService(this);break;caseR.id.btnSyncData:if(binder!=null){
binder.setData(etData.getText().toString());
}break;
}
}
@Overridepublic voidonServiceConnected(ComponentName componentName, IBinder iBinder) {
binder=(MyService.Binder) iBinder;
binder.getService().setCallback(newMyService.CallBack() {
@Overridepublic voidonDataChange(String data) {
Message msg= newMessage();
Bundle b= newBundle();
b.putString("data",data);
msg.setData(b);
handler.sendMessage(msg);
}
});
}
@Overridepublic voidonServiceDisconnected(ComponentName componentName) {
}private Handler handler = newHandler(){
@Overridepublic voidhandleMessage(Message msg) {super.handleMessage(msg);
tvOut.setText(msg.getData().getString("data"));
}
};
}