ListView続き。
いまいち脈絡ないですが、色々ListViewについて調べているうちにわかったということで^^;
ListViewでクリックを検知する方法について説明します。
ListViewでクリックを検知するには、AdapterViewのOnItemClickListenerを使用します。
引数の説明はいまいちわかりにくいですが、下記ソースコードのJavaDocを参照してください。
=====
itemlist.setOnItemClickListener(new OnItemClickListener() {
/**
* ListViewのクリックされたイベントを検知する。
*
* @param targetListView クリックされたItemを保持するListView
* @param clickedView クリックされたView
* @param index ListView中のクリックされたインデックス
* @param rowid クリックされたViewのrowid
*/
public void onItemClick(AdapterView<?> targetListView,
View clickedView, int index, long rowid)
{
//ListViewとして使用するためにキャスト
ListView listView = (ListView) targetListView;
//ListItemとして使用するためにキャスト
ListItem clickedItem = (ListItem) listView.getItemAtPosition(index);
}
});
=====
ちなみに、APIですと引数は下記のように記述されていました。
1.parent The AdapterView where the click happened.
2.view The view within the AdapterView that was clicked (this will be a view provided by the adapter)
3.position The position of the view in the adapter.
4.id The row id of the item that was clicked.
。。。結局実装してみるまでわからなったやん(汗
AndroidでListView中のItemに対するクリックを検知する方法
Androidアプリでリストを最後まで読んだら検知する方法(その2)
Androidアプリでリストを最後まで読んだら検知する方法
の続きです。
とりあえず、『リストを最後まで読んだら検知すること』は成功しました。
ともあれ、これだけでは全くわからないので、
使ったメソッドと、その動作についてまとめます。
『リストがスクロールしたこと』を検知することは前の投稿にも書いたとおり、http://developer.android.com/reference/android/widget/AbsListView.OnScrollListener.html
を使います。
使用するメソッドはonScrollです。
ただ、APIとして記述されている内容だけだとぶっちゃけわかりません(汗
英語力不足なんでしょうか。。。。
仕方がないので動作確認した結果、下記の動作となることがわかりました。
firstVisibleItem:一番上に表示されてるアイテムのインデックス
visibleItemCount:画面に表示されてるアイテム数
totalItemCount:リストに存在している全アイテム数
図に示すと下記のようになります。

なので、「firstVisibleItem + visibleItemCount == totalItemCount」の条件を
満たした場合のみOnScrollからイベントを発生させるようにすれば、
リストを最後までスクロールした場合に処理を行うことが可能となります。
差分がtotalの10%になったら発動、というようにすれば
「下の残りが少なくなったら随時追加読み込みを行う」という処理も
可能になります。
さて、とりあえず検知と、イベント発動が可能であることがわかったので、
後は読み込み処理を上手く共通化して扱うための手法、ですね。
作成が成功したらその3として投稿します。
AndroidのHttpURLConnectionで、httpsかつBasic認証込みの通信がこける。。。
もう1つ。
Androidアプリ内部で、HttpURLConnectionを用いてhttpsのBasic認証を行った場合
なぜか「1回目の通信のみがこける」という事象が発生中。
原因は不明ですが、1回目の通信はhttpsstatuscodeが-1なので、
そもそも外部にアクセスに行けずにこけている模様。
で、代わりになるようなものが無いか調べていたのですが、
DefaultHttpClientだと何とかなる可能性があります。
「https通信」「Basic認証」は各々実現している情報(下記2ページ)がありました。
・Android で HTTPS 通信をする
http://www.pshared.net/diary/20091123.html
・DefaultHttpClientでBasic認証使ったアクセスを行う
http://techbooster.jpn.org/application/3391/#more-3391
なので、「https通信」「Basic認証」の両立も可能?と考えたい所ではありますが、、、
とりあえず、試すまでにはちと間が空きそうです。
Androidでプロキシ使うとhttps通信が動かない!
最近Androidエミュレータを用いてAndroidの通信内容を確認するために
ローカルプロキシを適用していたんですが、
よく通信に失敗するという状態になっていました。
で、確認してみたんですが、https通信の時だけこけている模様。
http通信は正常に中身が確認できていたので、
https通信だけピンポイントにこけているようでした。
で、なぜかな~と調べてみると、Androidのバグ情報が。
http://code.google.com/p/android/issues/detail?id=2690
どうやら、Androidのバグとして、プロキシを通したhttps通信は出来なかったようです。
尚、このバグはGingerbread、つまりAndroid2.3では解消している模様。
なので、Androidエミュレータのhttps通信の中身を確認したい場合、
Android2.3のエミュレータを使う必要がありそうです。
Androidアプリでリストを最後まで読んだら検知する方法
現在作成中のアプリで、
「リスト表示されたアイテム(ListView)を最後までスクロールしたら次を読み込む」
処理が必要になったのですが、
Web上を調べてみてもいまいち見つからなかったので
メモとしてここに残しておきます。
とりあえず、検知出来そうな手段は見つけました。
http://developer.android.com/reference/android/widget/AbsListView.OnScrollListener.html
が使えそうです。
このページにある下記のメソッドは、
スクロールした際にコールバックを返す、というメソッドのため、
最後までスクロールしたら次読み込む用にすれば実現できそうです。
とまぁ、とりあえずはテスト用のプログラムを組んで確認してみよう。。。
public abstract void onScroll
(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
Androidエミュレータのネットワーク構成
前回の投稿で気になったので調べてみました。
Androidエミュレータは基本的にDalvik仮想マシンを起動し、
その上で動作しています。
そのため、起動時に仮想ネットワークを構成してその中にエミュレータがいるかたちになります。
仮想ネットワークの構成に関しては下記を参照。
https://sites.google.com/a/techdoctranslator.com/jp/android/developing/tools/emulator#emulatornetworking
Dalvik仮想マシン1つ1つに仮想ネットワークを構築するようなので、
Androidエミュレータ同士を通信させるには工夫が必要なようです。
https://sites.google.com/a/techdoctranslator.com/jp/android/developing/tools/emulator#connecting
こんどやってみるか。
Androidエミュレータがネットワークにつながらなくなったら
一番簡単かつ確実な手段=再起動
。。。と書いちゃうと全てぶち壊しではありますがw
ただ、基本Androidエミュレータは再起動を繰り返すものでしょうし、
再起動できるならしてしまった方がいいです。
ただ、それが出来ない場合は、ということで。
原因は大抵DNSによる問題解決が出来ないことです。
なので、下記のページ等を参考にDNSを再設定すべし。
■Androidのエミュレータがネットワークに接続できない場合の対処方法
http://magpad.jugem.jp/?eid=199
Xperiaで通話着信音、メール着信音を設定する方法
Xperiaを購入してから10カ月以上たちましたが、
今回初めて通話着信音、メール着信音をプリセットじゃない音に設定しました。
すると、意外にこの辺厄介なことが判明。
とりあえず、設定方法を。
ちなみに、「メール着信音」と同じ操作を行えば
通話着信音を設定することも可能です。
前提として、音楽ファイルをAndroid端末にダウンロードしておきます。
後、アストロファイルマネージャーもインストールしておくと何かと楽。
■通話着信音設定方法
1.ファイルマネージャーから音楽ファイルを選択して、
Mediascapeを使用して起動&再生する。
2.再生中にメニューボタンを押下して、「着信音に設定」を選択
3.通話着信音設定の選択肢にMediascapeで設定したファイルが
加わっているので、そこから設定
この操作をやってみたところ、メール着信音側には選択肢が追加されず。
てなわけで、下記の操作が必要になりました。
■メール着信音設定方法
A.通話着信音設定方法の「1」「2」を実行しておきます。
B.Androidマーケットから「Tone Picker」をダウンロードしてインストール
C.GmailアプリやGmailの通知系アプリのメール着信設定画面に
「Tone Picker」が追加されているので選択。
D.再度「Tone Picker」を選択する。
するとMediascapeの再生履歴が表示されるので、そこから選択。
以上の操作で設定できます。
後、何故か「D」のタイミングでアストロファイルマネージャーを選択して
音楽ファイルを指定した場合何故か再生されず。
音楽系アプリの履歴データから選択する必要があるようです。
意外に厄介な設定でした。
Eclipse+Android SDKでビルド中にこける
なんか、この間Eclipse+Android SDKでビルド中に落ちる事象が発生。
エラーを見てみると、
java.lang.IllegalArgumentException: already added: LXXXXX
てな感じでビルド途中にで例外を吐いて、最終的に
Conversion to Dalvik format failed with error 1で落ちるという状態。
エラーメッセージから丸わかりですが、
どうやらAndroidSDKでは「同じクラス」を2度ロード(?)することは出来ないようです。
見た感じ、クラス名をキーとしてバイナリファイルをマッピングし、
それをロードして使用している?
だからキーが重複したときに落ちるとか。
解消方法は、LXXXXと表示されているクラスが2度ロードされないように
クラスパスを見直すこと。
そんな構成にはなっていない、ということであれば、
クリーンビルドをすれば解消するはずです。
Androidで出来ることをどう実現するか知るためには?>ソースが公開されているアプリのソースを読みましょう
別にこれはAndroidに限ったことではないんですが、
アプリをどうやって作ればいいのか知るための一番の近道は、
『ソースが公開されているアプリのソースを読むこと』です。間違いなく。
あ、ただその前にAndroidの入門書1冊くらいは読んでおく必要があるか。
てなわけで現状一押しのソースを。
http://www.netmite.com/android/mydroid/packages/apps/AlarmClock/
Android公式のアラーム付時計のソースです。
アラーム付き時計って簡単に見えていろんな要素を含んでいて、
プラットフォームに依存した処理も多いため、
一通り作れるようになれば基礎的な機能はそれなりに押さえられるかと。
・レイアウト配置
・一定時間ごとの描画(表示している間だけ)
・サービス化
・メディア再生
後は、通信/認証系のアプリと、位置情報を利用したアプリが作れれば
基礎はほぼ舐めたと言っていいのかな。
今度その辺りも探してみよう。
【続】Android携帯のIPアドレス
この間の結果ですが、特に基地局をまたいでもIPアドレスは変わりませんでした。
普通に起動したときに基地局の更にバックグラウンドにある
存在からIPを割り振られている模様。
起動したときに表示される識別子っぽい
xxxx.mopera.netという値がIMPIだったり、IMPUを示しているのかな?
#IMPI/IMPUについてはこちら
ともあれ、これでServerman等も一度起動しておけば
終了するまでは固定アドレスでアクセス可能ということもわかりました。
当たり前と言えば当たり前な気もしますが、一つ何かわかった気はします。
Android携帯のIPアドレス
気になって調べてみたのが、Android携帯のIPアドレスって、
どうやって決まっているのかな?、ということ。
というか、Android携帯がどういう経路でネットワークを出ていっているのかな、
と書いた方が正確かも。
とりあえず何度か確認してわかったことは、下記の2点。
#但し、基地局エリアはおそらくまたいでいないので、
#同じ基地局エリアにいる、という前提で。
1.IPアドレスは端末を再起動すると変わる。
2.XXXX.mopera.netを経由してアクセスしているらしい。。。
基地局をまたいだ時点でIPが変わるかどうかは、
これから電車で移動して基地局またぐので、それで確認してきます。。。
Android Layout Editorでエラー起きて表示されない!
今度はレイアウト調整、ということでAndroid Layout Editorで画面を作成。
。。。なんですが、いまいち下記の問題があって使いにくい。
1.android:backgroundの指定次第ではWYSIWYGビューで例外発生
2.画像のサイズがWYSIWYGビューでは調整されない
1.android:backgroundの指定次第ではWYSIWYGビューで例外発生
android:backgroundにdrowable/XXXを指定してxmlファイルを読み込ませると
何故かWYSIWYGビューでUnsupportedOperationException: nullが発生してしまいます。
で、全くWYSIWYGビューが表示されないという状態に。
デフォルトのボタンだといまいち味気ないので、
デザインを変えようとすると毎回発生するという厄介な状態です。
2.画像のサイズがWYSIWYGビューでは調整されない
ImageViewに、ImageViewよりもサイズが大きい画像をandroid:srcに指定すると、
WYSIWYGビュー上では画像がフルサイズで表示されてしまいます。
なので、下のように画像が切れてしまう。
なんですが、実際にエミュレータや実機で表示してみると画像のサイズが
ImageViewのサイズに補正されて、切れない。
なんかこの辺りも解消する方法がありそうなんですが。。。
とはいえ、別にアプリが動かないわけではないから解消は気長に。
■切れる前
■切れた後
画面の縦横を切り替えてもonDestroy等が呼ばれない方法
昨日に引き続き。
あるんじゃないか、と思って調べていた
『画面の縦横を切り替えてもonDestroyが呼ばれない方法』ですが、
案の定ありました。
記述としては、AndroidManifest.xmlに下記のように記述すればいいようです。
===
<activity android:name=".AlarmTimerActivity"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden"> ★この行★
===
上記の記述をすることによって、
orientation(向き切替)、keyboardHidden(キーボード収納)をした際に
Activityが再生成(onDestroyとか)がされなくなるようです。
代わりに「onConfigurationChanged」というメソッドが呼ばれるので、
必要ならば上記のメソッドに処理を入れ込めばいいそうな。
尚、本来はkeyboardHidden(キーボード収納)を設定する必要が無いような
気がするのですが、keyboardHiddenを外してみると、
一部のフィールドが初期化されてしまって切替時にNullPointerExceptionが発生するため、
設定している状態です。
ちなみに詳細はAndroid:Activityのページにありました。
画面の縦横を切り替えるとonDestroyが呼ばれる?
テストアプリの動作確認を行っていたときにわかったのですが、
Androidって、画面の向きを変えるときに何故かonDestroyが呼ばれてしまうようです。
実際、ブレークポイントをはったらきっちり引っ掛かりました。
呼ばれるメソッドの流れは下記の模様。
。。。普通に終了処理になっているようです。
-onPause()→onStop()→onDestroy() →onCreate()→onStart()→onResume()
かつ、onDestroy→onCreateが呼ばれる際にActivityクラスも再生成されるため、
インスタンス変数に画面方向切替時に持たせたい情報を持たせておいても、
当然クリアされてしまう。
実際、ActivityのObjectIDもonDestroyのタイミングと
onCreateのタイミングでは変わっていました。
ただ、どうやらクラスはロードされっぱなしになるため、
クラス変数にフラグを持たせればどうやら保持される模様。
なので、タイマーの動作を引き継ぐのに必要な変数だけはクラス変数化して、
onCreate時にクラス変数の状態で処理を切り替えれば対応可能。。。なのかな?
ただ、それでもonDestroyが呼ばれてしまう以上Serviceクラスとかも
まるまる再生成されてしまいます。
さすがにonDestroyが呼ばれた際にサービス等をunbindしないわけにはいかないので。
何か効率が悪い気がするんですが。。。。はてさて。
Androidエミュレータにマーケットのアプリケーションをインストールする方法【詳細】
インストールする方法の詳細記述です。
1.Android携帯にインストールされているapkファイルをバックアップする
Android携帯で、バックアップ系のソフトを使ってインストールしているapkファイルを
ファイルとしてバックアップします。
例として、今回私が使ったのは『AppMonster』というアプリケーション。
Androidマーケットで『AppMonster』として入力すればすぐ見つかるはず。
起動するとインストールしてあるアプリケーションの一覧からバックアップ対象の
アプリケーションが選択できます。
選択すると、/sdcard/appmanager というディレクトリ配下にファイルが出力されます。
インストールしてあるアプリのapkファイルが
出力されていることを確認したら、次の手順へ。
2.PC⇔Android携帯で接続し、apkファイルをPCに移す
Android携帯をUSB経由でPCに接続し、apkファイルを取得します。
1で出力された「/sdcard/appmanager」のディレクトリを確認すると、あります。
それを、ローカルに配置する。こんな風に。
3.Androidエミュレータのコマンドを使用して、エミュレータにapkファイルをインストールする。
2まででapkファイルをローカルに置くことが出来ましたので、
後はインストールを行います。
ただ、その前にAndroidエミュレータを起動しておきます。
起動していないと、こんな感じにデバイスないよ、と怒られてしまいますので。
てなわけで、Androidエミュレータを起動。
ちなみに、インストール前はこんな状況です。
エミュレータが起動したのを確認したら、「adb install 【APKファイル】」
という形式のコマンドを実行します。
すると、インストールされます。
尚、この際複数のAndroidエミュレータを起動していたり、
実機のAndroid携帯を接続していたりすると、
どれか一つにだけインストールされますので注意。
Success、と表示されたらインストール成功。
成功すると、いつの間にやらアプリ一覧に追加されています。
特に画面の切り替えとかはしていませんが、いつの間にやら。
この辺りのリアルタイムさはさすがだなぁ。
これでインストール方法は以上。
インストールしたアプリケーションから通信も出来るようなので、
Android携帯を複数用意して試したい、という場合は有効かも。
Androidエミュレータにマーケットのアプリケーションをインストールする方法
AndroidエミュレータからではAndroidマーケットにアクセスすることはできませんが、
アプリケーションをインストールする方法は無いのかな。。。と考えていましたが、
とりあえず見つかりました。
手順は下記の通り。
1.Android携帯にインストールされているapkファイルをバックアップする。
2.PC⇔Android携帯で接続し、apkファイルをPCに移す。
3.Androidエミュレータのコマンドを使用して、エミュレータにapkファイルをインストールする。
・・・なんですが、時間なので、続きは明日に。
Androidのスレッド一覧を確認してみました
昨日のHandlerの存在を受けて、
Androidでのアプリ実行中のブレークに引っ掛かるスレッドと、
その時点でのスレッド一覧を確認してみました。
とりあえず、確認したのは下記の○パターン。
1.onCreateでActivityを初期化している時
2.画面上のボタンにListenerを設定して、Listenerから処理を実行している時
3.TimerからHandlerを経由してTaskを実行している時
4.TimerからTask実行時、Handlerに処理を委譲する前の時
結果としては、1、2、3はmainスレッドでの実行。
4だけ自前で作ったスレッド上での実行となっていました。
なーるほど。確かにmainに委譲されて実行されている。
で、Lisnenerから呼び出される処理についても、
待ち受け処理からHandler経由でmainに委譲されているのかな。
この辺りも調べてみると面白そうではありました。とまぁ、今日はここまで。
確認結果詳細は続きに。
タイマーが動かなかった理由、判明
昨日困っていた、タイマーが動かなかった件ですが、
実はタイマーが動かなかったのではなく、
Handlerを経由せずにGUIに対してアクセスするタスクを実行していたからでした。
#具体的にGUIアクセスしている個所は★参照
Handlerってなんじゃらほい、と思って調べてみると、
throw Life:AndroidのHandlerとは何か?に、解説が。
実は、AndroidのGUIはシングルスレッドで動いており、
画面に対してアクセスが可能なのはメインスレッドだけ、とのこと。
で、メインスレッド以外がアクセスすると例外(CalledFromWrongThreadException)吐くそうな。
今回の場合、CatchしているのがRemoteExceptionだけなので、
当然runから例外が飛び出してジエンド、という。
なので、タイマーからGUIを操作したい場合は
何かしらの形でメインスレッドに処理を委譲する必要があるわけでして。
その委譲を行ってくれるのがHandlerだそうな。
なるほどねぇ。。。GUIといっても、Swingとはこの辺りは全然違う。
ただ、気になるのはボタンにイベント定義してリスナ仕込んだ場合は
特にHandlerにpostしなくてもGUIに対する操作が動くんですよね。
てことは、タイマーから叩くのは別スレッドだけど、リスナから呼び出される場合は
メインスレッドを経由して実行されるということなのかな?
ただ、リスナって待ち受けスレッド用意するようなものだからなぁ。。。はてさて。
一度Androidのスレッドモデルについて調べてみる必要がありそうだなぁ。
とりあえず、明日デバッグかけて確認してみます。
===
TimerTask timerTask = new TimerTask() {
public void run()
{
try
{
Toast toast = Toast.makeText(getApplicationContext(), "Count Start", ★ここ★
Toast.LENGTH_SHORT);
toast.show();
targerCallback.updateTimerText();
}
catch (RemoteException e)
{
e.printStackTrace();
Toast toast = Toast.makeText(getApplicationContext(), "Count Failed",
Toast.LENGTH_SHORT);
toast.show();
}
}
};
===
酷いよね、KDDIさんって。
最近KDDIのIS03が予約27万件とかいろいろ騒がれています。
電車の中の吊広告でも、Android Au 解禁、とか出ているんですが。。。。
IS01はもう完全に忘れ去られたという認識でいいんでしょうか(笑
元々形状からしてネタ端末だった、というのはわかりますが。
携帯の癖してイヤホンつけないと話せないし。
しかも、AndroidのOSも1.6で放置というかなりひどい状態。
IS01より前に出たHTC Desireも、Xperiaも
きちんとバージョンアップされているのにねぇ。
流石に買った人がかわいそうだなぁ、と思ってしまう今日この頃。
