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());
Related
There is a holder
public class ClientTivarHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
public TextView texttovarname,texttovarprice;
public RoundedImageView imageTovar;
public CardView cardTovar;
public ItemClickListener itemClickListener;
private Dialog dialog;
private Context context;
public ClientTivarHolder(View itemView){
super(itemView);
texttovarname=itemView.findViewById(R.id.texttovrnme);
texttovarprice=itemView.findViewById(R.id.pricetexttovar);
imageTovar=itemView.findViewById(R.id.tovarImage);
cardTovar=itemView.findViewById(R.id.tovarcard);
}
public void setItemClickListner(ItemClickListener listner){this.itemClickListener=listner;}
#Override
public void onClick(View view){
itemClickListener.onClick(view,getAdapterPosition(),false);
}
}
There is an adapter
public class TovarsAdapter {
private String TovarName,TovarOpisanie,TovarPrice,TovarImage,ShopPhone,ShopUid;
public TovarsAdapter(){
}
public TovarsAdapter(String tovarName, String tovarOpisanie, String tovarPrice, String tovarImage, String shopPhone, String shopUid) {
this. TovarName = tovarName;
this. TovarOpisanie = tovarOpisanie;
this. TovarPrice = tovarPrice;
this. TovarImage = tovarImage;
this. ShopPhone = shopPhone;
this. ShopUid = shopUid;
}
public String getTovarName() {
return TovarName;
}
public void setTovarName(String tovarName) {
TovarName = tovarName;
}
public String getTovarOpisanie() {
return TovarOpisanie;
}
public void setTovarOpisanie(String tovarOpisanie) {
TovarOpisanie = tovarOpisanie;
}
public String getTovarPrice() {
return TovarPrice;
}
public void setTovarPrice(String tovarPrice) {
TovarPrice = tovarPrice;
}
public String getTovarImage() {
return TovarImage;
}
public void setTovarImage(String tovarImage) {
TovarImage = tovarImage;
}
public String getShopPhone() {
return ShopPhone;
}
public void setShopPhone(String shopPhone) {
ShopPhone = shopPhone;
}
public String getShopUid() {
return ShopUid;
}
public void setShopUid(String shopUid) {
ShopUid = shopUid;
}
}
And the interface class ItemClickListener
public interface ItemClickListener {
void onClick(View view, int position, boolean isLongClick);
}
Activate itself where I want to implement it
public class TovarActivity extends AppCompatActivity {
private DatabaseReference tovars;
private RecyclerView recyclerView;
private String uid,srav;
RecyclerView.LayoutManager layoutManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tovar);
layoutManager=new GridLayoutManager(this,2);
Log.d("Uid",getIntent().getExtras().get("ShopUid").toString());
recyclerView=(RecyclerView) findViewById(R.id.tovarrec);
tovars= FirebaseDatabase.getInstance().getReference().child("Tovars");
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
}
#Override
protected void onStart() {
super.onStart();
FirebaseRecyclerOptions<TovarsAdapter> options=new FirebaseRecyclerOptions.Builder<TovarsAdapter>()
.setQuery(tovars.orderByChild("ShopUid").equalTo(getIntent().getExtras().get("ShopUid").toString()),TovarsAdapter.class).build();
FirebaseRecyclerAdapter<TovarsAdapter, ClientTivarHolder> adapter=new FirebaseRecyclerAdapter<TovarsAdapter, ClientTivarHolder>(options) {
#Override
protected void onBindViewHolder( #androidx.annotation.NonNull ClientTivarHolder holder, int position, #androidx.annotation.NonNull TovarsAdapter model) {
holder.texttovarprice.setText(model.getTovarPrice());
holder.texttovarname.setText(model.getTovarOpisanie());
holder.texttovarname.setHint(model.getShopUid());
Transformation transformation=new RoundedTransformationBuilder().borderColor(Color.WHITE).borderWidthDp(3).cornerRadius(12).oval(false).build();
Picasso.get().load(model.getTovarImage()).transform(transformation).into(holder.imageTovar);
}
#Override
public ClientTivarHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.item_tovars,parent,false);
ClientTivarHolder holder=new ClientTivarHolder(view);
return holder;
}
};
recyclerView.setAdapter(adapter);
adapter.startListening();
}
}
Problem: I don’t know how to make a listener on a separate item send a hint from it with a uid to receive certain information in the bottomsheetdialogfragmemt. I tried to make a fragment manager in the holder but it didn't work out. How can I solve my problem?
tried to make fragment manager inside holder but didn't work
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();
}
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
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?
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;
}
}