FirebaseUI-Android icon indicating copy to clipboard operation
FirebaseUI-Android copied to clipboard

App crashes when Minimise and Resumed

Open John-keno opened this issue 2 years ago • 5 comments

Welcome to FirebaseUI and thanks for submitting an issue!

Please take a look at open issues, as well as resolved issues, to see if your issue is either already being addressed, or has been solved by someone else.

If not, please feel free to fill in the following info so we can help faster!

Step 1: Are you in the right place?

  • For issues or feature requests related to the code in this repository file a GitHub issue.
  • For general technical questions, post a question on StackOverflow tagged appropriately.
  • For general Firebase discussion, use the firebase-talk google group
  • For help troubleshooting your application that does not fall under one of the above categories, reach out to the personalized Firebase support channel

Step 2: Describe your environment

  • Android device: Techno Pouvoir 3
  • Android OS version: 8.1.0
  • Google Play Services version: 22.24.13
  • Firebase/Play Services SDK version: 20.0.5
  • FirebaseUI version: 8.0.1

Step 3: Describe the problem:

Whenever the fragment is populated with data in the recyclerView adapter and it is minimised, upon the restoration of the view app crashes.

Steps to reproduce:

  1. launch the app and wait for data to be populated to the recyclerView
  2. Minimise the app
  3. resume app

Observed Results:

  • What happened? This could be a description, logcat output, etc.

2022-07-10 23:38:21.648 23618-23653/com.KejoTech.SBSureOdd D/FA: Application going to the background 2022-07-10 23:38:21.784 23618-23618/com.KejoTech.SBSureOdd V/PhoneWindow: DecorView setVisiblity: visibility = 0, Parent = ViewRoot{199b55e com.KejoTech.SBSureOdd/com.KejoTech.SBSureOdd.MainActivity,ident = 1}, this = DecorView@75d6f57[MainActivity] 2022-07-10 23:38:21.840 23618-23618/com.KejoTech.SBSureOdd D/Surface: Surface::allocateBuffers(this=0x8e17c800) 2022-07-10 23:38:21.841 23618-23661/com.KejoTech.SBSureOdd E/libPowerStretch: TimeStamps from Cache: lucid = 20081231170000, customer = 20081231170000 2022-07-10 23:38:21.841 23618-23661/com.KejoTech.SBSureOdd E/libPowerStretch: Cache valid RC: lucid = 2, customer = 2 2022-07-10 23:38:21.843 23618-23661/com.KejoTech.SBSureOdd E/libPowerStretch: Priority black list: 0 2022-07-10 23:38:21.843 23618-23661/com.KejoTech.SBSureOdd E/libPowerStretch: Mode = WVS 2022-07-10 23:38:21.844 23618-23661/com.KejoTech.SBSureOdd E/libPowerStretch: Ice is working with black list method 2022-07-10 23:38:21.845 23618-23661/com.KejoTech.SBSureOdd E/libPowerStretch: LUCID changing m_iceStateConfig from 0 to 2 2022-07-10 23:38:21.847 23618-23661/com.KejoTech.SBSureOdd E/libPowerStretch: EglCreateWindowSurfaceImp pid 23618 != tid 23661 mResized = 1 [720 1500] 1.000000 mIsIceDelayed_wl 1 mIsIceMainThread 0 m_HardCodedBlackListed 1 X 2022-07-10 23:38:21.847 23618-23661/com.KejoTech.SBSureOdd D/Surface: Surface::connect(this=0x8e17c800,api=1) 2022-07-10 23:38:21.939 23618-23653/com.KejoTech.SBSureOdd V/FA: Activity resumed, time: 286672293 2022-07-10 23:38:23.320 23618-23618/com.KejoTech.SBSureOdd D/AndroidRuntime: Shutting down VM 2022-07-10 23:38:23.329 23618-23618/com.KejoTech.SBSureOdd E/AndroidRuntime: FATAL EXCEPTION: main Process: com.KejoTech.SBSureOdd, PID: 23618 java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionMyViewHolder{3372b3a position=5 id=-1, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached no parent} androidx.recyclerview.widget.RecyclerView{bcdd158 VFED..... .F....I. 0,0-720,1108 #7f0a016d app:id/recycler_predict}, adapter:com.KejoTech.SBSureOdd.ui.predictions.PredictionFragment$2@843817c, layout:androidx.recyclerview.widget.LinearLayoutManager@d913472, context:com.KejoTech.SBSureOdd.MainActivity@724ec8d at androidx.recyclerview.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:6156) at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6339) at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6300) at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6296) at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2330) at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1631) at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1591) at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:668) at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep1(RecyclerView.java:4255) at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:4010) at androidx.recyclerview.widget.RecyclerView.onLayout(RecyclerView.java:4578) at android.view.View.layout(View.java:20323) at android.view.ViewGroup.layout(ViewGroup.java:6199) at androidx.swiperefreshlayout.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:625) at android.view.View.layout(View.java:20323) at android.view.ViewGroup.layout(ViewGroup.java:6199) at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1873) at android.view.View.layout(View.java:20323) at android.view.ViewGroup.layout(ViewGroup.java:6199) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) at android.widget.FrameLayout.onLayout(FrameLayout.java:261) at android.view.View.layout(View.java:20323) at android.view.ViewGroup.layout(ViewGroup.java:6199) at androidx.constraintlayout.widget.ConstraintLayout.onLayout(ConstraintLayout.java:1873) at android.view.View.layout(View.java:20323) at android.view.ViewGroup.layout(ViewGroup.java:6199) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) at android.widget.FrameLayout.onLayout(FrameLayout.java:261) at android.view.View.layout(View.java:20323) at android.view.ViewGroup.layout(ViewGroup.java:6199) at androidx.appcompat.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:536) at android.view.View.layout(View.java:20323) at android.view.ViewGroup.layout(ViewGroup.java:6199) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) at android.widget.FrameLayout.onLayout(FrameLayout.java:261) at android.view.View.layout(View.java:20323) at android.view.ViewGroup.layout(ViewGroup.java:6199) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1791) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1635) at android.widget.LinearLayout.onLayout(LinearLayout.java:1544) at android.view.View.layout(View.java:20323) at android.view.ViewGroup.layout(ViewGroup.java:6199) at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323) at android.widget.FrameLayout.onLayout(FrameLayout.java:261) at com.android.internal.policy.DecorView.onLayout(DecorView.java:764) at android.view.View.layout(View.java:20323) at android.view.ViewGroup.layout(ViewGroup.java:6199) at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2612) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2317) 2022-07-10 23:38:23.332 23618-23618/com.KejoTech.SBSureOdd E/AndroidRuntime: at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1453) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7052) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:924) at android.view.Choreographer.doCallbacks(Choreographer.java:732) at android.view.Choreographer.doFrame(Choreographer.java:664) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:910) at android.os.Handler.handleCallback(Handler.java:790) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6549) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:888)

Expected Results:

  • What did you expect to happen?

The app should resume without crashing

Relevant Code:



import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.paging.PagingConfig;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import com.KejoTech.SBSureOdd.DAOPrediction;
import com.KejoTech.SBSureOdd.DataPrediction;
import com.KejoTech.SBSureOdd.R;
import com.KejoTech.SBSureOdd.databinding.FragmentPredictionBinding;
import com.firebase.ui.database.FirebaseRecyclerOptions;
import com.google.android.material.snackbar.Snackbar;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;

import java.util.Objects;

public class PredictionFragment extends Fragment {

  private static final String TAG = "prediction frag: ";
  private FragmentPredictionBinding binding;
  private RecyclerView recyclerView;
  private PredictionViewModel predictionViewModel;
  private ListAdapter listAdapter;
  private SwipeRefreshLayout swipe;

  public View onCreateView(@NonNull LayoutInflater inflater,
                           ViewGroup container, Bundle savedInstanceState) {

      binding = FragmentPredictionBinding.inflate(inflater, container, false);
      View root = binding.getRoot();

      recyclerView = binding.recyclerPredict;
      int c1 = getResources().getColor(R.color.accent);
      int c2 = getResources().getColor(R.color.primary_dark);
      swipe = binding.swipe;
      swipe.setColorSchemeColors(c1,c2);
      swipe.setRefreshing(true);
      setAdapter();

      recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
      recyclerView.setAdapter(listAdapter);

      swipe.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
          @Override
          public void onRefresh() {
              listAdapter.onDataChanged();
          }
      });

      return root;
  }

  private void setAdapter() {
      DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference();
      Query query = databaseReference.child("Data");

      FirebaseRecyclerOptions<DataPrediction> options =
              new FirebaseRecyclerOptions.Builder<DataPrediction>()
                      .setLifecycleOwner(getViewLifecycleOwner())
                      .setQuery(query, DataPrediction.class)
                      .build();
      listAdapter = new ListAdapter(options){
          @Override
          public void onDataChanged() {
              swipe.setRefreshing(false);
          }

          @Override
          public void onError(@NonNull DatabaseError error) {

          }
      };


  }


  @Override
  public void onDestroyView() {
      super.onDestroyView();
      binding = null;
  }
}

John-keno avatar Jul 10 '22 22:07 John-keno

@John-keno thanks for opening this, I was able to reproduce the issue. A workaround that worked for me was to disable the item animator as suggested here:

recyclerView.setItemAnimator(null);

I think the fix should be implemented on the library itself, so that works as a temporary workaround for now. I'll continue to investigate how to fix this on the library and will post an update here once it's done.

thatfiredev avatar Jul 15 '22 14:07 thatfiredev

@thatfiredev I have a fix to it. Since it was a fragment I am using, I just placed the adapter listeners to start at onCreateView() and stop at onDestroyView(). I suggest that it should be implemented in the library also for the auto listeners so that they can be placed as mentioned above for fragments. The example code snippet below:

     public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
     // -------------After inflating view----------------------
        setAdapter();
        ListAdapter.startListening();
      return view;
    }

    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
        ListAdapter.stopListening();
    } 

John-keno avatar Jul 19 '22 21:07 John-keno

@John-keno I'm glad you figured it out and thanks for letting me know what the problem was.

I'll be sure to update the library to address that :)

thatfiredev avatar Jul 20 '22 15:07 thatfiredev

@thatfiredev Thanks I'm anticipating that too 😊

John-keno avatar Jul 20 '22 19:07 John-keno

@John-keno Thanks your code works like charm. I was stuck on it for a long time.

Prateek-kannojia avatar Mar 24 '23 14:03 Prateek-kannojia