Bescottee苦しいときは伸びてるとき、楽なときは伸びていないとき

7 Androidタブレット向けアプリ開発方法

admin to development — Tags: , ,  

「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にしよう

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 マスター!!

7件のコメント »

  1. tomorrowkey より:

    とてもよくADLの内容がまとまっていて、参考になりました。
    フィード登録させていただきました。
    よろしければ、twitterアカウントも教えていただけないでしょうか。

  2. admin より:

    tomorrowkeyさん、コメントありがとうございます。
    こちらもいつもブログを参考にさせて頂いております。Google I/O 報告会も参加させて頂き、ありがとうございました。
    アカウントは別途ご連絡させて頂きました。

  3. わかめ より:

    Androidタブレット向けアプリ開発方法 – http://andbrowser.com/develop...

  4. vvakame より:

    Androidタブレット向けアプリ開発方法 http://ff.im/-HDzJc

  5. bilyakudan より:

    Androidタブレット向けアプリ開発方法 http://ff.im/-HDzJc

  6. gom より:

    Androidタブレット向けアプリ開発方法 « Bescottee – http://andbrowser.com/develop...

  7. gom より:

    Androidタブレット向けアプリ開発方法 « Bescottee – http://andbrowser.com/develop...

このコメント欄の RSS フィード トラックバック URL

コメントをどうぞ