当前位置: 首页 > 知识库问答 >
问题:

如何观察LiveData,然后将这些数据传递给适配器?

许沛
2023-03-14

我有一个日历。要创建这个,我有一个日历片段,它打开了自定义日历视图

(扩展LinearLayout的类)。

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

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

我在我的道类中有一个查询:Log_Entries_Dao,它被传递到LogEntriesRepository,然后传递到LogEntriesViewModel

查询:

@Query(“从log_entries_table中选择日期,其中log_entries_table.date=:date”)LiveData

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

现在,我想在我的setupCalendar方法中观察这个LiveData,并向我的gridAdater类中显示日志项的日期列表,这样我就可以在所有显示日志项的单元格中添加圆圈。

问题是,我认为在CustomCalendarView(LinearLayout类)中使用我的LogViewModel类是不好的做法。如何正确地查询我的数据库、观察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;
    }

}


共有2个答案

张绍晖
2023-03-14

我希望如果你理解这一点并应用到你的代码中,如果我没有错的话,这将解决你的问题。我没有通读您的所有代码,但我得到了您的查询,即“如何将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);
     }
  }
}

在摘要中,

在Dao中的第一步:

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

在ViewModel中执行第2步:

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);
薄龙光
2023-03-14

尝试以下通用模式:

  1. 由于您的Room方法具有可以在片段生命周期中更改的参数的功能,因此ViewModel中应该有两个活动数据字段,而不是一个。首先,不可变(LiveData)——您将从存储库中获得结果。第二,mutable(MutableLiveData)应该包含日期列表(在日历中可见)。那么你应该使用转印术。switchMap使MutableLiveData成为不可变数据的源。举例来说,你可以在这个答案中阅读这个方法的解释

我希望能有所帮助

 类似资料:
  • 此外,为什么Viewmodel不能观察到它自己的LiveData的变化?

  • 使用RxJS如何在观察者上传递新属性?所以基本上我希望道具“customProp”可以被观察到 添加更多的信息-所以基本上,我试图创建一个冷可观察的,其中制片人需要一个道具,应该来自订户 添加用法信息--coldObservable是DB连接函数,customProp是需要在DB上执行的查询

  • 问题是: 使用及其其他功能不是更好吗?

  • 组件具有变量作为观察者: 当

  • 我有一个单独的类来处理数据提取(特别是Firebase),我通常从它返回LiveData对象并异步更新它们。现在我希望将返回的数据存储在ViewModel中,但问题是为了获得所述值,我需要观察从数据提取类返回的LiveData对象。observe方法需要一个LifecycleOwner对象作为第一个参数,但我的ViewModel中显然没有这个对象,而且我知道我不应该在ViewModel中保留对ac