zoukankan      html  css  js  c++  java
  • Android Service与Activity之间通信的几种方式

    在Android中,Activity主要负责前台页面的展示,Service主要负责需要长期运行的任务,所以在我们实际开发中,就会常常遇到Activity与Service之间的通信,我们一般在Activity中启动后台Service,通过Intent来启动,Intent中我们可以传递数据给Service,而当我们Service执行某些操作之后想要更新UI线程,我们应该怎么做呢?接下来我就介绍两种方式来实现Service与Activity之间的通信问题

    • 通过Binder对象

    当Activity通过调用bindService(Intent service, ServiceConnection conn,int flags),我们可以得到一个Service的一个对象实例,然后我们就可以访问Service中的方法,我们还是通过一个例子来理解一下吧,一个模拟下载的小例子,带大家理解一下通过Binder通信的方式

    首先我们新建一个工程Communication,然后新建一个Service类

    import android.app.Service;
    import android.content.Intent;
    import android.os.Binder;
    import android.os.IBinder;
    
    public class MsgService extends Service {
        /**
         * 进度条的最大值
         */
        public static final int MAX_PROGRESS = 100;
        /**
         * 进度条的进度值
         */
        private int progress = 0;
    
        /**
         * 增加get()方法,供Activity调用
         * @return 下载进度
         */
        public int getProgress() {
            return progress;
        }
    
        /**
         * 模拟下载任务,每秒钟更新一次
         */
        public void startDownLoad(){
            new Thread(new Runnable() {
                
                @Override
                public void run() {
                    while(progress < MAX_PROGRESS){
                        progress += 5;
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        
                    }
                }
            }).start();
        }
    
    
        /**
         * 返回一个Binder对象
         */
        @Override
        public IBinder onBind(Intent intent) {
            return new MsgBinder();
        }
        
        public class MsgBinder extends Binder{
            /**
             * 获取当前Service的实例
             * @return
             */
            public MsgService getService(){
                return MsgService.this;
            }
        }
    
    }

    上面的代码比较简单,注释也比较详细,最基本的Service的应用了,相信你看得懂的,我们调用startDownLoad()方法来模拟下载任务,然后每秒更新一次进度,但这是在后台进行中,我们是看不到的,所以有时候我们需要他能在前台显示下载的进度问题,所以我们接下来就用到Activity了

    Intent intent = new Intent("com.example.communication.MSG_ACTION");  
    bindService(intent, conn, Context.BIND_AUTO_CREATE);

    通过上面的代码我们就在Activity绑定了一个Service,上面需要一个ServiceConnection对象,它是一个接口,我们这里使用了匿名内部类

    ServiceConnection conn = new ServiceConnection() {
            
            @Override
            public void onServiceDisconnected(ComponentName name) {
                
            }
            
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //返回一个MsgService对象
                msgService = ((MsgService.MsgBinder)service).getService();
                
            }
        };

    在onServiceConnected(ComponentName name, IBinder service) 回调方法中,返回了一个MsgService中的Binder对象,我们可以通过getService()方法来得到一个MsgService对象,然后可以调用MsgService中的一些方法,Activity的代码如下

    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.ProgressBar;
    
    public class MainActivity extends Activity {
        private MsgService msgService;
        private int progress = 0;
        private ProgressBar mProgressBar;
        
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            
            //绑定Service
            Intent intent = new Intent("com.example.communication.MSG_ACTION");
            bindService(intent, conn, Context.BIND_AUTO_CREATE);
            
            
            mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
            Button mButton = (Button) findViewById(R.id.button1);
            mButton.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    //开始下载
                    msgService.startDownLoad();
                    //监听进度
                    listenProgress();
                }
            });
            
        }
        
    
        /**
         * 监听进度,每秒钟获取调用MsgService的getProgress()方法来获取进度,更新UI
         */
        public void listenProgress(){
            new Thread(new Runnable() {
                
                @Override
                public void run() {
                    while(progress < MsgService.MAX_PROGRESS){
                        progress = msgService.getProgress();
                        mProgressBar.setProgress(progress);
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    
                }
            }).start();
        }
        
        ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceDisconnected(ComponentName name) {
                
            }
            
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //返回一个MsgService对象
                msgService = ((MsgService.MsgBinder)service).getService();
                
            }
        };
    
        @Override
        protected void onDestroy() {
            unbindService(conn);
            super.onDestroy();
        }
    
    
    }

    其实上面的代码我还是有点疑问,就是监听进度变化的那个方法我是直接在线程中更新UI的,不是说不能在其他线程更新UI操作吗,可能是ProgressBar比较特殊吧,我也没去研究它的源码,知道的朋友可以告诉我一声,谢谢!

    上面的代码就完成了在Service更新UI的操作,可是你发现了没有,我们每次都要主动调用getProgress()来获取进度值,然后隔一秒在调用一次getProgress()方法,你会不会觉得很被动呢?可不可以有一种方法当Service中进度发生变化主动通知Activity,答案是肯定的,我们可以利用回调接口实现Service的主动通知,不理解回调方法的可以看看http://blog.csdn.net/xiaanming/article/details/8703708

    新建一个回调接口

    public interface OnProgressListener {
        void onProgress(int progress);
    }

    MsgService的代码有一些小小的改变,为了方便大家看懂,我还是将所有代码贴出来

    import android.app.Service;
    import android.content.Intent;
    import android.os.Binder;
    import android.os.IBinder;
    
    public class MsgService extends Service {
        /**
         * 进度条的最大值
         */
        public static final int MAX_PROGRESS = 100;
        /**
         * 进度条的进度值
         */
        private int progress = 0;
        
        /**
         * 更新进度的回调接口
         */
        private OnProgressListener onProgressListener;
        
        
        /**
         * 注册回调接口的方法,供外部调用
         * @param onProgressListener
         */
        public void setOnProgressListener(OnProgressListener onProgressListener) {
            this.onProgressListener = onProgressListener;
        }
    
        /**
         * 增加get()方法,供Activity调用
         * @return 下载进度
         */
        public int getProgress() {
            return progress;
        }
    
        /**
         * 模拟下载任务,每秒钟更新一次
         */
        public void startDownLoad(){
            new Thread(new Runnable() {
                
                @Override
                public void run() {
                    while(progress < MAX_PROGRESS){
                        progress += 5;
                        
                        //进度发生变化通知调用方
                        if(onProgressListener != null){
                            onProgressListener.onProgress(progress);
                        }
                        
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        
                    }
                }
            }).start();
        }
    
    
        /**
         * 返回一个Binder对象
         */
        @Override
        public IBinder onBind(Intent intent) {
            return new MsgBinder();
        }
        
        public class MsgBinder extends Binder{
            /**
             * 获取当前Service的实例
             * @return
             */
            public MsgService getService(){
                return MsgService.this;
            }
        }
    
    }

    Activity中的代码如下

    package com.example.communication;
    
    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.ProgressBar;
    
    public class MainActivity extends Activity {
        private MsgService msgService;
        private ProgressBar mProgressBar;
        
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            
            //绑定Service
            Intent intent = new Intent("com.example.communication.MSG_ACTION");
            bindService(intent, conn, Context.BIND_AUTO_CREATE);
            
            
            mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
            Button mButton = (Button) findViewById(R.id.button1);
            mButton.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    //开始下载
                    msgService.startDownLoad();
                }
            });
            
        }
        
    
        ServiceConnection conn = new ServiceConnection() {
            @Override
            public void onServiceDisconnected(ComponentName name) {
                
            }
            
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //返回一个MsgService对象
                msgService = ((MsgService.MsgBinder)service).getService();
                
                //注册回调接口来接收下载进度的变化
                msgService.setOnProgressListener(new OnProgressListener() {
                    
                    @Override
                    public void onProgress(int progress) {
                        mProgressBar.setProgress(progress);
                        
                    }
                });
                
            }
        };
    
        @Override
        protected void onDestroy() {
            unbindService(conn);
            super.onDestroy();
        }
    
    
    }

    用回调接口是不是更加的方便呢,当进度发生变化的时候Service主动通知Activity,Activity就可以更新UI操作了

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

    package com.example.communication;
    
    import android.app.Activity;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.ProgressBar;
    
    public class MainActivity extends Activity {
        private ProgressBar mProgressBar;
        private Intent mIntent;
        private MsgReceiver msgReceiver;
        
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            //动态注册广播接收器
            msgReceiver = new MsgReceiver();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction("com.example.communication.RECEIVER");
            registerReceiver(msgReceiver, intentFilter);
            
            
            mProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
            Button mButton = (Button) findViewById(R.id.button1);
            mButton.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    //启动服务
                    mIntent = new Intent("com.example.communication.MSG_ACTION");
                    startService(mIntent);
                }
            });
            
        }
    
        
        @Override
        protected void onDestroy() {
            //停止服务
            stopService(mIntent);
            //注销广播
            unregisterReceiver(msgReceiver);
            super.onDestroy();
        }
    
    
        /**
         * 广播接收器
         * @author len
         *
         */
        public class MsgReceiver extends BroadcastReceiver{
    
            @Override
            public void onReceive(Context context, Intent intent) {
                //拿到进度,更新UI
                int progress = intent.getIntExtra("progress", 0);
                mProgressBar.setProgress(progress);
            }
            
        }
    
    }
    package com.example.communication;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    
    public class MsgService extends Service {
        /**
         * 进度条的最大值
         */
        public static final int MAX_PROGRESS = 100;
        /**
         * 进度条的进度值
         */
        private int progress = 0;
        
        private Intent intent = new Intent("com.example.communication.RECEIVER");
        
    
        /**
         * 模拟下载任务,每秒钟更新一次
         */
        public void startDownLoad(){
            new Thread(new Runnable() {
                
                @Override
                public void run() {
                    while(progress < MAX_PROGRESS){
                        progress += 5;
                        
                        //发送Action为com.example.communication.RECEIVER的广播
                        intent.putExtra("progress", progress);
                        sendBroadcast(intent);
                        
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        
                    }
                }
            }).start();
        }
    
        
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            startDownLoad();
            return super.onStartCommand(intent, flags, startId);
        }
    
    
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
    
    }

    总结:

    1. Activity调用bindService (Intent service, ServiceConnection conn, int flags)方法,得到Service对象的一个引用,这样Activity可以直接调用到Service中的方法,如果要主动通知Activity,我们可以利用回调方法
    2. Service向Activity发送消息,可以使用广播,当然Activity要注册相应的接收器。比如Service要向多个Activity发送同样的消息的话,用这种方法就更好
    转载自:http://blog.csdn.net/xiaanming/article/details/9750689
  • 相关阅读:
    发现个atan2的正确使用方式
    Forward+ Shading架构
    fatal: unable to connect to gitee.com: gitee.com[0: 180.97.125.228]: errno=Unknown error 解决方案
    HDFS HA(高可用性)集群规划
    如何使用RTP引擎对语音编码进行转码
    关于 Angular 应用 tsconfig.json 中的 target 属性
    浅谈 Orbeon form builder 的权限控制
    关于 Angular 应用 tsconfig.json 中的 lib 属性
    orbeon form 通过 url 的方式同第三方应用集成的开发明细
    orbeon form 的配置介绍
  • 原文地址:https://www.cnblogs.com/tyjsjl/p/3708915.html
Copyright © 2011-2022 走看看