# #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`