Service与Activity之间的通讯(二)

本文详细介绍了在Android中如何通过三种不同的方法实现服务的绑定:扩展Binder类、使用Messenger及AIDL,使Service与Activity或其他组件间能进行有效的通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

开启服务是不能使Service和Activity之间通讯的,所以只能通过绑定服务完成。

有三种方式来创建绑定服务,接下来一个一个的介绍:

一、扩展 Binder 类

此方法只有在客户端和服务位于同一应用和进程内这一最常见的情况下方才有效。

1、在服务中,创建一个可满足下列任一要求的 Binder 实例:

1)包含客户端可调用的公共方法

2)返回当前 Service 实例,其中包含客户端可调用的公共方法

3)或返回由服务承载的其他类的实例,其中包含客户端可调用的公共方法

2、从 onBind() 回调方法返回此 Binder 实例。

3、在客户端中,从 onServiceConnected() 回调方法接收 Binder,并使用提供的方法调用绑定服务。

接下来通过代码来说话吧

public class MyService extends Service {

    private final MyIBinder myIBinder = new MyIBinder();

    //其他绑定了该Service的组件可以通过IBinder对象与该Service进行通讯,该方法只执行一次
    @Override
    public IBinder onBind(Intent intent) {
        return myIBinder;//返回IBinder对象,传给onServiceConnected
    }
    //继承Binder而不是继承IBinder的原因:Binder是IBinder的子类,若果要继承IBinder会需要实现很多的方法,比较复杂也没什么用
    public class MyIBinder extends Binder {
         MyService getServiceInstance() {
            return MyService.this;
        }
    }

    //这个就是服务要做的东东了,必须是公共的,可被外界调用的
    public InputStream getImageFromNet(String path){

        InputStream inputStream = null;
        try {
            URL url = new URL(path);
            try {
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                connection.setConnectTimeout(3000);

                if(connection.getResponseCode() == 200){
                    inputStream = connection.getInputStream();
                    return inputStream;
                }

            } catch (IOException e) {
                e.printStackTrace();
            }

        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return  null;
    }
}
public class MainActivity extends AppCompatActivity {

    private ImageView imageView;
    private MyService myService;
    private MyService.MyIBinder myIBinder;
    private boolean isBond;
    private ServiceConnection serviceConnection= new ServiceConnection() {
        //服务连接成功调用的方法
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            myIBinder = (MyService.MyIBinder) iBinder;
            //通过IBinder的到服务(IBinder很关键的)
            myService = myIBinder.getServiceInstance();
            isBond = true;
            //可以在这里调用服务里的那个公共方法,耗时的不要在主现场直接写哈
        }
        //服务连接失败调用的方法
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            isBond = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.image);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, MyService.class);
        //绑定服务,注意第三个参数哈,写错了可能看不到想要的结果
        bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);

    }
    //我是在界面可见时绑定了服务,当点击按钮时才开始执行里面的访问网络的操作
    public void startService(View view) {
        Intent intent = new Intent(this,MyService.class);
        startService(intent);

        if (isBond) {
            //开启子线程做耗时操作,不要忘了调用start方法,否则白写了
            new Thread(new Runnable() {
                @Override
                public void run() {
                    InputStream inputStream = myService.getImageFromNet("http://dl.iteye.com/upload/attachment/533746/cdfa048a-d545-31c5-b250-2ec546863eb3.jpg");
                    final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                    //不能在非UI线程中更新UI,这个里面的runnable是运行在主线程的
                    imageView.post(new Runnable() {
                        @Override
                        public void run() {
                            imageView.setImageBitmap(bitmap);
                        }
                    });
                }
            }).start();
        }
    }

    public void stopService(View view) {
        if(isBond){
            unbindService(serviceConnection);
            isBond = false;
        }
    }

二、使用 Messenger

如需让服务与远程进程通信,则可使用 Messenger 为您的服务提供接口。利用此方法,您无需使用 AIDL 便可执行进程间通信 (IPC)。

与 AIDL 比较 当您需要执行 IPC 时,为您的接口使用 Messenger 要比使用 AIDL 实现它更加简单,因为Messenger 会将所有服务调用排入队列,而纯粹的 AIDL 接口会同时向服务发送多个请求,服务随后必须应对多线程处理。

对于大多数应用,服务不需要执行多线程处理,因此使用 Messenger 可让服务一次处理一个调用。如果您的服务必须执行多线程处理,则应使用AIDL 来定义接口。

  • 1、服务实现一个 Handler,由其接收来自客户端的每个调用的回调

  • 2、 Handler 用于创建 Messenger 对象(对 Handler 的引用)

  • 3、Messenger 创建一个 IBinder,服务通过 onBind() 使其返回客户端

  • 4、客户端使用 IBinder 将 Messenger(引用服务的 Handler)实例化,然后使用后者将 Message 对象发送给服务

  • 5、服务在其 Handler 中(具体地讲,是在 handleMessage() 方法中)接收每个 Message

接下来上代码来说明吧

public class MessengerServiceDemo extends Service {

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //通过messenger得到IBinder对象并返回
        return messenger.getBinder();
    }
    //为了创建Messenger创建,
    class MyHandle extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);         
                Log.e("------>","fgfgfgfgs");
        }
    }
    //创建Messenger对象
    Messenger messenger = new Messenger(new MyHandle());
}
public class MainActivity extends AppCompatActivity {

    private ImageView imageView;
    private boolean isBond;
    private Messenger messenger;

    private ServiceConnection messengerconn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            messenger = new Messenger(iBinder);
            isBond = true;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            messenger = null;
            isBond = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        imageView = (ImageView) findViewById(R.id.image);
    }

    @Override
    protected void onStart() {
        super.onStart();
        Intent intent = new Intent(this, MessengerServiceDemo.class);
        bindService(intent, messengerconn, Context.BIND_AUTO_CREATE)
    }

    public void startService(View view) {
        if (isBond) {

            Message message = Message.obtain();
            message.what = 1;

            try {
                messenger.send(message);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

        }
    }

    public void stopService(View view) {
        if(isBond){
            unbindService(messengerconn);
            isBond = false;
        }
    }

三、AIDL

这个没有用过,不太会,就不多说了,以免误导大家……

点这里看AIDL文档

AIDL实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值