简体   繁体   中英

Viewmodel shows empty recyclerview when activity rotated

I am pretty new to the Android architecture components and have been trying out room for data storage from my server. Problem is no data is being shown on the recycler view IMMEDIATELY. There's a searchview(no logic implemented just there) right above my recyclerview and when I click searchview for input, the recyclerview shows all the data which was supposed to be shown earlier.

RestaurantsAdapter:

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

MainActivity:

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

ViewModel:

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

If you don't use the DiffUtil with its diffResult.dispatchUpdatesTo(this); you should do notifyDataSetChanged(). In your case, in RestaurantsAdapter.setData add one line:

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

You have an issue in your setData method:

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

When your newData is null your change the data source of your adapter, but you don't call notifyDataSetChanged .

This way the data that you are seeing on the screen will not be updated.


So in order to fix it:

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

Another thing, if not a very good practice setting your adapter dataset has null. So my suggestion is to set your data as an empty list instead of null:

data = new ArrayList<>();

The issue: you're using ViewModels incorrectly. You are only returning data from the ViewModel, but never saving data in the ViewModel

Start by reading how ViewModels work here: https://developer.android.com/topic/libraries/architecture/viewmodel

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM