美文网首页Android开发经验谈Android开发Android开发
Activity与Service之间交互(通过Binder对象和

Activity与Service之间交互(通过Binder对象和

作者: 芒果味的你呀 | 来源:发表于2017-10-13 11:33 被阅读268次

    android开发中,作为4大组件的service在开发中经常会使用到。activity用于在前台展示,service用于在后台下载,很多时候,我们的activity和service之间需要进行相应的交互,activity需要调用service里面的方法实现某些功能,service需要调用activity的方法,实现界面更新等的交互。

    一般在Activity中启动后台Service,通过Intent来启动,Intent中我们可以传递数据给Service,而当我们Service执行某些操作之后想要更新UI线程,我们应该怎么做呢?我们通过一个下载的小例子来理解它们通信的方式

    效果
    ibinder.gif

    【通过Binder对象】

    1.Activity通过Intent向服务发送消息,通过调用bindService(Intent service, ServiceConnection conn,int flags)并绑定,此时我们可以得到一个Service的一个对象实例,我们就可以调用其公开的方法。通过IBinder拿到Service的引用调用其公开的方法。

    2.核心总结下来就是service中有个类部类继承Binder,然后提供一个公有方法,返回当前service的实例。 activity通过bindService来开启一个service,通过onServiceConnected方法,获取IBinder实例,然后再通过IBinder实例来获取service实例,这样,我们得到了service的实例,那么我们的activity就可以随心所欲的使用它里面的各种方法来操作它了。如果要主动通知Activity,我们可以利用回调方法。

    3.放出代码~

    布局就不放了,就是一个小demo,有一个button,一个progressbar,一个textview
    首先要写一个service的类 ,我们命名为MyService
    public class MyService extends Service {
        //进度条最大值
        public static final int MAX_PROGRESS = 100;
        // 进度条的当前进度值
        public int currentProgress=0;
        /**
         * 更新进度的回调接口
         */
        private OnProgressListener onProgressListener;
        //开启下载任务
        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);//进度发生变化通知调用方
                            if(onProgressListener != null){
                                onProgressListener.onProgress(currentProgress);
                            }
                            output.write(data, 0, count);
                        }
                        output.flush();
                        output.close();
                        input.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
    
                }
            }).start();
        }
        //提供一个对外的获得的progress的值
        public int getProgress(){
            return currentProgress;
        }
        /**
         * 注册回调接口的方法,供外部调用
         */
        public void setOnProgressListener(OnProgressListener onProgressListener) {
            this.onProgressListener = onProgressListener;
        }
        public MyService() {
        }
    
        /**
         * 返回一个Binder对象
         */
        @Override
        public IBinder onBind(Intent intent) {
                return  new MyBinder();
        }
        //1.service中有个类部类继承Binder,然后提供一个公有方法,返回当前service的实例。
        public class  MyBinder extends Binder{
            public MyService getService(){
                return MyService.this;
            }
    
        }
    }
    

    对于这个类提供的几点说明:
    1.新建一个内部类MyBinder继承Binder,提供一个公有的方法返回当前Service的实例
    2.在onbind()方法中返回我们1中的Binder对象,activity也是通过绑定服务bindservice,并在onServiceConnected中获取IBinder实例,然后再通过IBinder实例来获取service实例。
    3.剩下的方法我们直接在activity中调用即可

    OnProgressListener接口代码,通过这个接口回调当前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) {
                     //返回一个MyService对象
                    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);
        }
    }
    

    对于这个类提供的几点说明:
    1.在oncreate中通过bindservice绑定服务,在 onServiceConnected中获取service实例,并通过回调返回的progress更新UI。

    【通过广播】

    当我们的进度发生变化的时候我们发送一条广播,然后在Activity的注册广播接收器,接收到广播之后更新ProgressBar。

    放代码:

    不同于上一个service,我们新建一个service通过广播的方式向activity传递

    public class MyService2 extends Service {
    
       public MyService2() {
       }
       //进度条最大值
       public static final int MAX_PROGRESS = 100;
       // 进度条的当前进度值
       public int currentProgress=0;
       private Intent intent = new Intent("com.test.service.RECEIVER");
       //开启下载任务
       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);//进度发生变化通知调用方
                           //发送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) {
           //通过startservice启动服务,调用的是service的onStartCommand方法
           //此时service通过发送广播实现,activity注册广播接收器接受进度
           startDownloadTask((String) intent.getSerializableExtra("url"));
           return super.onStartCommand(intent, flags, startId);
       }
    
       @Override
       public IBinder onBind(Intent intent) {
           //通过bindservice绑定服务,调用的是onbind方法,此时是通过IBinder传递参数
           //这个service主要演示的通过广播传递参数 这个方法直接返回空即可
        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);
            //动态注册广播接收器
            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) {
                 //启动服务
                   startService(intent);
                }
            });
        }
        /**
         * 广播接收器
         * @author len
         *
         */
        public class MyReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {
                //拿到进度,更新UI
                int progress = intent.getIntExtra("progress", 0);
                progressBar.setProgress(progress);
                textview.setText(progress+"%");
            }
    
        }
        @Override
        protected void onDestroy() {
            //停止服务
            stopService(intent);
            //注销广播
            unregisterReceiver(myReceiver);
            super.onDestroy();
        }
    }
    
    

    相比较,如果某个service要向多个activity发送,用广播的方式更好一点

    Android IntentService和ResultReceiver的异步处理实现service与activity的交互

    其他在学习过程中应该了解的小知识点
    startService与bindService的区别
    静态/动态注册广播的区别


    亲,给个赞鼓励一下吧~

    相关文章

      网友评论

        本文标题:Activity与Service之间交互(通过Binder对象和

        本文链接:https://www.haomeiwen.com/subject/pkuoyxtx.html