getPurchases()初始化mService的NullPointerException

时间:2014-01-05 06:00:40

标签: android nullpointerexception in-app-billing

修改:Please see my answer below for my solution


我在尝试使用getPurchases()检查自有项目时收到NullPointerException错误,我不确定为什么我跟着the documentation。我发现文档有时会产生误导,所以我在这里。

我已经设置了应用内结算,以便初始化正常,我收到了成功消息。在初始化之后,我想检查用户是否先前购买了项目并根据结果显示按钮。这是我的代码到目前为止,下面是我的LogCat。错误出现在try / catch的开头。

public class MainActivity extends Activity
{
    IabHelper mHelper;
    IInAppBillingService mService;
    private Button buyButton;
    AdView adView;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        adView = (AdView)this.findViewById(R.id.adView);
        AdRequest adRequest = new AdRequest.Builder().build();
        adView.loadAd(adRequest);

        buyButton = (Button)findViewById(R.id.buyButton);

        String base64EncodedPublicKey = "public_key";

        mHelper = new IabHelper(this, base64EncodedPublicKey);

        mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener()
        {
            @Override
            public void onIabSetupFinished(IabResult result)
            {
                if(!result.isSuccess())
                {
                    Log.d("TEST", "In-app Billing setup failed: " + result);
                }
                else
                {
                    Log.d("TEST", "In-app Billing is set up OK"); //This passes!
                }
            }
        });

        bindService(new Intent("com.android.vending.billing.InAppBillingService.BIND"), mServiceConn, Context.BIND_AUTO_CREATE);

        try
        {
            Bundle ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null); //This is line 66 referenced in LogCat error

            if(ownedItems.getInt("RESPONSE_CODE") == 0)
            {
                ArrayList ownedSkus = ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
                ArrayList purchaseDataList = ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
                ArrayList signatureList = ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE");
                String continuationToken = ownedItems.getString("INAPP_CONTINUATION_TOKEN");

                for(int i=0; i<purchaseDataList.size(); ++i)
                {
                    String purchaseData = (String) purchaseDataList.get(i);
                    String signature = (String) signatureList.get(i);
                    String sku = (String) ownedSkus.get(i);

                    Log.d("TEST", "Purchased: "+i+ " -> "+sku);
                }
            }
            else
            {
                Log.d("TEST", "Not Items Owned!");
            }
        }
        catch(RemoteException e)
        {
            //TODO: Error, unable to get owned items
            e.printStackTrace();
            Log.d("TEST", "owned items check failed: "+e);
        }           
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    ServiceConnection mServiceConn = new ServiceConnection() 
    {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            mService = IInAppBillingService.Stub.asInterface(service);
            Log.d("TEST", "mService ready to go!"); //This displays if try/catch above is commented out. Is it not waiting for mService to be initialized before running try/catch?     
        }

        @Override
        public void onServiceDisconnected(ComponentName name)
        {
            mService = null;            
        }
    };

    @Override
    public void onDestroy()
    {
        super.onDestroy();

        if(mServiceConn != null)
        {
            unbindService(mServiceConn);
        }
    }
}

Logcat错误

01-04 22:39:35.052: E/AndroidRuntime(32375): FATAL EXCEPTION: main
01-04 22:39:35.052: E/AndroidRuntime(32375): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.test.iab/com.test.iab.MainActivity}: java.lang.NullPointerException
01-04 22:39:35.052: E/AndroidRuntime(32375):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at android.app.ActivityThread.access$600(ActivityThread.java:141)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at android.os.Handler.dispatchMessage(Handler.java:99)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at android.os.Looper.loop(Looper.java:137)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at android.app.ActivityThread.main(ActivityThread.java:5041)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at java.lang.reflect.Method.invokeNative(Native Method)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at java.lang.reflect.Method.invoke(Method.java:511)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at dalvik.system.NativeStart.main(Native Method)
01-04 22:39:35.052: E/AndroidRuntime(32375): Caused by: java.lang.NullPointerException
01-04 22:39:35.052: E/AndroidRuntime(32375):    at com.test.iab.MainActivity.onCreate(MainActivity.java:66)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at android.app.Activity.performCreate(Activity.java:5104)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
01-04 22:39:35.052: E/AndroidRuntime(32375):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
01-04 22:39:35.052: E/AndroidRuntime(32375):    ... 11 more
01-04 22:39:35.083: E/GooglePlayServicesUtil(32375): The Google Play services resources were not found. Check your project configuration to ensure that the resources are included.

我的猜测是我没有正确初始化mService?但我不明白我是不是因为我认为我完全按照文档概述。感谢您的指导。

2 个答案:

答案 0 :(得分:3)

这不起作用的原因是因为onServiceConnected()onCreate()完成之前无法保证被调用。所以我将try / catch代码移到onServiceConnected()。我不确定这是否是最佳做法,但它似乎解决了我的问题。以下是任何发现自己有同样错误的人的结果代码。这是按钮和购买逻辑。我推荐this tutorial代码。

public class MainActivity extends Activity
{
    IabHelper mHelper;
    IInAppBillingService mService;
    static final String ITEM_SKU = "android.test.purchased";
    private Button buyButton;
    AdView adView;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        adView = (AdView)this.findViewById(R.id.adView);
        AdRequest adRequest = new AdRequest.Builder().build();
        adView.loadAd(adRequest);

        buyButton = (Button)findViewById(R.id.buyButton);

        bindService(new Intent("com.android.vending.billing.InAppBillingService.BIND"), mServiceConn, Context.BIND_AUTO_CREATE);      
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    ServiceConnection mServiceConn = new ServiceConnection() 
    {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service)
        {
            mService = IInAppBillingService.Stub.asInterface(service);
            Log.d("TEST", "mService ready to go!");
            checkOwnedItems();    
        }

        @Override
        public void onServiceDisconnected(ComponentName name)
        {
            mService = null;            
        }
    };

    private void checkownedItems()
    {
        try
        {
            Bundle ownedItems = mService.getPurchases(3, getPackageName(), "inapp", null);

            if(ownedItems.getInt("RESPONSE_CODE") == 0)
            {
                ArrayList<String> ownedSkus = ownedItems.getStringArrayList("INAPP_PURCHASE_ITEM_LIST");
                ArrayList<String> purchaseDataList = ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
                ArrayList<String> signatureList = ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE");
                String continuationToken = ownedItems.getString("INAPP_CONTINUATION_TOKEN");

                if(purchaseDataList.size() > 0)
                {
                    //Item(s) owned

                    for(int i=0; i<purchaseDataList.size(); ++i)
                    {
                        String purchaseData = purchaseDataList.get(i);
                        String signature = signatureList.get(i); //Note signatures do not appear to work with android.test.purchased (silly google)
                        String sku = ownedSkus.get(i);
                    }
                }
                else
                {
                    //Item(s) not owned

                    String base64EncodedPublicKey = "public_key";

                    mHelper = new IabHelper(this, base64EncodedPublicKey);

                    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener()
                    {
                        @Override
                        public void onIabSetupFinished(IabResult result)
                        {
                            if(!result.isSuccess())
                            {
                                Log.d("TEST", "In-app Billing setup failed: " + result);
                            }
                            else
                            {
                                Log.d("TEST", "In-app Billing is set up OK");
                            }
                        }
                    });
                }
            }
            else
            {
                //Error checking owned items
            }
        }
        catch(RemoteException e)
        {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();

        if(mServiceConn != null)
        {
            unbindService(mServiceConn);
        }
    }
}

答案 1 :(得分:1)

您的代码只是说

IInAppBillingService mService;

它是null,你需要初始化它。

System.out.println()方法中放置onServiceConnected以查看它是否正在初始化。如果不是,则表示未调用onServiceConnected,因此bindService方法可能无法正常工作

编辑:我想我知道这个问题。

在onCreate方法之外添加它作为类变量......

ServiceConnection mServiceConn;

然后改变

ServiceConnection mServiceConn = new ServiceConnection()

mServiceConn = new ServiceConnection()