【问题标题】:Viewmodel shows empty recyclerview when activity rotated活动旋转时,Viewmodel 显示空的回收站视图
【发布时间】:2018-11-18 19:06:33
【问题描述】:

我对 Android 架构组件非常陌生,并且一直在尝试从我的服务器存储数据的空间。问题是回收站视图上没有立即显示数据。在我的 recyclerview 上方有一个 searchview(没有实现逻辑),当我单击 searchview 进行输入时,recyclerview 会显示所有应该早先显示的数据。

餐厅适配器:

public class RestaurantsAdapter extends RecyclerView.Adapter<RestaurantsAdapter.MyViewHolder> {

private List<Restaurant> data;
private Context context;
private LayoutInflater layoutInflater;
private final Random r = new Random();

public RestaurantsAdapter(Context context) {
    this.data = new ArrayList<>();
    this.context = context;
    this.layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

@Override
public RestaurantsAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_restaurant, parent, false);
    return new RestaurantsAdapter.MyViewHolder(view);
}

@Override
public void onBindViewHolder(@NonNull RestaurantsAdapter.MyViewHolder holder, int position) {
    holder.rName.setText(data.get(position).getName());
}

public void setData(List<Restaurant> newData) {
    if (data != null) {
        RestaurantDiffCallback restaurantDiffCallback = new RestaurantDiffCallback(data, newData);
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(restaurantDiffCallback);

        data.clear();
        data.addAll(newData);
        diffResult.dispatchUpdatesTo(this);
    } else {
        // first initialization
        data = newData;
    }
}

@Override
public int getItemCount() {
    return data.size();
}

public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    TextView rName;

    public MyViewHolder(View itemView) {
        super(itemView);
        rName = (TextView) itemView.findViewById(R.id.restaurant_name);
        itemView.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
    }
}

class RestaurantDiffCallback extends DiffUtil.Callback {

    private final List<Restaurant> oldRestaurants, newRestaurants;

    public RestaurantDiffCallback(List<Restaurant> oldPosts, List<Restaurant> newPosts) {
        this.oldRestaurants = oldPosts;
        this.newRestaurants = newPosts;
    }

    @Override
    public int getOldListSize() {
        return oldRestaurants.size();
    }

    @Override
    public int getNewListSize() {
        return newRestaurants.size();
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return oldRestaurants.get(oldItemPosition).getIdentifier().equals(newRestaurants.get(newItemPosition).getIdentifier());
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        return oldRestaurants.get(oldItemPosition).equals(newRestaurants.get(newItemPosition));
    }
}}

主活动:

public class MainActivity extends AppCompatActivity {
private RestaurantsAdapter restaurantsAdapter;
private RestaurantViewModel restaurantViewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

restaurantsAdapter = new RestaurantsAdapter(this);

restaurantViewModel = ViewModelProviders.of(this).get(RestaurantViewModel.class);
restaurantViewModel.getAllRestaurants().observe(this, restaurants -> restaurantsAdapter.setData(restaurants));

RecyclerView recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(restaurantsAdapter);
 }}

视图模型:

public class RestaurantViewModel extends AndroidViewModel {
private RestaurantDao restaurantDao;
private ExecutorService executorService;
private ApiInterface webService;

public RestaurantViewModel(@NonNull Application application) {
    super(application);
    restaurantDao = RestaurantsDatabase.getInstance(application).restaurantDao();
    executorService = Executors.newSingleThreadExecutor();
    webService = ApiClient.getApiClient().create(ApiInterface.class);
}

LiveData<List<Restaurant>> getAllRestaurants() {
    refreshUser();
    return restaurantDao.findAll();
}

private void refreshUser() {
    executorService.execute(() -> {

    int numOfRestaurants = restaurantDao.totalRestaurants();

    if (numOfRestaurants < 30) {
        Call<RestaurantsModel> call = webService.getRestaurants();
        call.enqueue(new Callback<RestaurantsModel>() {
            @Override
            public void onResponse(@NonNull Call<RestaurantsModel> call, @NonNull Response<RestaurantsModel> response) {
                restaurantDao.saveAll(response.body().getData().getData());
            }

            @Override
            public void onFailure(@NonNull Call<RestaurantsModel> call, @NonNull Throwable t) {
            }
        });
    }
});
}}

【问题讨论】:

    标签: java android viewmodel android-recyclerview


    【解决方案1】:

    如果您不使用 DiffUtil 及其 diffResult.dispatchUpdatesTo(this);你应该做 notifyDataSetChanged()。在您的情况下,在 RestaurantsAdapter.setData 添加一行:

    // first initialization
    data = newData;
    notifyDataSetChanged();
    

    【讨论】:

    • 它现在可以工作,但是当我将屏幕更改为横向时,它又是空白的。
    【解决方案2】:

    您的setData 方法有问题:

    public void setData(List<Restaurant> newData) {
        if (data != null) {
            RestaurantDiffCallback restaurantDiffCallback = new RestaurantDiffCallback(data, newData);
            DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(restaurantDiffCallback);
    
            data.clear();
            data.addAll(newData);
            diffResult.dispatchUpdatesTo(this);
        } else {
            // first initialization
            data = newData;
        }
    }
    

    当您的 newDatanull 时,您更改适配器的数据源,但您不调用 notifyDataSetChanged

    这样您在屏幕上看到的数据将不会更新。


    所以为了修复它:

    public void setData(List<Restaurant> newData) {
        if (data != null) {
            RestaurantDiffCallback restaurantDiffCallback = new RestaurantDiffCallback(data, newData);
            DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(restaurantDiffCallback);
    
            data.clear();
            data.addAll(newData);
            diffResult.dispatchUpdatesTo(this);
        } else {
            // first initialization
            data = newData;
            notifyDataSetChanged();
        }
    }
    

    另一件事,如果不是一个很好的做法,将您的适配器数据集设置为空。所以我的建议是将您的数据设置为空列表而不是 null:

    data = new ArrayList<>();
    

    【讨论】:

    • 它现在可以工作了,感谢您的建议,但是当我将屏幕更改为横向时,它又是空白的。
    【解决方案3】:

    问题:您错误地使用了 ViewModel。您只是从 ViewModel 返回数据,但绝不会在 ViewModel 中保存数据

    首先阅读 ViewModel 的工作原理:https://developer.android.com/topic/libraries/architecture/viewmodel

    【讨论】:

    • 感谢您的反馈。我没有遇到改造问题。您能否指出如何解决这个问题“但从不在 ViewModel 中保存数据”?
    猜你喜欢
    • 1970-01-01
    • 2020-09-11
    • 1970-01-01
    • 2015-02-26
    • 1970-01-01
    • 2013-06-20
    • 2018-07-07
    相关资源
    最近更新 更多