And*_*per 5 android android-manifest android-activity google-play internal-app-sharing
问题:
我遇到一个不寻常的问题,即我的应用程序启动器活动 (MainActivity) 的 onCreate() 方法被调用两次,但仅当我安装该应用程序后首次启动该应用程序时(从 Google Play 内部应用程序共享链接或在设备上安装签名的 apk 文件)。此行为会导致同时创建 MainActivity 的多个实例。
描述:
我已经彻底检查了我的代码,并且可以确认没有意外调用 startActivity 或任何会导致 onCreate() 被多次调用的显式代码。我检查了这个,但这些错误似乎已经过时了
观察结果:
代码:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xyz">
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<!-- Required to maintain app compatibility. -->
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<application
android:name=".framework.presentation.BaseApplication"
android:allowBackup="false"
android:fullBackupOnly="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="${enableCrashReporting}" />
<activity
android:name="xyz.framework.presentation.MainActivity"
android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="xyz.framework.presentation.main.RecipeActivity"
android:windowSoftInputMode="adjustResize"
android:exported="true" />
<activity
android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:theme="@style/com_facebook_activity_theme"
android:exported="false" />
<activity
android:name="com.facebook.CustomTabMainActivity"
android:exported="false" />
<activity
android:name="androidx.test.core.app.InstrumentationActivityInvoker$BootstrapActivity"
android:theme="@android:style/Theme"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyActivity"
android:theme="@android:style/Theme"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
<activity
android:name="androidx.test.core.app.InstrumentationActivityInvoker$EmptyFloatingActivity"
android:theme="@android:style/Theme.Dialog"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
</application>
</manifest>
Run Code Online (Sandbox Code Playgroud)
基础应用程序
@FlowPreview
@ExperimentalCoroutinesApi
@HiltAndroidApp
open class BaseApplication : Application()
Run Code Online (Sandbox Code Playgroud)
主要活动
@AndroidEntryPoint
class MainActivity : AppCompatActivity(), UIController {
@Inject
lateinit var editor: SharedPreferences.Editor
@Inject
lateinit var sharedPreferences: SharedPreferences
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
private val viewModel: SplashViewModel by viewModels {
viewModelFactory
}
private val signInLauncher = registerForActivityResult(
FirebaseAuthUIActivityResultContract()
) { res ->
this.onSignInResult(res)
}
@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Toast.makeText(this, "oncreate called", Toast.LENGTH_SHORT).show()
setContent {
SplashProvider()
}
viewModel.hasSyncBeenExecuted()
.observe(this) { hasSyncBeenExecuted ->
if (hasSyncBeenExecuted) {
startActivity(Intent(this, RecipeActivity::class.java))
// Use lifecycleScope for the coroutine
lifecycleScope.launch {
delay(2000) // Adjust the delay time as needed
finish()
}
}
}
if (sharedPreferences?.getString(
PreferenceKeys.USER_UID,
null
) != null && FirebaseAuth.getInstance().currentUser != null
) {
viewModel.syncCacheWithNetwork()
} else {
createSignInIntent()
}
}
private fun createSignInIntent() {
// [START auth_fui_create_intent]
// Choose authentication providers
val providers = arrayListOf(
AuthUI.IdpConfig.EmailBuilder().build(),
AuthUI.IdpConfig.GoogleBuilder().build()
)
Toast.makeText(this, "createSignInIntent called", Toast.LENGTH_SHORT).show()
// Create and launch sign-in intent
val signInIntent = AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.setTheme(R.style.LoginTheme)
.setLogo(R.drawable.handshake) // Set logo drawable
.build()
signInLauncher.launch(signInIntent)
// [END auth_fui_create_intent]
}
override fun hideSoftKeyboard() {
if (currentFocus != null) {
val inputMethodManager = getSystemService(
Context.INPUT_METHOD_SERVICE
) as InputMethodManager
inputMethodManager
.hideSoftInputFromWindow(currentFocus!!.windowToken, 0)
}
}
private fun onSignInResult(result: FirebaseAuthUIAuthenticationResult) {
val response = result.idpResponse
if (result.resultCode == AppCompatActivity.RESULT_OK) {
// Successfully signed in
val user = FirebaseAuth.getInstance().currentUser
// ...
editor?.putString(PreferenceKeys.USER_UID, user?.uid)
editor?.apply()
viewModel.syncCacheWithNetwork()
} else if (response != null) {
Toast.makeText(
this,
response.error?.errorCode.toString().plus(response.error?.message),
Toast.LENGTH_LONG
).show()
} else {
finish()
}
}
}
Run Code Online (Sandbox Code Playgroud)
SplashProvider
@Composable
fun SplashProvider(
) {
val images = listOf(R.drawable.splash1, R.drawable.splash2, R.drawable.splash3)
val imageIndex = Random.nextInt(images.size)
Splash(images[imageIndex])
}
@Composable
fun Splash(img: Int) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Image(
contentDescription = "Recipe",
painter = painterResource(img),
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop
)
Column(
modifier = Modifier
.wrapContentSize()
.clip(CircleShape)
.background(Color.Black.copy(alpha = 0.6f))
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator(
modifier = Modifier.size(50.dp),
strokeWidth = 4.dp,
color = Color.White
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "Loading...",
color = Color.White,
fontSize = 16.sp
)
}
}
}
Run Code Online (Sandbox Code Playgroud)
您的启动模式MainActivity未在您的AndroidManifest.xml. 默认启动模式为“ standard”,允许创建任意数量的实例。您可能想尝试将其设置为“ singleTop”,以确保如果新实例已位于堆栈顶部,则不会创建新实例:
供测试用:
<activity
android:name="xyz.framework.presentation.MainActivity"
android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize"
android:exported="true">
Run Code Online (Sandbox Code Playgroud)
另外,在您的 中MainActivity,您启动RecipeActivity,然后在 2000 毫秒的延迟后,您finish()调用MainActivity。MainActivity如果系统或用户在该时间范围内触发重新创建(例如旋转或向后导航),则可能允许重新创建。
finish()尝试在启动后立即调用RecipeActivity,或者更好的是,使用该FLAG_ACTIVITY_NO_HISTORY标志来确保MainActivity不保留在活动堆栈中:
Intent intent = new Intent(this, RecipeActivity.class.java);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
finish();
Run Code Online (Sandbox Code Playgroud)
为了帮助您调试此问题,请使用onCreate()时间戳和其他相关数据记录每次调用,并尝试追溯它被调用两次的原因:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("MainActivity", "onCreate called at " + System.currentTimeMillis());
// Rest of the code
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
428 次 |
| 最近记录: |