简体   繁体   English

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

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

I have a Calendar .我有一个日历 To create this I have a CalendarFragment which opens CustomCalendarView要创建它,我有一个CalendarFragment打开CustomCalendarView

(a class which extends LinearLayout). (扩展线性布局的 class)。

This then uses MyGridAdapter (class which extends ArrayAdapter) to construct the calendar.然后使用MyGridAdapter (扩展 ArrayAdapter 的类)来构造日历。

When you click a cell on the calendar, you are taken to a new activity in which you can save a log containing some info (and the date of the cell in the calendar which was clicked).当您单击日历上的单元格时,您将进入一个新活动,您可以在其中保存包含一些信息的日志(以及单击日历中单元格的日期)。

I have a query in my Dao class: Log_Entries_Dao which is passed to LogEntriesRepository and then LogEntriesViewModel .我在我的 Dao class: Log_Entries_Dao中有一个查询,它被传递给LogEntriesRepository然后是LogEntriesViewModel

The Query:查询:

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

The query receives a list of all dates of the calendar month and then returns a list of all the dates in which a logEntry is present.该查询接收日历月的所有日期的列表,然后返回存在 logEntry 的所有日期的列表。

Now i would like to observe this LiveData in my setupCalendar method and pas the list of dates in which a logEntry is present to my gridAdater class so I can add circles to all of the cells in which a logEntry is present.现在我想在我的setupCalendar方法中观察这个 LiveData 并将 logEntry 存在的日期列表传递给我的gridAdater class,这样我就可以向所有存在 logEntry 的单元格添加圆圈。

The trouble is, I believe that it is bad practice to use my LogViewModel class inside CustomCalendarView (LinearLayout class).问题是,我认为在CustomCalendarView (LinearLayout 类)中使用我的LogViewModel class 是不好的做法。 How could correctly query my database, observe the liveData and send this to my adapter from inside my setUpCalendar method?如何正确查询我的数据库、观察 liveData 并将其从我的 setUpCalendar 方法中发送到我的适配器?

Calendar Fragment日历片段

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

CustomCalendarView自定义日历视图


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

}

Try this general schema:试试这个通用模式:

  1. Since you Room-method has function with parameter that could be changed during Fragment lifecycle - in your ViewModel should be two Live-data fields instead of one.由于您的 Room 方法具有 function 的参数,可以在片段生命周期期间更改 - 在您的 ViewModel 中应该是两个实时数据字段而不是一个。 First, immutable (LiveData) - you'll get result there from your repository.首先,不可变 (LiveData) - 您将从存储库中获得结果。 Second, mutable (MutableLiveData) should hold list of your dates (that are visible one your calendar).其次,可变的 (MutableLiveData)应该包含您的日期列表(在您的日历中可见)。 Then you should use Transfromation.switchMap to make MutableLiveData to be a source for immutable one.然后您应该使用Transfromation.switchMap使 MutableLiveData 成为不可变数据的来源。 Explanation to this method you can read in this answer for example.例如,您可以在此答案中阅读此方法的说明。
  2. You should set value of your MutableLiveData from your Fragment (you can do it even from inside your CustomCalendarView since it holds the reference to your Fragment's context. That means that it has an access to ViewModel as well).您应该从 Fragment 设置 MutableLiveData 的值(您甚至可以从 CustomCalendarView 内部进行设置,因为它包含对 Fragment 上下文的引用。这意味着它也可以访问 ViewModel)。 So at the moment when current month in your Calendar sets or changes (maybe you can add some method changeMonth() there?), you should set new value of your MutableLiveData and... wait for Room's LiveData response.因此,当日历中的当前月份设置或更改时(也许您可以在那里添加一些方法changeMonth() ?),您应该设置 MutableLiveData 的新值并...等待 Room 的 LiveData 响应。
  3. In your Fragment onViewCreated() you should observe your immutable LiveData value and getting it - to invoke method setupCalendar() of your CustomCalendarView (since you have an access to it) and put there your Room's given dates list.在您的 Fragment onViewCreated() 中,您应该观察您的不可变 LiveData 值并获取它 - 调用您的 CustomCalendarView 的 setupCalendar() 方法(因为您可以访问它)并将您的房间的给定日期列表放在那里。 It is important to set value of MutableLiveData before you start to observe your LiveData value.在开始观察 LiveData 值之前设置 MutableLiveData 的值很重要。 To be clear - I propose to change (setup) your calendar view after getting value from Room.需要明确的是 - 我建议在从 Room 获得价值后更改(设置)您的日历视图。 But there could be other ways, it's a matter of taste.但可能还有其他方法,这是一个品味问题。
  4. Next steps (setting list to adapter inside your CustomCalendarView and drawing circles inside your Views) I think you know how to implement.下一步(在您的 CustomCalendarView 中设置适配器列表并在您的视图中绘制圆圈)我想您知道如何实现。

I hope it can help我希望它可以帮助

I hope if you understand this and apply to your code, That will solve your query if i'm not wrong.我希望如果您理解这一点并将其应用于您的代码,如果我没有错,那将解决您的查询。 i didn't went through all of your code but i get your query which is "How to set Livedata to adapter" and here is the solution for that.我没有查看您的所有代码,但我得到了您的查询,即“如何将 Livedata 设置为适配器”,这是解决方案。

Here the reference code you can compare with yours.您可以在此处与您的参考代码进行比较。

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

In Summary,总之,

Step 1 In your Dao:第 1 步在您的道中:

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

Step 2 In your ViewModel:第 2 步在您的 ViewModel 中:

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

And Finally in your Activity/Fragment:最后在您的活动/片段中:

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

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

相关问题 Android ROOM - 如何观察 LiveData 变化(每次设置日历时)并将 LiveData 列表结果发送到我的适配器? - Android ROOM - How can I Observe LiveData changes (every time my calendar is set-up) and send the LiveData list results to my adapter? 如何从我的片段之一添加数据,并将其传递给我的适配器,并将其设置为我的数组列表? - How can I add data from one of my fragments, and pass it to my adapter, and set it to my array list? 如何在 ViewModel 中观察 LiveData? - How to observe on LiveData in ViewModel? 如何使用接口将数据传回适配器 - How can I pass data back to an adapter using an interface 如何在我的存储库中访问我的 LiveData 模型的值 - How can I access the value of my LiveData model in my respository 如何将数据从 FireBase 检索到我的适配器而不是关键 - How can I retrieve data from FireBase to my adapter not the key 无法观察空数据-具有Livedata的MVVM - Cannot observe null data - MVVM with Livedata 如何观察 ZK 元素的数据属性? - How can I observe data-attributes of ZK elements? 如何将当前数据从适配器传递到适配器? - How to pass current data from Adapter to Adapter? 如何将数据传递到我的片段中以显示我的视图? - How can i pass data into my fragments to my view?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM