我正在开发一个新应用,但是当用户使用电子邮件和密码登录时崩溃
来自Logcat的错误
android.view.WindowLeaked: Activity com.empowered.healo.ui.activities.main.MainActivity has leaked window DecorView@adb6956[MainActivity] that was originally added here
at android.view.ViewRootImpl.<init>(ViewRootImpl.java:572)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:331)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:97)
at android.app.Dialog.show(Dialog.java:419)
at com.empowered.healo.mvp.BaseMvpActivity.showError(BaseMvpActivity.java:70)
at com.empowered.healo.ui.activities.main.MainPresenter$getHelpTexts$2.accept(MainPresenter.kt:132)
at com.empowered.healo.ui.activities.main.MainPresenter$getHelpTexts$2.accept(MainPresenter.kt:25)
at io.reactivex.internal.observers.LambdaObserver.onError(LambdaObserver.java:74)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.checkTerminated(ObservableObserveOn.java:276)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:172)
at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:252)
at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:109)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6682)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
在我的MainActivity.kt下面
class MainActivity : BaseMvpActivity(), MainView {
companion object {
const val ACTION_FRAGMENT = "FRAGMENT_CHANGE"
const val DELETE_THERAPY = "DELETE_THERAPY"
const val CHANGE_PROFILE = "CHANGE_PROFILE"
const val UPDATE_DATA = "UPDATE_DATA"
}
private var presenter = MainPresenter(this)
private var navigator: Navigator? = null
private var needUpdateData: Boolean = false
private var pushData: Bundle = Bundle()
private var needRedirect: Boolean = false
private var fragmentReceiver: BroadcastReceiver? = null
private var actionDrawerClose: (() - Unit)? = null
private var firstScreen: String = Screen.HOME
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
handleInComeIntent()
initNavigation()
initData()
initUI()
}
private fun initData() {
presenter.subscribeToNotification()
if (needUpdateData)
presenter.getSession(firstScreen)
else moveToScreen(firstScreen, null)
presenter.getHelpTexts()
}
private fun initNavigation() {
navigator = getNavigator()
(application as HealApplication).setNavigator(navigator)
}
private fun initUI() {
Glide.with(this)
.load(R.drawable.splash)
.into(backgroundImage)
initNavDrawer()
val keyboardUtil = KeyboardUtil(this, drawerLayout.getChildAt(1))
keyboardUtil.enable()
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
this.intent = intent
handleInComeIntent()
if (needRedirect) {
needRedirect = false
(application as HealApplication).router.navigateTo(firstScreen, pushData)
}
}
override fun onStart() {
super.onStart()
fragmentReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
when (intent?.action) {
ACTION_FRAGMENT - {
changeBackground()
}
DELETE_THERAPY - {
checkMenuState()
}
CHANGE_PROFILE - {
updateIcons()
navList.updateMenuItems()
}
}
}
}
val intentFilter = IntentFilter(ACTION_FRAGMENT)
intentFilter.addAction(DELETE_THERAPY)
intentFilter.addAction(CHANGE_PROFILE)
fragmentReceiver?.let { LocalBroadcastManager.getInstance(this).registerReceiver(it,
intentFilter) }
}
fun changeBackground() {
val fragment = supportFragmentManager.findFragmentById(R.id.fragmentContainer)
if (fragment != null && fragment is BaseMvpFragment && fragment.rootView != null) {
fragment.rootView.isDrawingCacheEnabled = true
(fragment as? HomeFragment)?.take()
fragment.rootView.buildDrawingCache(true)
val cache = fragment.rootView.getDrawingCache(true)
cache?.let {
if (backgroundImage.scaleType == ImageView.ScaleType.FIT_XY) {
backgroundImage.scaleType = ImageView.ScaleType.FIT_CENTER
}
backgroundImage.setImageDrawable(null)
val bitmap = Bitmap.createBitmap(cache)
backgroundImage.setImageBitmap(bitmap)
}
fragment.rootView.isDrawingCacheEnabled = false
}
}
private fun updateIcons() {
presenter.getGender()?.let {
when (it) {
User.Gender.MALE - navList.updateIconForMenuItem(R.string.item_menu_pain_profile,
R.drawable.ic_icon_menu_pain_profile_man)
User.Gender.FEMALE - navList.updateIconForMenuItem(R.string.item_menu_pain_profile,
R.drawable.ic_menu_pain_profile_woman)
}
}
}
private fun checkMenuState() {
navList.updateState(if (presenter.isFullMenu()) MenuView.MenuState.FULL else MenuView.MenuState.SHORT)
}
override fun onStop() {
super.onStop()
fragmentReceiver?.let { LocalBroadcastManager.getInstance(this).unregisterReceiver(it) }
}
private fun handleInComeIntent() {
needRedirect = false
intent?.let { intent -
needUpdateData = intent.getBooleanExtra(UPDATE_DATA, true)
//Local reminder
when (intent.getStringExtra(Notifications.PushData.ACTION)) {
Notifications.PushData.Reminder.OPEN_SESSION - {
pushData.putAll(intent.extras)
firstScreen = Screen.START_SESSION
needRedirect = true
}
}
//From server push notification
when (intent.getStringExtra(Notifications.PushData.HEAL_EVENT)?.substringAfterLast("\\"))
{
Notifications.PushData.Message.MESSAGE_EVENT - {
firstScreen = Screen.CHAT
needRedirect = true
}
Notifications.PushData.Evaluation.EVALUATION_EVENT - {
pushData.putInt(Notifications.PushData.Evaluation.EVALUATION_ID,
intent.getStringExtra(Notifications.PushData.Evaluation.EVALUATION_ID).toInt())
pushData.putString(Notifications.PushData.ACTION,
Notifications.PushData.Evaluation.EVALUATION)
firstScreen = Screen.START_SESSION
needRedirect = true
}
}
intent?.extras?.clear()
val closeIntent = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
sendBroadcast(closeIntent)
toggleDrawerScreen(false)
}
}
override fun handleNewDialogMessage() {
val currentFragment = supportFragmentManager.findFragmentById(R.id.fragmentContainer)
if (currentFragment !is ChatFragment) {
val badgeCount = navList.updateBadgeForMenuItem(R.string.support_feedback, 1)
Notifications.sendNotification(this,
Notifications.MessageNotification(this, Notifications.PushData.Message.LOCAL_PUSH_ID,
badgeCount).createNotification(),
Notifications.PushData.Message.LOCAL_PUSH_ID)
}
}
override fun setChatBadgeCount(count: Int) {
navList.clearBadgeForMenuItem(R.string.support_feedback)
navList.updateBadgeForMenuItem(R.string.support_feedback, count)
}
override fun startEvaluation(evaluationId: Int) {
EvaluationDialog(evaluationId, activity = this).build()?.show()
}
private fun initNavDrawer() {
closeDrawer.setOnClickListener { toggleDrawerScreen(false) }
drawerLayout?.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED,
Gravity.END)
drawerLayout?.addDrawerListener(object : DrawerLayout.DrawerListener {
override fun onDrawerStateChanged(newState: Int) {
}
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
}
override fun onDrawerClosed(drawerView: View) {
actionDrawerClose?.invoke()
}
override fun onDrawerOpened(drawerView: View) {
actionDrawerClose = null
}
})
/*
navList.setOnItemClickListener(object : ItemClickListener<MenuView.MenuItem {
override fun onItemClicked(t: MenuView.MenuItem, position: Int) {
val fragment = Fragment()
val data = Bundle()
when (position) {
0 - {
fragment = NameOfYourFragment()
}
1 - {
fragment = NameOfYourFragment()
}
2 - {
fragment = NameOfYourFragment()
}
3 - {
fragment = NameOfYourFragment()
}
4 - {
fragment = NameOfYourFragment()
}
5 - {
fragment = NameOfYourFragment()
}
6 - {
fragment = NameOfYourFragment()
}
7 - {
toggleDrawerScreen(false)
presenter.logOut()
return
}
8 - {
navList.clearBadgeForMenuItem(R.string.support_feedback)
Notifications.cancelNotification(this@MainActivity,
Notifications.PushData.Message.LOCAL_PUSH_ID)
fragment = NameOfYourFragment()
}
9 - {
data.putBoolean("profile", true)
fragment = NameOfYourFragment()
}
10 - {
fragment = NameOfYourFragment()
}
11 - {
data.putBoolean(AboutFragment.BACKGROUND_VIDEO, true)
fragment = NameOfYourFragment()
}
12 - {
fragment = NameOfYourFragment()
}
13 - {
fragment = NameOfYourFragment()
data.putBoolean(WebPageFragment.DIALOG, false)
data.putString(WebPageFragment.TOOLBAR_TITLE, getString(t.title))
data.putString(WebPageFragment.URL, BuildConfig.PRIVACY_POLICY)
}
14 -
fragment = NameOfYourFragment()
16 - fragment = NameOfYourFragment()
else - toggleDrawerScreen(false)
}
toggleDrawerScreen(false)
}
})
*/
navList.setOnItemClickListener(object : ItemClickListener<MenuView.MenuItem {
override fun onItemClicked(t: MenuView.MenuItem, position: Int) {
val fragment = supportFragmentManager.findFragmentById(R.id.fragmentContainer)
var screen = ""
@Suppress("Annotator", "Annotator", "Annotator", "Annotator", "Annotator", "Annotator", "Annotator", "Annotator",
"Annotator") val currentScreen =
fragment!!.arguments?.getString(ScreenNavigator.SCREEN_NAME)
val data = Bundle()
when (t.title) {
R.string.item_menu_home - {
screen = Screen.HOME
}
R.string.item_menu_session - {
screen = Screen.START_SESSION
}
R.string.item_menu_pain_profile - {
screen = Screen.SELF_DIAGNOSIS
}
// it crashed? lets try again.
R.string.item_menu_favourite - {
screen = Screen.FAVOURITE_EXERCISES
}
R.string.item_menu_progress_prognosis - {
screen = Screen.PROGRESS
}
R.string.item_menu_schedule_reminders - {
screen = Screen.SCHEDULE
}
R.string.item_menu_therapy_settings - {
screen = Screen.THERAPY_SETTINGS
}
R.string.sign_out - {
toggleDrawerScreen(false)
presenter.logOut()
return
}
R.string.support_feedback - {
navList.clearBadgeForMenuItem(R.string.support_feedback)
Notifications.cancelNotification(this@MainActivity,
Notifications.PushData.Message.LOCAL_PUSH_ID)
screen = Screen.CHAT
}
R.string.item_menu_account - {
data.putBoolean("profile", true)
screen = Screen.PROFILE
}
R.string.therapy_information - {
screen = Screen.THERAPY_INFO
}
R.string.about_healo - {
data.putBoolean(AboutFragment.BACKGROUND_VIDEO, true)
screen = Screen.ABOUT
}
R.string.activity_journal - {
screen = Screen.ACTIVITY_JOURNAL
}
R.string.privacy_policy_title - {
screen = Screen.WEB_PAGE
data.putBoolean(WebPageFragment.DIALOG, false)
data.putString(WebPageFragment.TOOLBAR_TITLE, getString(t.title))
data.putString(WebPageFragment.URL, BuildConfig.PRIVACY_POLICY)
}
R.string.payment_settings -
screen = Screen.PAYMENT_SETTINGS
R.string.subscriptions - screen = Screen.SUBSCRIPTIONS
else - toggleDrawerScreen(false)
}
toggleDrawerScreen(false)
if (!screen.isEmpty() && screen != currentScreen) {
actionDrawerClose = if ((fragment is OnBackPressed) && (fragment.onBackPressed(screen, data))) {
null
} else {
{ HealApplication.INSTANCE.router.navigateTo(screen, data) }
}
} else {
actionDrawerClose = null
}
}
})
navList.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
super.getItemOffsets(outRect, view, parent, state)
val position = parent.getChildAdapterPosition(view)
if (position == 0) {
outRect.top = 9.5f.dp
}
}
})
updateIcons()
navList.layoutParams.width = getScreenWidth() / 2
drawerListContainer.layoutParams.width = getScreenWidth() / 2
drawerListContainer.invalidate()
navList.requestLayout()
}
fun toggleDrawerScreen(open: Boolean) {
if (open) {
hideKeyboard()
setDrawerAnimation()
drawerLayout?.openDrawer(Gravity.END)
} else {
drawerLayout?.closeDrawer(Gravity.END, true)
}
}
private fun setDrawerAnimation() {
val animatorRecycler = ObjectAnimator.ofFloat(navList, View.TRANSLATION_X, 250f, 0f)
animatorRecycler.duration = 500
animatorRecycler.interpolator = LinearInterpolator()
animatorRecycler.start()
}
private fun getScreenWidth(): Int {
val display = windowManager.defaultDisplay
val size = Point()
display.getSize(size)
return Math.max(size.x, size.y)
}
override fun onBackPressed() {
val fragment = supportFragmentManager.findFragmentById(R.id.fragmentContainer)
if (fragment is OnBackPressed) {
if (fragment.onBackPressed(null, null))
super.onBackPressed()
} else {
if (drawerLayout.isDrawerOpen(Gravity.END)) {
drawerLayout.closeDrawer(Gravity.END, true)
} else {
super.onBackPressed()
}
}
}
override fun moveToScreen(screen: String, data: Bundle?) {
val bundle = Bundle()
if (data != null)
bundle.putAll(data)
bundle.putAll(pushData)
checkMenuState()
if (needRedirect) {
(application as HealApplication).router.newRootScreen(Screen.HOME, null)
(application as HealApplication).router.navigateTo(screen, bundle)
} else {
(application as HealApplication).router.newRootScreen(screen, bundle)
}
}
override fun onDestroy() {
super.onDestroy()
presenter.disconnectFromNotification()
}
private fun hideKeyboard() {
KeyboardUtil.hideKeyboard(this)
}
override fun startGuide() {
startActivityForResult(Intent(this, GuidanceActivity::class.java), GuidanceActivity.REQUEST_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
DiagnosticActivity.handleResult(data, requestCode, resultCode, (application as HealApplication).router)
if (requestCode == GuidanceActivity.REQUEST_CODE) {
moveToScreen(Screen.PROFILE, null)
}
}
override fun onLogout() {
finish()
HealApplication.logout()
}
private fun getNavigator(): Navigator {
return ScreenNavigator(this, R.id.fragmentContainer, Screen::class.java).navigator
}
override fun networkAvailable(isNetworkAvailable: Boolean) {
}
}
MainPresenter类
class MainPresenter(var view: MainView) : BaseMvpPresenter() {
private val exerciseRepository = SessionsRepository()
private val reportDb = SessionReportDatabase()
private val db = DiagnosticHistoryDatabase()
private val dbTherapy = TherapyDatabaseV2()
private val apiDiagnostic = DiagnosticNetwork()
private val chatRepository = ChatRepository()
private val usersNetwork = UsersNetwork()
fun subscribeToNotification() {
chatRepository.getUnreadMessageCount()
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
view.setChatBadgeCount(it)
}, Throwable::printStackTrace)
val user = UsersDatabase.getCurrentUser()
if (user == null)
return
SocketNetwork.instance.connect(SocketNetwork.instance.NOTIFICATION,user.id)
val clazz = HashMap<String, Any()
SocketNetwork.instance.addEvent(SocketNetwork.instance.NOTIFICATION +
":${user.id}", SocketNetwork.instance.NOTIFICATION, clazz.javaClass)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
Log.i("NOTIFICATION", it.toString())
when (it.getValue("event")) {
Notifications.PushData.Evaluation.EVALUATION_EVENT - {
val value = (it.getValue(Notifications.PushData.Evaluation.EVALUATION_ID) as
Double).toInt()
view.startEvaluation(value)
}
Notifications.PushData.Message.MESSAGE_EVENT - {
view.handleNewDialogMessage()
}
}
}, {
it.printStackTrace()
})
}
fun disconnectFromNotification() {
SocketNetwork.instance.closeSocket(SocketNetwork.instance.NOTIFICATION)
}
fun getSession(screen: String = Screen.HOME) {
view.showLoading()
exerciseRepository.getTherapyActive()
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
view.hideLoading()
if (!it.isEmpty())
view.moveToScreen(screen, Bundle())
else checkLastDiagnostic()
}, {
view.hideLoading()
it.printStackTrace()
view.moveToScreen(Screen.SELF_DIAGNOSIS, Bundle())
// logOut()
})
exerciseRepository.syncReports()
.observeOn(AndroidSchedulers.mainThread())
.flatMapIterable { it }
.subscribe({
reportDb.updateSessionReport(it)
}, Throwable::printStackTrace)
}
fun isFullMenu(): Boolean =
dbTherapy.getAllTherapyCount() 0
private fun checkLastDiagnostic() {
view.showLoading()
apiDiagnostic.getLastDiagnostic()
.observeOn(AndroidSchedulers.mainThread())
.switchIfEmpty {
view.hideLoading()
view.startGuide()
}
.subscribe({
view.hideLoading()
db.saveDiagnosticHistory(it)
val data = Bundle()
data.putBoolean("enable", false)
view.moveToScreen(Screen.SELF_DIAGNOSIS, data)
}, {
view.hideLoading()
view.startGuide()
})
}
fun logOut() {
usersNetwork.logOut(UsersDatabase().getToken())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ view.onLogout() }, { view.showError(it.message) })
}
fun getHelpTexts() {
usersNetwork.getHelpTexts(UsersDatabase().getToken())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ data - UsersDatabase().saveHelpText(data) }, { view.showError(it.message) })
}
fun getGender(): User.Gender? = UsersDatabase.getCurrentUser()?.getGender()
}
答案 0 :(得分:-1)
您可以尝试一下吗
在显示对话框之前,我添加了检查活动是否正在关闭的功能。除了消息,还要接受上下文并尝试。
@Override
public void showError(Context context, String errorMessage) {
if (errorMessage == null || errorMessage.trim().isEmpty())
errorMessage = getString(R.string.default_error_message);
AlertDialog dialog = new CustomAlertDialogBuilder(context)
.addMessage(errorMessage)
.setPositiveButton("OK", DialogInterface::dismiss)
.build();
try {
if (dialog != null) {
dialogs.add(dialog);
//Added this line
if(!isFinishing())
dialog.show();
}
} catch (Exception e) {
Crashlytics.logException(e);
}
}
@Override
public void showError(Context context, int errorMessage) {
showError(context, getString(errorMessage));
}