2011年6月13日月曜日

Themeを設定したDialogがActivityに重なって表示されない

Themeを指定したProgressDialogが、2.3以降の端末(バージョンアップ後のGalaxySとかXperiaArcとか)で表題のような状態になった。
ちょうど別のActivityに遷移してしまったような感じ。
ProgressDialog dlg = new ProgressDialog(this, R.style.ProgressDialog);


一応下記のようにThemeにはparentでTheme.Dialog.Alertを指定していたのに、Dialogたるべき属性を継承してくれてない。

styles.xml



しょうがないので、継承したかったAlertDialogのThemeから設定を引っ張ってきた。

styles.xml


ネタ元はココ

windowContentOverlayはあってもなくても見た目変化ない気がする。念のため。

2011年5月17日火曜日

In-app Billingで(softbankを除く?)キャリア決済ができない

これは、私個人ではまだ解決に至っていない問題。(2011/5/17時点)

アプリ内課金を実装してみて、いざ実機(Xperia Arc SO-01C)で確認してみると、クレジットカード払いは上手くいったが、「NTT Docomo利用料金と一緒に支払い」を選択すると、購入に失敗する。
spモードパスワードを入力するダイアログを閉じた後、何も音沙汰がない。

ログを確認してみると、spモードパスワード入力ダイアログである、
com.android.vending/.billing.CarrierPasswordActivity
を起動するインテントを飛ばした後に、REQUEST_PURCHASEに対してRESULT_USER_CANCELEDが返ってきている。
継続しなければならない課金認証処理中に、作り上予期してないアクティビティが起動することによって中断されてしまっているのだろうか。

ネットで調べてみると、同様の事象で苦戦している人がいた。
In-app Billing(アプリ内課金)+SPモード決済=動作不良?
私個人ではDocomo以外では未検証だったのだけど、これによればauでも同様に発生する問題みたい。softbankはパスワードを要求されないから大丈夫だったともある。


そもそも、Android2.1以前の端末ではアプリ内課金キャリア決済もまともに動かないようで。
せっかく普及してきたAndroidユーザーの多くが対象にならないのなら、しばらくは様子見がよいのかな。

---------------------
追記(2011/7/5)

Android Developer Lab Tokyoにおいて、AndroidマーケットのセッションでIn-app BillingおよびCarrier Billing(キャリア決済)について触れられていたので、もしかしてこの件知らずにこの機能オススメしてるんじゃなかろうかと心配になった。
そこでこの件について尋ねてみたところ、その場にいらっしゃったGoogleのエンジニアの方からも問題解決を加速するよう働きかけてくださりました。
Issue 23: Direct carrier billing doesn't function

これは既知の問題で、数週間以内に Android Market アプリケーションのアップデートに含まれて修正される予定です。­ いましばらくお待ちください。
とのこと。

----------------------
追記(2011/7/14)

問題修正されたAndroidマーケットアプリが近日リリースされるとのこと。
この問題はこれでおしまいかな。

アプリ内課金のキャリア課金に関して

Android Market クライアントアプリのバージョンアップのお知らせ

ADLで質問してからの流れは非常に早いんだけど、実際言わなかったらどうなっていたんだろう、なんて思った。ほんとはバックグラウンドで動いてただけで私が質問したことなんて何の関係もなかったのならいいんだけど…

2011年3月23日水曜日

Designing for PerformanceからAvoid Enumsが消えてた

In-app Billingのテスト実装をするためサンプルソースを読んでいたら、
ガッツリenum型が使われていた。

以前パフォーマンスの問題で単なるintと同じ扱いするだけならなるべく使うなって、
Designing for Performanceに記述があったのに、と思って改めて調べてみると、
記述が削除されてた。


推測される理由?

static final intはガラケーを彷彿させて嫌だったので、
パフォーマンスに影響ない限りは使うべきところには今後enumを使っていきたい。


しかもこのサンプル、int型のレスポンスコードをordinal()で取ってるんだよなあ。
Effective Javaの項目31にこういう使い方は微妙って書いてあったような気が。
私が誤読してるのかな?
まあコピペしちゃいけない処理だしいいのか。

2011年3月22日火曜日

AndroidでXMLを読み込む(ユーティリティを使ったSAXパーサ)

AndroidでのXMLの読み込み方法は、

  1. SAX
  2. DOM
  3. XMLプルパーサ
がある。

今回は、1.SAXを使用した。

SAXでのXMLの解析は、
処理の大部分はハンドラに記述するわけだけど、
対象のXMLがネストの深い構造だったりすると、途端にソースの可読性が下がる。
(私がまだ綺麗な書き方を知らないだけかもしれない…)

AndroidでSAXを扱う場合、
android.saxパッケージにユーティリティクラスが用意されている。これホントに便利。
プルパーサに書き換えようと思っていたけど、とりあえずはこっちでいいかも。

※参考
AndroidでXMLを扱う
http://www.ibm.com/developerworks/jp/xml/library/x-android/



要素の属性を取得する場合は、
StartElementListenerTextlementListenerを使用する必要がある。
<xml>
<root>
<tag id="A001">data</tag>
</root>
みたいなものには、

public List<Data> parse() {
    final Data currentData = new Data();
    List<Data> list = new ArrayList<Data>();

    RootElement root = new RootElement("root");
    Element tag = root.getChild("tag");
    tag.setTextElementListener( new TextElementListener() {
        @Override
        public void start(Attributes attributes) {
            // id属性を取得
            String id = attributes.getValue("id");
            currentData.setId(id);
        }

        @Override
        public void end(String body) {
            // tag要素を取得
            currentData.setData(body);
            list.add(new Data(currentData));
        }
    });
    try {
        Xml.parse(getInputStream(), Xml.Encoding.UTF_8, root.getContentHandler());
        return list;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

最初はよく理解せず、
ElementListenerとEndTextElementListenerを組み合わせていたけど、
リスナの呼び出し順が、
  1. ElementListener$start
  2. ElementListener$end
  3. EndTextElementListener$end
で、当然意図していたのと違っていた。(2と3が逆だと思った)

Simple Typeの要素にはTextElementListenerを、
Complex Typeの要素にはElementListenerを設定してあげるのが正しいやり方。

2011年3月11日金曜日

ViewAnimator.bringChildToFront()のバグ

というのか仕様というのか。

ViewAnimatorでアニメーションでどのViewが上に描画されるかは、ViewGroupで管理されている子Viewの配列順のようだ。
そこで、確実に上に描画されるようにViewAnimator.bringChildToFront()を使っていると、どうも期待する描画にならなくなってくる。

そこでViewAnimatorのソースを見てみると、どうも表示している子Viewの配列番号を指すべきprivateフィールドであるmWhichChildが、ViewAnimator.bringChildToFront()の呼び出しによりズレていっていた。
ズレが発生した後に、mWhichChildを参照している
ViewAnimator.showNext()
ViewAnimator.showPrevious()
ViewAnimator.getDisplayedChild()
ViewAnimator.getCurrentView()
なんかを使うとアプリの挙動が意図しないモノになる。

対処方法としては、

  1. 子Viewの並び替えが必要ないように最初から追加しておく
  2. showNext(),showPrevious()を使用せず、setDisplayedChild()で表示する。
  3. カスタムViewAnimatorクラスを作成する。
てところだろうか。

1は、ある程度の固定数の子Viewしか持たないことがわかっていれば何も問題ない。
今回は可変の数の子Viewが必要となるため、ListViewのようにViewを使い回し、必要なViewにだけ描画を行うようにしたかったので却下。
2は、更にViewAnimatorを使用する側のクラスでmWhichChildのような子View管理データを持つ必要がある。面倒。
今回は3で解決した。流用が効くし。ViewAnimatorからソース引っ張ってきて、以下のメソッドを追加。

@Override
public void bringChildToFront(View child) {
    int index  = indexOfChild(child);
    if (index < mWhichChild) {
        mWhichChild--;
    } else if (index == mWhichChild) {
        mWhichChild = getChildCount() - 1;
    }
    super.bringChildToFront(child);
}

ViewAnimatorってViewFlipper/ViewSwitcher/ImageSwitcher/TextSwitcherとかの親クラスになってて、結構この辺で問題起きそうな気がする。

addViewとかで現在表示しているViewの裏側になるindex指定してもmWhichChildはズレる可能性ありそう。
でも今回の用途には使用しないので詳しくはみてない。

2011年3月10日木曜日

開発の記録として

Macbook airを買ったので、プライベートでの開発を頑張る。
家は椅子が折りたたみ式の木製の椅子で落ち着かず、誘惑も多々あるので、
外で憧れのカフェプログラミングてのをやってみたい。
当面はAndroid開発をメインに。

とりあえずeclipseをインストール。