カテゴリー: 未分類

Androidプログラミングを学ぶ上で大切だと思うこと

この記事は最終更新から3ヶ月以上が経過しています。情報が古い可能性があります。

こっちのブログで書くか、別のブログで書くか迷ったのだが、プログラミングの話だしこっちに書こうかなと思う。

書こうと思ったきっかけは、Androidプログラミングを教える仕事を受けたこと。まあ個人的に、私などが人様に何かを教えるなどおこがましいという思いはあったものの、まあ何事もやってみなければわからないということでやってみた。

Android特有の、ライフサイクル周りの話だとかは、まあ知っていないと辛いよねっていうことではあるんだけど、それよりもっと基礎的な、プログラミングを学ぶ姿勢とでも言おうか、今回書きたいのはそこについてだ。Androidプログラミングとタイトルにしているのは、私がAndroidしか知らないから限定しているだけで、たぶん他の言語でも同じなんじゃないかなと思う。

私はずっと一人でAndroidのプログラミングをやってきた。ほぼ独学である。書籍とネットの情報を頼りに黙々とやってきた1。そんなやつが人様にプログラミングを教えるのもおこがましい気がするものの、3ヶ月間教えてみて大事だなと思ったことが3つある。

1つ目は言ってしまえばコミュニケーション能力である。いきなりプログラミング関係ないじゃないかと思われるかもしれないが、これはとても大事である。別に話を弾ませたり、相手の気持ちを慮ったりする能力が必要だというわけではなく2、自分の考えを相手に伝えようと努力できることって、プログラミング関係なしに大事だなと思ったのである。具体的なシチュエーションとしてはエラーを伝える場面でよくそう思った。なんだかよくわからないけれどもこういうエラーが出たんですと、わからないなりに説明しようとする人とそうでない人がいる。エラーの確認の仕方は知っているかどうかの問題なので、初心者だから見込みがないとかそういう話ではない。しかし、わからないなりに説明をしようとする人に、私は伸び代を感じたのである。

2つ目はチャレンジ精神である。とりあえずやってみることが大事だということ。こう書いたら動いた、だったらこう書けば違う動きになるのではないかと仮説を立てて、挑戦してみる姿勢が大事だ。知らなければどうしようもない部分もあるので、教えてもらうことも大事ではあるが、教えてもらうのを待つだけではなく、自ら挑戦する姿勢もまた大事なのであると言いたい。

3つ目は自分で調べる力である。Androidは特にソースコードがすべて公開されているので、なぜそう動くのかはコードを読めば分かる3。ソースコードを読むのでなくても、公式のドキュメントを読んで調べることなら誰でもできるはず4。Androidのプログラムを書いていると、便利なライブラリのお世話になることがとても多いが、そういったライブラリの使い方を、ライブラリのドキュメントやソースコードから調べることは重要だ。

以上3つ。プログラミングを教えているのに、プログラミングの知識、変数がどうのとかJavaがどうのとかとかよりも、もっと基礎的なことの方が大事に思えたことが意外に感じられた。

最後に、これからプログラミングを勉強しようと思っている人は、できるだけ効率的に学びたいなと思っていることだろう。きっと、いい師匠(先生)を見つけるのが効率的なんだろうけれど、どうやって探すのかは私が知りたい。だからそんな効率的に学ぶ方法を探す前に、さっさと何かプログラミングしてみる方が早いと私は思っている。

Androidプログラミングで言えば、とりあえず市販の本でもネットの情報でもなんでいいので、とりあえず書いてあるとおりにやってみるのがよいと思う。書いてある通りにやってうまくいかなければ、誰かに聞くのがいいだろう。

実は、そういう「書いてあるとおりにやってみたけど動かない」という状況は、スキルアップにちょうどいいシチュエーション5なのだけど、初心者はただ辛いだけなので、誰かに聞くのが手っ取り早い。Twitterでつぶやいてみるとか、teratailとかStackoverflowとかで質問してみるとか6。学校の先生がいるなら、先生に質問するのがいいだろう。聞ける人がいるということはとても恵まれたことなので7、そんな環境にいる人は今のうちに有効活用するべきだと思う。

大事だと思った3つのこと。コミュニケーション能力、チャレンジ精神、自分で調べる力。何にでも言えることじゃないかと思うけど、何にでも言えるからこそ大事なんじゃなかろうか。実際、教えていてこの人はプログラムに向いている・向いていないと感じることが何回かあった。それはなぜそう思うのかと考えてみたら、プログラミングの知識よりも本人の姿勢によるところが大きいと思ったのだ。


  1. ネットで公開される知見に頼るところが大きいのでとてもありがたく拝見している 
  2. あるにこしたことはないが 
  3. 理解できるかはともかく 
  4. 理解できるかはともかく 
  5. 原因を調べて解決することは、プログラミングをしていく上で何度も通る道であり、そういうハマりを経て人は成長していくのである 
  6. 質問する敷居の高さは、teratailの方が低いとは思うが、思い出してほしい。コミュニケーション能力が大切だということを。インターネット上の人々はあなたの状況を理解しているエスパーではないので、聞き方が悪いと答えは返ってこないどころか、逆に傷つくことになるかもしれない。 
  7. 学生という立場は学生という立場を失ってはじめてそのありがたみが分かるのだ 

CIを導入してみた

この記事は最終更新から3ヶ月以上が経過しています。情報が古い可能性があります。

FilteredHatebuにCIを導入してみました。

CI上での設定も必要なので、これだけで導入できるわけではありませんが、CI導入のための変更はこんな感じです。エミュレータが必要なEspressoでのテストがこけないよう、テストコードを修正した変更も含まれています。

そもそもこのアプリをpublicなリポジトリでやっているのは、実はCIを導入してみたかったからという理由がありました。

最初はとりあえずCIを導入してみようというだけで作業を始めたのですが、結局よく目にするTravisCI、CircleCI、Werckerの3つを試してみました。

CIを使うにあたっては、publicなリポジトリで運用する、無料でできる範囲でやる、あまりにややこしいことはやらない(できればそのCI単体で完結させる、ただしSlackへの通知は除く)という3点を念頭にやってみました。

各CIサービスを使ってみた感想

  • TravisCIは秘匿情報を比較的安全に運用しやすい
  • CircleCIはテストレポートを確認しやすい
  • Werckerは圧倒的にビルドが早い

publicなリポジトリでの運用という観点で、秘匿情報(署名ファイルなど)の取扱、テストレポートの確認手段、ビルド時間の長さ、導入難易度について私の主観でまとめてみるとこんな感じです。

CIサービス 秘匿情報 テストレポート ビルド時間 導入難易度
TravisCI × ×
CircleCI × ×
Wercker ×

秘匿情報については後述。

テストレポートは、./gradlew connectedAndroidTestなどを実行した後に生成されるHTML形式のレポートを確認できるかということです。CircleCIはCIサービス上でHTMLファイルにアクセスすることが可能です。Werckerは直接見れませんがファイルをダウンロードできます。Travisはそもそも見れません。どこか外部のストレージサービスでも使って、ファイルをアップロードするしかないようです。

ビルド時間はWerckerの圧勝です。TravisCIもCircleCIもSDKのアップデートに時間を食われるため、一度のビルドに18分くらいかかります。Werckerビルド環境をDockerで構築してしまえるので、SDKのアップデートが発生しません。初回を除けばだいたい6分くらいで済んでいます。圧倒的な早さです。

導入難易度については、TravisCIとCircleCIはどちらもあまり大差はないと思います。ドキュメントも日本語情報も充実しています。設定もYAMLで記述するだけですから、CIサービスごとの方言はあるもののそうハマるものでもありません(CircleCIは微妙にドキュメントが現状に追いついていない部分があって惑わされたりもしましたけど)。

一方でWerckerはドキュメントが他2つと比較して充実しているわけではありません(他2つと比較すると分かりにくいと感じました)。さらにDockerの知識が必要にもなるので、導入までにかかった時間は一番長かったです。(逆にDockerの知識があって、Androidの環境を構築するのが簡単にできてしまう人であれば、Wercker使うのが一番ラクかもしれません)

3つのサービスを使ってみましたが、それぞれ一長一短で、このサービスが最強といえないもどかしさがありました。ただprivateリポジトリで使うなら、Werckerが一番いい気がします(早さと設定の自由度が魅力)。

秘匿情報の取扱

困ったのは、署名ファイル(release.keystore)をCIでどう扱うのかという問題です。

どのCIサービスでも同じですが、release.keystoreなどの秘匿情報をCIでも扱えるようにするためには、そのファイルをリポジトリに含めるか、もしくはインターネット経由でアクセスできるどこかに別途公開しておくかしかありません。

前者の方法はpublicなリポジトリでは使えません。privateリポジトリであれば問題ないのでしょうが、私のケースでは採用できませんでした。

かといって後者のどこか別の場所に置くという方法も、適切な場所が思いつきませんでした。誰でもアクセスできるような場所に置くことはできませんし、適切なアクセス制限がかけられる置き場所となると、選択肢はそう多くはないと思います。

どのCIサービスでも、privateな情報についてはCI側で環境変数を利用することができます。publicなリポジトリで運用しても、パスワードなどが見えないように配慮することができます。TravisとWerckerは環境変数にセキュアな項目にする設定があるので、その点いくらか安心です。ただしCircleCIは、publicなプロジェクトではパスワードとか漏れたら困る情報を環境変数に入れるなと注意書きがありました。

しかし環境変数で扱えるのは文字列です。署名に使うrelease.keystoreというバイナリファイルを環境変数で扱うことはできません。

私が試した3つのサービスで、唯一秘匿情報ファイルの取扱がCIサービス単体で解決できるのはTravisだけです。解決できると言っても、暗号化してリポジトリに含めるという方法ですけれど。

他のサービスでは別途ストレージサービスを利用するなどして、そこからファイルをとってくるという手法を使わなければなりません。

エミュレータを使うテストは鬼門

今回CIを導入したプロジェクトでは、Espressoを使ったテストを行っています。手元の実機では安定していても、CIで実行すると失敗ばかりで非常に困りました。

Espressoテストレコーダーは万能ではない

ローカルの実機だと問題ないのにCI上だとエラーが起こりました。例えばこんなコード。

-        ViewInteraction appCompatTextView = onView(
-                allOf(withId(android.R.id.text1), withText("test.com/"),
-                      childAtPosition(
-                              allOf(withClassName(
-                                      is("com.android.internal.app.AlertController$RecycleListView")),
-                                    withParent(withClassName(is("android.widget.FrameLayout")))),
-                              0),
-                      isDisplayed()));
-        appCompatTextView.perform(click());
+        onData(anything())
+                .atPosition(0)
+                .perform(click());

onData~にコードを書き換えるとCI上でも問題なく動くようになりました。Espressoテストレコーダーは便利ですが、こればかりに頼る訳にはいかないという教訓です。

DataBindingを使っていると起こるエラー

java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation at android.databinding.DataBindingUtil.<clinit>(DataBindingUtil.java:31)という謎のエラーが発生しました。

最初に導入していたTravisでぶち当たった問題で、Android Studioでテストを実行する分には問題ないのに、TravisとWerckerではコケました。Werckerは利用するDockerイメージによるものだとは思います。CircleCIは特に問題になりませんでした。

https://code.google.com/p/android/issues/detail?id=182715

どういうエラーなんだかよく把握していないのですが、DataBindingを使っていて、かつテスト対象のActivityでDataBindingを使っていると発生するようです。

#31に回避策が書いてあります。

エミュレータの起動を待つ処理

CIでエミュレータを使ったテストを行うためには、エミュレータが起動するのを待たなければなりません。TravisCIにもCircleCIにも、エミュレータの起動を待つためのスクリプトが用意されています。Werckerを使う場合はそんな便利なコマンドは用意されていないので、自分でシェルスクリプトを書く必要があります。

しかしこれがまあ安定しない。

試行錯誤の結果、最終的にはkeyeventを送る前に10秒スリープ処理を挟むことで安定しました。(ネットで探し回っていたらsleep 30としている情報にあたり、それで安定するようになった。30秒は長すぎる気がして5秒にしたら時折コケるので10秒にした、という経緯があります)

CIを導入してみて

最初はデプロイまでやってやろうとはじめましたが、途中で方針転換しました。初めてやるなら簡単なところからやるべきだなと思います。

とりあえず最初はprivateなリポジトリ、publicでやるならせめてdebugビルドのみでの運用がおすすめです。publicかつリリースビルドもやって、デプロイまでやろうなんていうのは大変だと思います。

そしてやるにしてもユニットテストまでにしておいたほうが無難ではないかなと思います。UIテスト(Espressoなどエミュレータを使ってやるテスト)までやろうとすると、これまた大変です。(大変でした)

最終的に3つのCIサービスを設定してみましたが、それぞれのサービスごとの特色が見えて面白かったです。

DataBindingを試す

この記事は最終更新から3ヶ月以上が経過しています。情報が古い可能性があります。

DataBindingがアツいらしいと聞いて試してみました。簡単な使い方をするなら想像以上に簡単でした。

今までActivityなどでfindViewByIdを書きたくないから、ButterKnifeをどのプロジェクトでも使っていたのですが、DataBindingを使えば同じようなことができます。

両者を使ってみて感じたのは、ButterKnifeがレイアウトXMLをJavaコードに持ってくるイメージであるとすれば、DataBindingはJavaコードをレイアウトXMLに持っていくイメージであるということです。

DataBindingを使うことで、Javaで作成したコードを、レイアウトXMLに埋め込むことができるようになります。レイアウトXMLでどのデータを使うか指定しておけば、Activityで「このクラス(のインスタンス)を使ってくれ」と指定するだけでその内容を表示できたりします。

具体的な使い方はData Binding Guide – Android Developersを参照してください。

DataBindingを使う設定

Android Studio 1.3以上であることが必須です。

Android Gradle Plugin 1.5.0-alpha1以上を使っていることが必須、でした。

Android Studio 2.0 betaになると、コード補完のサポートがより強力になってます。

build.gradleでDataBindingの設定を有効にすることで利用できます。

android {
....
dataBinding {
enabled = true
}
}

表示するデータを保持するクラスの作成

“`public class Character{
public String name;
public int age;
public String skill;

<pre><code>public Character(String name, int age, String skill){
this.name = name;
this.age = age;
this.skill = skill;
}
</code></pre>

}“`

DataBindingを使ってアクセスするには、publicなフィールドであるか、privateなフィールドである場合publicなgetterがあることが必須です。

レイアウトXML

“`
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
>

<pre><code><data>
<variable
name="chara"
type="jp.gcreate.sample.databinding.Character"
/>
</data>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="jp.gcreate.sample.databinding.MainActivity"
>

<TextView
android:id="@+id/chara_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{chara.name}"
/>

<TextView
android:id="@+id/chara_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{Integer.toString(chara.age)}"
/>

<TextView
android:id="@+id/chara_skill"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{chara.skill}"
/>

</LinearLayout>
</code></pre>

</layout>“`

ポイントはこんな感じ。

  • レイアウトXMLを<layout>タグで囲む
  • レイアウトXML内で利用するクラスを<data>タグ内で宣言する
  • <data>タグ内で宣言するクラス名は完全修飾ドメイン名
  • <variables>タグ内で宣言したnameを使ってアクセスする
  • Javaのコードを埋め込める(Integer.toString()とか)
  • コードは@{}で囲む

ちなみにandroid:textのところに埋め込むデータは、TextView.setText()を使って設定されるので、ここにint型のデータを埋め込むときは注意が必要です。何も考えずにint型のデータを表示しようとすると、そのint値がリソースIDとして認識されてしまいエラーになるからです。その際のエラー内容も、「そんなリソースIDないぞ」という内容で軽くハマりました。

Activityの処理

ちなみにDataBindingによって生成されるクラス名は、レイアウトXMLのファイル名をスネークケースからキャメルケースに変換したものに、Bindingを付け加えたものになります。

activity_main.xmlならActivityMainBindingに、hoge_hoge.xmlならHogeHogeBindingになります。

“`public class MainActivity extends AppCompatActivity {
ActivityMainBinding binding;
Character chara;

<pre><code>@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
chara = new Character("桃太郎", 18, "きびだんご");
binding.setChara(chara);
}
</code></pre>

}“`

レイアウトXMLに紐付けるクラスを、setChara()で渡すことで、渡したCharacterクラスのデータが表示されます。ちなみにレイアウトXMLで<variables name="chara" .../>と設定しているからsetChara()になっています。nameをhogeにしていたらsetHoge()になります。

データの変更を反映させたい

単に表示するだけでは「何が便利なのか」という感じるかもしれません。

例えば桃太郎のスキルを「鬼退治」に変更したいとします。findViewByIdを使わずとも、DataBindingを使えばレイアウトXMLでidを割り振ったViewにアクセスすることができます。

@Override
public boolean onTouchEvent(MotionEvent event) {
binding.charaSkill.setText("鬼退治");
return super.onTouchEvent(event);
}

これを追加すると、タッチイベントが発生したらスキルの内容が「鬼退治」に変わります。

インスタンスの内容が変わったら自動的に反映されるようにする

レイアウトXMLと紐付けるクラスを以下のように書き換えると、インスタンスの内容が変更されるだけでUIに表示されるデータも変わります。

“`public class Character extends BaseObservable {
public String name;
@Bindable
public int age;
public String skill;

<pre><code>public Character(String name, int age, String skill) {
this.name = name;
this.age = age;
this.skill = skill;
}

public void countUp(){
age++;
notifyPropertyChanged(jp.gcreate.sample.databinding.BR.age);
}
</code></pre>

}“`

  • BaseObservableのサブクラスにする
  • 自動的に変更させたいpublicなフィールド、もしくはgetterに@Bindableアノテーションを付ける
  • データの変更が生じるメソッドでnotifyPropertyChanged()を呼ぶ

Activityのコードを以下のように書き換えてみます。

@Override
public boolean onTouchEvent(MotionEvent event) {
chara.countUp();
return super.onTouchEvent(event);
}

こうするとタッチイベントが生じる度に桃太郎が年をとるようになります。いちいち自分でTextViewに変更済みのデータを設定する必要がなくなります。

今のところ私はこの程度しか使っていないのですが、これだけでも充分便利だなぁと思います。とりあえずは簡単なところから試してみてはいかがでしょうか。

アプリを公開してコメントもらえて嬉しかった話

この記事は最終更新から3ヶ月以上が経過しています。情報が古い可能性があります。

Google Playで公開しているカスタムフォトウォッチで初めてコメントをもらいました。

英語でのコメントだったのですが、「12時間表示のオプションが欲しい」っていう内容でした。

おそらく私は、単にそれだけのコメントでも嬉しかったと思います。自分で作ったものに対して反応がもらえるっていうのは、それだけでうれしいのです。

しかし今回のコメントはさらに嬉しい要素がありました。「12時間表示が必要だからアンインストールしたけど、時刻や日付の色やサイズを変えれるのはとてもいい」と褒めてくれていました。

英語でのコメントでしたけど、褒めてくれてるっぽくてテンションが上りました。

つたない英語力とGoogle Translateの力を借りつつ、コメントくれた人とメッセージのやり取りしました。思えば生まれて初めて海外の人とコミュニケーションした気がします。

12時間表示は実は奥が深い

今回の話は「単に嬉しかった」だけに終わりません。実はいい勉強にもなりました。それは12時間表示についてです。

今回もらったコメントに対して、さっそく12時間表示への対応を行いました。スマホの時刻設定で12時間表示にしている場合、wear側での表示を12時間表示にするようにしたのです。12時になったら0時と表示するようにしたわけです。

しかしコメントをくれた方とのやりとりの中で、「うちの国では0時は深夜の0時(24時)を意味するんだ」ということを言われました。

カスタムフォトウォッチでは日付の表示方法についてはいろいろなパターンを提供するようにしていました。海外では月/日ではなく、日/月と表示する場合もあることは知っていたからです。

しかし時刻の表示についても似たような問題があることを、ここにきて初めて知りました。

アプリの海外対応は、文字面だけを英語にするだけではないのだなと、とてもいい勉強になりました。

とりあえず公開してしまえも必要なのかも

アプリを公開するにあたって、「こんな機能も要るかな」とかいろいろ迷ったりもしました。色の選択肢はもっと増やしたほうがいいのかとか、デザインはこれでいいのかとか。

それでも最終的には「ぐだぐだ考えるの面倒くさくなったからもういいや」でアプリを公開しました。いつまでたっても公開できる気がしないし、何のリアクションももらえない状態で開発するのもモチベーションが保てなかったのです。

全てのユーザが今回の方のように丁寧なレビューをくれるとは限りません。それどころか「何やねんこの糞アプリ」みたいなコメントが寄せられるかもしれません。が、それでも公開しなければ何の反応ももらえません。

作るところまで作ったら、後は利用者の反応を見ながら開発するっていうのもいいのかもしれません。

コメント付きレビューをもらえたのが初めてだったので、なんか無性に嬉しかったっていう話でした。

DroidKaigiに参加してきました

この記事は最終更新から3ヶ月以上が経過しています。情報が古い可能性があります。

DroidKaigiに行ってきました。飛行機使って前泊での参加です。

満員でしたね。熱気がすごい。

今日ほど分身の術が使えたらと思うことはなかったでしょう。それくらい、全部のセッション聞きたかったです。

今後のアプリ開発に役立つ情報がいっぱいでした。現状動いてはいるけど、ちゃんとできてなかったところとか、「そうなんだ」っていう気付きもあって有意義でした。

とりあえず面倒臭がらずに少しずつテストを書くことから始めようかなと思います。

テストを動かす環境づくりがよくわからないとか、テストの書き方がよく分からないとか、個人でやってると仕様の変更で対応してしまってテストまで書き換える必要が出てきて面倒くさいとかで敬遠してたんですけど、つべこべ言わずにテスト書こうと思いました。

一方で、周りの空気に飲まれて受け身になりすぎたのが反省点です。なんかもうちょっと攻めの姿勢で聞けたら良かったのにと、振り返って思います。

質問とかできたら良かったんですけど、頭働かなくてそれどころではありませんでした。

言い訳ですけど、参加してる間はそれどころではなかったんですよね・・・。周りスゲーし、人はいっぱいだし、席の確保も大変だし、スケジュールは過密だしで話を聞くのが精一杯でした。

幸い皆さんスライドを公開してくださっている上に、スライド見るだけでも話の内容がある程度分かるようになってるので、後でじっくり復習したいと思います。

個人でアプリ作ってると、こういった周りの開発者さんたちの空気感とか全くわからないので、参加してよかったなと思います。わざわざ岡山から出張った甲斐はあったかな・・・。

運営の皆さん、発表者の皆さん、参加者の皆さん、お疲れ様でした。

Master of Fragmentの更新を首を長くして待ってます。

Android Wearでwearとスマホ間でデータをやりとりする話

この記事は最終更新から3ヶ月以上が経過しています。情報が古い可能性があります。

データのやりとりはWearable.DataApiを使うことでやりとりできます。Wearable.MessageApiを使うことでもできます。

両者の違いはこんな感じ。

DataApi

  • 接続が切れていても送信できる
  • データはonDataChangedで受け取る
  • 送れるデータは100KBまでだが、Assetを使うことで大きいデータも送れる
  • データを送信するというより、DataItemを更新して、その更新を通知するイメージ

MessageApi

  • 現在接続中のノードに対してデータを送信することができる
  • データはonMessageReceivedで受け取る
  • データを送る際にはノードを指定する必要がある

ノードIDについて

当たり前ですが、ノードIDはAndroid Wear端末とスマホで異なります。

WatchFaceを作成して、その設定画面を用意している場合、WearのノードIDはスマホ側では簡単に取得できます。

mobile側の設定画面となるActivityでgetIntent().getStringExtra(WatchFaceCompanion.EXTRA_PEER_ID)とするとWearのノードIDが取得できます。これは設定画面の起動がAndroid Wearアプリ経由で行われるためです。

一方Wearから、もしくはmobileからでもAndroid Wearアプリを経由しない起動の仕方をするアプリの場合はこの方法では取得できません。

その場合はNodeApi.getConnectedNodesを使うことで、接続されている端末のノードリストを取得することができます。現状スマホとAndroid Wearは1:1でペアリングされるはずなので、これで相手方のノードIDを取得できるでしょう。(将来的に複数ペアリングできるようになったらどうやればいいんでしょうね?)

DataApiを使ったデータ送信の注意点

[DataApi – Android Developers]のConcurrencyにありますが、DataApiを使ったからといってmobileとwearでDataItemが全く同じになるわけではありません。

onDataChanged()内であれば正しいデータが参照できます。これは変更があったDataItemが通知されてきているからです。

しかしAndroid Wear端末を再起動した後に、DataApiを使って送信された設定データを読み込もうとした時に問題が生じます。

wear側からDataItemを識別するUriでデータを取りに行っても、mobile側の設定と齟齬が生じている可能性があります。

その理由はDataItemが以下のように識別されているからです。

wear://ノードID/パス

mobileで作ったDataItemはmobileのノードIDで識別されます。同じパス文字列で識別しているからといって、勝手にwearのノードIDのものが変更されるわけではありません。

これはWatchFaceのサンプルコード(com.example.android.wearable.watchface)を見ると何となく分かると思います。サンプルコードでは、mobileからのDataItemの変更を受け取ると、wear側で同じデータを上書きする処理を行っています。

サンプルのようにmobileからもwearからもデータを送り合うようなアプリの場合、どちらのノードのDataItemも常に同じ状態にするように配慮しないと齟齬が生じて困ることになると思います。

片側からしか送らないというのであれば、ノードIDを指定してDataItemを取りに行くのもありかもしれません。

MacをYosemiteにバージョンアップしたらAndroid Studioが起動しなくなった

この記事は最終更新から3ヶ月以上が経過しています。情報が古い可能性があります。

MacをYosemiteにバージョンアップしたらAndroid Studioが起動しなくなりました。

原因はYosemiteへのアップデートでJDK 1.6が消えてしまったことが原因のようでした。(消えたのか参照できなくなったのかはよく分かりませんが・・・)

ターミナルで/usr/libexec/java_home -v 1.6と打つと、Unable to find any JVMs matching version “1.6”.と表示されました。JDK 1.7と1.8はバージョンアップ前と同じように存在してくれてましたが、1.6だけ参照できなくなってました。

対策はJDK 1.6(Java 6)を再インストールすればOKです。JDK1.6(Java 6)はこちらからダウンロードできます