2012-07-12 30 views
5

Khi người dùng nhấn nút mua, họ sẽ được đưa đến màn hình phát Android để mua mặt hàng trong ứng dụng. Nhưng khi họ nhấn trở lại, họ nhận được ngoại lệ này về việc không thể để bắt đầu dịch vụ thanh toán:Thanh toán trong ứng dụng Android - ngoại trừ khi nhấn mua, sau đó nhấn lại từ màn hình mua hàng

java.lang.RuntimeException: Unable to start service [email protected] with Intent { act=com.android.vending.billing.RESPONSE_CODE cmp=com.problemio/.BillingService (has extras) }: java.lang.NullPointerException 
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2387) 
at android.app.ActivityThread.access$2800(ActivityThread.java:132) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1111) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:150) 
at android.app.ActivityThread.main(ActivityThread.java:4293) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:507) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 
at dalvik.system.NativeStart.main(Native Method) 
Caused by: java.lang.NullPointerException 
at com.problemio.ExtraHelpActivity.prependLogEntry(ExtraHelpActivity.java:561) 
at com.problemio.ExtraHelpActivity.logProductActivity(ExtraHelpActivity.java:569) 
at com.problemio.ExtraHelpActivity.access$4(ExtraHelpActivity.java:565) 
at com.problemio.ExtraHelpActivity$ExtraHelpPurchaseObserver.onRequestPurchaseResponse(ExtraHelpActivity.java:187) 
at com.problemio.ResponseHandler.responseCodeReceived(ResponseHandler.java:137) 
at com.problemio.BillingService$RequestPurchase.responseCodeReceived(BillingService.java:285) 
at com.problemio.BillingService.checkResponseCode(BillingService.java:582) 
at com.problemio.BillingService.handleCommand(BillingService.java:427) 
at com.problemio.BillingService.onStart(BillingService.java:398) 
at android.app.Service.onStartCommand(Service.java:428) 
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2370) 
... 10 more 
java.lang.NullPointerException 
at com.problemio.ExtraHelpActivity.prependLogEntry(ExtraHelpActivity.java:561) 
at com.problemio.ExtraHelpActivity.logProductActivity(ExtraHelpActivity.java:569) 
at com.problemio.ExtraHelpActivity.access$4(ExtraHelpActivity.java:565) 
at com.problemio.ExtraHelpActivity$ExtraHelpPurchaseObserver.onRequestPurchaseResponse(ExtraHelpActivity.java:187) 
at com.problemio.ResponseHandler.responseCodeReceived(ResponseHandler.java:137) 
at com.problemio.BillingService$RequestPurchase.responseCodeReceived(BillingService.java:285) 
at com.problemio.BillingService.checkResponseCode(BillingService.java:582) 
at com.problemio.BillingService.handleCommand(BillingService.java:427) 
at com.problemio.BillingService.onStart(BillingService.java:398) 
at android.app.Service.onStartCommand(Service.java:428) 
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2370) 
at android.app.ActivityThread.access$2800(ActivityThread.java:132) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1111) 
at android.os.Handler.dispatchMessage(Handler.java:99) 
at android.os.Looper.loop(Looper.java:150) 
at android.app.ActivityThread.main(ActivityThread.java:4293) 
at java.lang.reflect.Method.invokeNative(Native Method) 
at java.lang.reflect.Method.invoke(Method.java:507) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 
at dalvik.system.NativeStart.main(Native Method) 

Nó đặc biệt đề cập đến những dòng này trong lớp học của tôi:

Nguyên nhân:

java.lang.NullPointerException 
at com.problemio.ExtraHelpActivity.prependLogEntry(ExtraHelpActivity.java:561) 
at com.problemio.ExtraHelpActivity.logProductActivity(ExtraHelpActivity.java:569) 
at com.problemio.ExtraHelpActivity.access$4(ExtraHelpActivity.java:565) 
at com.problemio.ExtraHelpActivity$ExtraHelpPurchaseObserver.onRequestPurchaseResponse(ExtraHelpActivity.java:187) 

trên dòng 561 Tôi có mã này:

private void prependLogEntry(CharSequence cs) { 
    SpannableStringBuilder contents = new SpannableStringBuilder(cs); 
    contents.append('\n'); 
    contents.append(mLogTextView.getText()); // Line 561 
    mLogTextView.setText(contents); 
} 

trên dòng 569 Tôi có mã này:

private void logProductActivity(String product, String activity) { 
    SpannableStringBuilder contents = new SpannableStringBuilder(); 
    contents.append(Html.fromHtml("<b>" + product + "</b>: ")); 
    contents.append(activity); 
    prependLogEntry(contents); // Line 569 
} 

Nhân tiện, nhật ký nào đây? Có thực sự cần thiết? Có lẽ nó đáng giá để bình luận ra những phương pháp này?

Trong mọi trường hợp, đầu dây bên kia những điểm lỗi đến là 187 và đây là mã cho rằng:

@Override 
public void onRequestPurchaseResponse(RequestPurchase request, 
     ResponseCode responseCode) { 
    if (Consts.DEBUG) { 
     Log.d(TAG, request.mProductId + ": " + responseCode); 
    } 
    if (responseCode == ResponseCode.RESULT_OK) { 
     if (Consts.DEBUG) { 
      Log.i(TAG, "purchase was successfully sent to server"); 
     } 
     logProductActivity(request.mProductId, "sending purchase request"); 
    } else if (responseCode == ResponseCode.RESULT_USER_CANCELED) { 
     if (Consts.DEBUG) { 
      Log.i(TAG, "user canceled purchase"); 
     } 
     logProductActivity(request.mProductId, "dismissed purchase dialog"); 
     // This is line 187 right above this comment. 
    } else { 
     if (Consts.DEBUG) { 
      Log.i(TAG, "purchase failed"); 
     } 
     logProductActivity(request.mProductId, "request purchase returned " + responseCode); 
    } 
} 

Vì vậy, bạn thấy, nó giữ có một vấn đề về điều khai thác gỗ này. Nhật ký này là gì? Tôi có thể thấy nó ở đâu? Làm thế nào tôi có thể sửa nó để nó không mắc lỗi?

Tôi không chắc chắn, nhưng có thể vấn đề lớn hơn là yêu cầu đó là rỗng. Tại sao yêu cầu có thể là null ở đây?

Dưới đây là toàn bộ lớp ExtraHelpActivity:

public class ExtraHelpActivity extends BaseActivity implements ServiceConnection 
{ 
    // , OnClickListener 
    private static final String TAG = "Pay"; 

    String issueProductIdWebMarketing = "1";  
    String issueProductIdDonate = "2"; 
    String issueProductIdPsych = "3"; 

    /** 
    * The developer payload that is sent with subsequent 
    * purchase requests. 
    */ 
    private String payloadContents = null; 

    /** 
    * Used for storing the log text. 
    */ 
    private static final String LOG_TEXT_KEY = "DUNGEONS_LOG_TEXT"; 

    /** 
    * The SharedPreferences key for recording whether we initialized the 
    * database. If false, then we perform a RestoreTransactions request 
    * to get all the purchases for this user. 
    */ 
    private static final String DB_INITIALIZED = "db_initialized"; 

    private ExtraHelpPurchaseObserver mExtraHelpPurchaseObserver; 
    private Handler mHandler; 
    private Handler handler; 


    private BillingService mBillingService; 
    private Button mBuyButton; 
    private Button mEditPayloadButton; 
    private Button mEditSubscriptionsButton; 
    private TextView mLogTextView; 
    private Spinner mSelectItemSpinner; 
    private ListView mOwnedItemsTable; 
    private SimpleCursorAdapter mOwnedItemsAdapter; 
    private PurchaseDatabase mPurchaseDatabase; 
    private Cursor mOwnedItemsCursor; 
    private Set<String> mOwnedItems = new HashSet<String>(); 

    /** 
    * The developer payload that is sent with subsequent 
    * purchase requests. 
    */ 
    private String mPayloadContents = null; 

    private static final int DIALOG_CANNOT_CONNECT_ID = 1; 
    private static final int DIALOG_BILLING_NOT_SUPPORTED_ID = 2; 
    private static final int DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID = 3; 

    /** 
    * Each product in the catalog can be MANAGED, UNMANAGED, or SUBSCRIPTION. MANAGED 
    * means that the product can be purchased only once per user (such as a new 
    * level in a game). The purchase is remembered by Android Market and 
    * can be restored if this application is uninstalled and then 
    * re-installed. UNMANAGED is used for products that can be used up and 
    * purchased multiple times (such as poker chips). It is up to the 
    * application to keep track of UNMANAGED products for the user. 
    * SUBSCRIPTION is just like MANAGED except that the user gets charged monthly 
    * or yearly. 
    */ 
    private enum Managed { MANAGED, UNMANAGED, SUBSCRIPTION } 

    /** 
    * A {@link PurchaseObserver} is used to get callbacks when Android Market sends 
    * messages to this application so that we can update the UI. 
    */ 
    private class ExtraHelpPurchaseObserver extends PurchaseObserver { 
     public ExtraHelpPurchaseObserver(Handler handler) { 
      super(ExtraHelpActivity.this, handler); 
     } 

     @Override 
     public void onBillingSupported(boolean supported, String type) { 
      if (Consts.DEBUG) { 
       Log.i(TAG, "supported: " + supported); 
      } 
      if (type == null || type.equals(Consts.ITEM_TYPE_INAPP)) { 
       if (supported) { 
        restoreDatabase(); 
        mBuyButton.setEnabled(true); 
        mEditPayloadButton.setEnabled(true); 
       } else { 
        showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID); 
       } 
      } else if (type.equals(Consts.ITEM_TYPE_SUBSCRIPTION)) { 
       mCatalogAdapter.setSubscriptionsSupported(supported); 
      } else { 
       showDialog(DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID); 
      } 
     } 

     @Override 
     public void onPurchaseStateChange(PurchaseState purchaseState, String itemId, 
       int quantity, long purchaseTime, String developerPayload) { 
      if (Consts.DEBUG) { 
       Log.i(TAG, "onPurchaseStateChange() itemId: " + itemId + " " + purchaseState); 
      } 

      if (developerPayload == null) { 
       logProductActivity(itemId, purchaseState.toString()); 
      } else { 
       logProductActivity(itemId, purchaseState + "\n\t" + developerPayload); 
      } 

      if (purchaseState == PurchaseState.PURCHASED) { 
       mOwnedItems.add(itemId); 

       // If this is a subscription, then enable the "Edit 
       // Subscriptions" button. 
       for (CatalogEntry e : CATALOG) { 
        if (e.sku.equals(itemId) && 
          e.managed.equals(Managed.SUBSCRIPTION)) { 
         mEditSubscriptionsButton.setVisibility(View.VISIBLE); 
        } 
       } 
      } 
      mCatalogAdapter.setOwnedItems(mOwnedItems); 
      mOwnedItemsCursor.requery(); 
     } 

     @Override 
     public void onRequestPurchaseResponse(RequestPurchase request, 
       ResponseCode responseCode) { 
      if (Consts.DEBUG) { 
       Log.d(TAG, request.mProductId + ": " + responseCode); 
      } 
      if (responseCode == ResponseCode.RESULT_OK) { 
       if (Consts.DEBUG) { 
        Log.i(TAG, "purchase was successfully sent to server"); 
       } 
       logProductActivity(request.mProductId, "sending purchase request"); 
      } else if (responseCode == ResponseCode.RESULT_USER_CANCELED) { 
       if (Consts.DEBUG) { 
        Log.i(TAG, "user canceled purchase"); 
       } 
       logProductActivity(request.mProductId, "dismissed purchase dialog"); 
      } else { 
       if (Consts.DEBUG) { 
        Log.i(TAG, "purchase failed"); 
       } 
       logProductActivity(request.mProductId, "request purchase returned " + responseCode); 
      } 
     } 

     @Override 
     public void onRestoreTransactionsResponse(RestoreTransactions request, 
       ResponseCode responseCode) { 
      if (responseCode == ResponseCode.RESULT_OK) { 
       if (Consts.DEBUG) { 
        Log.d(TAG, "completed RestoreTransactions request"); 
       } 
       // Update the shared preferences so that we don't perform 
       // a RestoreTransactions again. 
       SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE); 
       SharedPreferences.Editor edit = prefs.edit(); 
       edit.putBoolean(DB_INITIALIZED, true); 
       edit.commit(); 
      } else { 
       if (Consts.DEBUG) { 
        Log.d(TAG, "RestoreTransactions error: " + responseCode); 
       } 
      } 
     } 
    } 

    private static class CatalogEntry { 
     public String sku; 
     public int nameId; 
     public Managed managed; 

     public CatalogEntry(String sku, int nameId, Managed managed) { 
      this.sku = sku; 
      this.nameId = nameId; 
      this.managed = managed; 
     } 
    } 

    /** An array of product list entries for the products that can be purchased. */ 
    private static final CatalogEntry[] CATALOG = new CatalogEntry[] { 
     new CatalogEntry("marketing_001", 1 , Managed.MANAGED), 
     new CatalogEntry("potion_001", 2 , Managed.UNMANAGED), 
     new CatalogEntry("subscription_monthly", 3, 
       Managed.SUBSCRIPTION), 
     new CatalogEntry("subscription_yearly", 4 , 
       Managed.SUBSCRIPTION) 
    }; 


    private String mItemName; 
    private String mSku; 
    private Managed mManagedType; 
    private CatalogAdapter mCatalogAdapter; 


    //outside onCreate() Within class 
// public Handler mTransactionHandler = new Handler(){ 
//  public void handleMessage(android.os.Message msg) { 
//   Log.i(TAG, "Transaction complete"); 
//   Log.i(TAG, "Transaction status: "+BillingHelper.latestPurchase.purchaseState); 
//   Log.i(TAG, "Item purchased is: "+BillingHelper.latestPurchase.productId); 
// 
//   if(BillingHelper.latestPurchase.isPurchased()){ 
//    //code here which is to be performed after successful purchase 
//   } 
//  }; 
// 
// };  


    // TODO: 
    // TODO: 
    @Override 
    public void onCreate(Bundle savedInstanceState) 
    { 
      super.onCreate(savedInstanceState); 

      setContentView(R.layout.extra_help); 

      //Now setup the in-app billing</pre> 
      handler = new Handler();    

      mExtraHelpPurchaseObserver = new ExtraHelpPurchaseObserver(handler); 

      mBillingService = new BillingService(); 

      mBillingService.setContext(this); 
      mPurchaseDatabase = new PurchaseDatabase(this); 

      ResponseHandler.register(mExtraHelpPurchaseObserver); 

      //Check if billing is supported. (Optional) 
      //boolean check = mBillingService.checkBillingSupported(); 




//    startService(new Intent(mContext, BillingService.class)); 
//    BillingHelper.setCompletedHandler(mTransactionHandler);    

      // Make sure the user is logged in 
      SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ExtraHelpActivity.this); 
      final String user_id = prefs.getString("user_id" , null);   

      Button donate = (Button)findViewById(R.id.donate); 
      donate.setOnClickListener(new Button.OnClickListener() 
      { 
       public void onClick(View v) 
       { 

        // Send me an email that a comment was submitted on a question. 

//     boolean val = mBillingService.requestPurchase(
//       "android.test.purchased", payloadContents); 
        //Replace "android.test.purchased" with your product ID that you added to Google Play or make it a variable that is populated from a list. 
        //Place this code in a button event or where ever it fits in your process flow. 

        if (mBillingService.requestPurchase(issueProductIdDonate, Consts.ITEM_TYPE_INAPP , null)) 
        { 

        } 
        else 
        { 

         Log.i("tag", "Can't purchase on this device"); 

        } 
       } 
      });     


      try 
      { 
        boolean bindResult = bindService(
        new Intent("com.android.vending.billing.MarketBillingService.BIND"), 
        this, 
        Context.BIND_AUTO_CREATE); 
        if (bindResult) 
        { 
        Log.i("Err" , "Service bind successful."); 
        } 
        else 
        { 
        Log.e("Err", "Could not bind to the MarketBillingService."); 
        } 
      } 
      catch (SecurityException e) 
      { 
        Log.e("Err" , "Security exception: " + e); 
      }   

    } 




    /** 
    * Save the context of the log so simple things like rotation will not 
    * result in the log being cleared. 
    */ 
    @Override 
    protected void onSaveInstanceState(Bundle outState) 
    { 
     super.onSaveInstanceState(outState); 
     //outState.putString(LOG_TEXT_KEY, Html.toHtml((Spanned) mLogTextView.getText())); 
    } 

    /** 
    * Restore the contents of the log if it has previously been saved. 
    */ 
    @Override 
    protected void onRestoreInstanceState(Bundle savedInstanceState) 
    { 
     super.onRestoreInstanceState(savedInstanceState); 
     if (savedInstanceState != null) 
     { 
      //mLogTextView.setText(Html.fromHtml(savedInstanceState.getString(LOG_TEXT_KEY))); 
     } 
    } 

    @Override 
    protected Dialog onCreateDialog(int id) 
    { 
     switch (id) 
     { 
      case DIALOG_CANNOT_CONNECT_ID: 
      return createDialog(1,1); 
     case DIALOG_BILLING_NOT_SUPPORTED_ID: 
      return createDialog(2,2); 
      case DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID: 
       return createDialog(3,3); 

     //   case DIALOG_CANNOT_CONNECT_ID: 
//    return createDialog(R.string.cannot_connect_title, 
//      R.string.cannot_connect_message); 
//   case DIALOG_BILLING_NOT_SUPPORTED_ID: 
//    return createDialog(R.string.billing_not_supported_title, 
//      R.string.billing_not_supported_message); 
//    case DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID: 
//     return createDialog(R.string.subscriptions_not_supported_title, 
//       R.string.subscriptions_not_supported_message); 
      default: 
       return null; 
     } 
    } 

    private Dialog createDialog(int titleId, int messageId) { 
     String helpUrl = replaceLanguageAndRegion("help_url"); 
     if (Consts.DEBUG) { 
      Log.i(TAG, helpUrl); 
     } 
     final Uri helpUri = Uri.parse(helpUrl); 

     // TODO: replace 1 with the thing its supposed to be - I think learn more url :) 
     AlertDialog.Builder builder = new AlertDialog.Builder(this); 
     builder.setTitle(titleId) 
      .setIcon(android.R.drawable.stat_sys_warning) 
      .setMessage(messageId) 
      .setCancelable(false) 
      .setPositiveButton(android.R.string.ok, null) 
      .setNegativeButton(1, new DialogInterface.OnClickListener() { 
       public void onClick(DialogInterface dialog, int which) { 
        Intent intent = new Intent(Intent.ACTION_VIEW, helpUri); 
        startActivity(intent); 
       } 
      }); 
     return builder.create(); 
    } 

    /** 
    * Replaces the language and/or country of the device into the given string. 
    * The pattern "%lang%" will be replaced by the device's language code and 
    * the pattern "%region%" will be replaced with the device's country code. 
    * 
    * @param str the string to replace the language/country within 
    * @return a string containing the local language and region codes 
    */ 
    private String replaceLanguageAndRegion(String str) { 
     // Substitute language and or region if present in string 
     if (str.contains("%lang%") || str.contains("%region%")) { 
      Locale locale = Locale.getDefault(); 
      str = str.replace("%lang%", locale.getLanguage().toLowerCase()); 
      str = str.replace("%region%", locale.getCountry().toLowerCase()); 
     } 
     return str; 
    } 

    /** 
    * Sets up the UI. 
    */ 
    private void setupWidgets() 
    { 
     mOwnedItemsCursor = mPurchaseDatabase.queryAllPurchasedItems(); 
     startManagingCursor(mOwnedItemsCursor); 
     String[] from = new String[] { PurchaseDatabase.PURCHASED_PRODUCT_ID_COL, 
       PurchaseDatabase.PURCHASED_QUANTITY_COL 
     }; 
//  int[] to = new int[] { R.id.item_name, R.id.item_quantity }; 
//  mOwnedItemsAdapter = new SimpleCursorAdapter(this, R.layout.item_row, 
//    mOwnedItemsCursor, from, to); 
//  mOwnedItemsTable = (ListView) findViewById(R.id.owned_items); 
//  mOwnedItemsTable.setAdapter(mOwnedItemsAdapter); 
    } 

    private void prependLogEntry(CharSequence cs) { 
     SpannableStringBuilder contents = new SpannableStringBuilder(cs); 
     contents.append('\n'); 
     contents.append(mLogTextView.getText()); 
     mLogTextView.setText(contents); 
    } 

    private void logProductActivity(String product, String activity) { 
     SpannableStringBuilder contents = new SpannableStringBuilder(); 
     contents.append(Html.fromHtml("<b>" + product + "</b>: ")); 
     contents.append(activity); 
     prependLogEntry(contents); 
    } 

    /** 
    * If the database has not been initialized, we send a 
    * RESTORE_TRANSACTIONS request to Android Market to get the list of purchased items 
    * for this user. This happens if the application has just been installed 
    * or the user wiped data. We do not want to do this on every startup, rather, we want to do 
    * only when the database needs to be initialized. 
    */ 
    private void restoreDatabase() { 
     SharedPreferences prefs = getPreferences(MODE_PRIVATE); 
     boolean initialized = prefs.getBoolean(DB_INITIALIZED, false); 
     if (!initialized) { 
      mBillingService.restoreTransactions(); 
      Toast.makeText(this, 3, Toast.LENGTH_LONG).show(); 
      // Used to be R.string.restoring_transactions instead of 3 
     } 
    } 

    /** 
    * Creates a background thread that reads the database and initializes the 
    * set of owned items. 
    */ 
    private void initializeOwnedItems() { 
     new Thread(new Runnable() { 
      public void run() { 
       doInitializeOwnedItems(); 
      } 
     }).start(); 
    } 

    /** 
    * Reads the set of purchased items from the database in a background thread 
    * and then adds those items to the set of owned items in the main UI 
    * thread. 
    */ 
    private void doInitializeOwnedItems() { 
     Cursor cursor = mPurchaseDatabase.queryAllPurchasedItems(); 
     if (cursor == null) { 
      return; 
     } 

     final Set<String> ownedItems = new HashSet<String>(); 
     try { 
      int productIdCol = cursor.getColumnIndexOrThrow(
        PurchaseDatabase.PURCHASED_PRODUCT_ID_COL); 
      while (cursor.moveToNext()) { 
       String productId = cursor.getString(productIdCol); 
       ownedItems.add(productId); 
      } 
     } finally { 
      cursor.close(); 
     } 

     // We will add the set of owned items in a new Runnable that runs on 
     // the UI thread so that we don't need to synchronize access to 
     // mOwnedItems. 
     mHandler.post(new Runnable() { 
      public void run() { 
       mOwnedItems.addAll(ownedItems); 
       mCatalogAdapter.setOwnedItems(mOwnedItems); 
      } 
     }); 
    } 

    /** 
    * Called when a button is pressed. 
    */ 
    public void onClick(View v) { 
     if (v == mBuyButton) { 
      if (Consts.DEBUG) { 
       Log.d(TAG, "buying: " + mItemName + " sku: " + mSku); 
      } 

      if (mManagedType != Managed.SUBSCRIPTION && 
        !mBillingService.requestPurchase(mSku, Consts.ITEM_TYPE_INAPP, mPayloadContents)) { 
       showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID); 
      } else if (!mBillingService.requestPurchase(mSku, Consts.ITEM_TYPE_SUBSCRIPTION, mPayloadContents)) { 
       // Note: mManagedType == Managed.SUBSCRIPTION 
       showDialog(DIALOG_SUBSCRIPTIONS_NOT_SUPPORTED_ID); 
      } 
     } else if (v == mEditPayloadButton) { 
      showPayloadEditDialog(); 
     } else if (v == mEditSubscriptionsButton) { 
      editSubscriptions(); 
     } 
    } 

    /** List subscriptions for this package in Google Play 
    * 
    * This allows users to unsubscribe from this apps subscriptions. 
    * 
    * Subscriptions are listed on the Google Play app detail page, so this 
    * should only be called if subscriptions are known to be present. 
    */ 
    private void editSubscriptions() { 
     // Get current package name 
     String packageName = getPackageName(); 
     // Open app detail in Google Play 
     Intent i = new Intent(Intent.ACTION_VIEW, 
          Uri.parse("market://details?id=" + packageName)); 
     startActivity(i); 
    } 

    /** 
    * Displays the dialog used to edit the payload dialog. 
    */ 
    private void showPayloadEditDialog() 
    { 
     AlertDialog.Builder dialog = new AlertDialog.Builder(this); 
     final View view = View.inflate(this, R.layout.edit_payload, null); 
     final TextView payloadText = (TextView) view.findViewById(R.id.payload_text); 
     if (mPayloadContents != null) { 
      payloadText.setText(mPayloadContents); 
     } 

     dialog.setView(view); 
     dialog.setPositiveButton(
       R.string.edit_payload_accept, 
       new DialogInterface.OnClickListener() { 
        public void onClick(DialogInterface dialog, int which) { 
         mPayloadContents = payloadText.getText().toString(); 
        } 
       }); 
     dialog.setNegativeButton(
       R.string.edit_payload_clear, 
       new DialogInterface.OnClickListener() { 
        public void onClick(DialogInterface dialog, int which) { 
         if (dialog != null) { 
          mPayloadContents = null; 
          dialog.cancel(); 
         } 
        } 
       }); 
     dialog.setOnCancelListener(new DialogInterface.OnCancelListener(
+0

Một vấn đề có thể xảy ra mà tôi nhận thấy là trong BillingService của tôi, tôi đã phải nhận xét chỉ thị @override cho các phương thức: onServiceDisconnected và onServiceConnected - nếu không nó sẽ không biên dịch. Bất kỳ ý tưởng tại sao nó sẽ không biên dịch và nếu đó có thể là vấn đề nghiêm trọng của tôi ở đây? – Genadinik

+0

nếu người dùng nhấn nút quay lại, gọi lại trênRequestPurchaseResponse (Yêu cầu RequestPurchase, ResponseCode responseCode) sẽ được gọi. Sự cố trong logProductActivity (request.mProductId, "hộp thoại mua bị loại bỏ"); trong trường hợp (responseCode == ResponseCode.RESULT_USER_CANCELED). Hãy thử bình luận logProductActivity (yêu cầu.mProductId, "hộp thoại mua bị loại bỏ"); đó. –

+0

Nếu bạn không muốn nhật ký nhận xét tất cả các phương thức logBlahBlah() và sau đó thử .. Một trong những sự cố là do phần ghi nhật ký .. Một trong hai là tác dụng phụ của sự cố đầu tiên .. Không thể khởi động dịch vụ thanh toán .. – Ronnie

Trả lời

3

oops.

mLogTextView chưa bao giờ được khởi tạo.

thêm mLogTextView = findViewById(R.id.blaaa);

tôi chắc chắn bạn đã biết rằng

xin vui lòng cho tôi biết nếu tôi đã sai lầm vì vậy mà tôi xóa câu trả lời này (:

+0

cảm ơn câu trả lời của bạn. Tôi là một chút bối rối, nơi tôi nên thêm này, và cũng .... những gì nên findViewById (R.id.blaaa) được? Ý tôi là ... quan điểm của tôi là gì? Tôi đã không thực hiện một cái nhìn đặc biệt cho logTextView và tôi đã không nhận thấy rằng đang được thực hiện trong ví dụ Dungeons từ hướng dẫn Android. – Genadinik

+0

Sau khi bạn 'setContentView' trong hàm' onCreate', bạn nên khởi tạo 'mLogTextView'. Chỉ cho tôi 'tệp extra_help.xml'. Oh, tôi nghĩ rằng 'TextView' này được sử dụng để hiển thị các giao dịch trong ví dụ Dungeons, vì vậy nó có lẽ không cần thiết cho một ứng dụng thực, bạn có thể thay đổi cơ chế ghi nhật ký này. Dù sao, chỉ cho tôi 'extra_help.xml' –

+0

Tôi đã thêm một câu trả lời với tệp extra_help.xml của mình vì tôi đã chạy vào giới hạn ký tự trong câu hỏi ban đầu của tôi. – Genadinik

3

Bạn có cho phép trong tập tin menifest?

<uses-permission android:name="com.android.vending.BILLING" />

+0

có chắc chắn bằng cách sử dụng đó. Thậm chí tôi có thể cho bạn biết một ngoại lệ tương tự xảy ra nếu người dùng thực hiện giao dịch mua và họ nhận được hóa đơn, nhưng sau khi quay lại ứng dụng của tôi, họ nhận được ngoại lệ buộc phải đóng – Genadinik

+0

Bạn tạo lớp trợ giúp cho phản hồi. Bạn có thể đăng nó không? –

+0

Tôi sẽ đăng toàn bộ lớp học ... đăng ngay bây giờ ... – Genadinik

1

tôi thêm một câu trả lời vì tôi đạt đến nhân vật giới hạn trong câu hỏi ban đầu của tôi vì lớp học của tôi quá dài.

Đây là tệp extra_help.xml

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
     android:orientation="vertical" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     >   

<include android:id="@+id/header" 
     layout="@layout/header" 
     android:layout_height="wrap_content" 
     android:layout_width="fill_parent"/> 

<ScrollView 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:padding="5px">  

<LinearLayout 

     android:orientation="vertical" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:padding="5px" 
     > 

<TextView 
    android:id="@+id/heading_1"  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:textColor="@color/light_best_blue" 
    android:text="THE APP IS FREE TO HELP AS MANY PEOPLE AS POSSIBLE, PLEASE GIVE BACK" 
    /> 

    <Button 
    android:id="@+id/donate" 
    android:layout_marginTop ="10dp"   
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Donate $1.99 Since the App is Free" 
    /> 

</LinearLayout> 

</ScrollView> 

</LinearLayout> 
Các vấn đề liên quan