Android中的跨应用服务通信

文章中大部分代码来自网络,在此基础上我做了一定量的修改,这篇文章只是为了方便自己以后查看,转载请注明地址。
内容是安卓中跨应用的服务与界面的相互通信。

首先是文件结构,如下图,分别创建两个APP,app(service)和remoteApp(client),App只负责服务部分,remoteApp用于显示服务回传的数据和修改服务的数据的功能。现在需要跨应用通信的app中创建AIDL文件,分别为ITaskBinder.aidl和ITaskCallback.aidl,ITaskCallback,ITaskBinder用于编写提供给client回调用的接口,ITaskCallback用于编写注册callback的方法。



ITaskCallback.aidl代码
// ITaskBinder.aidl
//注意修改包名
package ***.***.learnservice;
import ***.***.learnservice.ITaskCallback;

interface ITaskBinder {
     void registerCallback(ITaskCallback cb);  //用于注册callback
     void unregisterCallback(ITaskCallback cb);//用于解除callback的注册
     void setServicePrint(String str);
}


ITaskBinder.aidl代码
// ITaskCallback.aidl
//注意修改包名
package ***.***.learnservice;

interface ITaskCallback {
    void sendString(String str); //向client回传字符串数据
}



下面来讲讲service中需要实现的内容
MyService.java代码
package ***.***.learnservice;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;


public class MyService extends Service {
    private boolean running=false;
    private String outStr="服务运行中...";
    private boolean reg=false;

    public MyService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        running=true;
        System.out.println("服务启动");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        running=false;
        System.out.println("服务销毁");
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        new Thread(){
            @Override
            public void run() {
                super.run();
                int i=0;
                while (running)
                {
                    String str=i+":"+outStr;
                    System.out.println(str);
                    if(reg){
                        callback(str);//条件符合就回传数据
                    }
                    i++;
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
        return super.onStartCommand(intent, flags, startId);
    }

    
    void callback(String str) {
        final int N = mCallbacks.beginBroadcast();
        System.out.println(N);
        for (int i=0; i<N; i++) {
            try {
                mCallbacks.getBroadcastItem(i).sendString(str);
            }
            catch (RemoteException e) {
            }
        }
        mCallbacks.finishBroadcast();
    }

    private final ITaskBinder.Stub mBinder = new ITaskBinder.Stub() {
        public void registerCallback(ITaskCallback cb) {
            if (cb != null) {
                mCallbacks.register(cb);
                reg=true;
            }
        }

        public void unregisterCallback(ITaskCallback cb) {
            if(cb != null) {
                mCallbacks.unregister(cb);
                reg=false;
            }
        }

        @Override
        public void setServicePrint(String str) throws RemoteException {
            MyService.this.outStr=str;
        }
    };

    final RemoteCallbackList<ITaskCallback> mCallbacks = new RemoteCallbackList <ITaskCallback>();
}


先来看 final RemoteCallbackList<ITaskCallback> mCallbacks = new RemoteCallbackList <ITaskCallback>();
快应用的通信时通过RemoteCallbackList来实现的,用一个RemoteCallbackList来存储callback的列表。
首先我们需要实现一个ITaskBinder.Stub,用于注册和接触注册,或者是更改服务里面的内容的IBinder实例,我们需要在onBind()中返回它给client。
然后编写一回调函数void callback(String str),在callback里面,先通过mCallbacks.beginBroadcast();来获取当前的数目(这里应该指的是注册了的回调函数的数目,不过我没有测试过),然后通过mCallbacks.getBroadcastItem(i).sendString(str);
向client发送数据,sendString(str);就是你之前在ITaskBinder.aidl中实现的接口。

下面来看removeApp的内容
MainActivity.java代码
//注意根据你的包名来更改
package ***.***.remoteapp;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

//注意根据你的包名来更改
import ***.***.learnservice.ITaskBinder;
import ***.***.learnservice.ITaskCallback;

public class MainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection {

    private TextView tv;
    private EditText et;
    private Intent anotherAppServiceIntent=new Intent();
    private static String backStr="";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//注意根据你的包名来更改
        anotherAppServiceIntent.setComponent(new ComponentName("***.***.learnservice","***.***.learnservice.MyService"));
        tv= (TextView) findViewById(R.id.tv);
        et= (EditText) findViewById(R.id.et);
        findViewById(R.id.startAnotherAppSercvice).setOnClickListener(this);
        findViewById(R.id.stopAnotherAppSercvice).setOnClickListener(this);
        findViewById(R.id.bindAnotherAppSercvice).setOnClickListener(this);
        findViewById(R.id.unbindAnotherAppSercvice).setOnClickListener(this);
        findViewById(R.id.changeAnothetAppService).setOnClickListener(this);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.startAnotherAppSercvice:
                startService(anotherAppServiceIntent);
                break;
            case R.id.stopAnotherAppSercvice:
                stopService(anotherAppServiceIntent);
                break;
            case R.id.bindAnotherAppSercvice:
                bindService(anotherAppServiceIntent,this, Context.BIND_AUTO_CREATE);
                break;
            case R.id.unbindAnotherAppSercvice:
                binder=null;
                unbindService(this);
                break;
            case R.id.changeAnothetAppService:
                if(binder!=null)
                {
                    try
                    {
                        binder.setServicePrint(et.getText().toString());
                    }
                    catch (RemoteException e)
                    {
                        e.printStackTrace();
                    }
                }
                break;
        }
    }
    private ITaskBinder binder;

    ITaskCallback mCallback = new ITaskCallback.Stub() {
        @Override
        public void sendString(String str) throws RemoteException {
            Message message=new Message();
            Bundle bundle=new Bundle();
            bundle.putString("callbackString",str);
            message.setData(bundle);
           handler.sendMessage(message);
        }
    };

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        System.out.println("绑定服务");
        binder=ITaskBinder.Stub.asInterface(service);
        try {
            binder.registerCallback(mCallback);
        } catch (RemoteException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        try {
            binder.unregisterCallback(mCallback);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        System.out.println("解绑服务");
    }

    Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            tv.setText(msg.getData().getString("callbackString"));
        }
    };


}


在client中,通过bindService绑定服务后,就可以在重写中的onServiceConnected方法中注册你写的callback函数, ITaskCallback mCallback = new ITaskCallback.Stub() {};
在mCallback里面通过复写sendString(String str)就可以获取到服务传过来的字符串数据了。由于安卓的安全机制,副线程不能更改当前的视图线程的资源,所以我们可以通过Handler来更新TextView中的内容。

猜你喜欢

转载自xlkgh.iteye.com/blog/2243519