2012-07-12 6 views
5

जब उपयोगकर्ता खरीद बटन दबाता है, तो इन-ऐप आइटम खरीदने के लिए उन्हें एंड्रॉइड प्ले स्क्रीन पर ले जाया जाता है।एंड्रॉइड इन-ऐप बिलिंग - खरीद दबाते समय अपवाद, और फिर खरीद स्क्रीन से वापस दबाकर

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) 

: की वजह से

:

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) 

यह विशेष रूप से मेरी कक्षा में इन पंक्तियों का उल्लेख है: लेकिन जब वे वापस दबाते हैं, तो वे बिलिंग सेवा शुरू करने के लिए सक्षम नहीं होने के बारे में इस अपवाद मिल लाइन 561 पर मेरे पास यह कोड है:

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

लाइन 569 पर मेरे पास यह कोड है:

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 
} 

वैसे, यह कौन सा लॉग है? क्या यह वास्तव में जरूरी है? शायद इन तरीकों से टिप्पणी करने के लिए उपयुक्त है?

किसी भी मामले में, दूसरी लाइन त्रुटि अंक 187 है और यहाँ उस के लिए कोड है:

@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); 
    } 
} 

तो आप देखते हैं, यह इस बात पर प्रवेश करने में समस्या आ रहता है। यह लॉग क्या है? मैं इसे कहां देखूं? मैं इसे कैसे ठीक कर सकता हूं ताकि यह त्रुटियां नहीं कर सके?

मुझे यकीन नहीं है, लेकिन शायद बड़ा मुद्दा यह है कि अनुरोध शून्य है। अनुरोध संभवतः यहां शून्य क्यों होगा?

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

मेरी एक संभावित समस्या यह है कि मेरी बिलिंग सेवा में मुझे विधियों के लिए @ ओवरराइड निर्देश पर टिप्पणी करना पड़ा: सेवा पर डिस्कनेक्ट और ऑन-सर्विस कनेक्ट - अन्यथा यह संकलित नहीं होगा। कोई विचार यह क्यों संकलित नहीं करेगा और अगर वह शायद मेरा घातक मुद्दा हो सकता है? – Genadinik

+0

यदि उपयोगकर्ता वापस बटन दबाता है, तो कॉलबैक ऑनRequestPurchaseResponse (RequestPurchase अनुरोध, ResponseCode प्रतिक्रिया कोड) कहा जाएगा। LogProductActivity में समस्या (request.mProductId, "खारिज खरीद संवाद"); मामले में विधि (प्रतिक्रिया कोड == ResponseCode.RESULT_USER_CANCELED)। LogProductActivity (अनुरोध पर टिप्पणी करने का प्रयास करें।mProductId, "खारिज खरीद संवाद"); क्या आप वहां मौजूद हैं। –

+0

यदि आप लॉग इन नहीं चाहते हैं तो सभी logBlahBlah() विधियों को टिप्पणी करें और फिर कोशिश करें .. क्रैश में से एक लॉगिंग भाग के कारण होता है .. दूसरा एक पहला दुर्घटना का दुष्प्रभाव है .. यह शुरू करने में असमर्थ है बिलिंग सेवा .. – Ronnie

उत्तर

3

उफ़।

mLogTextView कभी शुरू नहीं किया गया है।

जोड़ने mLogTextView = findViewById(R.id.blaaa);

मुझे यकीन है कि आप पहले से ही पता है कि

कृपया मुझे बताओ अगर मैं गलत तो है कि मैं इस सवाल का जवाब (हटाना हूँ हूँ:

+0

धन्यवाद पोस्ट किया है। मैं थोड़ी उलझन में हूं जहां मुझे इसे जोड़ना चाहिए, और यह भी .... .... क्या देखें ViewById (R.id.blaaa) होना चाहिए? मेरा मतलब है..मेरे विचारों में से कौन? मैंने logTextView के लिए विशेष दृश्य नहीं बनाया और मैंने यह नहीं देखा कि एंड्रॉइड ट्यूटोरियल से डंगऑन उदाहरण में किया जा रहा है। – Genadinik

+0

'ऑनक्रेट' फ़ंक्शन में 'setContentView' सेट करने के बाद, आपको' mLogTextView' प्रारंभ करना चाहिए। मुझे 'extra_help.xml' दिखाएं। ओह, वैसे, मुझे लगता है कि यह 'टेक्स्ट व्यू' का उपयोग डंगऑन उदाहरण में लेनदेन दिखाने के लिए किया जाता है, इसलिए शायद वास्तविक ऐप के लिए इसकी आवश्यकता नहीं है, आप या तो इस लॉगिंग तंत्र को बदल सकते हैं। वैसे भी, मुझे 'extra_help.xml' –

+0

दिखाएं मैंने अपने extra_help.xml के साथ एक उत्तर जोड़ा क्योंकि मैं अपने मूल प्रश्न में एक वर्ण सीमा में भाग गया। – Genadinik

3

आप menifest फ़ाइल में अनुमति दे रहे हैं:

यहाँ पूरे ExtraHelpActivity वर्ग है?

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

+0

हाँ निश्चित रूप से इसका उपयोग कर रहा है। यहां तक ​​कि मैं आपको एक समान अपवाद भी बता सकता हूं यदि उपयोगकर्ता खरीद के साथ जाता है, और उन्हें बिल मिलता है, लेकिन मेरे ऐप पर लैंडिंग के बाद, उन्हें मजबूर-बंद अपवाद मिलता है – Genadinik

+0

आप रिजॉन्स के लिए सहायक वर्ग बनाते हैं। क्या आप इसे पोस्ट कर सकते हैं? –

+0

मैं पूरी कक्षा पोस्ट करूंगा ... अब पोस्ट कर रहा हूं ... – Genadinik

1

क्योंकि मैं चरित्र पर पहुंच गया मैं एक जवाब द्वारा जोड़ा जा रहा अपने मूल प्रश्न में सीमित कर के बाद से मेरी कक्षा इतने लंबे समय है।

यह 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> 
है
संबंधित मुद्दे