在我旋转屏幕之前,LiveData 不会加载到片段中

Posted

技术标签:

【中文标题】在我旋转屏幕之前,LiveData 不会加载到片段中【英文标题】:LiveData doesn't load in fragmet until I rotate the screen 【发布时间】:2021-10-01 10:13:22 【问题描述】:

我有一个片段来展示我已经从实时数据库 (firebase) 中检索到的新闻。 我使用了liveDataviewModel,我试图观察片段中的数据,但数据不会加载到recyclerView,直到我旋转屏幕,然后它呈现在片段上。 我不知道我可以做些什么来让它在我打开片段时可见?

Fragment.java

public class GeneralFragment extends Fragment implements DataLoadListener 

    public  NewsAdapter adapter;
    private FragmentGeneralBinding binding;
    public  NewsViewModel newsViewModel;
    Context mContext;


    @Override
    public void onAttach(Context context) 
        super.onAttach(context);
        mContext = context;
    

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) 
        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_general, container, false);
        View view = binding.getRoot();

        return view;
    

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) 
        super.onViewCreated(view, savedInstanceState);

        newsViewModel = ViewModelProviders.of(getActivity()).get(NewsViewModel.class);
        newsViewModel.init(mContext);
        adapter = new NewsAdapter(mContext, newsViewModel.getData().getValue());

        RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getContext(), 1);
        binding.recyclerView.setLayoutManager(layoutManager);
        binding.recyclerView.addItemDecoration(new GridSpacingItemDecoration(1, dpToPx(10), true));
        binding.recyclerView.setItemAnimator(new DefaultItemAnimator());
        Log.d("ADAPTER", "item count: "+adapter.getItemCount());
        adapter.notifyDataSetChanged();
        Log.d("ADAPTER", "item count: "+adapter.getItemCount());
        binding.recyclerView.setAdapter(adapter);

    


    private int dpToPx(int dp) 

        Resources r = getResources();
        return Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()));

    

    @Override
    public void onNewsLoad() 
        newsViewModel.getData().observe(getViewLifecycleOwner(), new Observer<ArrayList<NewsModel>>() 
            @Override
            public void onChanged(ArrayList<NewsModel> newsModels) 
                adapter.notifyDataSetChanged();
            
        );
    

NewsViewModel.java

public class NewsViewModel extends ViewModel 
    MutableLiveData<ArrayList<NewsModel>> news;

    public void init(Context context)
        if(news != null)
            return;
        
        news = Repo.getInstance(context).getData();
    

    public LiveData<ArrayList<NewsModel>> getData()

        return news;
    

Repo.java

public class Repo 
    private static final String TAG = "Tracing Data";
    static Repo instance;
    private ArrayList<NewsModel> newsModels;
    static Context mContext;
    static DataLoadListener dataLoadListener;

    public static Repo getInstance(Context context) 
        if (instance == null) 
            instance = new Repo();
        
        mContext = context;
        dataLoadListener = (DataLoadListener) mContext;
        return instance;
    

    public MutableLiveData<ArrayList<NewsModel>> getData() 
        newsModels  = new ArrayList<>();
        RetrieveAllData();
        MutableLiveData<ArrayList<NewsModel>> newsModel = new MutableLiveData<>();
        newsModel.setValue(newsModels);

        return newsModel;
    

    private void RetrieveAllData() 
        Log.d(TAG, "before RetrieveAllData: "+newsModels.size());
        FirebaseDatabase database = FirebaseDatabase.getInstance();
        database.getReference("news").orderByChild("date").addValueEventListener(new ValueEventListener() 
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) 
                if (snapshot.exists()) 
                    newsModels.clear();
                    for (DataSnapshot postSnapshot : snapshot.getChildren()) 
                        newsModels.add(0, postSnapshot.getValue(NewsModel.class));
                    
                    dataLoadListener.onNewsLoad();
                    Log.d(TAG, "after RetrieveAllData: "+newsModels.size());
                
            

            @Override
            public void onCancelled(@NonNull DatabaseError error) 

            
        );
    

DataLoadListener.java

public interface DataLoadListener
    void onNewsLoad();

【问题讨论】:

【参考方案1】:

我正在尝试观察片段中的数据,但在我旋转屏幕之前,数据不会加载到 recyclView 中

因为onViewCreated() 再次被调用,并且适配器数据设置为adapter = new NewsAdapter(mContext, newsViewModel.getData().getValue()) 中的 ViewModel 的持久数据(不受配置更改/旋转的影响)

数据不会在初始启动时加载,因为片段的回调 onNewsLoad() 没有被触发,因为您传递给 ViewModel 的上下文与实现 @987654325 的当前片段不同@。

因此,要解决此问题,您需要替换:

newsViewModel.init(mContext); // mContex isn't considered as a `DataLoadListener` 

与:

newsViewModel.init(this); // this here refers to the `GeneralFragment` as a `DataLoadListener` 

【讨论】:

以上是关于在我旋转屏幕之前,LiveData 不会加载到片段中的主要内容,如果未能解决你的问题,请参考以下文章

屏幕旋转后Android片段重叠

Android 片段不保存状态,在旋转/屏幕锁定/返回时崩溃

安卓片段。在屏幕旋转或配置更改期间保留 AsyncTask

使用导航抽屉旋转时的片段更改

片段项目不会折叠

LiveData 没有观察具有共享视图模型的子视图页面片段