我如何观察 LiveData 然后将此数据传递给我的适配器?

How can I observe LiveData and then pass this data to my adapter?

我有一个Calendar。 为了创建这个,我有一个 CalendarFragment 打开 CustomCalendarView

(扩展 LinearLayout 的 class)。

然后使用 MyGridAdapter(class 扩展 ArrayAdapter)来构建日历。

当您单击日历上的一个单元格时,您将被带到一个新的 activity,您可以在其中保存包含一些信息的日志(以及日历中被单击的单元格的日期)。

我在 Dao class 中有一个查询:Log_Entries_Dao 传递给 LogEntriesRepository 然后 LogEntriesViewModel.

查询:

@Query("SELECT date FROM log_entries_table WHERE log_entries_table.date = :date " ) LiveData<List<LogDates>> getAllDatesWithLogs(List<Date> date);

查询收到一个日历月所有日期的列表,然后 returns 一个包含 logEntry 的所有日期的列表。

现在我想在我的 setupCalendar 方法中观察这个 LiveData 并将存在 logEntry 的日期列表传递给我的 gridAdater class 这样我就可以添加圆圈存在 logEntry 的所有单元格。

麻烦的是,我认为在 CustomCalendarView (LinearLayout class) 中使用我的 LogViewModel class 是不好的做法。 如何正确查询我的数据库、观察 liveData 并将其从我的 setUpCalendar 方法内部发送到我的适配器?

日历片段

public class CalendarFragment extends Fragment {

    CustomCalendarView customCalendarView;
    List<Date> dates = new ArrayList<>();
    LogEntriesViewModel logEntriesViewModel;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.calendar_activity_main, container,false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        customCalendarView =(CustomCalendarView) getView().findViewById(R.id.custom_calendar_view);
        ((AppCompatActivity) getActivity()).getSupportActionBar().hide();
    }
}

自定义日历视图


public class CustomCalendarView extends LinearLayout {
    ImageButton NextButton, PreviousButton;
    TextView CurrentDate;
    GridView gridView;
    public static final int MAX_CALENDAR_DAYS = 42;
    Calendar calendar = Calendar.getInstance(Locale.ENGLISH);
    Context context;
    MyGridAdapter myGridAdapter;
    SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM yyyy", Locale.ENGLISH);
    SimpleDateFormat monthFormat = new SimpleDateFormat("MMMM", Locale.ENGLISH);
    SimpleDateFormat yearFormat = new SimpleDateFormat("yyyy", Locale.ENGLISH);
    SimpleDateFormat eventDateFormat = new SimpleDateFormat(("dd-MM-yyyy"), Locale.ENGLISH);

    public static final String MY_PREFS_NAME = "MyPrefsFile";

    List<Date> dates = new ArrayList<>();
    List<Log_Entries> eventsList = new ArrayList<>();

    public CustomCalendarView(Context context) {
        super(context);
    }

    public CustomCalendarView(final Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        InitializeLayout();
        SetUpCalendar();

        PreviousButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                calendar.add(Calendar.MONTH, -1);
                SetUpCalendar();
            }
        });

        NextButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                calendar.add(Calendar.MONTH, 1);
                SetUpCalendar();
            }
        });


        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                AlertDialog.Builder builder = new AlertDialog.Builder(context);
                builder.setCancelable(true);

                final String date = eventDateFormat.format(dates.get(position));


                Intent i = new Intent(getContext(), WorkoutButtonsActivity.class);
                i.putExtra(WorkoutButtonsActivity.EXTRA_DATE, date);
                getContext().startActivity(i);
            }
        });
    }

    public CustomCalendarView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void InitializeLayout() {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.calendar_layout, this);
        NextButton = view.findViewById(R.id.nextBtn);
        PreviousButton = view.findViewById(R.id.previousBtn);
        CurrentDate = view.findViewById(R.id.current_Date);
        gridView = view.findViewById(R.id.gridview);
    }

    private void SetUpCalendar() {

        String currentDate = dateFormat.format(calendar.getTime());
        CurrentDate.setText(currentDate);
        dates.clear();
        Calendar monthCalendar = (Calendar) calendar.clone();
        monthCalendar.set(Calendar.DAY_OF_MONTH, 1);
        int FirstDayofMonth = monthCalendar.get(Calendar.DAY_OF_WEEK) - 1;
        monthCalendar.add(Calendar.DAY_OF_MONTH, -FirstDayofMonth);

        while (dates.size() < MAX_CALENDAR_DAYS) {
            dates.add(monthCalendar.getTime());
            monthCalendar.add(Calendar.DAY_OF_MONTH, 1);


        }
        myGridAdapter = new MyGridAdapter(context, dates, calendar, eventsList);
        gridView.setAdapter(myGridAdapter);

    }
}

MyGridAdapter


public class MyGridAdapter extends ArrayAdapter {
    List<Date> dates;
    Calendar currentDate;

    List<Log_Entries> logs;

    LayoutInflater inflater;

    public MyGridAdapter(@NonNull Context context, List<Date> dates, Calendar currentDate, List<Log_Entries> logs){
        super(context, R.layout.single_cell_layout);

        this.dates = dates;
        this.currentDate = currentDate;
        this.logs = logs;
        inflater = LayoutInflater.from(context);

        Log.i("dates", String.valueOf(dates));

    }
    @NonNull
    @Override
    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
        Date monthDate = dates.get(position);
        Calendar dateCalendar = Calendar.getInstance();
        dateCalendar.setTime(monthDate);
        int DayNo = dateCalendar.get(Calendar.DAY_OF_MONTH);
        int displayMonth = dateCalendar.get(Calendar.MONTH) +1;
        int displayYear = dateCalendar.get(Calendar.YEAR);
        int currentMonth = currentDate.get(Calendar.MONTH) + 1;
        int currentYear = currentDate.get(Calendar.YEAR);
        int currentDay = currentDate.get(Calendar.DAY_OF_MONTH);



        View view = convertView;
        if (view == null){
            view = inflater.inflate(R.layout.single_cell_layout, parent,false);
        }

        if (displayMonth == currentMonth && displayYear == currentYear){
            view.setBackgroundColor(getContext().getResources().getColor(R.color.green));
        }
        else{
            view.setBackgroundColor(Color.parseColor("#cccccc"));
        }

        TextView Day_Number = view.findViewById(R.id.calendar_day);
        Day_Number.setText(String.valueOf(DayNo));

        Calendar eventCalendar = Calendar.getInstance();

        if(DayNo == currentDay && displayMonth == eventCalendar.get(Calendar.MONTH) + 1 && displayYear == eventCalendar.get(Calendar.YEAR)){
            Day_Number.setTextColor(Color.parseColor("#FFFF33"));

        }


        ArrayList<String> arrayList = new ArrayList<>();
        for (int i = 0; i < logs.size(); i++){
        }
        return view;
    }

    @Override
    public int getCount() {
        return dates.size();
    }

    @Override
    public int getPosition(@Nullable Object item) {
        return dates.indexOf(item);
    }

    @Nullable
    @Override
    public Object getItem(int position) {
        return dates.get(position);
    }
}

LogEntriesRepository


public class LogEntriesRepository {

    private Log_Entries_Dao log_entries_dao;
    private LiveData<List<Log_Entries>> allLogEntries;
    private LiveData<List<Log_Entries>> allWorkoutLogEntries;

    private LiveData<List<LogDates>> allDatesWithLog;

    public LogEntriesRepository(Application application) {
        ExerciseDatabase database = ExerciseDatabase.getInstance(application);
        log_entries_dao = database.log_entries_dao();
        allLogEntries = log_entries_dao.getAllFromLogEntries();
    }

    public void insert(Log_Entries log_entries) {
        new InsertLogEntryAsyncTask(log_entries_dao).execute(log_entries);
    }

    public void update(Log_Entries log_entries) {
        new UpdateLogEntryAsyncTask(log_entries_dao).execute(log_entries);
    }

    public void delete(Log_Entries log_entries) {
        new DeleteLogEntryAsyncTask(log_entries_dao).execute(log_entries);
    }


    public LiveData<List<Log_Entries>> getAllLogEntries() {
        return allLogEntries;
    }

    public LiveData<List<Log_Entries>> getAllWorkoutLogEntries(int junctionID, String date) {
        allWorkoutLogEntries = log_entries_dao.getAllFromWorkoutLogEntries(junctionID, date);
        return allWorkoutLogEntries;
    }

    public LiveData<List<LogDates>> getAllDateLogEntries(List<String> date) {
        allDatesWithLog = log_entries_dao.getAllDatesWithLogs(date);
        return allDatesWithLog;
    }

    private static class InsertLogEntryAsyncTask extends AsyncTask<Log_Entries, Void, Void> {
        private Log_Entries_Dao log_entries_dao;

        private InsertLogEntryAsyncTask(Log_Entries_Dao log_entries_dao) {
            this.log_entries_dao = log_entries_dao;
        }

        @Override
        protected Void doInBackground(Log_Entries... log_entries) {
            log_entries_dao.insert(log_entries[0]);
            return null;
        }
    }

    private static class UpdateLogEntryAsyncTask extends AsyncTask<Log_Entries, Void, Void> {
        private Log_Entries_Dao log_entries_dao;

        private UpdateLogEntryAsyncTask(Log_Entries_Dao log_entries_dao) {
            this.log_entries_dao = log_entries_dao;
        }

        @Override
        protected Void doInBackground(Log_Entries... log_entries) {

            log_entries_dao.update(log_entries[0]);
            return null;
        }
    }

    private static class DeleteLogEntryAsyncTask extends AsyncTask<Log_Entries, Void, Void> {
        private Log_Entries_Dao log_entries_dao;

        private DeleteLogEntryAsyncTask(Log_Entries_Dao log_entries_dao) {
            this.log_entries_dao = log_entries_dao;
        }

        @Override
        protected Void doInBackground(Log_Entries... log_entries) {
            log_entries_dao.delete(log_entries[0]);
            return null;
        }
    }

}

LogEntriesViewModel

public class LogEntriesViewModel extends AndroidViewModel {

    private LogEntriesRepository repository;
    private LiveData<List<Log_Entries>> allLogEntries;
    private LiveData<List<Log_Entries>> allWorkoutLogEntries;

    private LiveData<List<LogDates>> allDateLogEntries;


    public LogEntriesViewModel(@NonNull Application application) {
        super(application);
        repository = new LogEntriesRepository(application);
        allLogEntries = repository.getAllLogEntries();
    }


    public void insert(Log_Entries log_entries){
        repository.insert(log_entries);
    }
    public void update(Log_Entries log_entries){
        repository.update(log_entries);
    }
    public void delete(Log_Entries log_entries ) {
        repository.delete(log_entries);
    }
   // public LiveData<List<Log_Entries>> getAllLogs(){
   //     return allLogEntries;
   // }

    public LiveData<List<Log_Entries>> getAllWorkoutLogEntries(int junctionID, String date){
        allWorkoutLogEntries = repository.getAllWorkoutLogEntries(junctionID, date);
        return allWorkoutLogEntries;
    }

    public LiveData<List<LogDates>> getAllDateLogEntries(List<String> date){
        allDateLogEntries = repository.getAllDateLogEntries(date);
        return allDateLogEntries;
    }

}

我希望如果您理解这一点并将其应用到您的代码中,如果我没记错的话,那将解决您的问题。我没有查看您的所有代码,但我得到了您的查询 "How to set Livedata to adapter",这是解决方案。

这里是参考代码,您可以与您的参考代码进行比较。

   @Dao
 interface UserDao {
 @Query("SELECT * FROM user ORDER BY lastName ASC")
 public abstract LiveData<List<User>> usersByLastName();
 }

 class MyViewModel extends ViewModel {
 public final LiveData<List<User>> usersList;
 public MyViewModel(UserDao userDao) {
     usersList = userDao.usersByLastName();
 }
 }

 class MyActivity extends AppCompatActivity {
 @Override
 public void onCreate(Bundle savedState) {
     super.onCreate(savedState);
     MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
     RecyclerView recyclerView = findViewById(R.id.user_list);
     UserAdapter<User> adapter = new UserAdapter();
     viewModel.usersList.observe(this, list -> adapter.submitList(list));
     recyclerView.setAdapter(adapter);
 }
 }

 class UserAdapter extends ListAdapter<User, UserViewHolder> {
 public UserAdapter() {
     super(User.DIFF_CALLBACK);
 }
 @Override
 public void onBindViewHolder(UserViewHolder holder, int position) {
     holder.bindTo(getItem(position));
 }
 public static final DiffUtil.ItemCallback<User> DIFF_CALLBACK =
         new DiffUtil.ItemCallback<User>() {
     @Override
     public boolean areItemsTheSame(
             @NonNull User oldUser, @NonNull User newUser) {
         // User properties may have changed if reloaded from the DB, but ID is fixed
         return oldUser.getId() == newUser.getId();
     }
     @Override
     public boolean areContentsTheSame(
             @NonNull User oldUser, @NonNull User newUser) {
         // NOTE: if you use equals, your object must properly override 
Object#equals()
         // Incorrectly returning false here will result in too many animations.
         return oldUser.equals(newUser);
     }
  }
}

总而言之,

你道中的第 1 步:

 public abstract LiveData<List<User>> usersByLastName();

您的 ViewModel 中的第 2 步:

public final LiveData<List<User>> usersList;
usersList = userDao.usersByLastName();

最后在您的 Activity/Fragment 中:

 UserAdapter<User> adapter = new UserAdapter();
 viewModel.usersList.observe(this, list -> adapter.submitList(list));
 recyclerView.setAdapter(adapter);

试试这个通用架构:

  1. 由于您的 Room-method 具有可以在 Fragment 生命周期中更改的参数函数 - 在您的 ViewModel 中应该有两个实时数据字段而不是一个。 首先,不可变的 (LiveData) - 您将从存储库中获得结果。 其次,可变的 (MutableLiveData) 应该包含您的日期列表(在您的日历中可见)。然后你应该使用 Transfromation.switchMap 使 MutableLiveData 成为不可变数据的来源。例如,您可以阅读此方法的说明
  2. 您应该从 Fragment 中设置 MutableLiveData 的值(您甚至可以在 CustomCalendarView 内部执行此操作,因为它包含对 Fragment 上下文的引用。这意味着它也可以访问 ViewModel)。因此,当您的日历中的当前月份设置或更改时(也许您可以在那里添加一些方法 changeMonth() ?),您应该设置 MutableLiveData 的新值并...等等用于 Room 的 LiveData 响应。
  3. 在你的 Fragment onViewCreated() 你应该观察你的 immutable LiveData 值 并获取它 - 调用你的方法 setupCalendar() CustomCalendarView(因为您可以访问它)并将您房间的给定日期列表放在那里。在开始观察 LiveData 值之前设置 MutableLiveData 的值很重要。要清楚 - 我建议在从 Room 获取价值后更改(设置)您的日历视图。但可能还有其他方式,这取决于个人喜好。
  4. 后续步骤(在您的 CustomCalendarView 中设置适配器列表并在您的视图中绘制圆圈)我想您知道如何实施。

希望能帮到你