销毁后碎片变为空白碎片

时间:2018-11-13 14:18:19

标签: android android-fragments kotlin

当我第一次开始活动时,一切都很好,但是我可以正常导航,但是旋转屏幕后,fragmentMananger似乎出错了,每次更改片段后,如果旋转屏幕,活动就会加载一个空白片段重新创建出现了正确的片段,但错误仍然存​​在。
当我退出该应用程序并重新使用它时,错误仍然存​​在,并且仅在清除用户数据后才消失,我尝试在每次更改片段后重新创建活动,但这只会使事情变得更糟。
解决该问题的一件事是在每次应用程序完成后清除用户数据,但它会删除应用程序在运行时管理的重要数据,这些数据需要通过文件持久保存以便下次执行。

我使用一个伴随对象来管理片段名称:

companion object {
    val TAG = this::class.java.canonicalName!!
    const val MAIN_FRAGMENT = "MainFragment"
    const val SECOND_FRAGMENT = "SecondFragment"
    const val THIRD_FRAGMENT = "ThirdFragment"
    const val FOURTH_FRAGMENT = "FourthFragment"
    const val FIFTH_FRAGMENT = "FifthFragment"
}

片段管理功能:

fun callFragment(s: String? = null) {
    validateFrag(s ?: MAIN_FRAGMENT, ::setFragment)
}

fun updateFragment() {
    Control.logData("updating fragment $fragment_state")
    validateFrag(fragment_state, ::setFragment)
}

private fun validateFrag(s: String, f: (String) -> Unit) {
    when (s) {
        SECOND_FRAGMENT -> f(s)
        THIRD_FRAGMENT -> f(s)
        FOURTH_FRAGMENT -> f(s)
        FIFTH_FRAGMENT -> f(s)
        else -> f(MAIN_FRAGMENT)
    }
}

private fun createFrag(id: String): Fragment = when (id) {
    SECOND_FRAGMENT -> SecondFragment.newInstance()
    THIRD_FRAGMENT -> ThirdFragment.newInstance()
    FOURTH_FRAGMENT -> FourthFragment.newInstance()
    FIFTH_FRAGMENT -> FifthFragment.newInstance(this)
    else -> MainFragment.newInstance()
}

private fun setFragment(id: String) {
    val userAuth = userAuth
    userAuth ?: return
    Control.logData("loading fragment $id")
    val frame = R.id.app_frame
    val fragment = (fragmentManager.findFragmentByTag(id) ?: createFrag(id))
    currentFragment = fragment as MyAppFragment
    fragment_state = id

    when{
        fragmentManager.fragments.size == 0 -> {
            fragmentManager.beginTransaction()
                    .add(frame, createFrag(MAIN_FRAGMENT), MAIN_FRAGMENT)
                    .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                    .commitNowAllowingStateLoss()
        }
        !fragmentManager.fragments.contains(fragment as Fragment) -> {
            fragmentManager.beginTransaction()
                    .add(frame, fragment, id)
                    .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                    .commitNowAllowingStateLoss()
        }
        else ->{
            with(fragmentManager.beginTransaction()) {
                replace(frame, fragment, id)
                setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                commitNowAllowingStateLoss()
            }
        }
    }
}

对于提交,我也尝试使用Commit()和CommitNow()

我的片段实现:

package com.domain.app.fragments

import android.content.Context
import android.support.v4.app.Fragment
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ScrollView
import com.reactivex.disposables.Disposable
import com.domain.app.Control
import com.domain.app.R
import com.domain.app.AppApplicatcomn
import com.domain.app.activities.appActivity
import com.domain.app.dagger.services.IRXService
import com.domain.app.recycler.adapter.DataListAdapter
import kotlinx.android.synthetic.main.fragment_main.*
import javax.inject.Inject

class MainFragment : Fragment(), AppFragment {

// instanciate data

compancomn object {
    fun newInstance(): MainFragment{
        return MainFragment()
    }
}

override fun onAttach(context: Context?) {
    super.onAttach(context)
    activity?.let { act ->
        //subscribe RX
    }
}

override fun onDetach() {
    super.onDetach()
    //disposeRX
}

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {
    return inflater.inflate(R.layout.fragment_main, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    dockInit()
    recyclerInit()
    if(Control.index.isEmpty()){
        noDataScreen()
    }
    else{
        Control.putOnScreen()
    }
}

override fun noDataScreen() {
    activity?.runOnUiThread {
        main_noDataQrButton?.visibility = View.VISIBLE
        main_noDataText?.visibility = View.VISIBLE
        Control.loadingDataStream.onNext(false)
        isInit = false
    }
}

override fun notifyRecycler() {
    activity?.runOnUiThread{
        if(::list.isInitialized){
            mAdapter.update()
            list.adapter?.notifyDataSetChanged()
        }
    }
}

private fun recyclerInit(){
    mAdapter = DataListAdapter(activity as appActivity)
    mAdapter.setHasStableIds(true)
    list = view!!.findViewById<RecyclerView>(R.id.main_listDataListRecycler).apply {
        setHasFixedSize(true)
        setItemViewCacheSize(8)
        layoutManager = LinearLayoutManager(context)
        adapter = mAdapter
    }

}

}

我的清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.domain.app">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE" />

<application
    android:name=".AppApplication"
    android:allowBackup="true"
    android:icon="@drawable/app"
    android:label="@string/app_name"
    android:roundIcon="@drawable/app_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme.NoActionBar"
    android:allowClearUserData="true"
    android:fullBackupContent="@xml/backup_descriptor">

    <!-- android:theme="@style/AppTheme" -->

    <activity
        android:name=".activities.AppActivity"
        android:screenOrientation="portrait"
        android:label="@string/app_name"
        android:theme="@style/AppTheme.NoActionBar">
        <intent-filter>

            <!-- para ser aberto com action APP -->
            <action android:name="android.intent.action.APP" />
            <action android:name="android.intent.action.MAIN" />
            <action android:name="io.ubivis.digitalmobility.action.CONSUME_APP_NOTIFICATION" />

            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.VIEW" />

            <category android:name="android.intent.category.DEFAULT" />
            <category android:name="android.intent.category.BROWSABLE" />

            <data
                android:host="app.domain.io"
                android:scheme="https" />
        </intent-filter>
    </activity>

    <service android:name=".services.FirebaseMessageService">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
    <service android:name=".services.FirebaseTokenService">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
    </service>

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/ic_logo_app_60dp" />
    <meta-data
        android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/colorPrimary" />

    <!-- Para Android 8 - Necessário um canal para notificações -->
    <!-- <meta-data -->
    <!-- android:name="com.google.firebase.messaging.default_notification_channel_id" -->
    <!-- android:value="@string/default_notification_channel_id"/> -->
</application>

我的活动xml是:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v7.widget.CardView
    android:id="@+id/app_connectionCard"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:visibility="gone"
    app:cardBackgroundColor="@android:color/holo_red_dark"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/app_toolbar">

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/connectionFail"
            android:textColor="@color/cardview_light_background"
            android:textSize="24sp"
            android:textStyle="bold"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>

<android.support.v7.widget.Toolbar
    android:id="@+id/app_toolbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/ubivis_background_blue"
    android:theme="@style/ThemeOverlay.AppCompat.Dark"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<android.support.v4.widget.DrawerLayout
    android:id="@+id/app_drawer"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/app_connectionCard"
    tools:openDrawer="start">

    <FrameLayout
        android:id="@+id/app_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">
    </FrameLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/app_navigation"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@color/colorPrimaryDark"
        android:fitsSystemWindows="true"
        android:theme="@style/UbivisDrawerTheme"
        app:headerLayout="@layout/nav_header_app"
        app:itemIconTint="@color/ubivis_orange"
        app:menu="@menu/activity_app_drawer" />

</android.support.v4.widget.DrawerLayout>

片段xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:theme="@style/AppTheme.NoActionBar"
tools:context=".fragments.MainFragment">

<ImageView
    android:id="@+id/imageView"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:adjustViewBounds="false"
    android:cropToPadding="false"
    android:scaleType="fitEnd"
    android:tint="@color/background"
    android:translationX="128dp"
    android:translationY="128dp"
    android:visibility="visible"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:srcCompat="@drawable/logo_domain_vasado" />

<android.support.v7.widget.RecyclerView
    android:id="@+id/main_listDataListRecycler"
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toStartOf="@+id/main_dock"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="0.0">

</android.support.v7.widget.RecyclerView>

<TextView
    android:id="@+id/main_noDataText"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginBottom="8dp"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:text="@string/noDataMessage"
    android:textAlignment="center"
    android:textSize="30sp"
    android:textStyle="bold"
    android:visibility="visible"
    app:layout_constraintBottom_toTopOf="@+id/main_noDataQrButton"
    app:layout_constraintEnd_toStartOf="@+id/main_dock"
    app:layout_constraintStart_toStartOf="parent" />

<Button
    android:id="@+id/main_noDataQrButton"
    android:layout_width="220dp"
    android:layout_height="220dp"
    android:layout_marginBottom="5dp"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="30dp"
    android:background="@drawable/shape_qr_code_frame"
    android:elevation="16dp"
    android:onClick="qrScan"
    android:theme="@style/AppTheme"
    android:visibility="visible"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toStartOf="@+id/main_dock"
    app:layout_constraintStart_toStartOf="@+id/main_listDataListRecycler"
    app:layout_constraintTop_toTopOf="parent"
    tools:ignore="OnClick" />

活动生命周期:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    Control.logData("creating activity")

    setContentView(R.layout.activity_app)
    // keep screen alive
    window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
    // set toolbar
    setSupportActionBar(findViewById(R.id.app_toolbar))
    supportActionBar?.title = getString(R.string.Datas)
    supportActionBar?.setDisplayHomeAsUpEnabled(true)
    supportActionBar?.setDisplayShowHomeEnabled(true)
    isWaitingResult = savedInstanceState?.getBoolean(isWaitingResultCode) ?: false
    savedInstanceState?.let{
        fragment_state =  savedInstanceState.getString(fragState) ?: fragment_state
        userAuth = savedInstanceState.getSerializable(userAuthCode) as? UserAuthentication?
    }
    val DataMenu = findViewById<NavigationView>(R.id.app_navigation)
            .menu.findItem(R.id.DataButton)
    DataMenu?.isChecked = true
    if (!Control.filters) filterMenu?.icon = drawable(R.drawable.filter_inactive)
    //injection
    if (!isInjected) {
        onInject()
    }
}

override fun onStop() {
    super.onStop()
    Control.logData("stopping activity")
    fragmentManager.executePendingTransactions()
    Control.mainRunning = false
    loop = false
    saveFav()
}

override fun onDestroy() {
    super.onDestroy()
    Control.logData("destroying activity")
    Control.rx.forEach { it.dismiss() }
    Control.rx.clear()
}

控件是一个具有一些功能和数据的对象,该功能和数据在整个App中通常使用

1 个答案:

答案 0 :(得分:0)

在我的情况下,黑屏是由主线程阻塞引起的,在api更新后,一些不赞成使用的函数开始返回null并阻塞了片段中的主线程以解决问题,我使用了api提供的新函数替换不推荐使用的