2013年11月28日

[Android] SQLのUPDATEで更新された行数を取得する

AndroidのSQLiteDatabaseクラスで用意されているupdate()では無理そうなSQLを発行する必要がありました。
ContentProviderのupdate()内で呼ぶために、UPDATEで変更された行数を知らなければなりません。
しかし、SQLiteDatabaseクラスのexecSQL()は戻り値を返しません。
UPDATEを行う前に同条件で該当行数を調べておくべきでしょうか。

少し調べてみたところ、SQLiteStatement#executeUpdateDelete()を使えば変更された行数を返してくれるようです。
SQLiteStatementはSQLiteDatabase#compileStatement()で取得することが出来そうです。
しかし、このメソッドが追加されたのはAPI Level 11でした。
残念ながら現在開発中のアプリはAPI Level 9から対応させる予定のため、このメソッドは使えません。

もう少し調べてみたところ、SQLにchanges()というメソッドがあるようです。
UPDATEを実行した後、続けてchanges()のSQLを発行すれば良さそうです。
public static int changes(SQLiteDatabase db) {
Cursor cursor = null;
try {
cursor = db.rawQuery("select changes();", null);
if (cursor.moveToFirst()) {
return cursor.getInt(0);
}
} finally {
if (cursor != null) {
cursor.close();
}
}
return -1;
}

上記のようなメソッドを作成し試してみたところ、期待した結果が返ってきました。
(僕が知らないだけで標準のクラスやメソッドで出来たりするんだろうか…?)
とりあえずはこのメソッドを使っていこうと思います。


タグ:android SQLite
posted by t2low at 21:00| Android

2013年11月27日

[Android] IME以外からパスワードを入力させるときでも、文字がわかるようにする

パスワードを入力する画面を作っています。
この画面ではアプリが表示するキーボードを使うため、IMEは使いません。
キーボードが押される度に以下のようなコードを実行していました。
textView.setText(textView.getText() + moji);

この方法でも文字の追加は出来ますが、入力した文字がわかりません。
マスクされた状態で表示されてしまうのです。
通常であればパスワード入力欄は*や●でマスクされる前に1秒程度文字を確認できる時間があります。

特別な処理が必要かと考えましたが、なんてことはありませんでした。
TextViewに文字を追加するためのメソッドが用意されていました。
textView.append(moji);

これで期待通りの動きになりました。

今までTextViewの操作はほとんどgetText()/setText()で行っていたので、append()の存在に気付きませんでした。
思い込みはダメですね。


posted by t2low at 21:00| Android

2013年11月26日

[Android] 壁紙を取得する

Activityに壁紙を取得するメソッドがあったような気がする、ということで、Eclipseの補完機能を頼りにとりあえず使ってみました。
Drawable wallpaper = getWallpaper();

取得できました。ばんざーい。
一応、リファレンスを見てみます。

Context | Android Developers

API Level5でdeprecatedになっていました。
(Eclipseでは警告が出ないのは何故でしょう…?)
何にしても、WallpaperManagerを使った方が良いようです。
WallpaperManager wpm = WallpaperManager.getInstance(getApplication());
Drawable wallpaper = wpm.getDrawable();
// または
Drawable wallpaper = wpm.getFastDrawable();

これでも問題なく取得できました。
壁紙の取得は簡単ですね。
posted by t2low at 21:00| Android

2013年11月25日

[Android] DialogFragmentの呼び出し元で結果を知るには

ダイアログ内のユーザが入力した情報を、ダイアログを呼び出したFragment側で知る必要が出てきました。
つまり、コールバックする仕組みが欲しいと思ったのです。
public class HogeDialogFragment extends DialogFragment {
// ... HogeDialogFragmentの実装

public interface Callback {
void onFuga();
}
}

ダイアログは上記のようにDialogFragmentを継承して実装しています。
そのため、コンストラクタやメソッドを使ってCallbackを渡すのはよろしくなさそう(※)です。
(※システム側でFragmentが再生成されたときに云々という話がありますね)
他に良い方法があるか調べてみましたが、どうもそういった仕組みはないようです。

いろいろと調べて、これしかないかなぁ、というのが以下のような方法

1.9. DialogFragment 実装例 − Kojionilk

android - Callback to a Fragment from a DialogFragment - Stack Overflow

ただ、この方法だと呼び出す側のクラス(ActivityかFragment)がCallbackを実装しなければならないんですよね。
public class HogeHogeFragment extends Fragment 
implements HogeDialogFragment.Callback {
// ...HogeHogeFragmentの実装
}

うーん、うーん…。なんだかイマイチな…。でも、これしか方法がなさそうな…。うーん…。
posted by t2low at 21:00| Android

2013年11月22日

[Android] AlertDialogのgetButton()がnullを返す

DialogのOKボタン(Positiveボタン)の長押しを判定したくて、以下のようなコードを書きました。
Builder builder = new Builder(getActivity());
builder.setTitle("title").setMessage("message");
builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
}
});

AlertDialog dialog = builder.create();
Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return false;
}
});


これを実行すると、NullPointerExceptionが発生してアプリが異常終了しました。
11行目のdialog.getButton()でnullが返却されているためです。
Webを検索してみると以下の情報が見つかりました。

Issue 6360 - android - AlertDialog getButton() return null - Android Open Source Project - Issue Tracker - Google Project Hosting

どうもDialogを表示してからでないとnullになってしまうようです。
ソースコードを読んでみるとDialogのonCreate()を通らないと中のViewが生成されないようですね(たぶん)。
Dialogが表示されたところでOnLongClickListenerをセットすることにしました。


Builder builder = new Builder(getActivity());
// ... 省略 ...

AlertDialog dialog = builder.create();
dialog.setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
Button positiveButton = ((AlertDialog) dialog).getButton(DialogInterface.BUTTON_POSITIVE);
positiveButton.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return false;
}
});
}
});


多少めんどくさいですが、これなら大丈夫でした。
posted by t2low at 21:00| Android

2013年11月21日

[Eclipse] override

継承元のクラスのメソッドをoverrideしたい場合、どのようにメソッドを書いていますか?
僕はこれまで、Eclipseのメニューから「Source→Override/Implement Methods...」を選んで、Eclipseに生成してもらっていました。
Windowsを使っていた頃は、Altキーを使ってキーボードだけで操作できていたのですが、Macを使うようになってからマウス(タッチパッド)を使わなければいけなくなり面倒に感じていました。
Macではキーボードショートカットを設定すれば良いのは知っていましたが、今回書きたいのはそこではありません。

いつものようにEclipseでコードを書いていて、ふと気づきました。
クラス内でoverrideしたいメソッド名を書き始めてから、コード補完を行うとそのメソッドの足りない記述を補ってくれるんですね!
override_completion.png
これは知りませんでした。
大変便利です。さすがEclipseですね。すごい。
いやー、コードを書くのが捗ります。

posted by t2low at 21:00| Eclipse

2013年11月20日

[Android] Toast


アプリの動作をちょっと確認したいときにToastを使うと便利です。
開発中によく↓こんな形のコードを組み込みます。

Toast.makeText(context, "hoge", Toast.LENGTH_SHORT).show();


ただ、Toastはキューイングされているようで、いくつも上記コードを入れてしまうと呼び出した回数分表示されてしまい、なかなか消えてくれなくなります。
そんなときはキャンセルしましょう。

if (toast != null) {
toast.cancel();
}
toast = Toast.makeText(context, "hoge", Toast.LENGTH_SHORT);
toast.show();


ただ、cancel()しても、パッと消えません。
また、キューイングされている未表示のToastをcancel()したとしても、少し時間を消費します。
元々連続して表示するようには作られていないので、大量の情報を表示したければLogクラスや他のクラスを使った方が良いですね。

Toastの使い方はこちら
Toasts | Android Developers

ToastのAPIリファレンスはこちら
Toast | Android Developers


(最近アウトプットが大事だと考えて、とりあえず何か書こうと思ったけど、書くこと思いつかなくてこんな記事を書いた次第)
タグ:android
posted by t2low at 21:00| Android

2013年11月15日

[Android] Fragment内のWebViewで先読みするにはどうすれば良いだろう?

仕事でAndroidアプリ開発をしています。
先日こんなリクエストがありました。

「広告が表示されるまでに時間がかかってるので先読みできませんか?」

DialogFragmentにWebViewを載せて、onCreateView()内でURLを読み込むようにしていましたが、その時点で読み込み始めたのでは遅すぎるようです。


・DialogFragmentのコンストラクタでWebViewを生成して読み込ませるのはどうか
→WebViewが生成できません…。

WebViewを生成するにはContextが必要ですが、contextがありません…。
getActivity()はこの時点ではnullを返します。
遅くともonAttach()まで呼ばれればgetActivity()がactivityを返してくれるようになりますが、onAttach()が呼ばれるのはいつかと考えると、DialogFragment#show()を呼んだ後ですので、先読みになりません。


・DialogFragmentを呼び出すクラスがWebViewを作ってはどうか
→WebViewが渡せません…。

Fragmentの使い方としては引数なしのコンストラクタが必要です。
Fragment利用時に値が必要であれば、setArguments()で渡す必要があります。
setArguments()の引数はBundleで、BundleにはViewは詰められません。
Viewを渡すメソッドを作れば渡せないこともないと思いますが、それはちょっとねぇ。


結局、解決策がわかりませんでした。
DialogFragmentを使うのをやめ、Dialog風に見せかけたレイアウトを作ってお茶をにごしました。
タグ:android
posted by t2low at 22:00| Android

2013年10月25日

特別であるということ

人は「自分は特別である」と思いたがります。たぶん。

例えば、「私は何でも美味しく食べられる」といった人がいたとします。
Javaのメソッド風に書くと以下のようになります。
PositiveFeedback eat(Food food) { ... }

何を食べても良い感想しか返さない。これは特別な感じがします。
素晴らしい特技・才能と言っても良いでしょう。

ただ、よく聞くとアレルギーでどうしても食べられないものがあるそうです。
メソッドを書き直しましょう。
PositiveFeedback eat(Food food) 
throws AllergyException { ... }

こんな感じでしょうか。アレルギーは仕方ありません。
え?なんでしょうか。今、思い出した?
食べると吐いてしまうくらい嫌いな食べ物が1つだけある?
他の食べ物は全部好き?
…そうですか。はい、わかりました。
PositiveFeedback eat(Food food)
throws AllergyException, HateFoodException { .. }

こうですね。ちょっと例外が増えてきました。
でも、いくつかの例外を除いて美味しく食べられるというのは素晴らしいことです。
あ、そういえば、この間一緒に食事に行った時、「マズイ」って言ってませんでしたっけ?
あはは、言ってましたよね。確かにあそこの料理は不味かった(笑)
Feedback eat(Food food)
throws AllergyException, HateFoodException { ... }

こうなりました。
普通じゃねーか、ばーか。

ということにならないように気をつけましょう。
posted by t2low at 13:44| 日記

2013年07月02日

Googleアカウントが復元された話

Googleアカウントを消されてしまった話の後の話です。
タイトルの通り、先日削除されたアカウント(以降、旧アカウント)が復元されました。
復元された理由はわかりません。
Googleから復元したという連絡はありませんでした。

運が良かったです。
メールクライアントから旧アカウントの設定を消さずにおいたおかげで気付くことができました。
アカウントを削除された後、起動する度にエラーダイアログが表示されていたのですが、その日は特にエラーになることなく起動出来ました。
どういうことかと受信トレイを見てみると、その日のメールが受信できていました。
急ぎ他のサービスも利用できるか確認してみて、どうやら復元してもらえたらしいことを知りました。
6/20の2:00頃でした。

Gmailをよくよく確認してみると、アカウントが削除されていた(と思われる)期間のメールは受信できていませんでした。
消される前の最後に受信したのが5/31 3:13で、その次のメールが6/19 14:29になっています。
この期間、確かに消されていて(停止されていて?)、19日の昼ころ復元してもらえたものと思われます。

しかし、復元したという連絡がないというのも恐ろしいですね。
せっかく復元してもらえても気付かない可能性があったということですものね。
Googleアカウントが消された人の中には、復元してもらえているのに気づいていない人もいるんじゃないでしょうか。

ちなみに息子のちんちんが写った写真はインスタントアップロード上にはありませんでした。
Googleが消したのか、それともアップロードされたという事自体、自分の勘違いだったのか…。
はっきりとは覚えていませんが、アップロードされてしまった気はするのでGoogleが消したのだと思います。
Googleが写真を消したのだとすれば、アカウントが削除された原因はやはり息子の写真だったのでしょうか。


理由がわからないというのはモヤモヤしますね。
削除されたのもそうですが、今回の復元された理由もわかりません。

前回の記事を多くの人に読んでもらったことで、Googleの中の人の目にも留まり特別対応してくれた
→これはなさそう。

・アカウント削除の判断が間違いだった
→これもないでしょう。

・時間がかかったが、以前出していた問い合わせのどれかに対応してくれた
→これは可能性としてはあるかも知れない。けど、返信がないから違う気もする。

・原因となった画像を削除したから復元した
→単純に画像削除で済むものではないような気がする。

・上記のような理由を総合的に考えて、児童ポルノ保持が目的ではなかったと判断した
→Googleが人によって基準が異なるような対応をするというのは想像がつかない。けど、そうならちょっと嬉しい。

やっぱり考えてもわかりません。
モヤモヤしてはいるものの、アカウントが復元されたことは素直に喜んでいます。
これまでのデータが使える、残っているということの他に、児童ポルノだと判断してアカウントを削除したGoogleが、再びアカウントを使えるようにしてくれた、ということが嬉しいです。
「児童ポルノ」として写真を撮ったわけではない、ということをわかってくれたような気がするのです。
これからは気をつけてGoogleサービスを使っていくつもりです。

あと、ご心配いただいた皆様、どうもありがとうございました。
皆様も同じようなことにならないようお気をつけください。
タグ:Google
posted by t2low at 03:04| 日記