繁体   English   中英

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

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

我有一个日历 要创建它,我有一个CalendarFragment打开CustomCalendarView

(扩展线性布局的 class)。

然后使用MyGridAdapter (扩展 ArrayAdapter 的类)来构造日历。

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

我在我的 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);

该查询接收日历月的所有日期的列表,然后返回存在 logEntry 的所有日期的列表。

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

问题是,我认为在CustomCalendarView (LinearLayout 类)中使用我的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);

    }
}

我的网格适配器


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);
    }
}

日志条目存储库


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;
        }
    }

}

日志条目视图模型

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;
    }

}

试试这个通用模式:

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

我希望它可以帮助

我希望如果您理解这一点并将其应用于您的代码,如果我没有错,那将解决您的查询。 我没有查看您的所有代码,但我得到了您的查询,即“如何将 Livedata 设置为适配器”,这是解决方案。

您可以在此处与您的参考代码进行比较。

   @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();

第 2 步在您的 ViewModel 中:

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

最后在您的活动/片段中:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM