【问题标题】:getPurchases() NullPointerException initializing mServicegetPurchases() NullPointerException 初始化 mService
【发布时间】:2014-01-22 17:14:05
【问题描述】:

编辑: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?但我不明白我是否不是因为我相信我完全按照文档的概述做了。感谢您的指导。

【问题讨论】:

    标签: android nullpointerexception in-app-billing


    【解决方案1】:

    这不起作用的原因是,在onCreate() 完成之前,不能保证调用onServiceConnected()。所以我把 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);
            }
        }
    }
    

    【讨论】:

    • 非常感谢!!!如果他们在开发人员参考资料处告诉我们这一点,这不会伤害谷歌。再也不要从 onCreate 活动中调用价目表了!明白了!
    【解决方案2】:

    你的代码只是说

    IInAppBillingService mService;
    

    为空,需要初始化。

    onServiceConnected方法中放一个System.out.println(),看看它是否正在初始化。如果不是,则意味着 onServiceConnected 没有被调用,因此 bindService 方法可能无法按预期工作

    编辑:我想我知道问题所在。

    将此作为类变量添加到 onCreate 方法之外...

    ServiceConnection mServiceConn;
    

    然后改变

    ServiceConnection mServiceConn = new ServiceConnection()
    

    mServiceConn = new ServiceConnection()
    

    【讨论】:

    • bindService() 在 try/catch 之前调用 mServiceConn 时不是在初始化它吗?
    • @user3001127 是的,这是我的错误,bindService 正在初始化它。试试我最近的编辑。我认为它可以解决问题。
    • 我尝试将 mServiceConn 创建为类变量,但 mServiceConn = new ServiceConnection() 会产生语法错误。具体来说,onCreateOptionsMenue() 方法的右括号会出现错误消息“标记上的语法错误“}”,删除此标记”。此外,mServiceConn 的关闭括号现在有错误“此行有多个标记 - 语法错误,插入“}”以完成 MethodBody -语法错误,插入“}”以完成 MethodBody”
    • 我已经编辑了我之前的评论以包含确切的错误消息。
    • @user3001127 你的 onServiceConnected 方法是在 bindService 被调用之后被调用的吗?使用 System.out.println() 语句进行验证。
    猜你喜欢
    • 1970-01-01
    • 2017-06-10
    • 2015-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多