Android根活动有时会自动启动,无需任何用户操作

时间:2014-09-16 07:51:26

标签: android android-intent android-activity

我有一个我无法解释的奇怪问题。在清单文件中,我的应用程序的启动活动定义如下:

<activity
    android:name="com.xxx.xxx.xxx.StartupActivity"
    android:label="@string/app_name"
    android:theme="@android:style/Theme.Light.NoTitleBar"
    android:screenOrientation="sensorPortrait" >
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

在StartUpActivity中执行以下检查:

protected void startIntent() {

    Intent intent;

    if (checkCurrentProfile()) {

        Notifier.showHttpToast(R.string.toastLoggedIn);

        //try to update the device token in the database
        Request.updateDeviceToken();

        intent = new Intent(this, GameListActivity.class);
    } else {
        intent = new Intent(this, RegisterActivity.class);
    }

    startActivity(intent);
    finish();
}

因此,如果用户拥有有效帐户,则GameListActivity将显示为root活动:

<activity
    android:name="com.xxx.xxx.xxx.xxx.GameListActivity"
    android:label="@string/app_name"
    android:theme="@style/MyTheme"
    android:screenOrientation="sensorPortrait" >       
</activity>

现在的问题如下:有时系统会自动将根活动带到前端而无需任何用户操作。它有时只会发生,但我无法弄清楚原因。任何人都可以帮助我吗?

StartUpActivity如下所示:

public class StartupActivity extends StartupCoreActivity implements OnRegisterGCMListener {

private IabHelper mHelper;
private IabHelper.QueryInventoryFinishedListener mQueryInventoryFinishedListener;

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    registerOnRegisterGCMListener(this);

    if (!registerGCMneeded()) {
        initInAppBilling();
    }
}

@Override
public void registerGCMfinished() {
    initInAppBilling();
}

private void initInAppBilling() {

    boolean hasPremium = Prefs.getBoolValue(getResources().getString(R.string.pref_key_upgrade_premium), false);

    if (hasPremium) {
        //unlocking contents not needed
        startIntent();
    } else {

        Prefs.storeValue(getResources().getString(R.string.pref_key_upgrade_premium), false);

        mHelper = new IabHelper(this, C.Billing.BILLING_KEY);

        mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {

            public void onIabSetupFinished(IabResult result) {

                if (result.isSuccess()) {
                    queryInventory();
                } else {
                    startIntent();
                }
            }
        });
    }
}

private void queryInventory() {

    String[] products = {C.Billing.ITEM_SKU};

    mQueryInventoryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {

        @Override
        public void onQueryInventoryFinished(IabResult result, Inventory inv) {

            if (result.isSuccess()) {
                checkPremiumVersion(inv);
            } else {
                startIntent();
            }
        }
    };

    mHelper.queryInventoryAsync(true, Arrays.asList(products), mQueryInventoryFinishedListener);
}

private void checkPremiumVersion(Inventory inv) {

    if (inv.hasPurchase(C.Billing.ITEM_SKU)) {

        Request.updPremiumVersion();
        Prefs.storeValue(getResources().getString(R.string.pref_key_upgrade_premium), true);

        Notifier.showHttpToast(R.string.toastPremiumContentsUnlocked);  
    }

    startIntent();
}
}

StartupCoreActivity看起来像这样:

public class StartupCoreActivity extends Activity {

private final static int PLAY_SERVICES_RESOLUTION_REQUEST = xxxx;

GoogleCloudMessaging mGcm;
Context mContext;
String mRegId;

/**
 * Substitute you own sender ID here. This is the project number you got
 * from the API Console, as described in "Getting Started."
 */
String SENDER_ID = "xxxxxxxxxx";

private OnRegisterGCMListener mOnRegisterGCMListener = null;

public void registerOnRegisterGCMListener(OnRegisterGCMListener listener) {
    mOnRegisterGCMListener = listener;
}

protected boolean registerGCMneeded() {

    mContext = getApplicationContext();

    // Check device for Play Services APK.
    if (checkPlayServices()) {
        // If this check succeeds, proceed with normal processing.
        // Otherwise, prompt user to get valid Play Services APK.
        mGcm = GoogleCloudMessaging.getInstance(this);
        mRegId = getRegistrationId(mContext);

        if (mRegId.isEmpty()) {
            registerInBackground();
            return true;
        } else {
            // note we never called setContentView()
            return false;
        }
    }

    return false;
}

protected void startIntent() {

    Intent intent;

    if (checkCurrentProfile()) {

        Notifier.showHttpToast(R.string.toastLoggedIn);

        //try to update the device token in the database
        Request.updateDeviceToken();

        intent = new Intent(this, GameListActivity.class);
    } else {
        intent = new Intent(this, RegisterActivity.class);
    }

    startActivity(intent);
    finish();
}

private boolean checkCurrentProfile() {

    KUPlayer me = G.getMySelf();

    if (me.getPlayerId() <= 0) {

        //database was not present yet and has been created
        //or database was present, but profile cannot be read anymore

        // make sure Login screen appears ONLY if PlayerID cannot be retrieved anymore
        if (G.getPlayerID() <=0) {
            Prefs.storeValue(Prefs.PREF_KEY_PWD_SAVED, false);
            return false;
        }
    }

    return true;
}

// You need to do the Play Services APK check here too.
@Override
protected void onResume() {
    super.onResume();
    checkPlayServices();
}

/**
 * Check the device to make sure it has the Google Play Services APK. If
 * it doesn't, display a dialog that allows users to download the APK from
 * the Google Play Store or enable it in the device's system settings.
 */
private boolean checkPlayServices() {
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
    if (resultCode != ConnectionResult.SUCCESS) {
        if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
            GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                    PLAY_SERVICES_RESOLUTION_REQUEST).show();
        } else {

            finish();
        }
        return false;
    }
    return true;
}

/**
 * Registers the application with mGcm servers asynchronously.
 * <p>
 * Stores the registration ID and the app versionCode in the application's
 * shared preferences.
 */
private void registerInBackground() {
    new AsyncTask<Void, Void, String>() {
        @Override
        protected String doInBackground(Void... params) {
            String msg = "";
            try {
                if (mGcm == null) {
                    mGcm = GoogleCloudMessaging.getInstance(mContext);
                }
                mRegId = mGcm.register(SENDER_ID);
                msg = "Device registered, registration ID=" + mRegId;

                // Persist the mRegId - no need to register again.
                storeRegistrationId(mContext, mRegId);
            } catch (IOException ex) {
                msg = "Error :" + ex.getMessage();
                // If there is an error, don't just keep trying to register.
                // Require the user to click a button again, or perform
                // exponential back-off.
            }
            return msg;
        }

        @Override
        protected void onPostExecute(String msg) {
            // note we never called setContentView()
            if (mOnRegisterGCMListener != null) {
                mOnRegisterGCMListener.registerGCMfinished();
            }
        }
    }.execute(null, null, null);
}

/**
 * @return Application's version code from the {@code PackageManager}.
 */
private static int getAppVersionCode(Context context) {
    try {
        PackageInfo packageInfo = context.getPackageManager()
                .getPackageInfo(context.getPackageName(), 0);
        return packageInfo.versionCode;
    } catch (NameNotFoundException e) {
        // should never happen
        throw new RuntimeException("Could not get package name: " + e);
    }
}

private static String getAppVersionName(Context context) {
    try {
        PackageInfo packageInfo = context.getPackageManager()
                .getPackageInfo(context.getPackageName(), 0);
        return packageInfo.versionName;
    } catch (NameNotFoundException e) {
        // should never happen
        throw new RuntimeException("Could not get package name: " + e);
    }
}

/**
 * Stores the registration ID and the app versionCode in the application's
 * {@code SharedPreferences}.
 *
 * @param mContext application's mContext.
 * @param mRegId registration ID
 */
private void storeRegistrationId(Context context, String regId) {

    Prefs.storeValue(Prefs.PREF_KEY_DEVICE_TOKEN, regId);
    Prefs.storeValue(Prefs.PREF_KEY_APP_VERSION_CODE, getAppVersionCode(context));
    Prefs.storeValue(Prefs.PREF_KEY_APP_VERSION_NAME, getAppVersionName(context));

    AppRate.resetAfterUpdate();
}

/**
 * Gets the current registration ID for application on mGcm service, if there is one.
 * <p>
 * If result is empty, the app needs to register.
 *
 * @return registration ID, or empty string if there is no existing
 *         registration ID.
 */
private String getRegistrationId(Context context) {

    String registrationId = Prefs.getStringValue(Prefs.PREF_KEY_DEVICE_TOKEN);
    if (registrationId.isEmpty()) {
        return "";
    }
    // Check if app was updated; if so, it must clear the registration ID
    // since the existing mRegId is not guaranteed to work with the new
    // app version.
    int registeredVersion = Prefs.getIntValue(Prefs.PREF_KEY_APP_VERSION_CODE);
    int currentVersion = getAppVersionCode(context);
    if (registeredVersion != currentVersion) {
        return "";
    }

    return registrationId;
}
}

1 个答案:

答案 0 :(得分:1)

我想这与以下已知的Android错误有关:

How to prevent multiple instances of an activity when it is launched with different intents

正如所建议的那样,将以下代码放在rootActivity的onCreate方法中:

// Possible work around for market launches. See http://code.google.com/p/android/issues/detail?id=2373
    // for more details. Essentially, the market launches the main activity on top of other activities.
    // we never want this to happen. Instead, we check if we are the root and if not, we finish.
    if (!isTaskRoot()) {
        final Intent intent = getIntent();
        final String intentAction = intent.getAction(); 
        if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) {
            finish();
            return;       
        }
    }

我对它进行了测试,当您从Google Play商店启动应用程序而非启动屏幕时,确实从上面的代码调用了finish()。