「Android デベロッパーラボ 東京 2011」に参加して、Androidタブレット向けアプリ開発方法を聞いてきました。
ハッシュタグは
#adl2011jp
です。
Togetterは
#adl11jp Android Developer Lab 2011 7/2-3
です。
以下のソースコードをベースに既存のスマートフォン向けのアプリ(Activityベース)をタブレット向けに変更していきます。
コードラボ向けソースコード
をダウンロードしてください。
手順はHoneypad Codelab Steps — Tokyo 2011に書かれていますが自分の復習のために以下に記載しておきます。
以下の情報だけでは今回のトレーニングの全体像がつかみづらく、いま何をしているのかがわかりにくいため、Androidタブレット向けアプリ開発方法その2に全体像がわかるように変更前と変更後のクラス図を記載しておきました。参考にしてください。
Honeypad コードラボ 東京2011 目次
- Step 1. ターゲットをHoneycombにしよう
- Step 2. アクションバーを利用しよう
- Step 3. Fragments(Honeycomb 3.0からの新機能)を利用して新しいActivityを作成しよう
- Step 4. Fragment対応するために NoteEdit クラスを変更しよう
- Step 5. Fragment対応するために Notepad クラスを変更しよう
- Step 6. 新しいActivityのために Manifest を更新しよう
- Step 7. Activityと Fragments をつなげよう。パート1
- Step 8. Activityと Fragments をつなげよう。パート2
- Step 9. 縦画面レイアウトに対応しよう
- 最終のクラス図とレイアウト図
Step 1. ターゲットをHoneycombにしよう
Step1のゴール
- プロジェクトのビルドターゲットをAPI level 11に変更する
- minSdkVersionを API level 11 として明記する
- Set the android “Theme.Holo.Light” theme on the application
- アプリケーションのテーマを “Theme.Holo.Light”に設定する
- おまけ(余裕があれば):ハードウェアアクセラレーションをオンにする
実施手順
- AndroidManifest.xml の タグのコメントを外す
<uses-sdk android:minSdkVersion="11" /> <activity android:name=".Notepad" android:label="@string/app_name" android:theme="@android:style/Theme.Holo.Light" android:hardwareAccelerated="true">
Step 2. アクションバーを利用しよう
Step2のゴール
- アクションとテキストを’Add Note’ オプションメニューを表示する
- 適切なアイコンを追加する
実施手順
- Notepad.java から古いonCreateOptionsMenuを削除して、新しいonCreateOptionsMenuのコメントを削除する
@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuItem add = menu.add(0, MENU_ADD_ID, 0, R.string.menu_add); add.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); add.setIcon(R.drawable.ic_menu_add); return true; }
- おまけ(余裕があれば):メニューをXMLで定義する
Step 3. Fragments(Honeycomb 3.0からの新機能)を利用して新しいActivityを作成しよう
Step3のゴール
- NotepadActivityを作成する
- プロジェクトに入っているレイアウトファイルの notepad.xml を利用する
- NotepadActivityの onCreate メソッドをオーバーライドする
- notepad.xml を content view にセットする
実施手順
- NotepadActivity.java の中で、クラス定義と onCreate() メソッドのコメントを外す。
- (注)onCreate() メソッド以外のメソッドのコメントは外さないでください!!
public class NotepadActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.notepad); } }
Step 4. Fragment対応するために NoteEdit クラスを変更しよう
概要
- Fragmentクラスを継承する
- 空のコンストラクタを追加する
- onCreateView()を実装する
- 目的のレイアウトをインフレートして、それを返す
View v = inflater.inflate(R.layout.note_edit, container, false);
- これでsetContentViewを呼ぶ必要はない
- onCreateView()に初期化ロジックを移動して、onCreate()メソッドを削除する
- 1つのスクリーン向けに setTitle() を行う必要はないでしょう
- findViewById() メソッドコールを実施して、view を利用する
- Fragmentは、Context を拡張するものではありません。例えば、Content Resolver にアクセスするために必要な場合など。
- Context にアクセスする必要な場合は、上位(親の)Activityから取得する
- NoteEdit スクリーンを閉じるためにコードを削除する
- intent で起動されるのではなく、起動intent によって特定された Data Uri の蓄積も削除する
- NoteEditをNoteEditFragment に名前変更する
実施事項
- NoteEdit.javaの中で、loadNote()とclear()メソッド以外のすべてのコメントを外す
- NoteEdit を NoteEditFragment に名前変更する
- おまけ(余裕があれば):タブレット向けの fragment を widgets に最適化する
- テキスト書体とパディングを適切に設定する
- widgetにバックグラウンドボーダーを設定する
Step 5. Fragment対応するために Notepad クラスを変更しよう
概要
- ListFragment を継承する
- 空のコンストラクタを追加する
- viewが作成された後の初期化場所を変更する
- onActivityCreated() メソッドをオーバーライドする
- onCreate()メソッドから初期化ロジックを移動する
- onCreate()メソッドを削除する
@Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); fillData(); registerForContextMenu(getListView()); }
- Fragment は Context を継承していません。そのため、Content Resolver を得るためには、上位(親の)Activityから取得する必要あり。
- オプションメニューのメソッド(onCreateOptionsMenu() & onMenuItemSelected() ) を NotepadActivity クラスに移動する
- メニューのアイテムIDも移動すること
- createNote()メソッドコールを削除する
- createNote() メソッドを削除する
- Notepad クラスを NoteListFragment クラスに名前変更する
実施事項
- Notepad.javaの中で、NoteListEventsCallback インタフェース, mContainerCallback フィールド, onAttach() メソッド以外のコードのほとんどのコメントを外す
- NoteListFragment クラスに名前変更する
- createNote()メソッドを削除する
- おまけ(余裕があれば):タブレット向けの notes_row エントリに最適化する
- ‘activated’ として選択済み row を設定する
Step 6. 新しいActivityのために Manifest を更新しよう
step6のゴール
- NotepadActivityをメインアクティビティに変更する
- NoteEditFragment のActivity 継承を削除する
実施事項
- AndroidManifest.xml の中で、2つめの
タグのコメントを外して、NoteEditFragment 向けの タグを削除する
Step 7. Activityと Fragments をつなげよう。パート1
設計上の留意点
- 追加した大半の部品を接続するための実装(コンポーネントを接続するためのコード)
- 次のようなUIイベントのルーティングを実施: Fragment (NoteList) –> Activity –> Fragment (NoteEdit).
- このルーティングを実装するために、NotepadActivity にインタフェース定義を実装を追加
- もう1つ(概要より少ない)の方法は NoteList を得るためにNoteEditに直接アクセスする方法。しかし、それでは密結合である。
- コンポーネントを疎結合にするために、NotepadActivity がここでルーターの役割を担う。
- Step7のPart1では、NoteListからNotepadActivityへの接続を実装する
- Step8のPart2では、NotepadActivityからNoteEditへの接続を実装する
概要
- リスト上のNoteの選択と削除のイベント処理のための(NoteListEventsCallbackを呼ぶために)コールバックインタフェースを定義する
public interface NoteListEventsCallback { public void onNoteSelected(Uri noteUri); public void onNoteDeleted(); }
- NotepadActivityの中でインタフェースを実装する
- NoteListFragment は含まれているアクティビティに接続されるときに、インタフェース実装と参照補助を確認する
- この参照のコールバックを実行可能にする
@Override public void onAttach(Activity activity) { super.onAttach(activity); try { // check that the containing activity implements our callback mContainerCallback = (NoteListEventsCallback) activity; } catch (ClassCastException e) { activity.finish(); throw new ClassCastException(activity.toString() + " must implement NoteSelectedCallback"); } }
- Call the relevant callback when a note is selected from the list
- リストからノートが選択されたときに、関連するコールバックを呼び出す
@Override public void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); Uri noteUri = ContentUris.withAppendedId(NotesProvider.CONTENT_URI, id); mContainerCallback.onNoteSelected(noteUri); }
- リストからノートが削除されたときに、関連するコールバックを呼び出す
@Override public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case DELETE_ID: AdapterContextMenuInfo info = (AdapterContextMenuInfo) item .getMenuInfo(); getActivity().getContentResolver().delete( ContentUris.withAppendedId(NotesProvider.CONTENT_URI, info.id), null, null); fillData(); mContainerCallback.onNoteDeleted(); return true; } return super.onContextItemSelected(item); }
実施事項
- NoteListFragment.java の中で、インタフェース定義をコメントを外す
- NoteListFragment.java の中で、onAttach() メソッドとmContainerCallback フィールドのコメントを外す
Step 8. Activityと Fragments をつなげよう。パート2
概要
- 与えられたUriでノートが開くように NoteEditFragment にメソッドを追加する
- 関連するメンバの値を Uri に保持する
- フィールドの値を代入する
- もし fragmentが初期化されたときにこのメソッドを呼びたい場合のみ、onCreateView()メソッドの中で状態の初期化を行う前にコールされないようにガードしてください。
protected void loadNote(Uri noteUri) { mCurrentNote = noteUri; if (isAdded()) { populateFields(); } }
- NoteEditFragment にテキストフィールドをクリアするためのメソッドを追加する
protected void clear() { mTitleText.setText(null); mBodyText.setText(null); mCurrentNote = null; }
- NotepadActivityの中で、リストからノートが選択されたときにノートの詳細を表示するためにNoteEditFragmentを呼び出す。
- もし NoteEditFragment がアクティビティに追加されていれば、FragmentManager をチェックに利用する
- ヒント:与えられたタグでFragmentをチェックする
- もし、Fragment が見つけられなければ、コンテナーに追加を行う
- タグ上の note_detail_container に NoteEditFragmentの新しいインスタンスを追加するためにFragmentTransaction を利用する
- 選択したノートを表示するために NoteEditFragment の新しいメソッドを呼び出す
- もしユーザが’Add Note’をクリックした場合は、edit fragment をクリアする
@Override public boolean onMenuItemSelected(int featureId, MenuItem item) { switch (item.getItemId()) { case MENU_ADD_ID: showNote(null); return true; } return super.onMenuItemSelected(featureId, item); }
private void showNote(final Uri noteUri) { // check if the NoteEditFragment has been added FragmentManager fm = getFragmentManager(); NoteEditFragment edit = (NoteEditFragment) fm .findFragmentByTag("Edit"); if (edit == null) { // add the NoteEditFragment to the container FragmentTransaction ft = fm.beginTransaction(); edit = new NoteEditFragment(); ft.add(R.id.note_detail_container, edit, "Edit"); ft.commit(); } else if (noteUri == null) { edit.clear(); } if (noteUri != null) { edit.loadNote(noteUri); } }
- もし、ユーザがノートを削除する場合、NoteEditFragment を取り除く。
public void onNoteDeleted() { // remove the NoteEditFragment after a deletion FragmentManager fm = getFragmentManager(); NoteEditFragment edit = (NoteEditFragment) fm .findFragmentByTag("Edit"); if (edit != null) { FragmentTransaction ft = fm.beginTransaction(); ft.remove(edit); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); ft.commit(); } }
- おまけ(余裕があれば):いくつかの画面では UI スレッド上でディスクアクセスを実行している。
- StrictMode上でこれらの場所を発見してみてください。
- そして、これらを修正してください。
Step 9. 縦画面レイアウトに対応しよう
Step9のゴール
- 縦画面用のレイアウト向けのフォルダを作成する
- すでに存在する notepad.xml レイアウトをコピーして、縦画面になったときにリストが詳細画面の上に配置されるように修正する
- widthとheightを適切な値に設定する
実施事項
- コメントアウトされていないところの場合、layout-port/notepad.xml の中で記載されているセクションで vertial(portrait)版に変更する
最終のクラス図とレイアウト図
以上、これであなたも honeycomb マスター!!
とてもよくADLの内容がまとまっていて、参考になりました。
フィード登録させていただきました。
よろしければ、twitterアカウントも教えていただけないでしょうか。
tomorrowkeyさん、コメントありがとうございます。
こちらもいつもブログを参考にさせて頂いております。Google I/O 報告会も参加させて頂き、ありがとうございました。
アカウントは別途ご連絡させて頂きました。
Androidタブレット向けアプリ開発方法 – http://andbrowser.com/develop...
Androidタブレット向けアプリ開発方法 http://ff.im/-HDzJc
Androidタブレット向けアプリ開発方法 http://ff.im/-HDzJc
Androidタブレット向けアプリ開発方法 « Bescottee – http://andbrowser.com/develop...
Androidタブレット向けアプリ開発方法 « Bescottee – http://andbrowser.com/develop...