woshidan's blog

そんなことよりコードにダイブ。

mixi Android Training 第二回分メモ

今回は雪だったせいで会場はかなり空いてました。前の方の席にも電源が欲しい……。

内容

  • mixiの中の人のまとめ
  • 中の人のまとめから気になったとこ
  • gitterから
  • 演習について
    • Fragmentのインタフェース未実装のエラーのメッセージ群の先頭がレイアウトの読み込みエラーだったので迷った
  • 課題について
    • 課題1
      • Fragmentからまだ生成されてないActivityを呼び出してnull pointer
    • 課題2
      • イベントリスナを外すメソッドが分からない
      • onSaveInstanceState()とonPause()
      • アクティビティがフォアグラウンドのまま、onDestroy()を呼びたい
      • Android Studioのシミュレータで画面の向きを変える
      • なんで向きを変えるとonDestroy()をよんでonCreate()から始めるんだ
      • onSaveInstanceState()で画面の一時データを保存/onRestoreInstanceState()で一時データを取出
    • 課題4
      • メモリリークを見つける話
      • 対応するライフサイクルのコールバック
      • イベントリスナとブロードキャストレシーバーの付け方・外し方

mixiの中の人のまとめ

ありがとうございます。

中の人のまとめから気になったとこ

  • onCreate内で、ボタンのクリック処理を無名クラスで追加したりしますよね?
    • ボタンのリスナー登録(ボタンを押した時に何をするかを記述すること)は、画面が表示されていない時にボタンのイベント監視をする必要がないので、onStartにした方がよいです。

gitterから

そういえば、第一回の課題とかの質問とかなかったけど、みんな大丈夫だったんだろうか…

第一回の最後の課題、紙とペンも動員して、じっくり2回書いてみたのですが、まだ7割程度な感じです。息をするようにXMLを書けるようになるには、そういうマゾい何かが必要なのかと思ってました。

違ったみたいですね。

演習について

Fragmentのインタフェース未実装のエラーのメッセージ群の先頭がレイアウトの読み込みエラーだったので迷った

Fragmentの課題でandroid:nameもきちんとFQDNで書いたし、ActivityもクラスをFragmentActivityに直して出来た!

と思って起動したら、アプリが強制終了して、XMLファイルの読み込みに失敗しました、みたいなエラーが出てました。

しばらく悩んでもう少し下の方までエラーを読んだら、

MainActivity must implement OnFragmentInteractionListener

と出ていたのでFragmentに用意されていたインタフェースを実装していないためだったことが分かりました。

エラーメッセージは全体を読みましょうという話ですね。

また、implementsにインタフェース名を書くときにクラスの中に定義したインタフェースをどう書いたらいいか少し悩みました。

ClassName.InterfaceName

ただのど忘れでしたね……。

課題について

課題1

Fragmentからまだ生成されてないActivityを呼び出してnull pointer

Fragmentのライフサイクルメソッドの中にもToastを置いてみようと思い、Activityが生成が保障される前のonCreate(),onATtach()内で

this.getActivity()

を呼び出してぬるぽを出しました。話聞けていなくて反省。

課題2

イベントリスナを外すメソッドが分からない

状態管理を適切に行ってくださいと言われて、何を書いたらいいのか一瞬戸惑いました。メソッド名とか出て来ないとイメージが湧かないタイプです。ぐぐれ。

onSaveInstanceState()とonPause()

onSaveInstanceState()はアクティビティがフォアグラウンドから外れるときに呼ばれて、下書きやチェックボックスの選択などの入力を一時的に保存するのに使うみたいです。

永続的なデータ保存=DBなどで、それはonPause()でやるみたいです。

アクティビティがフォアグラウンドのまま、onDestroy()を呼びたい

この課題は、たぶん

アクティビティをスタックから出さないでonDestroy=>onCreateの流れを起こす

=> フォームの入力が消えてないですね、をやりたいわけです。

そのためには、画面の向き等環境設定を変えてやればいいわけです。が、画面の向きを変えればいいことが分からなくて、ひたすら戻るボタンでアクティビティを破棄しては新しく作り直していました。

また、向きを変えればいいことが分かっても、しばらくシミュレータでの向きの変え方が分からなかったりしました。

Android Studioのシミュレータで画面の向きを変える

Android Emulator | Android Developers

より。 テンキーの7かテンキーの9,Ctrl+F11,Ctrl+F12あたりを押せばいいようです。

なんで向きを変えるとonDestroy()をよんでonCreate()から始めるんだ

回転させたときや言語設定を変えたとき、一旦ActivityがonDestroy()を経て破棄されて、またonCreate()が呼び出されます。

環境設定ごとにレイアウトファイルを用意する(できる)ようになっています。なので、環境設定に変更があったら自動的にその設定にあったレイアウトファイルをActivityにセットするようにしておいた方が都合がいいんでしょうね。と思いました(小並感)。

onSaveInstanceState()で画面の一時データを保存/onRestoreInstanceState()で一時データを取出

課題の解答のソースを使いつつメモ。

1. Activityのクラスに

private static final string FORM_NAME = "text";

のように、Bundleに変数を保存するためのキーを入れるクラス変数を用意

2. onSaveInstanceState()で1.のキーを利用して変数をBundleに入れる

@Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(FORM_NAME, textView.getText().toString());
    }

3. onRestoreInstanceState()で1.のキーを使用して、保存した変数を取り出す。

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        textView.setText(savedInstanceState.getString(FORM_NAME));
    }

ところで、このsavedInstanceStateはどのクラス、あるいはクラスのインスタンスが保持してるんでしょうね。

課題4

メモリリークを見つける話

メモリリークの話は、「対応するライフサイクルのメソッドでイベントリスナを外してください」という話だったので、メモリリークの発見自体はあんまり。

対応するライフサイクルのコールバック
  • onCreate() <=> onDestroy()
  • onResume() <=> onPause()
  • onStart() <=> onStop()
  • onSaveInstanceState <=> onRestoreInstanceState()
イベントリスナとブロードキャストレシーバーの付け方・外し方

例は、課題のコードより。

イベントリスナ

// つける
editText.addTextChangedListener(this);
// 外す
editText.removeTextChangedListener(this);

ブロードキャストレシーバ

// つける
mMyBroadcastReceiver = new MyBroadcastReceiver(); // MyBroadcastReceiverはBroadcastReceiverのサブクラス
registerReceiver(mMyBroadcastReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG));
// 外す
if (mMyBroadcastReceiver != null) {
       unregisterReceiver(mMyBroadcastReceiver);
}

授業の様子について

  • schooで公開してリモートの人が増えたので、チャットが活況
  • 会場は雪のため空いてました……