How to use Mockito test with recyclerView? - java

In my application I get some data from server and show into RecyslerView.
I can get data and fill adapter and show into RecyclerView, but I want write Test for this with Mockito Test and fill adapter for show into RecyclerView.
I use this link for json : https://api.learn2crack.com/android/jsonandroid/
I write below codes but I don't know how can I write Test for this.
My Activity class :
public class MainActivity extends AppCompatActivity {
private RecyclerView list;
private Context context;
private ApiServices apiServices;
private List<Android> model = new ArrayList<>();
private RecyclerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
apiServices = ApiClient.getClient().create(ApiServices.class);
list = findViewById(R.id.list);
list.setLayoutManager(new LinearLayoutManager(context));
list.setHasFixedSize(true);
adapter = new RecyclerAdapter(model);
list.setAdapter(adapter);
Call<AndroidResponse> call = apiServices.getAndroid();
call.enqueue(new Callback<AndroidResponse>() {
#Override
public void onResponse(Call<AndroidResponse> call, Response<AndroidResponse> response) {
if (response.isSuccessful()) {
if (response.body() != null) {
model.clear();
model.addAll(response.body().getAndroid());
adapter.notifyDataSetChanged();
}
}
}
#Override
public void onFailure(Call<AndroidResponse> call, Throwable t) {
}
});
}
}
My Adapter class :
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private List<Android> model;
public RecyclerAdapter(List<Android> model) {
this.model = model;
}
#NonNull
#Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_list, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerAdapter.ViewHolder holder, int position) {
holder.name.setText(model.get(position).getName());
holder.version.setText(model.get(position).getVer());
holder.api.setText(model.get(position).getApi());
}
#Override
public int getItemCount() {
return model.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView name, version, api;
public ViewHolder(View itemView) {
super(itemView);
name = itemView.findViewById(R.id.rowName);
version = itemView.findViewById(R.id.rowVersion);
api = itemView.findViewById(R.id.rowApi);
}
}
}
My Test class :
#LargeTest
#RunWith(AndroidJUnit4.class)
public class MainActivityTest extends InstrumentationTestCase {
#Rule
public ActivityTestRule<MainActivity> mainActivityTestRule = new ActivityTestRule<>(MainActivity.class, true, false);
private MockWebServer mockWebServer;
#Before
public void setUp() throws Exception {
super.setUp();
mockWebServer = new MockWebServer();
mockWebServer.start();
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
AppConstants.BASE_URL = mockWebServer.url("/").toString();
}
#Test
public void setupAndroidListAdapterTest() throws Exception {
String fileName = "android_list_response.json";
mockWebServer.enqueue(new MockResponse()
.setResponseCode(200)
.setBody(fileName));
Intent intent = new Intent();
mainActivityTestRule.launchActivity(intent);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#After
public void tearDown() throws Exception {
mockWebServer.shutdown();
}
}
I saved above json into asset folder.
I write above codes and when run test show me 1 test pass but not show me any data into recyclerView and adapter!
How can I do it?

Related

Unable to get data from Retrofit when used in for loop

I'm using MVVM and I'm trying to loop over a list of integers that has some IDs for movies genres, I'm using retrofit and I have a function that should return a list of movies based on the id, but it's working for some reason.
I tried to pass the id to the function and it worked, however when I tried to loop over a list of ids to get different results and put them in a RecyclerView it didn't work
MainActivity:
public class MainActivity extends AppCompatActivity {
RecyclerView mMainRecycler;
MoviesViewModel moviesViewModel;
MainRecyclerAdapter mainRecyclerAdapter;
Context context = this;
List<String> genresNames = new ArrayList<>();
List<Integer> genresIds = new ArrayList<>();
List<Movies.Result> listResults = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMainRecycler = findViewById(R.id.main_recycler);
mMainRecycler.setLayoutManager(new LinearLayoutManager(this));
moviesViewModel = new ViewModelProvider(this).get(MoviesViewModel.class);
moviesViewModel.getMoviesGenres();
moviesViewModel.mutableMoviesGenres.observe(this, new Observer<List<MoviesGenres.GenresBean>>() {
#Override
public void onChanged(List<MoviesGenres.GenresBean> genresBeans) {
for (int i = 0; i < genresBeans.size(); i++) {
genresIds.add(genresBeans.get(i).getId());
genresNames.add(genresBeans.get(i).getName());
}
mainRecyclerAdapter.addNames(genresNames);
}
});
for(int i = 0; i < genresIds.size(); i++) {
moviesViewModel.getMovieWithGenre(genresIds.get(i));
}
moviesViewModel.mutableMoviesWithGenre.observe(this, new Observer<List<Movies.Result>>() {
#Override
public void onChanged(List<Movies.Result> results) {
listResults.addAll(results);
mainRecyclerAdapter.addResults(listResults);
}
});
mMainRecycler.setLayoutManager(new LinearLayoutManager(this));
mainRecyclerAdapter = new MainRecyclerAdapter(context, genresNames, listResults);
mMainRecycler.setAdapter(mainRecyclerAdapter);
}
}
ViewModel:
public class MoviesViewModel extends ViewModel {
public MutableLiveData<List<Movies.Result>> mutablePopularMovies = new MutableLiveData<>();
public void getPopular(){
MoviesClient.getInstance().getPopular().enqueue(new Callback<Movies>() {
#Override
public void onResponse(#NonNull Call<Movies> call, #NonNull Response<Movies> response) {
if(response.isSuccessful() && response.body() != null) {
mutablePopularMovies.setValue(response.body().getResults());
}
}
#Override
public void onFailure(#NonNull Call<Movies> call, #NonNull Throwable t) {
t.printStackTrace();
}
});
}
public MutableLiveData<List<Movies.Result>> mutableMoviesWithGenre = new MutableLiveData<>();
public void getMovieWithGenre(int i){
MoviesClient.getInstance().getMoviesWithGenre(i).enqueue(new Callback<Movies>() {
#Override
public void onResponse(#NonNull Call<Movies> call, #NonNull Response<Movies> response) {
if(response.isSuccessful() && response.body() != null) {
mutableMoviesWithGenre.setValue(response.body().getResults());
}
}
#Override
public void onFailure(#NonNull Call<Movies> call, #NonNull Throwable t) {
t.printStackTrace();
}
});
}
public MutableLiveData<List<MoviesGenres.GenresBean>> mutableMoviesGenres = new MutableLiveData<>();
public void getMoviesGenres() {
MoviesClient.getInstance().getMoviesByGenre().enqueue(new Callback<MoviesGenres>() {
#Override
public void onResponse(#NonNull Call<MoviesGenres> call, #NonNull Response<MoviesGenres> response) {
if(response.isSuccessful() && response.body() != null) {
mutableMoviesGenres.setValue(response.body().getGenres());
}
}
#Override
public void onFailure(#NonNull Call<MoviesGenres> call, #NonNull Throwable t) {
t.printStackTrace();
}
});
}
}
MainRecyclerViewAdapter:
public class MainRecyclerAdapter extends RecyclerView.Adapter<MainRecyclerAdapter.MainViewHolder> {
private Context mContext;
private List<Movies.Result> moviesResults;
private List<String> moviesNames;
public MainRecyclerAdapter(Context context, List<String> moviesNames, List<Movies.Result> moviesResults) {
this.mContext = context;
this.moviesNames = moviesNames;
this.moviesResults = moviesResults;
}
#NonNull
#Override
public MainRecyclerAdapter.MainViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new MainViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.category_rv_item, parent, false));
}
#Override
public void onBindViewHolder(#NonNull final MainRecyclerAdapter.MainViewHolder holder, int position) {
holder.genresTv.setText(moviesNames.get(position));
setCatItemRecycler(holder.mRecycler, moviesResults);
}
#Override
public int getItemCount() {
return moviesNames.size();
}
public void addNames(List<String> moviesGenres) {
moviesNames.addAll(moviesGenres);
notifyDataSetChanged();
}
public void addResults(List<Movies.Result> listResults) {
moviesResults.addAll(listResults);
notifyDataSetChanged();
}
public class MainViewHolder extends RecyclerView.ViewHolder {
TextView genresTv;
RecyclerView mRecycler;
public MainViewHolder(#NonNull View itemView) {
super(itemView);
genresTv = itemView.findViewById(R.id.cat_title);
mRecycler = itemView.findViewById(R.id.item_recycler);
}
}
private void setCatItemRecycler(RecyclerView recyclerView, List<Movies.Result> moviesResults){
MovieAdapter movieAdapter = new MovieAdapter(mContext, moviesResults);
recyclerView.setLayoutManager(new LinearLayoutManager(mContext, RecyclerView.HORIZONTAL, false));
recyclerView.setAdapter(movieAdapter);
}
}
Chile (inner) RecyclerView:
public class MovieAdapter extends RecyclerView.Adapter<MovieAdapter.MovieViewHolder> {
private List<Movies.Result> moviesResult;
private Context mContext;
public MovieAdapter(Context context, List<Movies.Result> moviesResult) {
this.moviesResult = moviesResult;
this.mContext = context;
}
#NonNull
#Override
public MovieAdapter.MovieViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new MovieViewHolder(LayoutInflater.from(mContext).inflate(R.layout.movie_item, parent, false));
}
#Override
public void onBindViewHolder(#NonNull MovieAdapter.MovieViewHolder holder, int position) {
String imageUrl = MoviesClient.IMAGE_URL + moviesResult.get(position).getPosterPath();
Glide.with(holder.mPosterImage.getContext()).load(imageUrl).into(holder.mPosterImage);
}
#Override
public int getItemCount() {
return moviesResult.size();
}
public class MovieViewHolder extends RecyclerView.ViewHolder {
ImageView mPosterImage;
public MovieViewHolder(#NonNull View itemView) {
super(itemView);
mPosterImage = itemView.findViewById(R.id.poster_image);
}
}
}
first of all you didn't share the ViewModel class, I thing you may have a problem with the observers, because your listResults will only be updated after the Retrofit returns the result, so when you call mMainRecycler.setAdapter(mainRecyclerAdapter) you are doing it with your empty list.
Another thing that may be causing this is because your data does not know it has returned, so when you use listResults.addAll(results), make sure that inside the adapter you call .notifyDataSetChanged()
A function like this should do the trick (inside the adapter):
public void updateGenres(List<Genres> genres){
listResults.addAll(genres);
this.notifyDataSetChanged();
}

How to fill adapter with mock data in unit test on Android?

In my application I get some data from server and show into RecyclerView.
I can get data and fill adapter and show into RecyclerView, but I want to write Test for this with Mockito Test and fill adapter for show into RecyclerView.
I use this link for json : https://api.learn2crack.com/android/jsonandroid/
I write below codes but I don't know how can I write Test for this.
My Activity class :
public class MainActivity extends AppCompatActivity {
private RecyclerView list;
private Context context;
private ApiServices apiServices;
private List<Android> model = new ArrayList<>();
private RecyclerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
apiServices = ApiClient.getClient().create(ApiServices.class);
list = findViewById(R.id.list);
list.setLayoutManager(new LinearLayoutManager(context));
list.setHasFixedSize(true);
adapter = new RecyclerAdapter(model);
list.setAdapter(adapter);
Call<AndroidResponse> call = apiServices.getAndroid();
call.enqueue(new Callback<AndroidResponse>() {
#Override
public void onResponse(Call<AndroidResponse> call, Response<AndroidResponse> response) {
if (response.isSuccessful()) {
if (response.body() != null) {
model.clear();
model.addAll(response.body().getAndroid());
adapter.notifyDataSetChanged();
}
}
}
#Override
public void onFailure(Call<AndroidResponse> call, Throwable t) {
}
});
}
}
My Adapter class :
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private List<Android> model;
public RecyclerAdapter(List<Android> model) {
this.model = model;
}
#NonNull
#Override
public RecyclerAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_list, parent, false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerAdapter.ViewHolder holder, int position) {
holder.name.setText(model.get(position).getName());
holder.version.setText(model.get(position).getVer());
holder.api.setText(model.get(position).getApi());
}
#Override
public int getItemCount() {
return model.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView name, version, api;
public ViewHolder(View itemView) {
super(itemView);
name = itemView.findViewById(R.id.rowName);
version = itemView.findViewById(R.id.rowVersion);
api = itemView.findViewById(R.id.rowApi);
}
}
}
My Test class :
#RunWith(AndroidJUnit4.class)
public class MainActivityTest extends InstrumentationTestCase {
#Rule
public ActivityTestRule<MainActivity> activityTest = new ActivityTestRule<>(MainActivity.class, true, false);
private MockWebServer mockWebServer;
#Before
public void setUp() throws Exception {
super.setUp();
mockWebServer = new MockWebServer();
mockWebServer.start();
injectInsrumentation(InstrumentationRegistry.getInstrumentation());
AppConstants.BASE_URL = mockWebServer.url("/").toString();
}
#Test
public void setupAndroidListAdapterTest() throws Exception {
}
#After
public void tearDown() throws Exception {
mockWebServer.shutdown();
}
}
I saved above json into asset folder.
I don't know how can I write test into setupAndroidListAdapterTest() for fill adapter and show mock data into recyclerView.
How can I do it?
Mock this Method to fill your Model with fake Data model.addAll(response.body().getAndroid());

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

Network Paging With pagedList in arch library

Android add Paging Library as part of Architecture Component for using the pagination of the resource. I use this example for do it. I write these codes but in my DataSource.Factory I can't return my received DataSource from network. let's see my codes:
PostDataSource:
public class PostDataSource extends PageKeyedDataSource {
private final APIUtils api = RetrofitHelper.getInstance().create(APIUtils.class);
private final String TOKEN = TokenUtil.getCachedAuthToken();
private int page = 1;
private GeneralWebResult<ArrayList<Post>> postList;
#Override
public void loadInitial(#NonNull LoadInitialParams params, #NonNull LoadInitialCallback callback) {
api.getMainPosts("all",10,"new",page,TOKEN).enqueue(new Callback<GeneralWebResult<ArrayList<Post>>>() {
#Override
public void onResponse(Call<GeneralWebResult<ArrayList<Post>>> call, Response<GeneralWebResult<ArrayList<Post>>> response) {
postList = response.body();
callback.onResult(/*return ArrayList<Post> */postList.getResult(),null, ++ page);
Log.e("RESULT",response.code()+" ");
}
#Override
public void onFailure(Call<GeneralWebResult<ArrayList<Post>>> call, Throwable t) {
Log.e("ERROR",t.getLocalizedMessage());
}
});
}
#Override
public void loadBefore(#NonNull LoadParams params, #NonNull LoadCallback callback) {
}
#Override
public void loadAfter(#NonNull LoadParams params, #NonNull LoadCallback callback) {
ArrayList<Post> postList = new ArrayList<>();
api.getMainPosts("all",10,"new",page,TOKEN).enqueue(new Callback<GeneralWebResult<ArrayList<Post>>>() {
#Override
public void onResponse(Call<GeneralWebResult<ArrayList<Post>>> call, Response<GeneralWebResult<ArrayList<Post>>> response) {
postList.addAll(response.body().getResult());
callback.onResult(postList,null);
Log.e("RESULT",response.code()+" ");
}
#Override
public void onFailure(Call<GeneralWebResult<ArrayList<Post>>> call, Throwable t) {
Log.e("ERROR",t.getLocalizedMessage());
}
});
}
}
PostDataSourceFactory:
public class PostDataSourceFactory extends DataSource.Factory {
private PostDataSource dataSource;
#Override
public DataSource create() {
return new PostDataSource();
}
}
PostViewModel:
public class PostViewModel extends ViewModel {
public LiveData<PagedList<Post>> liveDataSource;
public PostViewModel() {
Executor executor = Executors.newFixedThreadPool(5);
PostDataSourceFactory factory = new PostDataSourceFactory(executor);
PagedList.Config config = new PagedList.Config.Builder().setEnablePlaceholders(false)
.setInitialLoadSizeHint(10).setPageSize(10).setPrefetchDistance(4).build();
liveDataSource = (new LivePagedListBuilder(factory,config)).setFetchExecutor(executor).build();
//Log.e("LIVE DATA SOURCE", liveDataSource.getValue().get(0).getContent());
}
}
PostAdapter:
public class PostAdapter extends PagedListAdapter<Post, PostAdapter.Holder> {
private PagedList<Post> items;
public void setItems(PagedList<Post> items) {
this.items = items;
}
public class Holder extends RecyclerView.ViewHolder{
TextView content;
Holder(View itemView) {
super(itemView);
content = itemView.findViewById(R.id.item_post_test_content);
}
void bindTo(Post post){
content.setText(post.getContent());
}
}
PostAdapter() {
super(Post.DiffCAllback);
}
#NonNull
#Override
public PostAdapter.Holder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
return new Holder(LayoutInflater.from(parent.getContext()).inflate(R.layout.post_test_item,parent,false));
}
#Override
public void onBindViewHolder(#NonNull PostAdapter.Holder holder, int position) {
holder.bindTo(getItem(position));
}
}
MainActivity:
list = findViewById(R.id.home_list);
list.setLayoutManager(new LinearLayoutManager(this));
PostViewModel viewModel = ViewModelProviders.of(this).get(PostViewModel.class);
PostAdapter adapter = new PostAdapter();
viewModel.liveDataSource.observe(this,items ->{
Log.e("ITEMS SIZE",items.size()+" ");
adapter.setItems(items);
} );
list.setAdapter(adapter);
Where is my mistake? why PostDataSourceFactory return null on create()?
Use a MutableLiveData object to wrap your data source
MutableLiveData is used for notifying your UI when observing any data
When using LivePagedListBuilder it is advisable to use a MutableLiveData as a wrapper for data source
See PagingWithNetworkSample
You also need to update your data source PagedKeyDataSource
public class PostDataSourceFactory extends DataSource.Factory<Integer, Post> {
public MutableLiveData<PostDataSource> datasourceLiveData = new MutableLiveData<>();
public PostDataSourceFactory(
}
#Override
public DataSource<Integer, Post> create() {
PostDataSource dataSource = new PostDataSource();
datasourceLiveData.postValue(dataSource);
return dataSource;
}
}

Cannot call method of RecyclerView adapter from an activity

I am trying to set the data for recycler view to display from an AsyncTask. I am calling the method setdataEntries from the postExecute of inner class AsyncTask. But the android studio is showing me error could not find the method.
Adapter class
public class EntryAdapter extends RecyclerView.Adapter<EntryAdapter.ViewHolder> {
List<UserTuple> entries;
final private itemClickListener mOnClickListener;
public interface itemClickListener{
void onItemClick(UserTuple utuple);
}
public EntryAdapter(itemClickListener clickhandler) {
mOnClickListener = clickhandler;
}
public void setdataEntries(List<UserTuple> Data) {
entries = Data;
notifyDataSetChanged();
}
#Override
public EntryAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.singleusertuple,parent,false);
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(EntryAdapter.ViewHolder holder, int position) {
holder.Username.setText(entries.get(position).getUsername());
holder.Password.setText(entries.get(position).getPassword());
}
#Override
public int getItemCount() {
return entries.size();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView Username;
private TextView Password;
private CardView card;
public ViewHolder(View itemView) {
super(itemView);
Username = itemView.findViewById(R.id.susername);
Password=itemView.findViewById(R.id.pass);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int adapterPosition = getAdapterPosition();
UserTuple ut=new UserTuple(entries.get(adapterPosition).getUsername(),entries.get(adapterPosition).getPassword());
mOnClickListener.onItemClick(ut);
}
}
}
Calling Activity
public class Usertuple extends AppCompatActivity implements EntryAdapter.itemClickListener {
private RecyclerView recyclerView ;
private RecyclerView.Adapter adapater;
private SnapHelper snapHelper;
private List<UserTuple> entries;
private ProgressBar mLoadingIndicator;
private Bundle extras;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_logins);
extras = getIntent().getExtras();
//String site= extras.getString("sitename");
mLoadingIndicator = (ProgressBar) findViewById(R.id.pb_loading_indicator);
Log.i("Logins","Size of returned list "+entries.size());
recyclerView = findViewById(R.id.recycleview);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setHasFixedSize(true);
adapater = new EntryAdapter(this);
recyclerView.setAdapter(adapater);
snapHelper= new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
dataView();
}
public void dataView() {
String site= extras.getString("sitename");
recyclerView.setVisibility(View.VISIBLE);
new FetchDataTask().execute(site);
}
#Override
public void onItemClick(UserTuple utuple) {
}
private String key(){
SharedPreferences sharedPref = getSharedPreferences(
"User", this.MODE_PRIVATE);
final String passphrase = sharedPref.getString("userid", "none");
return passphrase;
}
public void showerror(){
recyclerView.setVisibility(View.GONE);
Toast.makeText(this,"Error in retrieving",Toast.LENGTH_SHORT).show();
}
public setdata(List<UserTuple> data){
adapater.setdataEntries(data);
}
public class FetchDataTask extends AsyncTask<String, Void, List<UserTuple>> {
#Override
protected void onPreExecute() {
super.onPreExecute();
mLoadingIndicator.setVisibility(View.VISIBLE);
}
#Override
protected List<UserTuple> doInBackground(String... params) {
/* If there's no zip code, there's nothing to look up. */
if (params.length == 0) {
return null;
}
String site = params[0];
try {
AppDatabase db = Room.databaseBuilder(getApplicationContext(),AppDatabase.class, "production")
.build();
entries =db.entryDao().getSpecific(site);
for(UserTuple ut : entries){
Log.i("password",ut.getPassword());
String st = new Decryption().decrypt(ut.getPassword(),key());
Log.i("After decryption",st);
ut.setPassword(st);
}
return entries;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(List<UserTuple> Data) {
mLoadingIndicator.setVisibility(View.INVISIBLE);
if (Data != null) {
adapater.setdataEntries(Data);
} else {
showerror();
}
}
}
}
I want the database calls to be a background task. I don't want the activity to freeze waiting for database calls. Any ideas? Thanks
Declare adapter like
private EntryAdapter adapter;
instead of
private RecyclerView.Adapter adapater;
because RecyclerView.Adapter class does not have any method named setdataEntries but only EntryAdapter class has this method so only the object of type EntryAdapter can call setdataEntries method.
Or you can use down-casting as
((EntryAdapter)adapater).setdataEntries(data);

Categories