简体   繁体   English

Android应用内结算问题

[英]Android In-App Billing Issue

I am trying to implement in-app billing as a form of donation inside my Android app. 我正在尝试将应用内结算作为一种捐赠形式在我的Android应用中实现。
Whenever I call startService(new Intent(mContext, BillingService.class)); 每当我调用startService(new Intent(mContext, BillingService.class)); from my main Java file, the app force closes when I run it. 从我的主要Java文件中,应用程序强制在我运行时关闭。 So either I am missing something somewhere or something is wrong with the BillingService. 因此,我在某处缺少某处或BillingService有问题。 Any help would be greatly appreciated, I have been stuck on this for days now. 任何帮助将不胜感激,我已经坚持了好几天了。

LOG: 日志:

12-07 22:56:08.983: E/dalvikvm(23762): could not disable core file generation for pid 23762: Operation not permitted
12-07 22:56:09.764: I/BillingService(23762): Starting
12-07 22:56:09.819: D/AndroidRuntime(23762): Shutting down VM
12-07 22:56:09.819: W/dalvikvm(23762): threadid=1: thread exiting with uncaught exception (group=0x40018560)
12-07 22:56:09.819: E/AndroidRuntime(23762): FATAL EXCEPTION: main
12-07 22:56:09.819: E/AndroidRuntime(23762): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.Calculator.SalesTaxCalculator/com.Calculator.SalesTaxCalculator.Calculator}: java.lang.NullPointerException
12-07 22:56:09.819: E/AndroidRuntime(23762):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1696)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1716)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at android.app.ActivityThread.access$1500(ActivityThread.java:124)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:968)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at android.os.Handler.dispatchMessage(Handler.java:99)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at android.os.Looper.loop(Looper.java:123)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at android.app.ActivityThread.main(ActivityThread.java:3806)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at java.lang.reflect.Method.invokeNative(Native Method)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at java.lang.reflect.Method.invoke(Method.java:507)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at dalvik.system.NativeStart.main(Native Method)
12-07 22:56:09.819: E/AndroidRuntime(23762): Caused by: java.lang.NullPointerException
12-07 22:56:09.819: E/AndroidRuntime(23762):    at android.content.ComponentName.<init>(ComponentName.java:75)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at android.content.Intent.<init>(Intent.java:2720)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at com.Calculator.SalesTaxCalculator.Calculator.onCreate(Calculator.java:86)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
12-07 22:56:09.819: E/AndroidRuntime(23762):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1660)
12-07 22:56:09.819: E/AndroidRuntime(23762):    ... 11 more

MANIFEST: 表现:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.Calculator.SalesTaxCalculator"
      android:versionCode="3" android:versionName="2">

      <uses-sdk android:minSdkVersion="4" /> 

    <application android:icon="@drawable/calculator_icon" android:label="@string/app_name">
        <activity android:name=".Calculator"
                  android:label="@string/app_name">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
         <service android:name="com.Calculator.SalesTaxCalculator.BillingService" />
         <receiver android:name="com.Calculator.SalesTaxCalculator.BillingReceiver">
         <intent-filter>
        <action android:name="com.android.vending.billing.IN_APP_NOTIFY" />
        <action android:name="com.android.vending.billing.RESPONSE_CODE" />
        <action android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" />
      </intent-filter>
    </receiver>
    </application>
     <uses-permission android:name="com.android.vending.BILLING" />
     <activity android:name=".BillingHelper" />
     <activity android:name=".BillingSecurity" />
     <activity android:name=".C" />
</manifest>

I hope this will help you somewhat.It works for me. 我希望这会对您有所帮助,对我有用。

public class CheckoutActivity extends Activity implements OnClickListener,
OnItemSelectedListener  {

    private static final String TAG = "HCA";
    private ProgressDialog dialog;

    /**
     * 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 static Bundle bundle = null;

    private DungeonsPurchaseObserver mDungeonsPurchaseObserver;
    private Handler mHandler;

    private BillingService mBillingService;
    private Button mBuyButton;
    private Button mEditPayloadButton;
    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;

    /**
     * Each product in the catalog is either MANAGED or UNMANAGED.  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.
     */
    private enum Managed { MANAGED, UNMANAGED }

    /**
     * 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 DungeonsPurchaseObserver extends PurchaseObserver {
        public DungeonsPurchaseObserver (Handler handler) {
            super(CheckoutActivity.this, handler);
        }

        @Override
        public void onBillingSupported(boolean supported) {
            if (Consts.DEBUG) {
                Log.i(TAG, "supported: " + supported);
            }
            if (supported) {
                restoreDatabase();
                mBuyButton.setEnabled(true);
                mEditPayloadButton.setEnabled(true);
            } else {
                showDialog(DIALOG_BILLING_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);
                new BackgroundTask ().execute();

            }
            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 ("sword_001", R.string.two_handed_sword, Managed.MANAGED),
        new CatalogEntry ("potion_001", R.string.potions, Managed.UNMANAGED),
        new CatalogEntry ("android.test.purchased", R.string.android_test_purchased,
        Managed.UNMANAGED),
        new CatalogEntry ("android.test.canceled", R.string.android_test_canceled,
        Managed.UNMANAGED),
        new CatalogEntry ("android.test.refunded", R.string.android_test_refunded,
        Managed.UNMANAGED),
        new CatalogEntry ("android.test.item_unavailable", R.string.android_test_item_unavailable,
        Managed.UNMANAGED),
    };

    private String mItemName;
    private String mSku;
    private CatalogAdapter mCatalogAdapter;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        /*   ImageView userImage = (ImageView)findViewById(R.id.header_userImg);
           userImage.setImageResource(R.drawable.logo);*/

        ImageView backBtn =(ImageView) findViewById (R.id.header_optionImg);
        backBtn.setImageResource(R.drawable.back_btn_img);
        backBtn.setOnClickListener(new OnClickListener () {

            @Override
            public void onClick(View v) {
                Intent intent = new Intent(CheckoutActivity.this,
                        SelectRegistrationTypeActivity.class);
                startActivity(intent);
                CheckoutActivity.this.finish();
            }
        });
        TextView headerTitle =(TextView) findViewById (R.id.header_screenTitle);
        headerTitle.setText("Credit Card");

        mHandler = new Handler ();
        dialog = new ProgressDialog (CheckoutActivity.this);
        mDungeonsPurchaseObserver = new DungeonsPurchaseObserver (mHandler);
        mBillingService = new BillingService ();
        mBillingService.setContext(this);

        mPurchaseDatabase = new PurchaseDatabase (this);
        bundle = getIntent().getBundleExtra("RegistrationData");
        setupWidgets();

        // Check if billing is supported.
        ResponseHandler.register(mDungeonsPurchaseObserver);
        if (!mBillingService.checkBillingSupported()) {
            showDialog(DIALOG_CANNOT_CONNECT_ID);
        }
    }

    /**
     * Called when this activity becomes visible.
     */
    @Override
    protected void onStart() {
        super.onStart();
        ResponseHandler.register(mDungeonsPurchaseObserver);
        initializeOwnedItems();
    }

    /**
     * Called when this activity is no longer visible.
     */
    @Override
    protected void onStop() {
        super.onStop();
        ResponseHandler.unregister(mDungeonsPurchaseObserver);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPurchaseDatabase.close();
        mBillingService.unbind();
    }

    /**
     * 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(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);
            default:
            return null;
        }
    }

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

        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(R.string.learn_more, 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() {
        mLogTextView = (TextView) findViewById (R.id.log);

        mBuyButton = (Button) findViewById (R.id.buy_button);
        mBuyButton.setEnabled(false);
        mBuyButton.setOnClickListener(this);

        mEditPayloadButton = (Button) findViewById (R.id.payload_edit_button);
        mEditPayloadButton.setEnabled(false);
        mEditPayloadButton.setOnClickListener(this);

        mSelectItemSpinner = (Spinner) findViewById (R.id.item_choices);
        mCatalogAdapter = new CatalogAdapter (this, CATALOG);
        mSelectItemSpinner.setAdapter(mCatalogAdapter);
        mSelectItemSpinner.setOnItemSelectedListener(this);

        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, R.string.restoring_transactions, Toast.LENGTH_LONG).show();
        }
    }

    /**
     * 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);
            }
            String temSku = null;
            switch(Integer.parseInt(bundle.getString("PlanTypeValue"))) {
                case 0:
//              payment.setSubtotal(new BigDecimal("2.99"));
                temSku = "hca1";
                break;
                case 1:
//              payment.setSubtotal(new BigDecimal("25.00"));
                temSku = "hca2";
                break;
                case 2:
//              payment.setSubtotal(new BigDecimal("100.00"));
                temSku = "hca3";
                break;
                case 3:
//              payment.setSubtotal(new BigDecimal("500.00"));
                temSku = "hca4";
                break;
                case 4:
//              payment.setSubtotal(new BigDecimal("1000.00"));
                temSku = "hca5";
                break;

                default:
//              payment.setSubtotal(new BigDecimal("2.99"));
                temSku = "hca1";
                break;
            }
            if (!mBillingService.requestPurchase(temSku, mPayloadContents)) {
                showDialog(DIALOG_BILLING_NOT_SUPPORTED_ID);
            }
        } else if (v == mEditPayloadButton) {
            showPayloadEditDialog();
        }
    }

    /**
     * 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 () {
            public void onCancel(DialogInterface dialog) {
                if (dialog != null) {
                    dialog.cancel();
                }
            }
        });
        dialog.show();
    }

    /**
     * Called when an item in the spinner is selected.
     */
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        mItemName = getString(CATALOG[position].nameId);
        mSku = CATALOG[position].sku;
        mSku = "sword_001";
    }

    public void onNothingSelected(AdapterView<?> arg0) {
        mSku = "sword_001";
    }

    /**
     * An adapter used for displaying a catalog of products.  If a product is
     * managed by Android Market and already purchased, then it will be "grayed-out" in
     * the list and not selectable.
     */
    private static class CatalogAdapter extends ArrayAdapter<String> {
        private CatalogEntry [] mCatalog;
        private Set < String > mOwnedItems = new HashSet<String>();

        public CatalogAdapter (Context context, CatalogEntry[] catalog) {
        super(context, android.R.layout.simple_spinner_item);
        mCatalog = catalog;
        for (CatalogEntry element : catalog) {
        add(context.getString(element.nameId));
    }
        setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    }

        public void setOwnedItems(Set<String> ownedItems) {
            mOwnedItems = ownedItems;
            notifyDataSetChanged();
        }

        @Override
        public boolean areAllItemsEnabled() {
            // Return false to have the adapter call isEnabled()
            return false;
        }

        @Override
        public boolean isEnabled(int position) {
            // If the item at the given list position is not purchasable,
            // then prevent the list item from being selected.
            CatalogEntry entry = mCatalog [position];
            if (entry.managed == Managed.MANAGED && mOwnedItems.contains(entry.sku)) {
                return false;
            }
            return true;
        }

        @Override
        public View getDropDownView(int position, View convertView, ViewGroup parent) {
            // If the item at the given list position is not purchasable, then
            // "gray out" the list item.
            View view = super.getDropDownView(position, convertView, parent);
            view.setEnabled(isEnabled(position));
            return view;
        }
    }

    private class BackgroundTask extends AsyncTask<Void, Void, String> {

        protected void onPreExecute() {
            dialog.setMessage("Please wait...");
            dialog.show();
        }

        @Override
        protected String doInBackground(Void... arg0) {
        String response = null;
        try {

            String.valueOf(bundle.getString("UserTypeValue")),
            String.valueOf(bundle.getString("PlanTypeValue")),
            String.valueOf(bundle.getString("RegistrationFees")));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return response;
    }

        protected void onPostExecute(String response) {
            dialog.dismiss();

            AlertDialog alert = new AlertDialog.Builder(
                    CheckoutActivity.this).create();
            alert.setTitle("Thank you");
            alert.setMessage("Your account has been created");
            alert.setButton("Ok",
                    new DialogInterface . OnClickListener () {
                        public void onClick(DialogInterface dialog,
                                int which) {
                            dialog.dismiss();
                            Intent intent = new Intent(CheckoutActivity.this,
                                    HomeActivity.class);
                            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                            startActivity(intent);
                            CheckoutActivity.this.finish();

                        }
                    });

            alert.show();
            TextView messageView =(TextView) alert . findViewById (android.R.id.message);
            messageView.setGravity(Gravity.CENTER_HORIZONTAL);
            messageView.setTextSize(14);


        }
    }
}

Take a look at this line from your LogCat : 在您的LogCat中查看以下行:

at com.Calculator.SalesTaxCalculator.Calculator.onCreate(Calculator.java:86

You have a NullPointerException in your onCreate method, so check line 86 . 您的onCreate方法中有一个NullPointerException ,因此请检查第86行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM