1. 啟動Service并傳遞數(shù)據(jù)
新建項目ConnectService,在 activity_main.xml 修改布局為線性楚殿,走向垂直,添加兩個Button和一個EditText奋献。
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="默認(rèn)信息"
android:id="@+id/etData"/>
<Button
android:text="啟動服務(wù)"
android:id="@+id/btnStartService" />
<Button
android:text="停止服務(wù)"
android:id="@+id/btnStopService" />
然后創(chuàng)建一個Service店枣,接著在 MainActivity.java 創(chuàng)建事件監(jiān)聽器:
private EditText etData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
etData = (EditText) findViewById(R.id.etData);
findViewById(R.id.btnStartService).setOnClickListener(this);
findViewById(R.id.btnStopService).setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.btnStartService:
Intent i = new Intent(this, MyService.class);
i.putExtra("data", etData.getText().toString()); //啟動時,傳遞信息過去粪糙。
startService(i);
break;
case R.id.btnStopService:
stopService(new Intent(this, MyService.class));
break;
}
}
之后在 MyService.java 里邊重寫 onCreate() 和 onDestroy():
public class MyService extends Service {
private boolean running = false;
private String data = "這是默認(rèn)信息";
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
data = intent.getStringExtra("data"); //獲取傳來的信息
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
super.onCreate();
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();
running = false;
}
}
運(yùn)行點擊啟動强霎,控制臺輸出:默認(rèn)信息。
修改文本為 啦啦啦蓉冈,點擊啟動城舞,控制臺輸出:啦啦啦。
通過這種方式就可以在外界與一個服務(wù)進(jìn)行通信寞酿。
2. 綁定Service進(jìn)行通信(上)
通過Binder的方式在Activity和Servise組件中進(jìn)行通信家夺。相比startService那種方式更加方便,而且也會更加高效伐弹,因為這是直接的方法調(diào)用拉馋,比發(fā)一個Intent要方便得多和快得多。
在 activity_main.xml 新添三個按鈕:
<Button
android:text="綁定服務(wù)"
android:id="@+id/btnBindService" />
<Button
android:text="解除綁定服務(wù)"
android:id="@+id/btnUnBindService" />
<Button
android:text="同步數(shù)據(jù)"
android:id="@+id/btnSyncData" />
在 MaiinActivity.java 添加
private MyService.Binder binder = null;
findViewById(R.id.btnBindService).setOnClickListener(this);
findViewById(R.id.btnUnBindService).setOnClickListener(this);
findViewById(R.id.btnSyncData).setOnClickListener(this);
case R.id.btnBindService:
bindService(new Intent(this, MyService.class), this, Context.BIND_AUTO_CREATE);
break;
case R.id.btnUnBindService:
unbindService(this);
break;
case R.id.btnSyncData:
if (binder!=null){
binder.setData(etData.getText().toString());
}
break;
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = (MyService.Binder) service; //這里訪問到的就是MyService.java里邊onBind方法的返回值。
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
在 MyService.java 里創(chuàng)建一個 Binder 類用于連接 Activity 和 Service 組件:
@Override
public IBinder onBind(Intent intent) {
return new Binder();
}
public class Binder extends android.os.Binder{
public void setData(String data){
MyService.this.data =data;
}
}
3. 綁定Service進(jìn)行通信(下)
將內(nèi)部的信息呈現(xiàn)到外界煌茴,
修改 MyService.java:
@Override
public void onCreate() {
super.onCreate();
running = true;
new Thread(){ // 線程來輸出語句
@Override
public void run() {
super.run();
int i = 0;
while(running){
i++;
System.out.println(i+":"+data); //這段只會在控制臺輸出随闺,現(xiàn)在是想把它呈現(xiàn)到activity去
try { // 每隔一秒
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
在主布局activity_main.xml添加一個 TextView:
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/tvOut"/>
然后在 MianActivity.java 里邊獲取到它的Id:
private TextView tvOut;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvOut = (TextView) findViewById(R.id.tvOut);
}
接下就是如何讓內(nèi)部通知外界,使用回調(diào)機(jī)制蔓腐,如何做呢,修改 MyService.java:
private Callback callback = null;
public static interface Calback{ //寫一個接口
void onDataChange(String data)矩乐; //發(fā)一個文字出去
}
public void setCallback(Callback callback) {
this.callback = callback;
}
public Callback getCalkback(){
return callback;
}
@Override
public void onCreate() {
super.onCreate();
running = true;
new Thread(){ // 線程來輸出語句
@Override
public void run() {
super.run();
int i = 0;
while(running){
i++;
String str = i+":"+data; // newadd
System.out.println(str); // newadd
if(callback!=null) { //向外界派發(fā) newadd
callback.onDataChange(str);
}
try { // 每隔一秒
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
那么外界如何來添加這個事件的綁定呢?我們可以在Binder類里面寫一公開的函數(shù)
public class Binder extends android.os.Binder{
public MyService getService(){
return MyService.this;
}
}
接下來我們在外界就可以訪問到它了合住,修改 MainActivity.java :
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = (MyService.Binder) service;
binder.getService().setCallback(new MyService.Callback() {
@Override
public void onDataChange(String data) { //在這里我們就可以獲取Service內(nèi)部所改變的數(shù)據(jù)了
// 接著將數(shù)據(jù)傳給tvOut輸出到activity
// 由于不能直接使用tvOut.setText(),我們定義一個handler
Message msg = new Message();
Bundle b = new Bundle();
b.putString("data", data);
msg.setData(b); // 附加上一個數(shù)據(jù)
handler.sendMessage(msg); //把msg傳過去
}
});
}
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// 這里獲取到msg绰精,進(jìn)一步處理就能把數(shù)據(jù)呈現(xiàn)到activity去了。
tvOut.setText(msg.getData().getString("data"));
}
};
運(yùn)行啟動就可以看到Service內(nèi)部字符串輸出到activity了透葛。