android開(kāi)發(fā)中,作為4大組件的service在開(kāi)發(fā)中經(jīng)常會(huì)使用到。activity用于在前臺(tái)展示湿诊,service用于在后臺(tái)下載芬沉,很多時(shí)候望蜡,我們的activity和service之間需要進(jìn)行相應(yīng)的交互棍厂,activity需要調(diào)用service里面的方法實(shí)現(xiàn)某些功能,service需要調(diào)用activity的方法扯俱,實(shí)現(xiàn)界面更新等的交互书蚪。
一般在Activity中啟動(dòng)后臺(tái)Service,通過(guò)Intent來(lái)啟動(dòng)迅栅,Intent中我們可以傳遞數(shù)據(jù)給Service殊校,而當(dāng)我們Service執(zhí)行某些操作之后想要更新UI線程,我們應(yīng)該怎么做呢读存?我們通過(guò)一個(gè)下載的小例子來(lái)理解它們通信的方式
效果
ibinder.gif
【通過(guò)Binder對(duì)象】
1.Activity通過(guò)Intent向服務(wù)發(fā)送消息为流,通過(guò)調(diào)用bindService(Intent service, ServiceConnection conn,int flags)并綁定,此時(shí)我們可以得到一個(gè)Service的一個(gè)對(duì)象實(shí)例让簿,我們就可以調(diào)用其公開(kāi)的方法敬察。通過(guò)IBinder拿到Service的引用調(diào)用其公開(kāi)的方法。
2.核心總結(jié)下來(lái)就是service中有個(gè)類部類繼承Binder尔当,然后提供一個(gè)公有方法莲祸,返回當(dāng)前service的實(shí)例。 activity通過(guò)bindService來(lái)開(kāi)啟一個(gè)service椭迎,通過(guò)onServiceConnected方法锐帜,獲取IBinder實(shí)例,然后再通過(guò)IBinder實(shí)例來(lái)獲取service實(shí)例畜号,這樣缴阎,我們得到了service的實(shí)例,那么我們的activity就可以隨心所欲的使用它里面的各種方法來(lái)操作它了简软。如果要主動(dòng)通知Activity蛮拔,我們可以利用回調(diào)方法述暂。
3.放出代碼~
布局就不放了,就是一個(gè)小demo语泽,有一個(gè)button贸典,一個(gè)progressbar视卢,一個(gè)textview
首先要寫(xiě)一個(gè)service的類 踱卵,我們命名為MyService
public class MyService extends Service {
//進(jìn)度條最大值
public static final int MAX_PROGRESS = 100;
// 進(jìn)度條的當(dāng)前進(jìn)度值
public int currentProgress=0;
/**
* 更新進(jìn)度的回調(diào)接口
*/
private OnProgressListener onProgressListener;
//開(kāi)啟下載任務(wù)
public void startDownloadTask(final String url){
new Thread(new Runnable() {
@Override
public void run() {
try {
HttpURLConnection connection ;
InputStream input;
OutputStream output;
URL downloadUrl = new URL(url);
connection = (HttpURLConnection) downloadUrl.openConnection();
connection.connect();
input=connection.getInputStream();
output=new FileOutputStream("/sdcard/new.apk");
int fileLength = connection.getContentLength();
byte data[] = new byte[2048];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
currentProgress=(int) (total * 100 / fileLength);//進(jìn)度發(fā)生變化通知調(diào)用方
if(onProgressListener != null){
onProgressListener.onProgress(currentProgress);
}
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
//提供一個(gè)對(duì)外的獲得的progress的值
public int getProgress(){
return currentProgress;
}
/**
* 注冊(cè)回調(diào)接口的方法,供外部調(diào)用
*/
public void setOnProgressListener(OnProgressListener onProgressListener) {
this.onProgressListener = onProgressListener;
}
public MyService() {
}
/**
* 返回一個(gè)Binder對(duì)象
*/
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
//1.service中有個(gè)類部類繼承Binder据过,然后提供一個(gè)公有方法惋砂,返回當(dāng)前service的實(shí)例。
public class MyBinder extends Binder{
public MyService getService(){
return MyService.this;
}
}
}
對(duì)于這個(gè)類提供的幾點(diǎn)說(shuō)明:
1.新建一個(gè)內(nèi)部類MyBinder繼承Binder,提供一個(gè)公有的方法返回當(dāng)前Service的實(shí)例
2.在onbind()方法中返回我們1中的Binder對(duì)象绳锅,activity也是通過(guò)綁定服務(wù)bindservice西饵,并在onServiceConnected中獲取IBinder實(shí)例,然后再通過(guò)IBinder實(shí)例來(lái)獲取service實(shí)例鳞芙。
3.剩下的方法我們直接在activity中調(diào)用即可
OnProgressListener接口代碼眷柔,通過(guò)這個(gè)接口回調(diào)當(dāng)前progress值
public interface OnProgressListener {
void onProgress(int progress);
}
Activity代碼
public class MainActivity extends AppCompatActivity {
private MyService myService;
private ProgressBar progressBar;
private Button button;
private TextView textview;
private String url="xxx";
private ServiceConnection serviceConnection=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//返回一個(gè)MyService對(duì)象
myService=((MyService.MyBinder)service).getService();
myService.setOnProgressListener(new OnProgressListener() {
@Override
public void onProgress(int progress) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//主線程更新UI
progressBar.setProgress(progress);
textview.setText(progress+"%");
}
});
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button= (Button) findViewById(R.id.button);
progressBar= (ProgressBar) findViewById(R.id.progressBar);
textview= (TextView) findViewById(R.id.textView);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myService.startDownloadTask(url);
}
});
Intent intent = new Intent(this,MyService.class);
bindService(intent,serviceConnection,BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
對(duì)于這個(gè)類提供的幾點(diǎn)說(shuō)明:
1.在oncreate中通過(guò)bindservice綁定服務(wù),在 onServiceConnected中獲取service實(shí)例原朝,并通過(guò)回調(diào)返回的progress更新UI驯嘱。
【通過(guò)廣播】
當(dāng)我們的進(jìn)度發(fā)生變化的時(shí)候我們發(fā)送一條廣播,然后在Activity的注冊(cè)廣播接收器喳坠,接收到廣播之后更新ProgressBar鞠评。
放代碼:
不同于上一個(gè)service,我們新建一個(gè)service通過(guò)廣播的方式向activity傳遞
public class MyService2 extends Service {
public MyService2() {
}
//進(jìn)度條最大值
public static final int MAX_PROGRESS = 100;
// 進(jìn)度條的當(dāng)前進(jìn)度值
public int currentProgress=0;
private Intent intent = new Intent("com.test.service.RECEIVER");
//開(kāi)啟下載任務(wù)
public void startDownloadTask(final String url){
new Thread(new Runnable() {
@Override
public void run() {
try {
HttpURLConnection connection ;
InputStream input;
OutputStream output;
URL downloadUrl = new URL(url);
connection = (HttpURLConnection) downloadUrl.openConnection();
connection.connect();
input=connection.getInputStream();
output=new FileOutputStream("/sdcard/new.apk");
int fileLength = connection.getContentLength();
byte data[] = new byte[2048];
long total = 0;
int count;
while ((count = input.read(data)) != -1) {
total += count;
// publishing the progress....
currentProgress=(int) (total * 100 / fileLength);//進(jìn)度發(fā)生變化通知調(diào)用方
//發(fā)送Action為com.test.service.RECEIVER的廣播
intent.putExtra("progress", currentProgress);
sendBroadcast(intent);
output.write(data, 0, count);
}
output.flush();
output.close();
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//通過(guò)startservice啟動(dòng)服務(wù)壕鹉,調(diào)用的是service的onStartCommand方法
//此時(shí)service通過(guò)發(fā)送廣播實(shí)現(xiàn)剃幌,activity注冊(cè)廣播接收器接受進(jìn)度
startDownloadTask((String) intent.getSerializableExtra("url"));
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
//通過(guò)bindservice綁定服務(wù),調(diào)用的是onbind方法晾浴,此時(shí)是通過(guò)IBinder傳遞參數(shù)
//這個(gè)service主要演示的通過(guò)廣播傳遞參數(shù) 這個(gè)方法直接返回空即可
return null;
}
}
Activity代碼
public class Main2Activity extends AppCompatActivity {
private ProgressBar progressBar;
private Button button;
private TextView textview;
private String url="http://app-distribute.oss-cn-qingdao.aliyuncs.com/default/shengji.apk";
private Intent intent;
private MyReceiver myReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button= (Button) findViewById(R.id.button);
progressBar= (ProgressBar) findViewById(R.id.progressBar);
textview= (TextView) findViewById(R.id.textView);
//動(dòng)態(tài)注冊(cè)廣播接收器
myReceiver = new MyReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.test.service.RECEIVER");
registerReceiver(myReceiver, intentFilter);
intent=new Intent(this,MyService2.class);
intent.putExtra("url",url);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//啟動(dòng)服務(wù)
startService(intent);
}
});
}
/**
* 廣播接收器
* @author len
*
*/
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//拿到進(jìn)度负乡,更新UI
int progress = intent.getIntExtra("progress", 0);
progressBar.setProgress(progress);
textview.setText(progress+"%");
}
}
@Override
protected void onDestroy() {
//停止服務(wù)
stopService(intent);
//注銷廣播
unregisterReceiver(myReceiver);
super.onDestroy();
}
}
相比較,如果某個(gè)service要向多個(gè)activity發(fā)送脊凰,用廣播的方式更好一點(diǎn)
【Android IntentService和ResultReceiver的異步處理實(shí)現(xiàn)service與activity的交互】
其他在學(xué)習(xí)過(guò)程中應(yīng)該了解的小知識(shí)點(diǎn)
startService與bindService的區(qū)別
靜態(tài)/動(dòng)態(tài)注冊(cè)廣播的區(qū)別
親抖棘,給個(gè)贊鼓勵(lì)一下吧~