2014年11月11日火曜日

Android ActionBarとインタラクション

ActionBarとインタラクション制御


●ActionBarの基本


ActionBar:アプリにある複数の画面で恒久的に表示される、主にナビゲーションと適切なアクションの提示のために利用される重要なUIコンポーネント。

●4つのコンポーネント

□AppIcon

アプリのアイコン。ホームに戻る、階層を1つ戻るなどの役割を持たせることも可能。


□ViewControl

異なるViewに様々なデータを表示するような場合に、ユーザがすばやくViewを切り替えるためのもの。


□ActionItem Buttons(Action Buttons)

配置されるボタン類は、アプリやその画面のなかで最も重要なアクションを促す。シンプルな抽象化されたアイコンで表現することが多い。個数が多い場合は分割して、画面下部に表示させることも可能。


□Action Overflow

画面の大きさの影響で収まらなかったり、意図的にAction Overflowに入る様に設定したActionButtonsがここにまとめられる。
優先度が低い位置づけ。


●重要な要素1 NavigationMode

ActionBarの3つのナビゲーションモード。1つのActivityでは、3つのうちのいずれかを選択する。

□Standard Navigation

デフォルトのナビゲーションモード

□ListNavigation

ドロップダウンのリストから項目を1つ選択するタイプ。右下隅に▲が表示される。

ex)

getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);

□TabNavigation

複数のタブから1つを選択してコンテンツを切り替えるタイプのナビゲーションモード。

タブの位置は画面の大きさによって決定される。

・横幅の狭い画面:アクションバーの直下
・横幅の広い画面:タイトル部分の右端に統合
→ 画面の縦横切り替えでもアクションバーのレイアウトが入れ替わる。

ex)

getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);


●重要な要素2 ActionItem


OptionMenu(メニューキーを押して表示するメニュー)の代替で、アクションバーに含められるメニュー。

□android:showAsAction:アクションバーへの出し方を決定する属性


・always:常に表示します。もっとも重要度が高い。
・ifRoom:ほかのActionBarのコンポーネントが占める領域を見て、空があれば表示する。
・never:常にActionBar上に表示せず、その他(右端の3つの点)のメニューの中にまとめられる。もっとも重要度が低い。

always、ifRoom、neverのいずれか1つを選択

・withText:横幅の広い画面において、アイコンだけでなく、文言も一緒に表示するオプション。

端末の画面サイズに応じて、ActionBarが自動でAction Itemの表示をハンドリングする。


・タブレット型のような大きなディスプレイでは、アイコンとラベルを同時に表示。
・モバイル向けの端末では、横幅によってアイコンのみの場合と、ラベルとアイコンの同時表示がある。
・横画面が480dp以上ない場合、常にどちらかだけの表示。


●重要な要素3 App Icon Navigation


標準でアクションバーの左端に表示されるアプリのアイコンを、ナビゲーションのためのUIとして機能させる。

Androidの流儀としての使い方として、下記の2つの役割が想定されている。

・ホームボタンの役割
・階層構造を上に戻る役割(左向きの矢印が一緒に表示される。)

●重要な要素4 Split ActionBar


ActionItemを画面上部のActionBarから切り離し、画面下部に1列に表示するモード。

ex) <activity>の属性して以下を設定
android:uiOptionsにsplitActionBarWhenNarrow



●ActionBarSherlock

Android2.x でも ActionBarの導入を行うときに使用する。


●ActionBarの見た目を変える


StyleResourceとして、Drawablを利用してカスタマイズ可能。

***

●インタラクション制御

□ActivityやFragmentのコールバックについて


扱うメニューによって、コールバックメソッドが異なる。

□OptionsMenu

・onPrepareOptionsMenu:表示前に、メニュー要素の状態を管理するために呼び出す
・onCreateOptionsMenu:構成を初期化するため、ActivityやFragmentのライフサイクルの中で1度だけ呼ば荒れう
・onOptionsItemSelected:OptionMenuの選択状況を見て、適切なアクションを起こすために呼び出される

ex)

public class MainActivity extends Activity {
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // ここで、状態に応じてメニューの有効・無効を切り替えたりなどの処理をする
        return super.onPrepareOptionsMenu(menu);
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // ここで、この Activity で利用するメニューのリソースを読み込む
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // 選択されたメニューに対応するイベント処理をここで実行する
        return super.onOptionsItemSelected(item);
    }
}

□ContextMenu

Viewの長押しで表示されるメニューを構成する。

・onCreateContextMenu:ContextMenuの構成を初期化する
・onContextItemSelected:ContextMenuの選択状況を見て、適切なアクションを起こすために呼び出される


ex)

public class MainActivity extends Activity {
    @Override
    protected void onStart() {
        super.onStart();
        // View に長押しメニュー用のコールバックを設定する
        // 実際には、View に OnCreateContextMenuListener を設定するだけ
        // 登録処理を Activity が肩代わりしている
        View helloWorld = findViewById(R.id.HelloWorld);
        registerForContextMenu(helloWorld);
    }
    @Override
    protected void onStop() {
        // View に設定した長押しメニュー用のコールバックを解除する
        View helloWorld = findViewById(R.id.HelloWorld);
        unregisterForContextMenu(helloWorld);
        super.onStop();
    }
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        // ここで、長押しメニューで利用するメニューリソースを読み込む
        super.onCreateContextMenu(menu, v, menuInfo);
    }
    @Override
    public boolean onContextItemSelected(MenuItem item) {
        // ここで、選択されたメニューリソースに対応するイベント処理を実行する
        return super.onContextItemSelected(item);
    }
}

●Viewの状態とコールバックメソッド


View には、以下のような「状態(State)」が定義される。
View の種類によって、取り得る状態は様々。たとえばクリックされたとき、フォーカスがあたったとき、のActionを実施するために必要である。

□Viewの状態

・normal:何もしていない
・enabled:Viewがユーザ操作を受け付ける状態
・focused:Viewがユーザ操作によってフォーカスを持っている状態
・selected:Viewがユーザ操作によって選択されている状態
・checked:Viewがユーザ操作によってチェックされている状態
・pressed:Viewがユーザ操作によって押されている(クリック、タップ)状態

上記の各状態について、Observer パターンでイベントを監視する仕組みがある。
監視するためのオブジェクトの登録方法によって、Activityのライフサイクルに合わせて監視オブジェクトの管理をする必要がある。
以下のようなObserver(リスナー)がある。

・OnClickListener:View をタップした時に呼び出されるイベントを拾うためのObserver
・OnLongClickListener:Viewを長押ししたときに呼び出されるイベントを拾うためのObserver
・OnFocusChangedListener:Viewのフォーカスが移動したときのイベントを拾うためのObserver
・OnCheckedChangeListener:CheckBoxなどで、チェック状態が変化したときのイベントを拾うためのObserver
・TextWatcher:EditTexdtなどで、入力テキストが変更された時のイベントを拾うためのObserver

【Notice】TextWatcherは、ActivityやFragmentのライフサイクルに合わせて、適宜Viewへの登録と解除を行う。

ex)

public class MainActivity extends Activity {
    private TextWatcher mTextWatcher = new TextWatcher() {
        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {}
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
        @Override
        public void afterTextChanged(Editable s) {}
    };
    @Override
    protected void onStart() {
        super.onStart();
        // ライフサイクルに合わせて、Observer オブジェクトを登録する
        TextView helloEdit = (TextView) findViewById(R.id.HelloEdit);
        helloEdit.addTextChangedListener(mTextWatcher);
    }
    @Override
    protected void onStop() {
        // ライフサイクルに合わせて、Observer オブジェクトを解除する
        TextView helloEdit = (TextView) findViewById(R.id.HelloEdit);
        helloEdit.removeTextChangedListener(mTextWatcher);
        super.onStop();
    }
}

【参考】
https://github.com/mixi-inc/AndroidTraining/wiki/2.05.-ActionBar%E3%81%A8%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%A9%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E5%88%B6%E5%BE%A1

2014年11月7日金曜日

Eclipse Erro Could not open Selected VM debug port (8700) Make sure you do not have another instance of DDMS or of the eclipse plugin running

タイトルのエラーが出ると、デバッグが出来なかったりして不便。

Could not open Selected VM debug port (8700) Make sure you do not have another instance of DDMS or of the eclipse plugin running

hostsファイルのlocalhostの記述がコメントアウトされてしまってる場合にも出るので注意。

2014年11月6日木曜日

Android 5.0 (L) のインストール Nexus5

Android5.0 インストールメモ

準備


LG製のNexus5(SIMフリー)にインストールした。ここではwindow8を用いる。

まず、Nexus5をadb接続する。

adbがデバイスとして認識しないときは、Androidのストレージの設定が「MTP」接続でない場合がある。MTP接続にしておく。

以下のコマンドでデバイスが認識できたら、USBデバッグをONにして処理を開始する。

> adb devices 

OSの取得


以下のページからNexus5用のAndroid5.0 Preview Imageをダウンロードする。



ローカルで解凍しておく。


ブートローダのアンロック

bootloaderに接続

> adb reboot bootloader


ロックをはずす

> fastboot oem unlock


音量ボタンの大でYESを選び、電源ボタンでGOする。

OSのインストール

解凍しておいたImageのインストール用bat(Linux系の場合shell)を使うだけ。

> flash-all.bat


以上、新しいUIやARTを楽しもう。

Android メッセージと通知

Androidのメッセージングと通知についてのメモ


ざっと全体を把握し、Tipsとして使いやすく編集。

●Intent

Androidのメッセージで最も頻繁に使われる。やりとりするデータのまとまり。

送信者:Contextがメッセージとして送る仕組みをもつ。

受信者:Activity、Service、BroadcastReceiver

●Intentオブジェクト


□目的

メッセージを送信した相手に、処理を実行してもらう。

□Action 処理内容の記述

実行してほしい処理を示す。

・Activity用の代表的な処理内容

ACTION_VIEW
ACTION_MAIN
ACTION_SEND
ACTION_SENDTO
ACTION_EDIT
ACTION_PICK
ACTION_DELETE
ACTION_INSERT
ACTION_SEARCH
ACTION_CALL


・Broadcast用

ACTION_BOOT_COMPLETED
ACTION_SHUTDOWN
ACTION_PACKAGE_ADDED
ACTION_PACKAGE_REPLACE
ACTION_PACKAGE_REMOVED


□Category 処理すべき対象に期待する属性


CATEGORY_DEFAULT
CATEGORY_LAUNCHER
CATEGORY_HOME
CATEGORY_PREFERENCE
CATEGORY_BROWSABLE


□Data Actionの対象となるデータURI


ex)
ACTION_VIEWとしてDataを渡す → Dataを表示する


□Type Dataの種類を表すMIMEタイプ



□Component 期待するActionを実行するコンポーネント

すなわち、Intentっを送る対象のコンポーネント

・明示的Intent
Componentを明示する

・暗黙的Intent
Componentを明示しない


□Extras Intentを送る対象にわたす追加情報


KeyとValueのペアをBundleに追加してわたす。


□Flag

Activityの起動方法をシステムに通知するための情報


●Intent Filter


暗黙的インテントをうけとるコンポーネントが、Intentをハンドリグ可能かどうかを宣言するための仕組み
Androidフレームワークは、IntentFileterをもとにして暗黙的Intentの対象となるコンポーネントをリストアップし、
ユーザに選択肢を提供する。

□暗黙的Intentのハンドリング基準


・Action、Data、category の3つ

→ AndroidManifest で宣言が可能

<activity>の要素に<intent-filter>要素を追加する。

ex) 起動Activity

<intent-filter>
    <!-- アプリのメイン(入り口)となる Activity を起動するときの Action を受け取る -->
    <!-- Intent クラスに定義されている ACTION_MAIN 定数の実態は "android.intent.action.MAIN" という文字列 -->
    <action android:name="android.intent.action.MAIN" />
    <!-- ランチャーからの起動のものを受け取る -->
    <!-- Intent クラスに定義されている CATEGORY_LAUNCHER 定数の実態は "android.intent.category.LAUNCHER" という文字列 -->
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

ex) 画像共有Activity

 <intent-filter>
    <!-- ACTION_SEND または ACTION_SEND_MULTIPLE のいずれかを受け取る -->
    <!-- Intent に設定可能な Action は 1 つだけなので、<intent-filter> に Action を複数宣言すると -->
    <!-- その中からいずれかに該当するものを受け取る、という意味になる -->
    <action android:name="android.intent.action.SEND" />
    <action android:name="android.intent.action.SEND_MULTIPLE" />
    <!-- 暗黙的 Intent を扱う際に必須のカテゴリ -->
    <!-- システムは、Activity の起動に暗黙的 Intent を発行すると、 -->
    <!-- このカテゴリが付与されているものとして扱うため、Activity で暗黙的 Intent を受け取りたい場合は -->
    <!-- 必ずこのカテゴリを <intent-filter> に宣言しておく -->
    <!-- 複数のカテゴリを <intent-filter> に宣言した場合は、 -->
    <!-- 全てのカテゴリにマッチするもののみを受け取る、という意味になる -->
    <category android:name="android.intent.category.DEFAULT" />
    <!-- Data の種類の制限 -->
    <!-- MIME タイプのほか、URI のスキームを制限することもできる -->
    <data android:mimeType="image/jpeg" />
</intent-filter>


●Intentをつかった1対1のメッセージング


□Activityの起動


ex)
Intent intent = new Intent(this, NextActivity.class);
// Intent を Context に渡して、メッセージを送る
// この場合、NextActivity クラスにメッセージが送られ、NextActivity が立ち上がる
startActivity(intent);


□Activityを起動して、処理結果を期待する


ex) Intent送信
 startActivityForResult(new Intent(this, SubActivity.class), SubActivity.REQUEST_CODE_HOGE);


ex) 結果の受信
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // super.onActivityResult(int, int, Intent) の呼び出しは、条件に関係なくすること
    // Fragment から startActivityForResult(Intent, int) した場合の戻りの判定ができなくなってしまう
    super.onActivityResult(requestCode, resultCode, data);
    // requestCode には、startActivityForResult(Intent, int) の第 2 引数で指定したものが来る
    // resultCode には、呼び出し先で setResult(int, Intent) をコールした時の第 1 引数が来る
    // data には、呼び出し先で setResult(int, Intent) をコールした時の第 2 引数が来る
    switch (requestCode) {
        case SubActivity.REQEUST_CODE_HOGE:
             // REQUEST_CODE_HOGE の戻りが来た時の処理
             return;
        default:
             // 知らない requestCode の戻りが来た時の処理
             return;
    }
}

ex) Intent受信

public class SubActivity extends Activity {
    public static final int REQUEST_CODE_HOGE = 1;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 何かする
        // 呼び出し元に返す Intent オブジェクトをセットする
        // 第 1 引数には、RESULT_OK または RESULT_CANCELLED、あるいは、RESULT_FIRST_USER を起点にした独自の int 型定数を使う
        setResult(RESULT_OK, new Intent());
        finish();
    }
}


□Serviceを起動するIntent

Serviceを呼び出す。

ex)
// サービスのバインド要求
bindService(new Intent(this, MyService.class), mServiceConnection, Context.BIND_AUTO_CREATE);

// サービスの開始要求
startService(new Intent(this, MyIntentService.class));


●Intentを用いた、1対多のメッセージング

ブロードキャスト:アプリ内外に問わず、Intentを全体へ投げかける仕組み。Androidでは端末の状態を全アプリに通知するための仕組みとして利用している。

□BroadcastReceiver

ブロードキャストされるIntentを受信するためのコンポーネント

【注意】宣言の仕方によって、使われ方が異なる。


□BroadcastReceiverのライフサイクル


Intentを受け取るためのコールバックメソッド onReceive をオーバーライドする。
BroadcastReceiverのライフサイクル = オーバーライドした onReceive の実行されている間

ex)
public class MyBroadcastReceiver extends BroadcastReceiver {
    // Broadcast された Intent を受け取るコールバック
    @Override
    public void onReceive(Context context, Intent intent) {
    }
}

□BroadcastReceiverプロセスの優先順位


最も優先順位の高いフォアグラウンドプロセス

・BroadcastReceiverのライフサイクルが終了したプロセス = 動作している他のコンポーネントがもつ優先順位となる
・BroadcastReceiverのみがプロセス上動作している場合、BroadcastReceiverのライフサイクルが終了すると、空プロセスとなり、システムが優先してkillする。

どちらの場合も、BroadcastReceiverを実行したプロセスはシステムによって終了可能で、プロセス上で非同期処理を実行した場合、処理が終わってもどる前に、
プロセスがkillされる可能性がある。よって、BroadcastReceiverのプロセスは非同期処理に向いていない。

非同期処理には、Service と呼ばれる仕組みを利用する。

また、BroadcastReceiverの中でダイアログを表示することも推奨されない。これも、ライフサイクルがダイアログのイベント実行より先に終了し、プロセスがkillされるからである。
ダイアログは、Notification と呼ばれる仕組みを利用する。


□Static BroadcastReceiver(静的ブロードキャスト)

AndroidManifestに宣言されるBroadcastReceiverでありアプリがインストールされている間はずっとBroadcastReceiverが動作し、ブロードキャストするIntentの監視を続ける。
ただし、Honeycomb以降は、1度でも起動することが条件である。

ex) AndroidManifest <application>要素の子として登録する
<receiver
    android:name="jp.mixi.sample.MyBroadcastReceiver">
    <intent-filter>
    </intent-filter>
</receiver>

ex) 受信コード

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
    }
}

□Dynamic BroadcastReceiver(動的ブロードキャスト)


ActivityなどのContextで動的に登録/解除が行われるBroadcastReceiver。

・ActivityのContext
ActivityのContextの中で動的に登録する場合、解除もActivityのContextの中で実施する必要がある。
どのライフサイクルのContextで登録を行うかも大事。

「ActivityのContextで動的に登録 → ActivityのContextで解除する」のようにセットで行う必要がある。もし解除がされていない場合、
システムが自動で登録を解除し、適切に解除を行う指示をエラーログに出力する。

ex)
public class MyActivity extends Activity {
    private BroadcastReceiver mMyReceiver = new MyBroadcastReceiver();
    @Override
    protected void onStart() {
        super.onStart();
        // ACTION_PACKAGE_ADDED の Action を通す IntentFilter オブジェクトを作成
        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
        // MyBroadcastReceiver オブジェクトを、指定した IntentFilter オブジェクトで、Activity の Context に登録
        registerReceiver(mMyReceiver, filter);
    }
    @Override
    protected void onStop() {
        // MyBroadcastReceiver オブジェクトの登録を、Activity の Context 上から解除する
        // Activity のライフサイクルが終わりに向かうコールバックの中で実装する
        unregisterReceiver(mMyReceiver);
        super.onStop();
    }
}


・ApplicationのContext
アプリケーションの中でグローバルなスコープでBroadcastReceiverが動作する。
解除を忘れても、システムは自動で登録を解除しないので、リークの原因となる。


□Intentのブロードキャスト


・ブロードキャストの送信

ex)

Context#sendBroadcast(Intent)

ex) 定義したActionやCategoryで受け付けてくれるすべてのBroadcastReceiverがIntentを受信する。

public class MyActivity extends Activity {
    // 自分で独自の Action を定義することも可能
    public static final String ACTION_HOGEHOGE = "jp.mixi.sample.android.intent.action.HOGEHOGE";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...
        // Intent のブロードキャスト
        Intent intent = new Intent();
        intent.setAction(ACTION_HOGEHOGE);
        sendBroadcast(intent);
    }
}


□LocalBroadcastManager アプリ内全体へのブロードキャスト

他のアプリに知られたくない、自プロセス内※の閉じたBroadcastを実現する。
※LocalBroadcastManagerはマルチプロセスをサポートしない。
・Privateデータを送信しても安心
・エクスプロイト対策
・軽量に利用可能

ex)
// LocalBroadcastManager は Support Package に含まれている
import android.support.v4.content.LocalBroadcastManager;
public class MainActivity extends Activity {
    public static final String TAG = MainActivity.class.getSimpleName();
    public static final String ACTION_HOGEHOGE = "jp.mixi.sample.android.intent.action.HOGEHOGE";
    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.v(TAG, "local broadcast received.");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    @Override
    protected void onStart() {
        super.onStart();
        // この Activity の Context の中での、Local な Broadcast を管理する為の LocalBroadcastManager オブジェクト
        LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
        manager.registerReceiver(mReceiver, new IntentFilter(ACTION_HOGEHOGE));
    }
    @Override
    protected void onStop() {
        LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
        manager.unregisterReceiver(mReceiver);
        super.onStop();
    }
    // ボタンなどのクリックハンドラ
    public void onHogeClick(View v) {
        // Local な Broadcast として Intent を投げる
        // 通常の sendBroadcast(Intent) メソッドと違い、この仕組で投げた Intent は他のアプリ(プロセス)では拾うことが出来ない
        LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
        manager.sendBroadcast(new Intent(ACTION_HOGEHOGE));
    }
}


□Broadcastのバーミッション

Manifestにパーミッションを設定することで、パーミッションを得ているアプリのみがブロードキャストを受信できるようにする。
この場合、パーミッションをもっていれば、他のアプリでも受信が可能。

●Intentへの付加情報


□Intent Extras

いくつかのプリミティブ型と文字列、コレクション、Parcelebleオブジェクト(シリアライズ)を付加。


ex) Intent送信側

public class MyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...
        List<String> list = new ArrayList<String>();
        list.add("fuga");
        list.add("piyo");
        Intent intent = new Intent(this, NewActivity.class);
        intent.putExtra("StringExtraKey", "hogehoge");  // 文字列の場合
        intent.putExtra("BooleanExtraKey", true); // boolean の場合
        intent.putExtra("IntegerExtraKey", 10); // int の場合
        intent.putStringArrayListExtra("StringArrayListExtraKey", list); // ArrayList<String> の場合
        startActivity(intent);
    }
}

ex) Intent受信側

public class NewActivity extends Activity {
    @Override
    protected void onCreate(savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...
        // この Activity への Intent オブジェクトを取得する
        Intent received = getIntent();
        String stringExtra = received.getStringExtra("StringExtraKey"); // 文字列の Extra を取り出す
        boolean booleanExtra = received.getBooleanExtra("BooleanExtraKey"); // boolean の Extra を取り出す
        int integerExtra = received.getIntExtra("IntegerExtraKey"); // int の Extra を取り出す
        List<String> listExtra = received.getStringArrayListExtra("StringArrayListExtraKey"); // ArrayList<String> の Extra を取り出す
    }
}


●Notification

Anroidのステータスバーにアプリからのお知らせを知らせる仕組み。

Notificationの種類

□ Normal View

・通知のアイコン
・アプリのタイトル
・詳細メッセージ
・情報量
・小さいアイコン
・通知表示した時間

□ Big View (JellyBean以降)

・通知のアイコン
・アプリのタイトル
・詳細メッセージ
・情報量
・小さいアイコン
・通知表示した時間
・詳細表示View:スタイル(Bit Picture Style、Big Text Style、Inbox Style)

●Notificationの仕組み


通知表示用の窓口:NotificationManager

窓口が受け取るもの:Notificationオブジェクト

Notificationオブジェクトの生成:NotificationCompat.Builderを使う。(直接のインスタンス生成は不具合のもと)

Notificationの必要条件:アプリのアイコン、通知のタイトル、詳細メッセージの3つを保持

□PendingIntent

通知では、仕組みをシステム(この場合Androidシステム)にあわせる。PendingIntentを使うと、Intentの送信タイミングの遅延、Intentオブジェクトのハンドリングを委譲することが可能。

ex)

public class MyActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // do something...
        // Intent の準備。明示的 Intent でも、暗黙的 Intent でもどちらでも構わない
        Intent intent = new Intent(this, SubActivity.class);
        // PendingIntent オブジェクトの生成。このオブジェクトを他のアプリに渡すことで、引数に渡した Intent の送信を委ねることができる
        // PendingIntent は、Intent の送信先のコンポーネントの種類によって使い分けること
        PendingIntent activityIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }
}

PendingIntentオブジェクトは、遅延させるIntentオブジェクトのターゲットしているコンポーネントによって、利用するメソッドを変える。

・ActivityがターゲットのPendingIntentを作成する
PendingIntent#getActivity(Context, int, Intent, int)


・ActivityがターゲットのPendingIntentを作成するが、複数(配列でわたす)のActivityを扱う:Honeycomb以降
PendingIntent#getActivity(Context, int, Intent[], int)

・BroadCast用のIntentをもつPendingIntentオブジェクトを作成する
PendingIntent#getBroadcast(Context, int, Intent, int)

・ServiceがターゲットのPendingIntentオブジェクトを作成
PendingIntent#getService(Context, int, Intent, int)

全てのメソッドで第2引数にint型をrequireしている。これは、PendingIntentを一意に認識するためのIndexの役割をもつ。

第4引数のint型は、PendingIntentオブジェクトを受け取る側が、どのように扱うかを支持するもの。
以下の定数から選択する。

・既存の古いPendingIntentをキャンセルして、新しいPendingIntentを作成する場合
PendingIntent.FLAG_CANCEL_CURRENT

・既存のPendingIntentを使う(既存が無い場合はnull)
PendingIntent.FLAG_NO_CREATE

・ただ一度PendingIntentを使用する場合
PendingIntent.FLAG_ONE_SHOT

・既存のPendingIntentのExtrasのみ入れ替える
PendingIntent.FLAG_UPDATE_CURRENT


●NotificationCompat.Builder

Notificationオブジェクトの作成

ex)
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Intent intent = new Intent(this, SubActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
        Notification notification = builder
                // 通知の日時
                .setWhen(System.currentTimeMillis())
                // 通知のタイトル
                .setContentTitle("通知だヨ!")
                // 通知の詳細メッセージ
                .setContentText("通知の詳しい内容をここに書きます。")
                // 通知のアイコン
                .setSmallIcon(R.drawable.ic_launcher)
                // 通知を表示した瞬間、通知バーに表示するショートメッセージ
                .setTicker("通知だヨ!")
                // 通知をタップした時に使う PendingIntent
                .setContentIntent(pendingIntent)
                // この通知が未だ表示されていない時だけ、音やバイブレーション、ショートメッセージの表示を行う
                .setOnlyAlertOnce(true)
                // タップしたら消えるようにする
                .setAutoCancel(true)
                .build();
    }
}

●作成したNotificationオブジェクトの通知


ex)
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Notification notification = /* 通知オブジェクトの作成(省略) */
        // 直接インスタンス化せず、Context を経由してインスタンスを取得する
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        // 通知の種類に応じて id を割当てることが出来る。
        // id の異なる通知は違うものとして扱われる。
        manager.notify(0, notification);
    }
}

【参考】https://github.com/mixi-inc/AndroidTraining/wiki/2.04.-%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%83%B3%E3%82%B0%E3%81%A8%E9%80%9A%E7%9F%A5#Intent

2014年11月4日火曜日

Android Resource

Androidアプリケーションのリソースに関するメモ


Androidアプリのリソース

Androidアプリのリソースとは、コードとは分離された静的なデータである。
主にresディレクトリ配下を使用する。

Javaのプログラムからresディレクトリに配置した静的なデータにアクセスする場合、
生成されるRオブジェクトを介して行う。

【参考】Rについて
http://developer.android.com/intl/ja/reference/android/R.html

●扱うことができる読み取り専用リソース


String:文字列
Drawble:ビットマップ、ベクタ画像
Style:UIスタイル、テーマ
Menu:メニュー項目
ColorStateList:状態に対応した色の管理
Value:プリミティブ型(http://goo.gl/aQRTSN)
Animation:アニメーション
Raw:音声・動画・画像などのRawデータ
Layout:画面レイアウト
XMLResource:任意のXMLファイル

●アニメーションの種類

Animationには大きく3種類あります。

・Tweenアニメーション:1つのイメージを連続的に変化させるタイプ。ある対象に対するアフィン変換+フェードイン、アウト
・Propertyアニメーション:FragmetnやDrawableなど様々なオブジェクトにアニメーションを提供する。背景変化、透過変化(API Level 11 HoneyComb)
・Frameアニメーション:順番にイメージを並べて表示するタイプ。パラパラ漫画のような効果。

□Alpha:フェードイン、アウト

<alpha>要素
・android:fromAlpha属性
 アニメーション開始時のアルファ値
・android:toAlpha属性
 アニメーション終了時のアルファ値

□Scale:拡大・縮小

<scale>要素(全ての属性を設定する必要はない)
・android:fromXScale属性
 アニメーション開始時の、横方向の拡大率です。1.0 を基準に拡大率を決定。
・android:toXScale属性
 アニメーション終了時の、横方向の拡大率です。1.0 を基準に拡大率を決定。
・android:fromYScale属性
 アニメーション開始時の、縦方向の拡大率です。1.0 を基準に拡大率を決定。
・android:toYScale属性
 アニメーション終了時の、縦方向の拡大率です。1.0 を基準に拡大率を決定。
・android:pivotX属性
 拡大の中心点のX座標です。指定しないと 上端。
・android:pivotY属性
 拡大の中心点のY座標です。指定しないと 左端。

□Translate:並行移動

自分の大きさに対する % を指定。%pは、親要素の大きさに対するパーセンテージ
<trnslate>要素
・android:fromXDelta属性
 アニメーション開始時の X 座標。-100 から 100 までの % 単位または %p 単位の数字か、単位のない任意の数字を設定可能。
・android:toXDelta属性
 アニメーション終了時の X 座標。-100 から 100 までの % 単位または %p 単位の数字か、単位のない任意の数字を設定可能。
・android:fromYDelta属性
 アニメーション開始時の Y 座標。-100 から 100 までの % 単位または %p 単位の数字か、単位のない任意の数字を設定可能。
・android:toYDelta属性
 アニメーション終了時の Y 座標。-100 から 100 までの % 単位または %p 単位の数字か、単位のない任意の数字を設定可能。

□Rotate:回転

<rotate>要素
・android:fromDegrees属性
 アニメーション開始時の角度。
・android:toDegrees属性
 アニメーション終了時の角度。
・android:pivotX属性
 回転の中心点の X 座標。
・android:pivotY属性
 回転の中心点の Y 座標。

□複合

<set>要素を使用することで、複数のアニメーションを組み合わせることが可能。

□共通

・android:duration属性
 アニメーションを再生する時間です。millisecond 単位で指定します。
・android:repeatMode属性
 アニメーションが終了した時に、アニメーションを最初から再開するか、最後から最初へ戻るようにするかを設定する。
この設定が有効になるのは、後述するandroid:repeatCount属性が 0 以上か、若しくは infinite に設定された時のみ。
デフォルト値では、アニメーションを最初から再開するように設定される。
・android:repeatCount属性
 アニメーションを繰り返す回数です。infinite と設定することで、無限に繰り返すようにもできる。
・android:startOffset属性
 アニメーションのスタートの遅延時間です。指定した時間(msec)だけ遅延させることができる。

ex)
<set
    xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 回転は無限回 -->
    <!-- アニメーションする View のちょうど真ん中を中心に一周する -->
    <rotate
        android:duration="1000"
        android:repeatCount="infinite"
        android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="50%"
        android:pivotY="50%"/>
    <!-- 平行移動は 1 回だけ -->
    <!-- アニメーションする View の親の 40% の位置に移動する -->
    <translate
        android:duration="1000"
        android:repeatCount="0"
        android:toXDelta="40%p"
        android:toYDelta="40%p"/>
</set>

適用はJavaコードで行う。

ex)
View textView = findViewById(R.id.TextView1);
// Animation Resource を読み込んで、Animation オブジェクトを得る
Animation animation = AnimationUtils.loadAnimation(this, R.anim.sample_animation);
// Animation オブジェクトを View に渡して、アニメーションを開始する
textView.startAnimation(animation);


これらは同じアニメーションでも、静的データを配置する場所が異なるので注意が必要。


●読み取り専用リソースの配置場所(リソースディレクトリ)


res/animator:Propertyアニメーション
res/anim:Tweenアニメーション
res/color:ColorStateList
res/drawable:Drawable
res/layout:Layout
res/menu:Menu
res/raw:Raw
res/values:Values、Strin、Style
res/xml:任意のXML、GAの設定ファイル

●リソースディレクトリの命名規則


<resources_name>-<configuration_qualifier>

ex) drawable-hdpi(hdp向けdrawable)、values-en(英語ロケール向けvalues)、drawable-land-xhdpi(横画面xhdpi向けdrawable)

●リソースにアクセスする

ResourceID:aaptが自動生成する。リソースファイルに問題があるとaaptがコンパイルと最適化に失敗し、IDを生成できない。
aaptが生成した結果は Rクラスに反映され、IDに対応したint型の整数値が割り当てられる。

・XMLの属性でIDを割り当てるもの
・ファイル名をIDとするもの

以下の記述でアクセスする。package_nameは任意である。

(package_name).R.(resource_type).{resource_di}

AndroidフレームワークのもっているRクラスは直接importせず、FQDNでアクセスする。

import android.R;
R.id.text_1

android.R.id.text_1;

●XMLからリソースにアクセスする

layoutなどの記述で頻繁に記載する方法です。

ex)
@android:id/text_1

上記は、リソースIDを用いてアクセスする例。リソースの種類によって書き方が異なる。(http://goo.gl/kA8cl1)


●リソースの記述方法

□String Resource

UIで使用する定型文は直接XMLに記述せずに、String Resourceで定義することが推奨される。

ex)

<resources>
    <string name="hello_world">Hello World</string>
    <string name="image_recognize">Image Recognize</string>
</resources>

XMLファイルで使う場合、前述の「XMLからリソースにアクセスする」を参考に。
Contextをもっているクラスでは、以下のように取り出すことができる。

ex)

String hello = getString(R.string.hello_world);

□String Array

文字列の配列を定義する。受け取る側は配列として受け取ることができる。

ex)

<resources>
    <string-array name="foo_bar">
        <item>Foo</item>
        <item>Bar</item>
    </string-array>
</resources>

ex) Contextをもっているクラスでの受け取り。

getResources().getStringArray(R.array.foo_bar);


同じ構造でint型を使用した、Integer Array がある。


□Format

プレースホルダを用いて、可変な文字列をリソースで提供する。後から文字列の一部を変更したい場合などに用いる。$dは数字を示す。文字列を渡したいときは$sとする。Formatterで定義される(http://developer.android.com/intl/ja/reference/java/util/Formatter.html)。


ex)
<resources>
    <string name="my_format">私は、%1$d社製のギターをもっている。</string>
    <string name="my_format_2">私は、%1$d社製のベースと、%2$d社製のギターをもっている。</string>
</resources>

ex) 受け取り側で値を設定する

String formatted = getString(R.string.my_format_2, 'Fender', 'Gibson');


□Plurals

複数形の表示。

ex)
<resources>
    <plurals name="my_guiters">
        <item quantity="zero">I don't have guiter.</item>
        <item quantity="one">I have a guiter.</item>
        <item quantity="other">I have %d guiters.</item>
    </plurals>
</resources>

quantity属性は、zero、one、two、few、many、other から選択する。

ex) 受け取り側

String quantity = getResources().getQuantityString(R.plurals.my_guiters, 2, 2);
日本語端末の場合は注意が必要で、単数・複数形を持たない日本語の場合、常にotherが使用される。otherが定義されていないと落ちる。
http://qiita.com/mstssk/items/6697db6947918e58593b

□Drawable Resource(グラフィックリソース png/jpeg/gif/9patch形式の画像/XML定義の図形/アニメーションGIFは非対応)

推奨:png、容認:jpeg、非推奨:gif

解像度ごとのディレクトリ階層で分けていない場合、あるいは該当する解像度のリソースディレクトリがない場合は、システムによって適宜拡大・縮小が行われるため、画像が鮮明でなくなる可能性がある。

Drawableに配置したリソースはアプリのビルドで最適化される。最適化されたくない、元の状態を保持したい場合は、Rawに配置すること。

Drawableには種類がある。Bitmap、9-patch、Layer List、State List、Level List、Transition、Inset、Clip、Scale、Shape である。順に見ていく。【参考】http://goo.gl/7kvVdY

Bitmap
pngやjpg、gif
9-patch
ストレッチ可能な領域を指定した画像でデータ
Layer List
複数のDrawable要素をレイヤ上に並べたXMLのグラフィックリソース<item>要素でDrawableへの参照を記述したり、各種Drawableを子にもつレイヤをつくったりする。
ex)
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 一番下のレイヤに配置する、グレーで塗りつぶされた四角形の Drawable を持つ item 要素 -->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#f5f5f5"/>
        </shape>
    </item>
    <!-- 一番上のレイヤに配置する、薄茶色で塗りつぶされた四角形の Drawable を持つ item 要素 -->
    <!-- 上端から 30dp 分のオフセットが設定されている -->
    <item android:top="30dp">
        <shape android:shape="rectangle">
            <solid android:color="#deb887"/>
        </shape>
    </item>
</layer-list>

State List Drawable
UIの状態に応じたDrawable要素を管理する。ボタンのタップ、非タップで状態を変えたいときになどに使用。

ex)
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- View が押された状態の Drawable -->
    <item android:state_pressed="true">
        <shape android:shape="rectangle">
            <solid android:color="#696969"/>
        </shape>
    </item>
    <!-- View が通常の状態の Drawable -->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#f5f5f5"/>
        </shape>
    </item>
</selector>

Level List
一定の規定値に依存して、Drawable要素を管理する。例えば、カーソルによって変化する値によって表示状態を変えたい場合などに使用。

ex)
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Level が 最高 0 までの時の Drawable への参照 -->
    <item android:maxLevel="0" >
        <shape android:shape="rectangle">
            <solid android:color="#f5f5f5"/>
        </shape>
    </item>
    <!-- Level が 最高 1 までの時の -->
    <item android:maxLevel="1" >
        <shape android:shape="rectangle">
            <solid android:color="#696969"/>
        </shape>
    </item>
</level-list>


ex) 取り出し方(Drawable系共通)

Drawable drawable = getResources().getDrawable(R.drawable.hogehoge);

Transition
複数のDrawableのクロスフェードを管理する。例えばフェードインやフェードアウト効果に使用する。コード上で実行時間を与えるなどしてstartTransitionして実行する。

ex)
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 最初の状態 -->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#f5f5f5"/>
        </shape>
    </item>
    <!-- 次の状態 -->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#696969"/>
        </shape>
    </item>
</transition>

Inset
Drawableの中に別のDrawableを差し込むXMLリソース。ViewがView自身より小さい背景グラフィックを要求する時に便利。また、Drawableのマージン(画像の外側の余白)をつけることにも利用可能。

ex)
<inset
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_launcher"
    android:insetTop="10dp"
    android:insetLeft="10dp"/>


Clip
Drawableのレベルによって、別のDrawableを切り抜く。Levelを変換させることで、徐々に画像を表示させるなどが可能。

ex)
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_launcher"
    android:clipOrientation="horizontal"
    android:gravity="right"/>

コード側で、レベルをセットすることで切り抜き状態を変更する。

ex)
ClipDrawable clip = (ClipDrawable) clipView.getBackground();
clip.setLevel(1000);

Scale
大きさを変化させる。初期状態は0(0倍 = 表示されない)、コードでレベルを変化させる。

ex)
<scale
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_launcher"
    android:scaleGravity="center"
    android:scaleWidth="50%"
    android:scaleHeight="50%"/>

ex)
ScaleDrawable scale = (ScaleDrawable) scaleView.getBackground();
scale.setLevel(1);


Shape
色やグラデーション情報を含む、幾何学的図形をXMLで宣言するグラフィックリソース

ex)
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
        <!-- solid: 塗りつぶし -->
    <solid
        android:color="#f5f5f5"/>
        <!-- stroke: 枠線 -->
    <stroke
        android:width="1dp"
        android:color="#000000"/>
</shape>

●Style

Viewの各要素の属性値をまとめて、一定のフォーマットを基底するリソース。アプリ内で共通のUIを提供する際に活用する。

ex)
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <style name="BigTextViewStyle" parent="@android:style/Widget.TextView">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textSize">22sp</item>
    </style>
</resources>

上記のように定義したStyleを、各Viewに設定することで、Viewのフォーマットを指定します。

ex)
<TextView
        style="@style/BigTextViewStyle"
        android:id="@+id/HelloWorld1"
        android:text="@string/hello_world"/>


●Styleの継承

システムで定義されたスタイルを継承する。style要素にparent属性を追加。parent属性には、継承したいスタイルを設定。

ex)
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <style name="BigTextViewStyle" parent="@android:style/Widget.TextView">
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:textSize">22sp</item>
    </style>
</resources>

●parent属性以外の継承

名称で継承する。

ex)

  • <style name="BigTextViewStyle.Red">
  •     <item name="android:textColor">#FF0000</item>
  • </style>
  • <!-- BigTextViewStyle.Red を継承する -->
  • <style name="BigTextViewStyle.Red.Bold"> ←元のStyle名に.~で新しく定義するスタイルの名前を宣言する。
  •     <item name="android:textStyle">bold</item>
  • </style>


●Menu

メニュー(OptionMenu、ContextMenu)の各種項目。

・OptionMenu:デバイスのMenuキー。または、ActionBarの並びに入るメニュー。
・ContextMenu:UIの長押しで呼び出されるメニュー

□メニューのDefine


ex)
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item ← メニュー1つ文に相当する要素。子にmenu属性を配置して、submenuにできる。
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:showAsAction="never"
        android:title="@string/action_settings"/>
</menu>

□OptionMenu


以下のようなコードでメニューリソースにアクセスして、リソースファイルの状態を反映する。

ex)
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return super.onCreateOptionsMenu(menu);
}

□ContextMenu

明示的にviewに対して、ContextMenuを割り当てることでリッスン可能。ただし、リスナーのコールバックはonCreateContextMenu()で受け付けるため、Activityへの参照を他のオブジェクトがもつことになる。そのため、適切なタイミングでコールバックを受け付けないようにライフサイクルを管理する必要がある。詳細は後述。


●Color State List

例えばボタンがタップされたとき、そうでないときの色を変化させるなどの際に使用する。
ただし、カラーリソースはbackgroundなどのグラフィックリソースへの参照が必要な属性には指定できない。

ex) sample_color_state_list.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- View が押された状態の Drawable -->
    <item android:color="#696969" android:state_pressed="true"/>
    <!-- View が通常の状態の Drawable -->
    <item android:color="#f5f5f5"/>
</selector>

ex)
<Button
    android:id="@+id/ColorStateListButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="@color/sample_color_state_list"
    android:text="@string/hello_world"
    android:textSize="16sp"/>

●Value Resource

プリミティブ型を使用する。

ex)
<resources>
    <!-- 個別の値を定義する -->
    <integer name="DefaultEggs">1</integer>
    <integer name="DefaultBooks">3</integer>
    <integer name="DefaultPickaxe">100</integer>
</resources>

ex) 受け取る側
int eggs = getResources().getInteger(R.integer.DefaultEggs);

●Typed Array

様々な型を配列にできる。取り出すときは型に中ウイする。

ex)
<resources>
    <!-- String や Integer 以外のものでも配列にできる -->
    <array name="Drawables">
        <item>@drawable/ic_launcher</item>
    </array>
    <array name="Colors">
        <item>@color/Red</item>
        <item>@color/Green</item>
        <item>@color/Blue</item>
    </array>
    <!-- 異なる型のものを混ぜても良いが、Java のコード上で扱う際に、場所と型を気をつけないといけないので注意 -->
    <array name="MixedArray">
        <item>@drawable/ic_launcher</item>
        <item>@color/Blue</item>
    </array>
</resources>

ex) 取り出し側(Colors)
TypedArray colors = getResources().obtainTypedArray(R.array.Colors);
        int color2 = colors.getColor(0, Color.BLACK);


●Boolean

bool値

ex)
<resources>
    <bool name="isCompany">true</bool>
    <bool name="isPerson">false</bool>
</resources>

ex) 受け取り側
boolean bool = getResources().getBoolean(R.bool.isCompany);


●Dimension

寸法を指定する。Viewの大きさや文字サイズ。Javaコードで取り出すとFloat型になる。

ex)
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <!-- 文字の大きさも定義可能 -->
    <dimen name="TitleSize">16sp</dimen>
    <dimen name="BodySize">14sp</dimen>
</resources>

ex) 受け取り側
float titleDim = getResources().getDimension(R.dimen.TitleSize);

●Color

色コードを定義する。Javaコードで取り出すとint型整数値になる。

ex)
<resources>
    <color name="Red">#FF0000</color>
    <color name="Green">#00FF00</color>
    <color name="Blue">#0000FF</color>
</resources>

ex) 受け取り側
int color = getResources().getColor(R.color.Blue);

●ID

レイアウトのIDをまとめる。

ex)
<resources>
    <item type="id" name="HelloWorld"/>
    <item type="id" name="Hoge"/>
</resources>

●Raw(Binary)

最適化除外対象のバイナリデータ。
InpurStreamを使用してアクセスする。

ex)
InputStream in = getResources().openRawResource(R.raw.ファイル名);


●多様なデバイスへの対応

Contextを通してリソースへアクセスする設計により、リソースを使う側が端末に依存したリソースの取得を意識しないで済むようになっている。
configuration_qualifierは、各デバイスのリソースに関する特徴を決める部分であり、重要である。

□configuration_qualifierの仕様

以下の上から順にハイフン区切りでconfiguration_qualifierを連結し、リソースを定義する。

・Language and Region
 言語
 jaやenやfrなどと指定する
・Smallest Width
 ディスプレイの短辺の大きさ
 sw600dpやsw720dpなど、sw<N>dpの形式で、dpの単位で指定する
・Screen Orientation
 画面の向き
 landまたはport
・Screen Pixel Density
 ピクセル密度
 ldpi、mdpi、hdpi、xhdpi、xxhdpi、nodpi、tvdpiなどと指定する。
・Platform Version
 OS のバージョン
 v4、v7などと指定する。数字は API Level のものを使う。

ex)

values-en-v4:良い
values-v4-en:ダメ

●ロケール

端末で仕様している言語に応じてリソースを定義する。
言語コードISO 639-1、地域コードISO 3166-1-alpha-2 を使える。


●高解像度スクリーン

デフォルトで用意されており、頻繁に利用する。

・ldpi:drawable-ldpi
・mdpi:drawable-mdpi
・hdpi:drawable-hdpi
・xhdpi:drawable-xhdpi ← 現在主流である。
・xxhdpi:drawable-xxhdpi

●画面向き

向きによってリソースファイルを切り替えることが可能。

・縦:layout-land, drawable-land
・横:layout_port, drawable-port

Android ActivityとFragment

ActivityとFragmentに関するメモ


ActivityとFragmentの役割

MVCのControllerに相当する。画面のライフサイクル、UIイベントの管理を行う。
 特に、Fragmentは再利用可能なUIコンポーネントのまとまりを管理し、Activityに組み込んで使用する。
 
 

ライフサイクル

Activityや連動したFragmentにはライフサイクルがあり、状態によって異なるメソッドが呼ばる。


Activityのライフサイクル


onCreate:Activityが最初にとる状態。画面の構成(XMLレイアウトのロード)やViewコンポーネントを取り出すなどの処理をする。

onStart:UIのインタラクションの実施準備を行う。

onResume:インタラクションを実施できる状態

onPause:ユーザが画面を離れようとしている状態。必要ならばデータの永続化を行う。

onStop:画面がユーザから見えなくなった状態。この状態で戻ろうとすると、onRestartを経て、onStartの状態へ遷移する。

onDestroy:画面がシステムによってメモリから追放される。参照が残っているとメモリリークが起こる。システムによってプロセスがkillされると、この状態を経ずに、終了する。


Fragment特有のライフサイクル

FragmentはHoneyCombで導入された比較的新しいコンポーネントだが、support.v4 を使用することで、2.x系の端末でも使用することが出来る。

onAttach:FragmentがActivityに組み込まれた状態。FragmentがActivityにコールバックを提供する場合、Activityが必要なインターフェースを備えているかどうかをチェックしておく。

onCreate:Fragmentを構築する状態。

onCreateView:FragmentがもつViewを構築する状態。レイアウトXMLをロードして返す。Viewをもたない場合nullを返すことも可能。

onActivityCreated:ActivityのonCreateの処理終了の状態

onStart:FragmentのUIが構築されて、描画された状態

onResume:FragmentのUIが構築・描画され、インタラクション可能な状態

onPause:ユーザが別の画面へ遷移する状態。必要な情報は永続化する。

onStop:Fragmentがユーザに見えない状態

onDestroy:Fragmentがメモリから破棄される直前の状態

onDetach:FragmentがActivityから切り離される状態


AndroidManifestでのActivity宣言


アプリケーションを構成する要素は、application要素の子に指定する。
ランチャーから暗黙的Intentを受け取るActivityの宣言もする。


Activityのレイアウト

setContentViewにレウアウトXMLのIDを渡す。


Activityの中で、Fragmentを動的に切り替える


Fragmentを保持する目的のLayoutを用意しておく。

FragmentManagerを使って、FragmentTransactionを取得する。

transactionは、add、replace、remove、commitによって、レイアウトの中身を追加・変更することが出来る。


Fragmentについて注意

初期化の際、コンストラクタやsetterでデータを受け渡してはならない。Fragmentの復旧時デフォルトのコンスタラクタしか呼ばれないからである。


練習

・各状態をToast表示して確認してみると良い。
・ActivityにFragmentを組み込むと良い。レイアウトXMLを作成すれば、簡単に画面の切り替えが出来ることを確認すると良い。



Android OutOfMemory (メモリリーク) の調査方法

Android メモリリークの調査方法のメモ


1.エミュレータでアプリケーションを起動

2.DDMSを起動して、注目するアプリケーションのパッケージのスレッドを選択し、UpdateHeapを選択する。

3.いろいろ操作、リークの可能性がある箇所がわかっている場合、その周辺を重点的に
 ちなみに、画面の向きを90度回転させるには、Ctrl + F11

4.アプリケーションを閉じる。アプリケーションが全面に無い状態にすること。

5.DDMS上でGCを実施する。

6. Dump HPROF Fileを実施し、hprofファイルを出力する。
hprofはJava標準のプロファイラ

7.hprof-convコマンドで標準hprofファイルを作成し、jhatで解析する。
・hprof-convはAndroid SDKに付属する。
・jhatはJavaSDKに付属する。

> hprof-conv jp.mixi.assignment.controller.adv2.hprof adv2.hprof

> jhat adv2.hprof

8.http://localhost:7000 にアクセスして、jhatの解析結果を確認する。

パッケージごとに解析できたクラスが表示される。
自分のアプリケーションのクラスを確認して、References to this object を探す。
References to this objectには、リンクが残り、メモリにインスタンスが配置されたままであることを示す。

ActivityがDestroyされた場合、GCで回収されるはずなので、リークしていると考えられる。

どこから参照されているかは excludes weak refs (外部弱参照)で確認する。
外部参照を見つけたら、参照を破棄するなどの対策を行う。

ブロードキャストレシーバーなど、リークのつくりやすい例で試すと良い。