2013年12月26日木曜日

ActionBarActivityで finalになったonMenuItemSelectedのソースを追ってみた

ActionBarActivity#onOptionsItemSelectedのソースを追ってみた。

android.support.v7.app.ActionBarActivity ActionBarActivityDelegate mImpl; @Override public final boolean onMenuItemSelected(int featureId, android.view.MenuItem item) { if (mImpl.onMenuItemSelected(featureId, item)) { return true; } final ActionBar ab = getSupportActionBar(); if (item.getItemId() == android.R.id.home && ab != null && (ab.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) { return onSupportNavigateUp(); } return false; } 5行目で、ActionBarActivityDelegateのonMenuItemSelectedを呼び出している。
ActionBarActivityDelegateを実装は幾つかのOSレベル毎に分かれているので、 その1つActionBarActivityDelegateBaseを見てみる。

android.support.v7.app.ActionBarActivityDelegateBase @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { if (featureId == Window.FEATURE_OPTIONS_PANEL) { item = MenuWrapperFactory.createMenuItemWrapper(item); } return mActivity.superOnMenuItemSelected(featureId, item); } ActionBarActivityのsuperOnMenuItemSelectedを呼んでいる。

android.support.v7.app.ActionBarActivity boolean superOnMenuItemSelected(int featureId, MenuItem menuItem) { return super.onMenuItemSelected(featureId, menuItem); } ActionBarActivityの親クラスFragmentActivityのonMenuItemSelectedを呼んでいる。

android.support.v4.app.FragmentActivity /** * Dispatch context and options menu to fragments. */ @Override public boolean onMenuItemSelected(int featureId, MenuItem item) { if (super.onMenuItemSelected(featureId, item)) { return true; } switch (featureId) { case Window.FEATURE_OPTIONS_PANEL: return mFragments.dispatchOptionsItemSelected(item); case Window.FEATURE_CONTEXT_MENU: return mFragments.dispatchContextItemSelected(item); default: return false; } } 6行目の親クラスActivityActivityのonMenuItemSelectedを呼んでいる。
メニューが処理されなかったら、Fragmentのメニューを呼び出している。
  • Window.FEATURE_OPTIONS_PANEL - ActionBarや昔のメニューパネル
  • Window.FEATURE_CONTEXT_MENU - ロングタップで表示されるコンテキストメニュー


android.app.Activity public boolean onMenuItemSelected(int featureId, MenuItem item) { CharSequence titleCondensed = item.getTitleCondensed(); switch (featureId) { case Window.FEATURE_OPTIONS_PANEL: // Put event logging here so it gets called even if subclass // doesn't call through to superclass's implmeentation of each // of these methods below if(titleCondensed != null) { EventLog.writeEvent(50000, 0, titleCondensed.toString()); } if (onOptionsItemSelected(item)) { return true; } if (mFragments.dispatchOptionsItemSelected(item)) { return true; } if (item.getItemId() == android.R.id.home && mActionBar != null && (mActionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0) { if (mParent == null) { return onNavigateUp(); } else { return mParent.onNavigateUpFromChild(this); } } return false; case Window.FEATURE_CONTEXT_MENU: if(titleCondensed != null) { EventLog.writeEvent(50000, 1, titleCondensed.toString()); } if (onContextItemSelected(item)) { return true; } return mFragments.dispatchContextItemSelected(item); default: return false; } } メニューは、12行目でonOptionsItemSelectedを呼び出し。 コンテキストメニューは、32行目でonContextItemSelectedを呼び出し。


リファレンスのOnMenuItemSelectedの記述
Default implementation of onMenuItemSelected(int, MenuItem) for activities. This calls through to the new onOptionsItemSelected(MenuItem) method for the FEATURE_OPTIONS_PANEL panel, so that subclasses of Activity don't need to deal with feature codes.

この通り、onOptionsItemSelectedをオーバーライドしてメニューの処理を実装を行なうのが正しいようだ。

コンテキストメニューはonContextItemSelectedをオーバーライドして処理を実装を行なうのが正しいようだ。


Honycombから、Activity#onMenuItemSelectedにはFragmentやActionBarのメニュー処理が行なわれてるためオーバーライドは注意が必要。

2013年12月25日水曜日

ActionBarActivityのOnMenuItemSelectedはオーバーライドできない。

Supoport Libraryに追加されたandroid-support-v7-appcompatのActionBarActivityのOnMenuItemSelectedはオーバーライドできない。



OnMenuItemSelectedはfinalメソッドとなっている。
代わりに、
onOptionsItemSelectedをオーバーライドして使用します。

リファレンスのOnMenuItemSelectedの記述は以下の通りです。
Default implementation of onMenuItemSelected(int, MenuItem) for activities. This calls through to the new onOptionsItemSelected(MenuItem) method for the FEATURE_OPTIONS_PANEL panel, so that subclasses of Activity don't need to deal with feature codes.
 そもそも、OnMenuItemSelectedを実装しているのが間違っていた?

2013年5月16日木曜日

Android SDK 22 では、Build Toolsが必要になったようです。

今朝リリースされた Android SDK 22について注意

このバージョンより Android SDK Build-toolsが必要になりました。 

インストールしていないと、
ant debug/release 実行に、以下のようなメッセージが出て、ビルドできません。 {android-sdk}/tools/ant/build.xml:479: SDK does not have any Build Tools installed.

 Eclipseでも、
Android Tools > Export Signed/Unsigned Application Package... を実行すると同じようなエラーダイアログが表示されました。

 

SDK 22からToolsに Android SDK Build-tools が増えてるのでインストールしておくように!

2013年4月1日月曜日

うるさいLint先生にXMLの警告を無視させる方法

xmlns:tools="http://schemas.android.com/tools"
を定義して、
tools:ignore="ContentDescription,PxUsage"
無効にしたいチェックを記述します。


ImageView / ImageButton の contentDescriptionとか記述めんどくさいし。
セパレータに使用している ImageViewの heightは ピクセル(px)で定義したいし。

2012年12月23日日曜日

InputFilterとValidator

ValidatorじゃなくてAndroidには InputFilterがあるじゃないか?って話がでたので...

フィルタとは (filter): - IT用語辞典バイナリ
フィルターは、受け取ったデータに対して何らかの処理や加工を行った上で出力すること

Androidでは以下のInputFilterが提供されています。
InputFilter | Android Developers

public interface

InputFilter (view source)

android.text.InputFilter
Known Indirect Subclasses
DateKeyListenerFor entering dates in a text field. 
DateTimeKeyListenerFor entering dates and times in the same text field. 
DialerKeyListenerFor dialing-only text entry
As for all implementations of KeyListener, this class is only concerned with hardware keyboards. 
DigitsKeyListenerFor digits-only text entry
As for all implementations of KeyListener, this class is only concerned with hardware keyboards. 
InputFilter.AllCapsThis filter will capitalize all the lower case letters that are added through edits. 
InputFilter.LengthFilterThis filter will constrain edits not to make the length of the text greater than the specified length. 
LoginFilterAbstract class for filtering login-related text (user names and passwords)  
LoginFilter.PasswordFilterGMailThis filter is compatible with GMail passwords which restricts characters to the Latin-1 (ISO8859-1) char set. 
LoginFilter.UsernameFilterGMailThis filter rejects characters in the user name that are not compatible with GMail account creation. 
LoginFilter.UsernameFilterGenericThis filter rejects characters in the user name that are not compatible with Google login. 
NumberKeyListenerFor numeric text entry
As for all implementations of KeyListener, this class is only concerned with hardware keyboards. 
TimeKeyListenerFor entering times in a text field. 


これら以外のフィルターを行いたい場合はカスタムフィルタを作成する必要があります。
作成の方法はこちらが参考になると思います。
EditTextにカスタムInputFilterを適用して入力値の制限を行う | MoaiApps Labo 
Y.A.M の 雑記帳: Android Filterを使ってみた

フィルタは、特定の文字列以外は認めない機能です。
入力された文字列を検査する機能では有りません。
それがバリデータになります。

バリデータとは 「バリデーター」 (validator): - IT用語辞典バイナリ
入力されたデータが仕様にそって適切に記述されているかを判断し、不適切な箇所があった場合にはエラーとして通知する。


特定の文字以外を入力させなくしているから、バリデータは不要でしょうか?

そんなことは無いと思います。
  • ユーザーID/パスワードなどの必須項目は入力されているか? 
  • パスワードはある桁以上であるか?特定の文字列を含んでいるか?
  • パスワードの確認入力などの二つの項目が同じであるか?
  • 電話番号や郵便番号などの"-"区切りのフォーマットが正しいか?
など、入力確定後に検査をしなければならないと思います。
※フォーマット付き項目については、項目を分けたらとか、フォーマット無しで入力させたらいいじゃないかとかありますけどね。鶴様が既存PCのフォームがフォーマット付きだから踏襲し...(ry

検査のタイミングですが、
  • フォーカスが外れたタイミング
  • ボタン押下などアクションのタイミング
となると思います。
※必須項目の検査は、全ての入力項目を確定させたアクションでしか行えないと思います。

AndroidのEditViewの場合、

  1. android:inputType 入力制御 (IMEのパネルを制御)
  2. InputFilter 入力制御 入力されたタイミングでフィルタ
  3. Formatter 文字列入力後にフォーマット
  4. Validator 最終的な文字列の検査

の順に処理をすればいいんじゃないかと思います。

バリデータなんて古いぜこっちの方がクールだぜ。ってのあったら教えてほしいな〜。

でわでわ