2013/11/28

In-app billing v3のTrivialDriveをAndroid 2.1で動かすとエラーが発生する

Androidアプリでアプリ内課金(in-app billing v3) を実装するために、TrivialDriveを参考にしていると思います。

TrivialDriveでは、Android 2.2(android:minSdkVersion="8")のため問題なかったのですが、もし、Android 2.1(android:minSdkVersion="7")までを対象にしているアプリを作成していた場合、バックボタンやホームボタンでActivityを終了すると、下記のExceptionが発生します。

11-28 19:53:49.412: E/AndroidRuntime(3697): Uncaught handler: thread main exiting due to uncaught exception
11-28 19:53:49.422: E/AndroidRuntime(3697): java.lang.RuntimeException: Unable to destroy activity {jp.example.android.t
rivialdrivesample/jp.example.android.trivialdrivesample.MainActivity}: java.lang.IllegalArgumentException: Service not r
egistered: jp.example.android.trivialdrivesample.util.IabHelper$1@457a5280
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread.performDestroyActivity(ActivityThread.java
:3476)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:
3494)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread.access$2800(ActivityThread.java:123)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1903)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.os.Handler.dispatchMessage(Handler.java:99)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.os.Looper.loop(Looper.java:123)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread.main(ActivityThread.java:4370)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at java.lang.reflect.Method.invokeNative(Native Method)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at java.lang.reflect.Method.invoke(Method.java:521)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit
.java:850)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:608)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at dalvik.system.NativeStart.main(Native Method)
11-28 19:53:49.422: E/AndroidRuntime(3697): Caused by: java.lang.IllegalArgumentException: Service not registered: jp.ex
ample.android.trivialdrivesample.util.IabHelper$1@457a5280
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread$PackageInfo.forgetServiceDispatcher(Activi
tyThread.java:934)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ApplicationContext.unbindService(ApplicationContext.java:
819)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.content.ContextWrapper.unbindService(ContextWrapper.java:342)

11-28 19:53:49.422: E/AndroidRuntime(3697):     at jp.example.android.trivialdrivesample.util.IabHelper.dispose(IabHelpe
r.java:284)

11-28 19:53:49.422: E/AndroidRuntime(3697):     at jp.example.android.trivialdrivesample.MainActivity.onDestroy(MainActi
vity.java:432)
11-28 19:53:49.422: E/AndroidRuntime(3697):     at android.app.ActivityThread.performDestroyActivity(ActivityThread.java
:3463)
11-28 19:53:49.422: E/AndroidRuntime(3697):     ... 11 more


エラーが発生したソースコードの部分は、

IabHelper.java
public void dispose() {
    logDebug("Disposing.");
    mSetupDone = false;
    if (mServiceConn != null) {
        logDebug("Unbinding from service.");
        if (mContext != null) mContext.unbindService(mServiceConn);
        mServiceConn = null;
        mService = null;
        mPurchaseListener = null;
    }
}

です。Android 2.1 は、in-app-billing v3に対応しておらず、Serviceが立ち上がっていなかったのでunbindしようとしたときにエラーが発生しました。
そこで、下記のように修正します。

IabHelper.java
 public void startSetup(final OnIabSetupFinishedListener listener) {
    // If already set up, can't do it again.
    if (mSetupDone) throw new IllegalStateException("IAB helper is already set up.");

    // Connection to IAB service
    logDebug("Starting in-app billing setup.");
    mServiceConn = new ServiceConnection() {
        // 省略
    };

    Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
    if (!mContext.getPackageManager().queryIntentServices(serviceIntent, 0).isEmpty()) {
        // service available to handle that Intent
        mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
    }
    else {
        // no service available to handle that Intent
        if (listener != null) {
            listener.onIabSetupFinished(
                    new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE,
                    "Billing service unavailable on device."));
        }

        mServiceConn = null;// 追加
    }
}

一行追加することで、unbindService(mServiceConn)する直前のmServiceConnの null チェックにより、unbindServiceが呼ばれなくなるのでエラーが発生しなくなります。


ちなみに、最近サンプルコードがrev.5 になっていろいろと修正が加わっていますので、もし以前のサンプルコードを利用している場合は差分を確認することをおすすめします。

2013/11/22

「android.view.WindowManager$BadTokenException: Unable to add window -- 」エラーの対処

Androidアプリを制作中、Thread()を利用してshowDialog(int id)でダイアログを表示した場合、Activityが既に変わっていると下記のエラーが表示されました。

android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@42d617b8 is not valid; is your activity running?
    at android.view.ViewRootImpl.setView(ViewRootImpl.java:589)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:326)
    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:224)
    at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:149)
    at android.view.Window$LocalWindowManager.addView(Window.java:547)
    at android.app.Dialog.show(Dialog.java:285)
    at android.app.Activity.showDialog(Activity.java:3052)
    at android.app.Activity.showDialog(Activity.java:3002)
    at jp.sample.SampleActivity.showReviewDialog(SampleActivity.java:98)
    at android.os.Handler.handleCallback(Handler.java:615)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:213)
    at android.app.ActivityThread.main(ActivityThread.java:4786)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:556)
    at dalvik.system.NativeStart.main(Native Method)


そこで、対象のActivityが終了しているかどうかチェックを行うことで対応できます。

if ( isFinishing() == false ) {
            showDialog( DIALOG_ID );
}


ちなみに、showDialog() は、@Deprecated になっているので注意が必要です。


■参考サイト
progressdialog - Android: "BadTokenException: Unable to add window; is your activity running?" at showing dialog in PreferenceActivity - Stack Overflow

Android: android.view.WindowManager$BadTokenException & Android – Displaying Dialogs From Background Threads


2013/11/21

「ドライバー \Driver\WUDFRd を読み込めませんでした。」が発生したら・・・

ブルースクリーンが発生した際のエラーIRQL_NOT_LESS_OR_EQUALを解決するために、イベントビューアーの管理イベントから、エラーが起きたタイミングで発生していた

警告     2013/11/21 16:39:11     Kernel-PnP     219     (212)

デバイス USB\VID_147E&PID_2016\6&3af1eaa2&0&3 のドライバー \Driver\WUDFRd を読み込めませんでした。
をひとまず解決することにしました。(注:まだ未解決の記事です。)




日記という名の不定記 のサイトを参考に
  1. スタートメニューの「ファイル名を指定して実行」でservices.mscを入力する。
  2. 一覧から、Windows Driver Foundation - User-mode Driver Frameworkを探してWクリックする。
  3. スタートアップの種類を「手動」から「自動」に変更する。

を行いました。

はてさて、これで解決するのかしばらく様子見です。

■2013/11/22追記
変わらずブルースクリーンが発生し(このときはMEMORY_MANAGEMENT)、

警告    2013/11/22 12:52:28    Kernel-PnP    219    (212)
デバイス USB\VID_147E&PID_2016\6&3af1eaa2&0&3 のドライバー \Driver\WUDFRd を読み込めませんでした。


が発生しました。