Quantcast
Channel: かずきのBlog@hatena
Viewing all articles
Browse latest Browse all 1387

Android Wear → Androidの通信

$
0
0

こちらのページを参考に、メッセージ送信の部分だけを抜き出して作ってみました。

Android, Android Wear共通

両方のAndroidManifest.xmlのapplicationタグの下に以下の一行を追加します。こいつは通信につかうGoogleApiClientを使うのにいるっぽいです。

<meta-dataandroid:name="com.google.android.gms.version"android:value="@integer/google_play_services_version" />

Android Wear メッセージ送信側

まず、画面でGoogleApiClientのインスタンスを作っておきます。Builderがあるのでさくっと作れます。接続の成否を見るために、addConnectionCallbacksとaddOnConnectionFailedのリスナーを追加しておくといいと思われます。そして、addApiでWearable.APIを追加しておきます。

// フィールドに定義しておくprivate GoogleApiClient client;

// OnCreateとかそれに準ずるメソッドあたりで初期化this.client = new GoogleApiClient.Builder(this.getActivity())
        .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
            @Overridepublicvoid onConnected(Bundle bundle) {
                Log.d("MyFragment", "onConnected");
            }
            @Overridepublicvoid onConnectionSuspended(int i) {
                Log.d("MyFragment", "onConnectionSuspended");
            }
        })
        .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
            @Overridepublicvoid onConnectionFailed(ConnectionResult connectionResult) {
                Log.d("MyFragment", "onConnectionFailed");
            }
        })
        .addApi(Wearable.API)
        .build();
this.client.connect();

次にメッセージ送信処理です。これはボタンのクリックなど、送信したいタイミングのところに書くといいと思います。ポイントはUIスレッドでawait呼ぶと死ぬので別スレッドを立ててるところです。ただ、行儀がいいのかはちょっと個人的に疑問に残ったりするところです…。

Wearable.NodeApi.GetConnectionNodesメソッドで接続のノードを取得して、全ノードに対してsendMessageメソッドでメッセージを送っています。sendMessageは、GoogleClientApiと、ノードのIDと、メッセージ識別用のパスの文字列と、バイト列です。ここではHello worldをバイト配列にして渡してます。

結果に対してisSuccessで成否の判断ができます。到達確認までできてるのかは、未確認…。

new Thread(new Runnable() {
    @Overridepublicvoid run() {
        Log.d("MyFragment", "onClick");
        final String message = "Hello world";
        NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(client).await();
        for (Node node : nodes.getNodes()) {
            MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(
                    client,
                    node.getId(),
                    "/hello",
                    message.getBytes())
                    .await();
            if (result.getStatus().isSuccess()) {
                Log.d("onClick", "isSuccess is true");
            } else {
                Log.d("onClick", "isSuccess is false");
            }
        }
    }
}).start();

Android wear側のコードはこんな感じになってます。

package com.example.kazuki.myapplication;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.support.wearable.view.CardFragment;
import android.support.wearable.view.FragmentGridPagerAdapter;
import android.support.wearable.view.GridViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.MessageApi;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;

publicclass MyActivity extends Activity {

    private TextView mTextView;

    @Overrideprotectedvoid onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        final GridViewPager gvp = (GridViewPager) findViewById(R.id.gridPageView);
        gvp.setAdapter(new GridViewPagerAdapter(this.getFragmentManager()));
    }

    staticclass GridViewPagerAdapter extends FragmentGridPagerAdapter {

        public GridViewPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Overridepublic Fragment getFragment(int row, int col) {
            return MyFragment.newInstance();
        }

        @Overridepublicint getRowCount() {
            return1;
        }

        @Overridepublicint getColumnCount(int i) {
            return1;
        }
    }

    staticclass MyFragment extends CardFragment {
        private GoogleApiClient client;

        @Overridepublic View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            this.client = new GoogleApiClient.Builder(this.getActivity())
                    .addConnectionCallbacks(new GoogleApiClient.ConnectionCallbacks() {
                        @Overridepublicvoid onConnected(Bundle bundle) {
                            Log.d("MyFragment", "onConnected");
                        }

                        @Overridepublicvoid onConnectionSuspended(int i) {
                            Log.d("MyFragment", "onConnectionSuspended");
                        }
                    })
                    .addOnConnectionFailedListener(new GoogleApiClient.OnConnectionFailedListener() {
                        @Overridepublicvoid onConnectionFailed(ConnectionResult connectionResult) {
                            Log.d("MyFragment", "onConnectionFailed");
                        }
                    })
                    .addApi(Wearable.API)
                    .build();
            this.client.connect();

            Button button = new Button(this.getActivity());
            button.setText("OK");
            button.setOnClickListener(new View.OnClickListener() {
                @Overridepublicvoid onClick(View v) {
                    new Thread(new Runnable() {
                        @Overridepublicvoid run() {
                            Log.d("MyFragment", "onClick");
                            final String message = "Hello world";
                            NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(client).await();
                            for (Node node : nodes.getNodes()) {
                                MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(
                                        client,
                                        node.getId(),
                                        "/hello",
                                        message.getBytes())
                                        .await();
                                if (result.getStatus().isSuccess()) {
                                    Log.d("onClick", "isSuccess is true");
                                } else {
                                    Log.d("onClick", "isSuccess is false");
                                }
                            }
                        }
                    }).start();
                }
            });
            return button;
        }

        publicstatic MyFragment newInstance() {
            returnnew MyFragment();
        }
    }
}

ついでにレイアウトファイル

<?xml version="1.0" encoding="utf-8"?><android.support.wearable.view.GridViewPagerxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/gridPageView"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MyActivity"tools:deviceIds="wear"></android.support.wearable.view.GridViewPager>

受信側のAndroidの処理

受信側も、何処かでGoogleApiClientのインスタンスを作っておきます。この例では、ActivityのOnCreateで作ってます。手抜きして各種リスナーは登録しないでやりました。すっきり!

package com.example.kazuki.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.Wearable;


publicclass MyActivity extends Activity  {
    private GoogleApiClient client;

    @Overrideprotectedvoid onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        this.client = new GoogleApiClient.Builder(this)
                .addApi(Wearable.API)
                .build();
        this.client.connect();
    }


    @Overridepublicboolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.my, menu);
        returntrue;
    }

    @Overridepublicboolean 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_settings) {
            returntrue;
        }
        returnsuper.onOptionsItemSelected(item);
    }
}

データの受信にはWearableListenerServiceを継承したサービスを作ります。こいつは、onMessageReceivedをオーバーライドすればOKです。メッセージがきたら呼ばれます。getPathとgetDataでsendMessageしたときのパスとデータがとれます。ここでは、受信結果をログに出しています。

package com.example.kazuki.myapplication;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import com.google.android.gms.wearable.MessageEvent;
import com.google.android.gms.wearable.WearableListenerService;

publicclass MyService extends WearableListenerService {
    @Overridepublicvoid onMessageReceived(MessageEvent messageEvent) {
        Log.d("MyService", "onMessageReceived");
        Log.d("MyService", messageEvent.getPath());
        Log.d("MyService", new String(messageEvent.getData()));
    }
}

AndroidManifest.xmlには、以下のようなサービスの定義をしておきます。intent-filterのactionにcom.google.android.gms.wearable.BIND_LISTENERを追加しておくのがポイントです。

<serviceandroid:name=".MyService"><intent-filter><action android:name="com.google.android.gms.wearable.BIND_LISTENER" /></intent-filter></service>

これで、接続されているAndroidとAndroid Wearの両方でアプリを起動して、Android Wearでボタンを押すとAndroid側のログにメッセージが出ます。

おまけ

Android実機とAndroid Wearのエミュレータの接続方法は以下のページが参考になります。

Android Wear Previewの取得とかは今はいらないので後半の接続方法のところを参考にしてやればOKです。


Viewing all articles
Browse latest Browse all 1387

Trending Articles