课程背景:
Service 是 Android 四大基本组件之一,是无界面的应用程序,可以长期在后台运行,在实际工作中非常重要。
核心内容:
绑定Service并与之通信
启动 Service 并传递数据
启动Service,传数据
//定义一个文本框,获取文本
private EditText etData;
etData = (EditText) findViewById(R.id.etData);
//通过Intent,传递给Service
Intent i = new Intent(MainActivity.this, MyService.class);
i.putExtra("data", etData.getText().toString());
startService(i);
Service中接收数据,处理输出数据
private boolean running = false;
private String data = "这是默认信息";
//Service中通过Command获取传来的Intent
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
data = intent.getStringExtra("data");
return super.onStartCommand(intent, flags, startId);
}
//生命周期:第一次创建Service时,先onCreate(),再onStartCommand()。之后如果没有destroy,那么每次停止后重新启动,则只执行onCommand
@Override
public void onCreate() {
super.onCreate();
System.out.println("启动了");
running = true;
//创建Service后,创建一个线程用来输出
new Thread(){
@Override
public void run() {
super.run();
while (running) {
System.out.println(data);
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start()
}
绑定 Service 进行通信(上)
Service绑定详细说明见上一篇笔记:《Android笔记3.7》 认识 Android Service()
Service:MyService.java
public class MyService extends Service {
private boolean running = false;
private String data = "这是默认信息";
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return new Binder();
}
//这个类的继承是重点,将Serivice的引用binder传回给Activity,可以使用的所有操作,都在这个类下边的public方法中定义
public class Binder extends android.os.Binder {
//定义了public的方法,来供Activity操作Service中的变量数据
public void setData(String data) {
MyService.this.data = data;
}
//回调所必须的,用于返回Service实例的引用给Aty
public MyService getService(){
return MyService.this;
}
}
//Service中通过Command获取传来的Intent
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("执行onStartCommand");
data = intent.getStringExtra("data");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
super.onCreate();
System.out.println("启动了");
running = true;
new Thread(){
@Override
public void run() {
super.run();
while (running) {
System.out.println(data);
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("结束了");
running = false;
}
}
Activity:MainActivity.java
//定义Service的Binder
private MyService.Binder binder=null;
//重载连接时的方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//绑定连接成功后,得到Service实例的引用
binder = (MyService.Binder) service;
}
//用事先在Service中设置的public方法,进行对Serivce的数据操作
binder.setData(etData.getText().toString());
绑定 Service 进行通信(下)
本课时讲解如何侦听被绑定的 Service 的内部状态。
关于动态侦听Service中的变化,并显示到MainActivity,使用Callback回调。
原理:
onServiceConnected的时候会获取一个Service实例的引用,然后在Aty中传一个匿名Callback对象给Service,其中重载了Service里Callback接口的一个方法,这个Aty自定的方法实现的就是让Service自己执行修改Aty中内容
如onChangeData(String data){/*这里就可以定义Service回调接口方法的执行代码*/}
Aty中:
//Aty中获取Service实例,并重载设置接口的onDataChange方法,用于让Service自身具有回调修改Aty内容的功能
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
System.out.println("ServiceConnected");
binder = (MyService.Binder) service;
binder.getService().setCallback(new MyService.Callback() {
@Override
public void onDataChange(String data) {//方法在Service中先声明过,这里重载并写具体功能代码,最后是由Service来调用执行的,Service本事并不会写具体功能代码,只提供一个可以传递String的接口,或其他自定义借口i
Message msg = new Message();
Bundle b = new Bundle();
b.putString("data", data);
msg.setData(b);
handler.sendMessage(msg);//通过handler来修改Aty的Ui内容,修改代码是写在Aty中
}
});
}
Service中:
private Callback callback = null;
public void setCallback(Callback callback) {
this.callback = callback;
}
public Callback getCallback() {
return callback;
}
public static interface Callback {
//提供一个接口,具体功能代码由Aty去自己写
void onDataChange(String data);
}
Aty中:
//Service里的线程,不能直接操作Aty的UI,可通过android.os.Handler,来发送一条消息指令,具体代码写在Aty中,通过向Aty发送指令,让Aty自己实现修改。
public Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
tvOut.setText(msg.getData().getString("data"));
}
};
//调用接口,执行由Aty指定的具体功能
if (callback != null) {
callback.onDataChange(str);
}
Callback类本事是一个接口,在Service实现接口,自定义一个所需的方法:onChangeData(String data),但是Service本身不去实现这个接口,而是开放给所有的Activity来自己实现。
所以,本例中,Service做的事情,只是给出一个带有String参数的接口供Aty定义。
Aty定义这个接口为修改自身的TextView内容(通过Handler,因为Service中的Thread()是不能直接操作UI的,需通过HandlerMessage,来传回一个Bundle给Aty,再在Aty中处理HandlerMessage,来修改自己的UI内容)。
关于回调函数的思路的基本清晰了,虽然这里描述的有点随意,以后实际项目中再详细体会吧。进入下一章节。
贴一个完整的Service通信demo代码:
Service.java
1 package com.lanyunwork.l38_connectservice;
2
3 import android.app.Service;
4 import android.content.Intent;
5 import android.os.Binder;
6 import android.os.IBinder;
7
8 public class MyService extends Service {
9 private boolean running = false;
10 private String data = "这是默认信息";
11
12 public MyService() {
13 }
14
15 @Override
16 public IBinder onBind(Intent intent) {
17 // TODO: Return the communication channel to the service.
18 return new Binder();
19 }
20
21 public class Binder extends android.os.Binder {
22 public void setData(String data) {
23 MyService.this.data = data;
24 }
25
26 public MyService getService(){
27 return MyService.this;
28 }
29 }
30
31 //Service中通过Command获取传来的Intent
32 @Override
33 public int onStartCommand(Intent intent, int flags, int startId) {
34 System.out.println("执行onStartCommand");
35 data = intent.getStringExtra("data");
36
37 return super.onStartCommand(intent, flags, startId);
38 }
39
40 @Override
41 public void onCreate() {
42 super.onCreate();
43 System.out.println("启动了");
44
45 running = true;
46 new Thread() {
47 @Override
48 public void run() {
49 super.run();
50
51 int i = 0;
52
53 while (running) {
54
55 i++;
56
57 String str = i + ": " + data;
58 System.out.println(str);
59
60 if (callback != null) {
61 callback.onDataChange(str);
62 }
63
64 try {
65 sleep(1000);
66 } catch (InterruptedException e) {
67 e.printStackTrace();
68 }
69 }
70 }
71 }.start();
72 }
73
74 @Override
75 public void onDestroy() {
76 super.onDestroy();
77 System.out.println("结束了");
78
79 running = false;
80 }
81
82 private Callback callback = null;
83
84 public void setCallback(Callback callback) {
85 this.callback = callback;
86 }
87
88 public Callback getCallback() {
89 return callback;
90 }
91
92 public static interface Callback {
93 void onDataChange(String data);
94 }
95 }
MainActivity.java
1 package com.lanyunwork.l38_connectservice;
2
3 import android.content.ComponentName;
4 import android.content.Context;
5 import android.content.Intent;
6 import android.content.ServiceConnection;
7 import android.os.IBinder;
8 import android.os.Message;
9 import android.os.Parcelable;
10 import android.support.v7.app.ActionBarActivity;
11 import android.os.Bundle;
12 import android.os.Handler;
13 import android.view.Menu;
14 import android.view.MenuItem;
15 import android.view.View;
16 import android.widget.EditText;
17 import android.widget.TextView;
18
19
20
21 public class MainActivity extends ActionBarActivity implements View.OnClickListener, ServiceConnection {
22
23 private EditText etData;
24 private MyService.Binder binder;
25 private TextView tvOut;
26
27 @Override
28 protected void onCreate(Bundle savedInstanceState) {
29 super.onCreate(savedInstanceState);
30 setContentView(R.layout.activity_main);
31
32 etData = (EditText) findViewById(R.id.etData);
33 tvOut = (TextView) findViewById(R.id.tvOut);
34
35 findViewById(R.id.btnStartService).setOnClickListener(this);
36 findViewById(R.id.btnStopService).setOnClickListener(this);
37 findViewById(R.id.btnBindService).setOnClickListener(this);
38 findViewById(R.id.btnUnBindService).setOnClickListener(this);
39 findViewById(R.id.btnSyncData).setOnClickListener(this);
40 }
41
42 @Override
43 public boolean onCreateOptionsMenu(Menu menu) {
44 // Inflate the menu; this adds items to the action bar if it is present.
45 getMenuInflater().inflate(R.menu.menu_main, menu);
46 return true;
47 }
48
49 @Override
50 public boolean onOptionsItemSelected(MenuItem item) {
51 // Handle action bar item clicks here. The action bar will
52 // automatically handle clicks on the Home/Up button, so long
53 // as you specify a parent activity in AndroidManifest.xml.
54 int id = item.getItemId();
55
56 //noinspection SimplifiableIfStatement
57 if (id == R.id.action_settings) {
58 return true;
59 }
60
61 return super.onOptionsItemSelected(item);
62 }
63
64 @Override
65 public void onClick(View v) {
66 Intent i = new Intent(MainActivity.this, MyService.class);
67 i.putExtra("data", etData.getText().toString());
68 switch (v.getId()){
69 case R.id.btnStartService:
70 startService(i);
71 break;
72 case R.id.btnStopService:
73 stopService(i);
74 break;
75 case R.id.btnBindService:
76 bindService(new Intent(this, MyService.class), this, Context.BIND_AUTO_CREATE);
77 break;
78 case R.id.btnUnBindService:
79 unbindService(this);
80 break;
81 case R.id.btnSyncData:
82 if (binder != null){
83 binder.setData(etData.getText().toString());
84 }
85 break;
86 }
87 }
88
89 @Override
90 public void onServiceConnected(ComponentName name, IBinder service) {
91 System.out.println("ServiceConnected");
92
93 binder = (MyService.Binder) service;
94 binder.getService().setCallback(new MyService.Callback() {
95 @Override
96 public void onDataChange(String data) {
97 Message msg = new Message();
98 Bundle b = new Bundle();
99 b.putString("data", data);
100 msg.setData(b);
101 handler.sendMessage(msg);
102 }
103 });
104 }
105
106 @Override
107 public void onServiceDisconnected(ComponentName name) {
108 System.out.println("ServiceDisconnected");
109 }
110
111 public Handler handler = new Handler(){
112 @Override
113 public void handleMessage(Message msg) {
114 super.handleMessage(msg);
115
116 tvOut.setText(msg.getData().getString("data"));
117 }
118 };
119 }