Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/195.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 屏幕旋转和rxjava后查看实例null 问题_Android_Android Recyclerview_Kotlin_Rx Java2 - Fatal编程技术网

Android 屏幕旋转和rxjava后查看实例null 问题

Android 屏幕旋转和rxjava后查看实例null 问题,android,android-recyclerview,kotlin,rx-java2,Android,Android Recyclerview,Kotlin,Rx Java2,我正在使用Kotlin合成绑定、RxJava、改型和MVP模式开发一个Android应用程序。在这个应用程序上有一个屏幕,它应该从API获取一些数据,并用返回的数据填充RecyclerView 所有这些每次都在工作,直到我尝试旋转屏幕。。。重新创建活动和片段并尝试访问RecyclerView后,应用程序崩溃,出现以下异常: 10-25 18:20:00.368 4580-4580/com.sample.app E/AndroidRuntime: FATAL EXCEPTION: main

我正在使用Kotlin合成绑定、RxJava、改型和MVP模式开发一个Android应用程序。在这个应用程序上有一个屏幕,它应该从API获取一些数据,并用返回的数据填充
RecyclerView

所有这些每次都在工作,直到我尝试旋转屏幕。。。重新创建活动和片段并尝试访问RecyclerView后,应用程序崩溃,出现以下异常:

10-25 18:20:00.368 4580-4580/com.sample.app E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.sample.app, PID: 4580
    java.lang.IllegalStateException: recyclerView must not be null
        at com.sample.app.features.atendimento.ClientesAtendimentosFragment.onAtendimentosLoaded(ClientesAtendimentosFragment.kt:56)
        at com.sample.app.features.atendimento.ClienteAtendimentoActivity.showClientesAtendimento(ClienteAtendimentoActivity.kt:126)
        at com.sample.app.features.atendimento.ClienteAtendimentoPresenter$getClientesAtendimento$3.accept(ClienteAtendimentoPresenter.kt:38)
        at com.sample.app.features.atendimento.ClienteAtendimentoPresenter$getClientesAtendimento$3.accept(ClienteAtendimentoPresenter.kt:18)
        at io.reactivex.internal.observers.ConsumerSingleObserver.onSuccess(ConsumerSingleObserver.java:63)
        at io.reactivex.internal.operators.single.SingleDoAfterTerminate$DoAfterTerminateObserver.onSuccess(SingleDoAfterTerminate.java:71)
当我尝试调用此方法时会发生这种情况:

override fun onAtendimentosLoaded(atendimentos: List<UsuarioAtendimento>) {
    recyclerView.visibility = View.VISIBLE
    recyclerView.adapter = ClienteAtendimentoAdapter(atendimentos, this)
}
片段

class ClientesAtendimentosFragment : Fragment(), AtendimentosFragmentCallback, OnClickAtendimentoCallback {

    private lateinit var recyclerView: RecyclerView

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val rootView = inflater.inflate(R.layout.fragment_single_rv, container, false)

        recyclerView = rootView.findViewById(R.id.recyclerView) // I did this to test if Kotlin synthetic binding was the problem.

        return rootView
    }

    // ...

    override fun onAtendimentosLoaded(atendimentos: List<UsuarioAtendimento>) {
        recyclerView.visibility = View.VISIBLE // App is crashing here.
        recyclerView.adapter = ClienteAtendimentoAdapter(atendimentos, this)
    }

    // ...
}
但现在我得到了以下错误:

10-25 18:32:42.261 10572-10572/com.sample.app E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.sample.app, PID: 10572
    io.reactivex.exceptions.UndeliverableException: kotlin.UninitializedPropertyAccessException: lateinit property recyclerView has not been initialized
        at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
        at io.reactivex.internal.observers.ConsumerSingleObserver.onSuccess(ConsumerSingleObserver.java:66)
        at io.reactivex.internal.operators.single.SingleDoAfterTerminate$DoAfterTerminateObserver.onSuccess(SingleDoAfterTerminate.java:71)
        at io.reactivex.internal.operators.single.SingleDoOnSubscribe$DoOnSubscribeSingleObserver.onSuccess(SingleDoOnSubscribe.java:77)
        at io.reactivex.internal.operators.single.SingleObserveOn$ObserveOnSingleObserver.run(SingleObserveOn.java:81)
        at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:119)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:145)
        at android.app.ActivityThread.main(ActivityThread.java:6939)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)
     Caused by: kotlin.UninitializedPropertyAccessException: lateinit property recyclerView has not been initialized
        at com.sample.app.features.atendimento.ClientesAtendimentosFragment.onAtendimentosLoaded(ClientesAtendimentosFragment.kt:59)

编辑:我做了什么,我发现由于某种原因,当我旋转屏幕时,新的Rx调用仍在尝试使用旧的片段引用,即使已经成功创建并显示了新的片段引用。我不确定我应该在哪里清理它,或者它为什么会这样,也许它与
supportFragmentManager
有关?

首先,尝试调试它,并在
onandimentosloaded()中查找片段(
this
)的哈希代码。假设您没有使用
setRetainInstance
,则它们应该不同。如果它们是相同的,那么您没有正确地清除某些内容,很难说问题的确切原因,因为我们没有相关的片段、活动和演示者代码。

我经常遇到这个问题。每次我都会简单地使用Kotlin的空安全特性来解决这个问题

override fun onAtendimentosLoaded(atendimentos: List<UsuarioAtendimento>) {
    recyclerView?.visibility = View.VISIBLE
    recyclerView?.adapter = ClienteAtendimentoAdapter(atendimentos, this)
}
覆盖已加载的附件(ATendmentos:List){
recyclerView?.visibility=View.VISIBLE
recyclerView?.adapter=ClienteIndicationOAAPTER(AteIndicationOS,this)
}

请注意
recyclerView
之后的问号。我认为问题出在
部分SpagerAdapter.getItem
中,您应该始终实例化一个新片段:

override fun getItem(position: Int): Fragment {
    return if (position == 0) ClientesAtendimentosFragment.newInstance() else ClientesAtendimentosFragment.newInstance()
}
我知道
FragmentPagerAdapter
的文档不清楚,但是如果您查看它的
实例化Item
方法:

@Override
public Object instantiateItem(ViewGroup container, int position) {
    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }

    final long itemId = getItemId(position);

    // Do we already have this fragment?
    String name = makeFragmentName(container.getId(), itemId);
    Fragment fragment = mFragmentManager.findFragmentByTag(name);
    if (fragment != null) {
        if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
        mCurTransaction.attach(fragment);
    } else {
        fragment = getItem(position); // @Mauker it requires a new fragment instance!
        if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
        mCurTransaction.add(container.getId(), fragment,
                makeFragmentName(container.getId(), itemId));
    }
    if (fragment != mCurrentPrimaryItem) {
        fragment.setMenuVisibility(false);
        fragment.setUserVisibleHint(false);
    }

    return fragment;
}
很明显,每当调用
SectionsPagerAdapter.getItem
时,我们都需要提供一个新的片段实例。因此,在您的情况下,当屏幕旋转时,您的适配器(假设适配器被持久化)将返回片段的旧引用,这些片段的视图可能已经被破坏

您不应该在之后调用
getItem
,它应该只由适配器使用,它只会在您调用它时返回新的片段实例

如果您确实需要获得参考,请尝试以下方法:

val fragments = SparseArray<Fragment>()

fun getFragment(position: Int): Fragment? { // call this instead
    return fragments.get(position)
}

override fun getItem(position: Int): Fragment {
    val fragment = SomeFragment()
    fragments.put(position, fragment) // store it for later use
    return fragment
}
val fragments=SparseArray()
有趣的片段(位置:Int):片段?{//请改称此为
返回碎片。获取(位置)
}
覆盖趣味getItem(位置:Int):片段{
val fragment=SomeFragment()
fragments.put(position,fragment)//保存它以备将来使用
返回片段
}

我希望它能起作用,祝你好运

经过一番挖掘,在这里的一些答案的帮助下,我找到了答案

是的,问题出在
FragmentPagerAdapter
上,它返回了一个旧的片段实例,这导致了空指针

为了解决这个问题,首先我将创建片段的方式更改为:

inner class SectionsPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
    private val fragList = ArrayList<Fragment>()

    fun addFragment(frag: Fragment) {
        fragList.add(frag)
    }

    override fun getItem(position: Int): Fragment {
        return fragList[position]
    }

    override fun getCount(): Int = fragList.size
}

至于发生这种情况的原因,解释得很好。

您是否尝试过覆盖活动清单标记中的旋转和屏幕大小配置更改?我想知道您的演示者在MVP中是如何工作的:您的演示者是否也有对视图的引用?如果是这样,您的演示者可能会指向在旋转中被破坏的旧视图。您可以共享演示者和片段附件吗?演示者没有保存旧引用,我甚至取消了视图引用,并在Activity@Mauker感谢分享代码,我相信这与您的
部分SPAGERAAdapter
有关,我已经发布了一个答案。我希望它能起作用!它们确实不同。我已经编辑了这个问题,并添加了与MVP相关的代码。不幸的是,这只会掩盖问题。我需要执行那部分代码。你试过了吗?因为我会在我的案例中做类似的事情,它会起作用是的,我做了,代码最终没有执行,就像我说的,它只是掩盖了问题,问题是其他的,现在它甚至在第一次运行时就崩溃了:(我想是不同的崩溃?>\n不,同样的问题,RV是空的哦,我错过了一点,你不应该在之后调用getItem,它只由适配器使用,它会不断返回新的片段。从这里开始工作的最便宜的方法是提供一个类似getItem的新函数。哦,真的。我会检查一下。
@Override
public Object instantiateItem(ViewGroup container, int position) {
    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }

    final long itemId = getItemId(position);

    // Do we already have this fragment?
    String name = makeFragmentName(container.getId(), itemId);
    Fragment fragment = mFragmentManager.findFragmentByTag(name);
    if (fragment != null) {
        if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
        mCurTransaction.attach(fragment);
    } else {
        fragment = getItem(position); // @Mauker it requires a new fragment instance!
        if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
        mCurTransaction.add(container.getId(), fragment,
                makeFragmentName(container.getId(), itemId));
    }
    if (fragment != mCurrentPrimaryItem) {
        fragment.setMenuVisibility(false);
        fragment.setUserVisibleHint(false);
    }

    return fragment;
}
val fragments = SparseArray<Fragment>()

fun getFragment(position: Int): Fragment? { // call this instead
    return fragments.get(position)
}

override fun getItem(position: Int): Fragment {
    val fragment = SomeFragment()
    fragments.put(position, fragment) // store it for later use
    return fragment
}
inner class SectionsPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
    private val fragList = ArrayList<Fragment>()

    fun addFragment(frag: Fragment) {
        fragList.add(frag)
    }

    override fun getItem(position: Int): Fragment {
        return fragList[position]
    }

    override fun getCount(): Int = fragList.size
}
override fun instantiateItem(container: ViewGroup, position: Int): Any {
    val ret = super.instantiateItem(container, position)
    fragList[position] = ret as Fragment
    return ret
}