LiveData не загружается фрагментарно, пока я не поверну экран

# #android #android-fragments #firebase-realtime-database #android-livedata #mutablelivedata

Вопрос:

У меня есть фрагмент для представления новостей, которые я уже извлек из базы данных реального времени (firebase). Я использовал liveData и viewModel , пытаюсь наблюдать данные из фрагмента, но данные не загружаются, 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())

Данные не загружаются при первоначальном запуске, потому что обратный вызов фрагмента onNewsLoad() не запускается, так как контекст, который вы передали в ViewModel is, не совпадает с текущим фрагментом, который реализует DataLoadListener .

Итак, чтобы исправить это, вам нужно заменить:

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

С:

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