【问题标题】:Recylerview blank when using ViewModel in fragment在片段中使用 ViewModel 时 Recyclerview 空白
【发布时间】:2023-02-07 14:42:35
【问题描述】:

在这里,流程首先在屏幕中有三个按钮,它们也是使用回收器视图创建的。视图模型正在传递数据以填充按钮内容,即图像和文本。这工作正常。点击按钮,一个新的屏幕/片段加载,应该显示列表。使用以下方法获取 API 数据:

public class TrackRepository {

    MutableLiveData<TrackData> trackData;
    RestClient restClient;
    SharedPreferences sharedPreferences;


    public TrackRepository() {
        trackData = new MutableLiveData<>();
        this.restClient = new RestClient();
        sharedPreferences = SessionManager.getPreferences();
    
    }

    public void getTrackList(String startDate,String endDate,String searchTest){
    int centerId = ClientInfo.getCenterId(sharedPreferences);
    String auth = ClientInfo.getAuthToken(sharedPreferences);
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("CenterId",centerId);
        jsonObject.addProperty("SearchText",searchTest);
        jsonObject.addProperty("StartDate",startDate);
        jsonObject.addProperty("EndDate",endDate);

        restClient.getEndpoints().getTrackReports(auth,jsonObject).enqueue(new Callback<TrackData>() {
            @Override
            public void onResponse(Call<TrackData> call, Response<TrackData> response) {
                if (response.isSuccessful()){
                    boolean success = response.body().isSuccess();
                    String message = response.body().getMessage();
                    try {
                        if (success) {
                            trackData.postValue(response.body());
                        }else {
                            trackData.postValue(response.body());
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }

            @Override
            public void onFailure(Call<TrackData> call, Throwable t) {
                trackData.postValue(null);

            }
        });

    }

    public LiveData<TrackData> getTrackDataMutableLiveData() {
        return trackData;
    }
}

在此之后,追踪Home​​ViewModel创建后由片段 TrackHome 和 TrackScreen 使用,如下所示

public class TrackHomeViewModel extends ViewModel {

    ArrayList<String> btName;//button text
    ArrayList<Integer> btImage; //button image
    int FLAG;
    SimpleDateFormat inFormat;
    private TrackRepository trackRepository;
    List<TrackData> trackList;
    LiveData<TrackData> track;
 
    public TrackHomeViewModel() {
            btName = new ArrayList<>();
            this.btName.add("Previous Day");
            this.btName.add("Previous Three Days");

            btImage = new ArrayList<>();
            this.btImage.add(R.drawable.ic_baseline_calendar_today_24);
            this.btImage.add(R.drawable.ic_baseline_calendar_view_day_24);
            trackRepository = new TrackRepository();
            track = trackRepository.getTrackDataMutableLiveData();

        }

        public void captureCardClick(int adapterPosition) {
            String selectedChoice;
            String searchTest,startDate,endDate;

            SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
            inFormat = new SimpleDateFormat("HH:mm:ss", Locale.US);
            Calendar cal = Calendar.getInstance();

            selectedChoice = btName.get(adapterPosition);

            if (selectedChoice.equals("Previous Day")) {
                FLAG = 1;
                searchTest = "";
                endDate = dateFormatter.format(cal.getTime()); // get current date
                cal.add(Calendar.DATE, -1); //ONE day before of current date
                startDate = dateFormatter.format(cal.getTime()); // get PREVIOUS date
                //   int centerId = ClientInfo.getCenterId(preferences);
                getTrackList(startDate,endDate,searchTest);
            }else if(selectedChoice.equals("Previous Three Days")){
                FLAG = 2;
                searchTest = "";
                endDate = dateFormatter.format(cal.getTime()); // get current date
                cal.add(Calendar.DATE, -3); //Three day before of current date
                startDate = dateFormatter.format(cal.getTime()); // get PREVIOUS date
                //   int centerId = ClientInfo.getCenterId(preferences);
                getTrackList(startDate,endDate,searchTest);
            }
        }

        public void getTrackList(String startDate,String endDate,String searchTest) {
            trackRepository.getTrackList(startDate, endDate, searchTest);
         }

    public LiveData<TrackData> getTrackLiveData() {
  
        return track;
    }
}

在里面轨迹屏片段,像下面这样加载 RecyclerView:

public class TrackScreen extends Fragment {

    private TrackHomeViewModel trackHomeViewModel;
    RecyclerView recyclerView;
    TrackAdapter trackAdapter;
    LinearLayoutManager linearLayoutManager;
    Fragment trackHome;
    SearchView searchView;
    List<TrackData> trackDataList;
    TextView currentFragment;
    MaterialToolbar toolbar;
    ImageButton back;
    TrackInterface trackInterface;
    TrackData trackD;

    public static TrackScreen newInstance() {
        return new TrackScreen();
    }
  
    @Override
    public void onCreate(@Nullable Bundle saveInstanceState) {

        super.onCreate(saveInstanceState);
        trackHomeViewModel = new ViewModelProvider(this).get(TrackHomeViewModel.class);
        trackHomeViewModel.getTrackLiveData().observe(this, new Observer<TrackData>() {
            @Override
            public void onChanged(TrackData trackData) {
                trackD = trackData;
            }
        });

        trackInterface = new TrackInterface() {
            @Override
            public void captureRowClick(TrackData trackData, int adapterPosition) {
                String patId = trackData.getPatientId();
                Toast.makeText(getContext(), "Patient ID is " + patId, Toast.LENGTH_SHORT).show();
            }
        };


    }


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

   
        toolbar = view.findViewById(R.id.toolbar);
        searchView = view.findViewById(R.id.search_report);
        recyclerView = view.findViewById(R.id.track_recycler);
        currentFragment = view.findViewById(R.id.current_fragment);
        currentFragment.setText("Reports");
        back = view.findViewById(R.id.back_screen);
      
        trackHome = getParentFragmentManager().findFragmentByTag("TrackHome");
      
        linearLayoutManager = new LinearLayoutManager(getContext());
        recyclerView.setLayoutManager(linearLayoutManager);
        if(trackAdapter==null) {
        trackHomeViewModel.getTrackLiveData().observe(getViewLifecycleOwner(), new Observer<TrackData>() {
            @Override
            public void onChanged(TrackData trackData) {
                trackAdapter = new TrackAdapter(getContext(),trackData.getTrackData(),trackInterface);
                }
             });

                    recyclerView.setAdapter(trackAdapter);
                }else{
                    Toast.makeText(getContext(), "No Data Found", Toast.LENGTH_SHORT).show();
                }
     // other code
    }
}

数据从 API 加载,但 TrackScreen 显示空白屏幕E/RecyclerView:没有连接适配器;跳过布局消息,我测试了所有其他东西仍然是相同的消息。问题是当 TrackScreen 片段加载时列表为空,并且在执行 getTrackLiveData() 方法后加载 API 数据,因此加载列表为空,因此出现此消息。我不知道如何解决这个问题。

单击按钮时,它应该加载带有列表的 TrackScreen 片段。试过如上。

【问题讨论】:

    标签: android android-recyclerview android-adapter android-viewmodel


    【解决方案1】:

    你需要移动

    recyclerView.setAdapter(trackAdapter);
    

    里面

    public void onChanged(TrackData trackData) {
        ...
    }
    

    现在,当您将它设置为 recyclerView 时,trackAdapter 字段为空,因为 onChanged 是异步调用的。

    【讨论】:

    • 我做了同样的空白屏幕和同样的信息
    【解决方案2】:

    解决

    问题是对两个片段使用相同的视图模型。当对两个片段使用单个模型时,应该是

    viewModel = new ViewModelProvider(requireActivity()).get(ListViewModel.class);
    

    初始化视图模型时未获取生命周期所有者。

    之后,浪费时间转向 Android 官方文档并在这里找到这个Communicating with fragments

    因为,我使用的是trackHomeViewModel = new ViewModelProvider(this).get(TrackHomeViewModel.class);从视图模型中检索列表的代码没有执行(存储库代码运行将数据传递给视图模型,但不传递给此处的下一个片段 TrackScreen)因此列表为空。使用 Log.d 发现 trackData 为空。更改为 requireActivity() 并解决所有问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多