ViewModel 未在 Fragment 的第一个 onCreateView 上检索数据

ViewModel not retrieving data on Fragment´s first onCreateView

我正在尝试从我的 SQLite 数据库中检索警报列表。当我第一次进入 Fragment 时,列表未检索,但如果我退出 Fragment 并再次输入,它确实会正确检索。

片段是包含 3 个片段的 Activity(主Activity)的一部分。用户可以通过单击选项卡 (TabLayout) 在 Fragment 之间移动。 第一个片段使用相同的方法来检索列表。第一个片段用于创建警报列表。 创建的警报将在选定的工作日(所有星期一、星期二等)重复,然后是第二个,最后是第三个片段。最后一个用于显示 CalendarView

上的警报

如何让它在第三个片段中第一次尝试检索数据?

public class TabFragmentCalendar extends Fragment {
    private View view;
    private List<EventDay> events = new ArrayList<>();
    private com.applandeo.materialcalendarview.CalendarView calendarView;
    private MyViewModel myViewModel;
    private ArrayList<Alarm> listAlarms = new ArrayList<>();
    private ExecutorService executorService;

    public TabFragmentCalendario() {}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        
        view = inflater.inflate(R.layout.fragment_tab_calendar, container, false);
        
        myViewModel = new ViewModelProvider(this).get(MyViewModel.class);
        myViewModel.getAllAlarms().observe(getViewLifecycleOwner(), new Observer<List<Alarm>>() {
            @Override
            public void onChanged(List<Alarm> alarms) {
                listAlarms = (ArrayList<Alarm>) alarms;
            }
        });

        for(Alarm alarm : listAlarms){
            Log.d("FragmentCalendar", "Alarm = " + alarm.getHour() + ":" + alarm.getMinute());
        } // To check if the alarms are retrieved

        
        calendarView = view.findViewById(R.id.calendarView);
        executorService = Executors.newSingleThreadExecutor();
        executorService.execute(new DisplayEvents(calendarView, events, listAlarms));
        
        return view;

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //popularCalendario.interrupt();
        executorService.shutdown();
    }

如您所见,我创建了一个新线程以在 CalendarView 中显示警报。 创建闹钟以在选定的工作日(所有星期一)重复。

这是该线程的代码。

public class DisplayEvents implements Runnable {
    private final List<EventDay> events;
    private final CalendarView calendarView;
    private final ArrayList<Alarm> listAlarms;

    public DisplayEventos(CalendarView calendarView, List<EventDay> events, ArrayList<Alarm> listAlarms) {
        this.calendarView = calendarView;
        this.events = events;
        this.listAlarms = listAlarms;
    }

    @Override
    public void run() {
        for (Alarm alarm : listAlarms) {
            for (int j = 0; j < 12; j++) {
                if (alarma.getMonday()) {
                    for (int i = 1; i <= 5; i++) {
                        Calendar calendar = Calendar.getInstance();
                        calendar.set(Calendar.MONTH, j);
                        calendar.set(Calendar.DAY_OF_WEEK, 2);
                        calendar.set(Calendar.WEEK_OF_MONTH, i);
                        events.add(new EventDay(calendar, R.drawable.ic_alarm));
                    }
                }
                if (alarm.getTuesday()) {
                    for (int i = 1; i <= 5; i++) {
                        Calendar calendar = Calendar.getInstance();
                        calendar.set(Calendar.MONTH, j);
                        calendar.set(Calendar.DAY_OF_WEEK, 3);
                        calendar.set(Calendar.WEEK_OF_MONTH, i);
                        events.add(new EventDay(calendar, R.drawable.ic_alarm));
                    }
                }
                if (alarma.getWednesday()) {
                    for (int i = 1; i <= 5; i++) {
                        Calendar calendar = Calendar.getInstance();
                        calendar.set(Calendar.MONTH, j);
                        calendar.set(Calendar.DAY_OF_WEEK, 4);
                        calendar.set(Calendar.WEEK_OF_MONTH, i);
                        events.add(new EventDay(calendar, R.drawable.ic_alarm));
                    }
                }
                if (alarma.getThursday()) {
                    for (int i = 1; i <= 5; i++) {
                        Calendar calendar = Calendar.getInstance();
                        calendar.set(Calendar.MONTH, j);
                        calendar.set(Calendar.DAY_OF_WEEK, 5);
                        calendar.set(Calendar.WEEK_OF_MONTH, i);
                        events.add(new EventDay(calendar, R.drawable.ic_alarm));
                    }
                }
                if (alarma.getFriday()) {
                    for (int i = 1; i <= 5; i++) {
                        Calendar calendar = Calendar.getInstance();
                        calendar.set(Calendar.MONTH, j);
                        calendar.set(Calendar.DAY_OF_WEEK, 6);
                        calendar.set(Calendar.WEEK_OF_MONTH, i);
                        events.add(new EventDay(calendar, R.drawable.ic_alarm));
                    }
                }
                if (alarma.getSaturday()) {
                    for (int i = 1; i <= 5; i++) {
                        Calendar calendar = Calendar.getInstance();
                        calendar.set(Calendar.MONTH, j);
                        calendar.set(Calendar.DAY_OF_WEEK, 7);
                        calendar.set(Calendar.WEEK_OF_MONTH, i);
                        events.add(new EventDay(calendar, R.drawable.ic_alarm));
                    }
                }
                if (alarma.getSunday()) {
                    for (int i = 1; i <= 5; i++) {
                        Calendar calendar = Calendar.getInstance();
                        calendar.set(Calendar.MONTH, j);
                        calendar.set(Calendar.DAY_OF_WEEK, 1);
                        calendar.set(Calendar.WEEK_OF_MONTH, i);
                        events.add(new EventDay(calendar, R.drawable.ic_alarm));
                    }
                }
            }
        }
        
        calendarView.post(new Runnable() {
            @Override
            public void run() {
                calendarView.setEvents(events);
            }
        });
    }
}

Android Studio 表示:

I/Choreographer: Skipped 89 frames! The application may be doing too much work on its main thread.

我是这个世界的新手,我知道我犯了很多错误。欢迎任何建议:)

当你打电话时

 myViewModel.getAllAlarms().observe(getViewLifecycleOwner(), new Observer<List<Alarm>>() {
            @Override
            public void onChanged(List<Alarm> alarms) {
                listAlarms = (ArrayList<Alarm>) alarms;
            }
        });

特别是 myViewModel.getAllAlarms(),它 return 是您正在观察的 return 东西,但它不会 return 数据 立即。您唯一可以访问该数据的地方是 onChanged

  @Override
  public void onChanged(List<Alarm> alarms) {
  //here, we actually do have data, so do whatever you want here (probably should do a null check, just in case)

  executorService.execute(new DisplayEvents(calendarView, events, listAlarms));
                }

所以当你打电话时 :

 executorService.execute(new DisplayEvents(calendarView, events, listAlarms));

您的列表还没有数据。

像这样更改您的 onCreateView 方法

 @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    
    view = inflater.inflate(R.layout.fragment_tab_calendar, container, false);

    calendarView = view.findViewById(R.id.calendarView);
    executorService = Executors.newSingleThreadExecutor();

    myViewModel = new ViewModelProvider(this).get(MyViewModel.class);
    myViewModel.getAllAlarms().observe(getViewLifecycleOwner(), new Observer<List<Alarm>>() {
        @Override
        public void onChanged(List<Alarm> alarms) {
            listAlarms = (ArrayList<Alarm>) alarms;
           executorService.execute(new DisplayEvents(calendarView, events, listAlarms));
        }
    });

    for(Alarm alarm : listAlarms){
        Log.d("FragmentCalendar", "Alarm = " + alarm.getHour() + ":" + alarm.getMinute());
    } // To check if the alarms are retrieved

    
    
    
    
    
    return view;

}

因为在你的代码中 executorService.execute(new DisplayEvents(calendarView, events, listAlarms));在 onChanged 方法之前被调用 return 报警列表