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è)類(lèi)部類(lèi)繼承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的類(lèi) ,我們命名為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è)類(lèi)部類(lèi)繼承Binder,然后提供一個(gè)公有方法,返回當(dāng)前service的實(shí)例。
    public class  MyBinder extends Binder{
        public MyService getService(){
            return MyService.this;
        }

    }
}

對(duì)于這個(gè)類(lèi)提供的幾點(diǎn)說(shuō)明:
1.新建一個(gè)內(nèi)部類(lè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è)類(lèi)提供的幾點(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);
        //注銷(xiāo)廣播
        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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容