Activity與Service之間交互(通過(guò)Binder對(duì)象和廣播)

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ì)一下吧~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市笙各,隨后出現(xiàn)的幾起案子钉答,更是在濱河造成了極大的恐慌,老刑警劉巖杈抢,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件数尿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡惶楼,警方通過(guò)查閱死者的電腦和手機(jī)右蹦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)诊杆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人何陆,你說(shuō)我怎么就攤上這事晨汹。” “怎么了贷盲?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵淘这,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我巩剖,道長(zhǎng)铝穷,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任佳魔,我火速辦了婚禮曙聂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鞠鲜。我一直安慰自己宁脊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布贤姆。 她就那樣靜靜地躺著榆苞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪庐氮。 梳的紋絲不亂的頭發(fā)上语稠,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音弄砍,去河邊找鬼仙畦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛音婶,可吹牛的內(nèi)容都是我干的慨畸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼衣式,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼寸士!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起碴卧,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤弱卡,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后住册,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體婶博,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年荧飞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凡人。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片名党。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖挠轴,靈堂內(nèi)的尸體忽然破棺而出传睹,到底是詐尸還是另有隱情,我是刑警寧澤岸晦,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布欧啤,位于F島的核電站,受9級(jí)特大地震影響委煤,放射性物質(zhì)發(fā)生泄漏堂油。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一碧绞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吱窝,春花似錦讥邻、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至照激,卻和暖如春发魄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背俩垃。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工励幼, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人口柳。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓苹粟,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親跃闹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嵌削,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • HandlerThread是一個(gè)Android 已封裝好的輕量級(jí)異步類。HandlerThread本質(zhì)上是一個(gè)線程...
    kjy_112233閱讀 1,290評(píng)論 0 9
  • 本文主要搜集記錄一下Android開(kāi)發(fā)的四大組件:一望艺、Activity詳解二苛秕、Service詳解三、Broadca...
    AFinalStone閱讀 604評(píng)論 0 2
  • 最近剛從舊公司離職找默,為面試在做準(zhǔn)備艇劫,因?yàn)槠綍r(shí)開(kāi)發(fā)CV大法用得比較多,很多基礎(chǔ)知識(shí)掌握得不是很牢靠以及很多工具框架只...
    黎清海閱讀 2,196評(píng)論 1 19
  • Service是Android四大組件中與Activity最相似的組件啡莉,他們都代表可執(zhí)行的程序港准,Service與A...
    AndYMJ閱讀 1,806評(píng)論 0 3
  • 人的一生貌似是刻意規(guī)劃和安排的旨剥。父母在他們認(rèn)為合適的時(shí)機(jī)讓我們降生,在合適年齡送我們?nèi)W(xué)校浅缸,指導(dǎo)我們考大學(xué)轨帜,安排我...
    面條君閱讀 1,274評(píng)論 2 2