Androidのアプリ開発関連のブログ

MatrixCursorを使ってListViewを更新することにした

前回のListViewの内容とデータベースの整合が取れてなかった件で、完全に理解できてないのだが、
setViewBinderで変更時イベントを設定してデータベースの更新をして、行追加は1行目に挿入されるってやってた。
そうすると、行を追加した際は表示済みの行のViewBinderは再発動せずに中のEditTextの文字列が変わるだけ。
って感じなんだと思う。
だからその時にTextWatcherが変更を検知しちゃって予期せぬ行のデータベースが変更されてたような・・・

で、その方法で解決できないこともないと思うのだが、解決するために無駄にコード量増えちゃいそうだし、
そもそも本来細かくDB更新すべきじゃないし、TextWatcherは使わないでアプリ終了時とかにまとめて更新することにした。


いつもはSimpleAdapterを使っててSimpleCursorAdapterは初めて使った気がするのだが、
データベースの更新が不要ならSimpleCursorAdapterではなくSimpleAdapterでいいんでね?
と思ったのだが、初めて気づいたがSimpleAdapterって作成した後に行を追加する機能が無いような・・・
SimpleCursorAdapterにしろ何にしろ、ListViewは更新がやたら不便なような・・・

今回は結局SimpleCursorAdapterでSQLiteDatabaseからselectした内容を表示して、
行追加の際はListViewに表示されている行のViewGroupを1行づつ取り出して、各Viewの状態からデータを取得。
取得できたデータを元にMatrixCursorを作成。
CursorAdapter.changeCursor()で新しいMatrixCursorと交換。
という方法に決めた。
うまく行ったはず。


なのだが、変更作業中にListViewが更新されない症状が発生して4時間ほどハマった。
原因は、ListViewの子要素からMatrixCursorを作成する処理を作ったが、
新しく挿入すべき行を挿入する処理を入れ忘れてたw
単にchangeCursor()するだけで更新される。

ちょっと開発やったのだが・・・

今日は年末に考えてたチェックリストの制作をちょっとやったのだが、
一応入力できる感じにはすぐ作れたが、変更して再起動すると何かおかしい事に・・・

今のところはEditTextとCheckBoxが並んだListViewで、
データ用のArrayListとか用意せずにSimpleCursorAdapterを使って直接表示したので変更が発生したら即時記録したかったので、
setViewBinderでListView内の各Viewにイベントを設定して保存するようにしたのだが、update対象の行がおかしいことになっているような・・・


今日は原因の究明は諦めたが、setViewBinderのsetViewValueが、
public boolean setViewValue(View view,Cursor cursor, int columnIndex){}
と、View,Cursor,columnIndexしかくれないのね。
columnIndexはSQLiteクエリのselect結果1行分のうち対象データのカラムの番号で0からになると思われるので、
primary keyもselectしておいて、primary keyが先頭のクエリなら、
cursor.getInt(0);
でキーが取得できるつもりでいるんで、
final intにしておいてupdateクエリの際にwhereで行指定したんだが、
なんかおかしな事なって、エラーにはならんしデバックも難しかった。
insertとupdateの発生する箇所と再起動の際に、細かくdbファイルを覗けば究明できるかな?


UIはシンプルにするんで、この問題が解決すれば時間はかからなそう。

4ヶ月も空いてしまったが・・・

とりあえず配信するつもりで8月にQRコード・リーダー作っていたが、
メインPCのストレージぶっ壊れて開発環境作りなおしたりで中断してた。

QRコード・リーダーに関しては最初から必要性を感じなかったのでやる気が無かったが、
この前通販する際に買おうと思ってたものを注文する際にカートに入れ忘れちゃったことがあって、
こういう時にチェックリストがあると良いな。

ということに気づいたんで、Androidでチェックリストアプリ作る気がわいてきたところ。
単に項目名を記入してチェックするだけのシンプルなものを作る予定。
QRリーダーは大したもの作れないし、類似品がいっぱいあるから放棄でいいやw
チェックリストも類似品多数あると思うが、個人的にも欲しいと思ったし、マジ作る方向。


あと、チェックリストのアプリはシンプルなものにする方針だが、高機能化についても検討して、
チェックリストを高機能化するならばSQLiteのデータベースマネージャを作っちゃえば良いという結論に至ったんで、
チェックリストが終わったらDBマネージャ的なのを作ろうかとも考えてる。

もう年末だし、年内は難しいかもしれない・・・

スキャン機能はだいたい出来上がった

制作中のQRリーダーは、スキャンしてテキストの表示する機能は大体できた。

QRの詳細情報の表示もしたかったが、Zxingのコード追ってみたが、やはり取得できなそう。
byte配列は取れそうなんで、それを解析処理と同じような処理作って詳細情報の取得も考えたが、かなりめんどいのと、マスクパターンに関してはかなり無理ありそうな感じに見えた。
というわけで、詳細情報の表示は無しの方向。

0.5秒間隔でプレビュー画像を解析して、スキャン成功したらAlertDialogでテキストの表示をするだけ。
広告は結果表示時だけにすることも考えたが、AlertDialogだと少なくとも普通にはAdMobは表示できない気配なんでスキャン画面に表示した。
メイン画面で広告つけちゃうと他のアプリと比べて一目でわかる優位性が無い気がするが、さほど邪魔ではないと思う。
結果表示は当初は別画面にすることも考えたが、AlertDialog使うのが簡単で再スキャンもしやすいUIにできると思うんでAlertDialogにした。

あと、画像ファイルに関連付けして画像ファイルを解析できるようにしたいと思ってる。

ZxingのライセンスはApache License 2.0ってやつで、ライセンス文書のコピーを添付するだけでいいみたい。
ぬるくて使いやすいですね。

QRリーダー制作中

QRリーダー制作中。


まずCameraのPreviewが止まっちゃう場合があってハマったが、
SurfaceHolder.CallbackのsurfaceCreatedでstartPreview()するとそうなるっぽい。
Camera.PreviewCallbackをsetPreviewCallback以外のsetPreviewCallbackWithBufferなんかも試したり、Previewを処理時に意図的に止めたりしてもダメだったが、surfaceCreatedではなくsurfaceChangedでstartPreview()したら問題なくなった。

ついでに、コールバックにTimer試したりもしたんだが、
setPreviewCallbackではなくsetOneShotPreviewCallbackだとコールバックが一回しか発生しない。
プレビューの間隔は端末依存で、手元のだと5fpsが最低ぽかった。
1秒1回も処理できればいいと思うんで、1回だけのsetOneShotPreviewCallbackでコールバックを設定して、
処理完了後にTimerで再度setOneShotPreviewCallbackを設定って方法で1秒間隔に変更した。


あと、カメラの向きとかアスペクト比なんかも考えなきゃと思ったんだが、端末を回転させると落ちることが判明した。
Camera.open()してる状態で再度open()が発生すると落ちるぽいんで、onCreateでopenではなく、onResumeでopenしてonPauseでreleaseにした。
releaseすると、release状態でプレビューの更新とかが発生すると例外が発生するんで、tryで回避した。

向きの変更はcamera.setDisplayOrientation(int)で変更できる(API14以降?)んだが、計算式がめんどくさい。
カメラの前背も考慮する必要がある様でよくわかってないが、リファレンスにサンプルコードが載ってるんで真似した。

アスペクト比は調整すると余白ができちゃうし、調整しなくても良いかなと思うことにした。


あと結果表示領域付けるだけでいいや。
できればQRコードの詳細情報を表示できるようにしたいんだが、ZxingだとDataMatrixの詳細は取得できそうなんだがQRの詳細は取得できなそうな・・・