Sending data from an Activity to WearableListenerS

2020-02-26 11:08发布

问题:

When I read about communication between an Activity and Service, I found that we can use either

  • IBinder
  • Messenger
  • AIDL

I am interested in the first two. So when I tried implementing this to communicate between an Activity and WearableListenerService, I needed to override the onBind function.

But then, I am getting a compiler error saying it

cannot override final method "onBind"

I dont get such an error when I use a normal Service. So,

1. Does that mean we cannot use IBinder or Messenger approach to communicate with the WearableListenerService from an Activity?

2. If so, what is the next best way to pass message to WearableListenerService from an Activity (or call a public method of that service from an Activity)?

回答1:

After some digging, I found the solution. Hope it helps somebody else.

We can send message from an Activity to WearableListenerService using Wearable.MessageApi functions. When the Activity and WearableListenerService are on the same Node (device), we need to get the instance of the local node (current node from which the message is sent) for sending the message as below

NodeApi.GetLocalNodeResult nodes = Wearable.NodeApi.getLocalNode(mGoogleApiClient).await();

rather than

NodeApi.GetConnectedNodesResult nodes  = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await();

which is used to get the list of other devices (such as wear) connected to the phone.

So, I was able to successfully send a message from my Activity to WearableListenerService as follows

Activity Code

public class PhoneActivity extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{

    private static final String TAG = "PhoneActivity";

    public static final String CONFIG_START = "config/start";
    public static final String CONFIG_STOP= "config/stop"

    Intent intent;
    TextView txtview;

    GoogleApiClient mGoogleApiClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_phone);

        if(null == mGoogleApiClient) {
            mGoogleApiClient = new GoogleApiClient.Builder(this)
                    .addApi(Wearable.API)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .build();
            Log.v(TAG, "GoogleApiClient created");
        }

        if(!mGoogleApiClient.isConnected()){
            mGoogleApiClient.connect();
            Log.v(TAG, "Connecting to GoogleApiClient..");
        }

        startService(new Intent(this, PhoneService.class));
    }

    @Override
    public void onConnectionSuspended(int cause) {
        Log.v(TAG,"onConnectionSuspended called");
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.v(TAG,"onConnectionFailed called");
    }

    @Override
    public void onConnected(Bundle connectionHint) {
        Log.v(TAG,"onConnected called");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.v(TAG, "onStart called");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.phone, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_start_) {
            new SendActivityPhoneMessage(CONFIG_START,"").start();
        }else if (id == R.id.action__stop) {
            new SendActivityPhoneMessage(CONFIG_STOP,"").start();
        }else if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    class SendActivityPhoneMessage extends Thread {
        String path;
        String message;

        // Constructor to send a message to the data layer
        SendActivityPhoneMessage(String p, String msg) {
            path = p;
            message = msg;
        }

        public void run() {
            NodeApi.GetLocalNodeResult nodes = Wearable.NodeApi.getLocalNode(mGoogleApiClient).await();
            Node node = nodes.getNode();
            Log.v(TAG, "Activity Node is : "+node.getId()+ " - " + node.getDisplayName());
            MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), path, message.getBytes()).await();
            if (result.getStatus().isSuccess()) {
                Log.v(TAG, "Activity Message: {" + message + "} sent to: " + node.getDisplayName());
            }
            else {
                // Log an error
                Log.v(TAG, "ERROR: failed to send Activity Message");
            }
        }
    }
}

Service Code

public class PhoneService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener{

    private static final String TAG = "PhoneService";

    public static final String CONFIG_START = "config/start";
    public static final String CONFIG_STOP = "config/stop";

    GoogleApiClient mGoogleApiClient;

    public PhoneService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.v(TAG, "Created");

        if(null == mGoogleApiClient) {
            mGoogleApiClient = new GoogleApiClient.Builder(this)
                    .addApi(Wearable.API)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .build();
            Log.v(TAG, "GoogleApiClient created");
        }

        if(!mGoogleApiClient.isConnected()){
            mGoogleApiClient.connect();
            Log.v(TAG, "Connecting to GoogleApiClient..");
        }
    }

    @Override
    public void onDestroy() {

        Log.v(TAG, "Destroyed");

        if(null != mGoogleApiClient){
            if(mGoogleApiClient.isConnected()){
                mGoogleApiClient.disconnect();
                Log.v(TAG, "GoogleApiClient disconnected");
            }
        }

        super.onDestroy();
    }

    @Override
    public void onConnectionSuspended(int cause) {
        Log.v(TAG,"onConnectionSuspended called");
    }

    @Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        Log.v(TAG,"onConnectionFailed called");
    }

    @Override
    public void onConnected(Bundle connectionHint) {
        Log.v(TAG,"onConnected called");

    }

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        super.onDataChanged(dataEvents);
        Log.v(TAG, "Data Changed");
    }

    @Override
    public void onMessageReceived(MessageEvent messageEvent) {
        super.onMessageReceived(messageEvent);
        if(messageEvent.getPath().equals(CONFIG_START)){
            //do something here
        }else if(messageEvent.getPath().equals(CONFIG_STOP)){
            //do something here
        }
    }

    @Override
    public void onPeerConnected(Node peer) {
        super.onPeerConnected(peer);
        Log.v(TAG, "Peer Connected " + peer.getDisplayName());
    }

    @Override
    public void onPeerDisconnected(Node peer) {
        super.onPeerDisconnected(peer);
        Log.v(TAG, "Peer Disconnected " + peer.getDisplayName());
    }
}