Android结算 - 购买inapp项目时BillingService例外

时间:2012-08-25 12:44:03

标签: android

我有这个例外:

java.lang.RuntimeException: Unable to start service com.problemio.BillingService@41342be8 with null: java.lang.NullPointerException
        at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2376)
        at android.app.ActivityThread.access$1900(ActivityThread.java:123)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4424)
        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:784)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
        at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
        at com.problemio.BillingService.handleCommand(BillingService.java:452)
        at com.problemio.BillingService.onStart(BillingService.java:442)
        at android.app.Service.onStartCommand(Service.java:438)
        at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2359)
        ... 10 more
java.lang.NullPointerException
        at com.problemio.BillingService.handleCommand(BillingService.java:452)
        at com.problemio.BillingService.onStart(BillingService.java:442)
        at android.app.Service.onStartCommand(Service.java:438)
        at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2359)
        at android.app.ActivityThread.access$1900(ActivityThread.java:123)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1210)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4424)
        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:784)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
        at dalvik.system.NativeStart.main(Native Method)

它指出了这两种方法:

@Override
public void onStart(Intent intent, int startId) {
    handleCommand(intent, startId);  //TODO intent is null.
}

调用此方法并发送null intent:

public void handleCommand(Intent intent, int startId) {
    String action = intent.getAction(); //Exception happens right here when intent is null.
    ...

我想知道为什么意图以非常规的方式发送为null。它必须是我在代码中做得不对的问题,而问题的根源可能在其他地方。

这是整个BillingReciever代码:

package com.problemio;

import utils.Consts;
import utils.Consts.ResponseCode;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class BillingReceiver extends BroadcastReceiver
{
    private static final String TAG = "BillingReceiver";

    /**
     * This is the entry point for all asynchronous messages sent from Android Market to
     * the application. This method forwards the messages on to the
     * {@link BillingService}, which handles the communication back to Android Market.
     * The {@link BillingService} also reports state changes back to the application through
     * the {@link ResponseHandler}.
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (Consts.ACTION_PURCHASE_STATE_CHANGED.equals(action)) {
            String signedData = intent.getStringExtra(Consts.INAPP_SIGNED_DATA);
            String signature = intent.getStringExtra(Consts.INAPP_SIGNATURE);
            purchaseStateChanged(context, signedData, signature);
        } else if (Consts.ACTION_NOTIFY.equals(action)) {
            String notifyId = intent.getStringExtra(Consts.NOTIFICATION_ID);
            if (Consts.DEBUG) {
                Log.i(TAG, "notifyId: " + notifyId);
            }
            notify(context, notifyId);
        } else if (Consts.ACTION_RESPONSE_CODE.equals(action)) {
            long requestId = intent.getLongExtra(Consts.INAPP_REQUEST_ID, -1);
            int responseCodeIndex = intent.getIntExtra(Consts.INAPP_RESPONSE_CODE,
                    ResponseCode.RESULT_ERROR.ordinal());
            checkResponseCode(context, requestId, responseCodeIndex);
        } else {
            Log.w(TAG, "unexpected action: " + action);
        }
    }

    /**
     * This is called when Android Market sends information about a purchase state
     * change. The signedData parameter is a plaintext JSON string that is
     * signed by the server with the developer's private key. The signature
     * for the signed data is passed in the signature parameter.
     * @param context the context
     * @param signedData the (unencrypted) JSON string
     * @param signature the signature for the signedData
     */
    private void purchaseStateChanged(Context context, String signedData, String signature) {
        Intent intent = new Intent(Consts.ACTION_PURCHASE_STATE_CHANGED);
        intent.setClass(context, BillingService.class);
        intent.putExtra(Consts.INAPP_SIGNED_DATA, signedData);
        intent.putExtra(Consts.INAPP_SIGNATURE, signature);
        context.startService(intent);
    }

    /**
     * This is called when Android Market sends a "notify" message  indicating that transaction
     * information is available. The request includes a nonce (random number used once) that
     * we generate and Android Market signs and sends back to us with the purchase state and
     * other transaction details. This BroadcastReceiver cannot bind to the
     * MarketBillingService directly so it starts the {@link BillingService}, which does the
     * actual work of sending the message.
     *
     * @param context the context
     * @param notifyId the notification ID
     */
    private void notify(Context context, String notifyId) 
    {
        Intent intent = new Intent(Consts.ACTION_GET_PURCHASE_INFORMATION);
        intent.setClass(context, BillingService.class);
        intent.putExtra(Consts.NOTIFICATION_ID, notifyId);
        context.startService(intent);
    }

    /**
     * This is called when Android Market sends a server response code. The BillingService can
     * then report the status of the response if desired.
     *
     * @param context the context
     * @param requestId the request ID that corresponds to a previous request
     * @param responseCodeIndex the ResponseCode ordinal value for the request
     */
    private void checkResponseCode(Context context, long requestId, int responseCodeIndex) {
        Intent intent = new Intent(Consts.ACTION_RESPONSE_CODE);
        intent.setClass(context, BillingService.class);
        intent.putExtra(Consts.INAPP_REQUEST_ID, requestId);
        intent.putExtra(Consts.INAPP_RESPONSE_CODE, responseCodeIndex);
        context.startService(intent);
    }

}

谢谢!

2 个答案:

答案 0 :(得分:2)

据我所知,你发布的代码看起来还不错。我的BillingService类中有一个空检查:

public void handleCommand(Intent intent, int startId)
{
    if (intent != null)
    {
        String action = intent.getAction();
            .....
    }
}

我前段时间做过,说实话,不能具体记住为什么会这样。

答案 1 :(得分:0)

这里发布了一个更好的解决方案: https://stackoverflow.com/a/12488357/1291879

这将解决空指针问题和与onStart()相关的弃用问题。

基本上,修复方法是使用onStartCommand()代替onStart(),如下所示:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
   handleCommand(intent, startId);
   return START_NOT_STICKY;
}