Retrofit bad request and RecyclerView: No adapter attached; skipping layout - java

Hi I am not sure why exactly my recycler view is not displaying but I get the following error even after initializing it on onCreate method as mentioned by other SO users who faced the same problem:
E/RecyclerView: No adapter attached; skipping layout
Also maybe Retrofit is not able to get the data so onResponse is never called hence onFailure is called. I am using an online JSON API. Link:
https://reqres.in/api/users?page=1&per_page=3
ApiClient.java
public class ApiClient {
public static final String BASE_URL = "https://reqres.in/api/";
public static Retrofit retrofit = null;
public static Retrofit getApiClient(){
if(retrofit == null){
retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create()).build();
}
return retrofit;
}}
DataResponse.java
public class DataResponse {
#SerializedName("page")
private int page;
#SerializedName("per_page")
private int per_page;
#SerializedName("total")
private int total;
#SerializedName("total_pages")
private int total_pages;
#SerializedName("data")
List<Data> data;
public int getPage() {
return page;
}
public int getPer_page() {
return per_page;
}
public int getTotal() {
return total;
}
public int getTotal_pages() {
return total_pages;
}
public List<Data> getData() {
return data;
}
}
class Data {
#SerializedName("id")
private int id;
#SerializedName("first_name")
private String first_name;
#SerializedName("last_name")
private String last_name;
#SerializedName("avatar")
private String avatar;
public int getId() {
return id;
}
public String getFirst_name() {
return first_name;
}
public String getLast_name() {
return last_name;
}
public String getAvatar() {
return avatar;
}
}
ApiInterface
public interface ApiInterface {
#GET("users")
Call<List<DataResponse>> getUsers(#Query("page") int page, #Query("per_page") int per_page);}
RecyclerAdapter.java
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {
private List<Data> dataList;
private Context context;
public RecyclerAdapter(List<Data> dataList, Context context){
this.dataList = dataList;
this.context = context;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Data data = dataList.get(position);
holder.fullname.setText(data.getFirst_name() + ", " + data.getLast_name());
Glide.with(context).load(data.getAvatar()).into(holder.avatar);
}
#Override
public int getItemCount() {
return dataList.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
ImageView avatar;
TextView fullname;
public MyViewHolder(View itemView) {
super(itemView);
avatar = (ImageView) itemView.findViewById(R.id.cardView_image);
fullname = (TextView) itemView.findViewById(R.id.cardView_location);
}
}
public void addData(List<Data> data){
for(Data d: data){
dataList.add(d);
}
}}
MainActivity
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ProgressBar progressBar;
private GridLayoutManager layoutManager;
private RecyclerAdapter adapter;
private ApiInterface apiInterface;
private int page_num = 1;
private int per_page = 3;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
adapter = null;
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
layoutManager = new GridLayoutManager(this, 2);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
progressBar.setVisibility(View.VISIBLE);
Call<List<DataResponse>> call = apiInterface.getUsers(page_num, per_page);
call.enqueue(new Callback<List<DataResponse>>() {
#Override
public void onResponse(Call<List<DataResponse>> call, Response<List<DataResponse>> response) {
Toast.makeText(MainActivity.this, "Response success....", Toast.LENGTH_SHORT).show();
List<Data> data = response.body().get(1).getData();
adapter = new RecyclerAdapter(data, MainActivity.this);
recyclerView.setAdapter(adapter);
Toast.makeText(MainActivity.this, "First page is loaded...", Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.GONE);
}
#Override
public void onFailure(Call<List<DataResponse>> call, Throwable t) {
Toast.makeText(MainActivity.this, "Bad request", Toast.LENGTH_SHORT).show();
}
});
}}
Would highly appreciate any help, thank you.

You are making an array request, convert it to object request(your api endpoint is returning json object). Change the call like this
Call<DataResponse> call = apiInterface.getUsers(page_num, per_page);
call.enqueue(new Callback<DataResponse>() {
#Override
public void onResponse(Call<DataResponse> call, Response<DataResponse> response) {
Toast.makeText(MainActivity.this, "Response success....", Toast.LENGTH_SHORT).show();
List<Data> data = response.body().getData();
adapter = new RecyclerAdapter(data, MainActivity.this);
recyclerView.setAdapter(adapter);
Toast.makeText(MainActivity.this, "First page is loaded...", Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.GONE);
}
#Override
public void onFailure(Call<DataResponse> call, Throwable t) {
Toast.makeText(MainActivity.this, "Bad request", Toast.LENGTH_SHORT).show();
}
});
and api interface should be like this
public interface ApiInterface {
#GET("users")
Call<DataResponse> getUsers(#Query("page") int page,
#Query("per_page") int per_page);
}

Its happen because you request is failed and you are not set adapter for recycler view change it
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;`
private ProgressBar progressBar;
private GridLayoutManager layoutManager;
private RecyclerAdapter adapter;
private ApiInterface apiInterface;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
adapter = null;
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
layoutManager = new GridLayoutManager(this, 2);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
adapter = new RecyclerAdapter(data, MainActivity.this);
recyclerView.setAdapter(adapter);
apiInterface = ApiClient.getApiClient().create(ApiInterface.class);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
progressBar.setVisibility(View.VISIBLE);
Call<List<DataResponse>> call = apiInterface.getUsers(page_num, per_page);
call.enqueue(new Callback<List<DataResponse>>() {
#Override
public void onResponse(Call<List<DataResponse>> call, Response<List<DataResponse>> response) {
Toast.makeText(MainActivity.this, "Response success....", Toast.LENGTH_SHORT).show();
List<Data> data = response.body().get(1).getData();
adapter.notifydatasetchanged()
Toast.makeText(MainActivity.this, "First page is loaded...", Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.GONE);
}
#Override
public void onFailure(Call<List<DataResponse>> call, Throwable t) {
Toast.makeText(MainActivity.this, "Bad request", Toast.LENGTH_SHORT).show();
}
});
}

Related

recyclerView missing error in Android Studio

I'm a beginner programmer and I'm trying to receive data from the server using node.js and display the list on Android Studio but I keep having the following error:
E/RecyclerView: No adapter attached; skipping layout
D/HistoryActivity: HistoryResponse{result=[com.sooryong.loginexample.data.HistoryData#3303f3c, com.sooryong.loginexample.data.HistoryData#33764c5]}
D/AndroidRuntime: Shutting down VM
As you can see, I can't recall my list properly as well and I don't know how to fix it. Here are my codes:
public interface ServiceApi {
#POST("/user/login")
Call<LoginResponse> userLogin(#Body LoginData data);
#POST("/user/join")
Call<JoinResponse> userJoin(#Body JoinData data);
#GET("/test/history")
Call<HistoryResponse> getData();
}
HistoryData.java
public class HistoryData {
#SerializedName("eventID")
private int eventID;
#SerializedName("eventType")
private String eventType;
#SerializedName("eventDate")
private String eventDate;
#SerializedName("userID")
private int userID;
#SerializedName("sensorID")
private String sensorID;
public HistoryData(int eventID, String eventType, String eventDate, int userID, String sensorID) {
super();
this.eventID = eventID;
this.eventType = eventType;
this.eventDate = eventDate;
this.userID = userID;
this.sensorID = sensorID;
}
public int getEventID() {
return eventID;
}
public String getEventType() {
return eventType;
}
public String getEventDate() { return eventDate; }
public int getUserID() {
return userID;
}
public String getSensorID() { return sensorID; }
}
HistoryResponse.java
public class HistoryResponse {
#SerializedName("code")
public String code;
#SerializedName("message")
public String message;
#SerializedName("result")
public List<HistoryData> result;
#Override
public String toString() {
return "HistoryResponse{" + "result=" + result +'}';
}
}
HistoryActivity.java
public class HistoryActivity extends AppCompatActivity {
HistoryResponse dataList;
List<HistoryData> dataInfo;
private RecyclerView recyclerView;
private RecyclerAdapter recyclerAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycler_view);
dataInfo = new ArrayList<>();
recyclerView = findViewById(R.id.recyclerView);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
ServiceApi apiInterface = RetrofitClient.getClient().create(ServiceApi.class);
Call<HistoryResponse> call = apiInterface.getData();
call.enqueue(new Callback<HistoryResponse>() {
#Override
public void onResponse(Call<HistoryResponse> call, Response<HistoryResponse> response) {
dataList = response.body();
Log.d("Response", dataList.toString());
dataInfo = dataList.result;
recyclerAdapter = new RecyclerAdapter(getApplicationContext(), dataInfo);
recyclerView.setAdapter(recyclerAdapter);
}
#Override
public void onFailure(Call<HistoryResponse> call, Throwable t) {
Log.d("Response", t.getMessage());
}
});
}
}
RecyclerAdapter.java
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder>{
private Context c;
private List<HistoryData> dataList;
public RecyclerAdapter(Context c, List<HistoryData> dataList) {
this.c = c;
this.dataList = dataList;
}
#NonNull
#Override
public RecyclerAdapter.MyViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(c).inflate(R.layout.recycler_view, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(#NonNull RecyclerAdapter.MyViewHolder holder, int position) {
holder.id.setText(dataList.get(position).getSensorID());
holder.type.setText("" + dataList.get(position).getEventType());
holder.date.setText("" + dataList.get(position).getEventDate());
}
#Override
public int getItemCount() {
return (dataList == null) ? 0 : dataList.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
TextView id;
TextView type;
TextView date;
public MyViewHolder(#NonNull View itemView) {
super(itemView);
id = (TextView)itemView.findViewById(R.id.sensorID);
type = (TextView)itemView.findViewById(R.id.eventType);
date = (TextView)itemView.findViewById(R.id.eventDate);
}
}
}
I don't think the data is being initialized properly inside the RecyclerAdapter class. Is it because I couldn't load the data properly from the server?
I ever face the same issue similiar to this.
What I've done was: initialize the adapter once only the activity created:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recycler_view);
dataInfo = new ArrayList<>();
initAdapter();
....
}
private void initAdapter() {
//The adapter should create once in onCreate
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext, LinearLayoutManager.VERTICAL, false);
recyclerAdapter = new RecyclerAdapter(getApplicationContext(), dataInfo);
recyclerView.setAdapter(recyclerAdapter);
}
Then when in callback result: you can clear the previous data before reload to the adapter:
call.enqueue(new Callback<HistoryResponse>() {
#Override
public void onResponse(Call<HistoryResponse> call, Response<HistoryResponse> response) {
dataList = response.body();
dataInfo.clear(); // <- here we clear all previous data before reload result to the adapter.
dataInfo = dataList.result;
recyclerAdapter.notifyDataSetChanged()
#Override
public void onFailure(Call<HistoryResponse> call, Throwable t) {
Log.d("Response", t.getMessage());
}
});
Hope this help.

app showing empty white screen on emulator

I am developing sport news android app but when I run app it is showing white screen screenshot of emulator.
below my adapter class
public class ArticleAdapter extends RecyclerView.Adapter {
private List<Article> articles;
public ArticleAdapter(List<Article> articles, SportNews sportNews) {
this.articles = articles;
}
#NonNull
#Override
public CustomViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View itemView = (View) LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.article_list, null);
return new CustomViewHolder(itemView);
}
#Override
public void onBindViewHolder(#NonNull CustomViewHolder customViewHolder, int position) {
Article article = articles.get(position);
customViewHolder.articleAuthor.setText(article.getAuthor());
customViewHolder.articleTitle.setText(article.getTitle());
Picasso.get().load(article.getUrlToImage()).into(customViewHolder.articleImage);
}
#Override
public int getItemCount() {
if(articles == null) return 0;
return articles.size();
}
public class CustomViewHolder extends RecyclerView.ViewHolder {
#BindView(R.id.articleAuthor)
TextView articleAuthor;
#BindView(R.id.articleTitle)
TextView articleTitle;
#BindView(R.id.articleImage)
ImageView articleImage;
public CustomViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
}
}
below Retrofit interface class
public interface SportInterface {
#GET("/v2/top-headlines?sources=bbc-sport&apiKey=d03441ae1be44f9cad8c38a2fa6db215")
Call<SportNews> getArticles();
}
below retrofit client
public class SportClient {
private static final String ROOT_URL = "https://newsapi.org";
/**
* Get Retrofit Instance
*/
private static Retrofit getRetrofitInstance() {
return new Retrofit.Builder()
.baseUrl(ROOT_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
/**
* Get API Service
*
* #return API Service
*/
public static SportInterface getApiService() {
return getRetrofitInstance().create(SportInterface.class);
}
}
below MainActivity.java
public class MainActivity extends AppCompatActivity {
private SportNews sportNews;
private List<Article> articleList;
private ArticleAdapter articleAdapter;
#BindView(R.id.recyclerView)
RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
SportInterface sportInterface = SportClient.getApiService();
Call<SportNews> call = sportInterface.getArticles();
call.enqueue(new Callback<SportNews>() {
#Override
public void onResponse(Call<SportNews> call, Response<SportNews> response) {
sportNews = response.body();
articleAdapter = new ArticleAdapter( articleList, sportNews);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(articleAdapter);
}
#Override
public void onFailure(Call<SportNews> call, Throwable t) {
}
});
}
}
below Model SportNews class
public class SportNews {
#SerializedName("status")
#Expose
private String status;
#SerializedName("totalResults")
#Expose
private Integer totalResults;
#SerializedName("articles")
#Expose
private List<Article> articles = null;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Integer getTotalResults() {
return totalResults;
}
public void setTotalResults(Integer totalResults) {
this.totalResults = totalResults;
}
public List<Article> getArticles() {
return articles;
}
public void setArticles(List<Article> articles) {
this.articles = articles;
}
}
below json response
{
"status": "ok",
"totalResults": 10,
"articles": [
{
"source": {
"id": "bbc-sport",
"name": "BBC Sport"
},
"author": "BBC Sport",
"title": "Gordon Taylor: PFA chief executive set to step down after 38 years",
"description": "Gordon Taylor to announce he will step down as chief executive of the Professional Footballers' Association (PFA) at the end of the season after 38 years.",
"url": "http://www.bbc.co.uk/sport/football/47691299",
"urlToImage": "https://ichef.bbci.co.uk/onesport/cps/624/cpsprodpb/13590/production/_97584297_breaking_news.png",
"publishedAt": "2019-03-27T13:04:18Z",
"content": "Gordon Taylor is set to announce he is standing down as chief executive of the Professional Footballers' Association after 38 years in the role.\r\nIt follows a mutiny from PFA chairman Ben Purkiss and former players over governance issues and controversy over … [+675 chars]"
},
]
}
Hi just copy paste below code because i have edited your MainActivity class where you forgot to add list from sportNews object that you can access in response of api calling.
public class MainActivity extends AppCompatActivity {
private SportNews sportNews;
private List<Article> articleList = new ArrayList<Article>();
private ArticleAdapter articleAdapter;
#BindView(R.id.recyclerView)
RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
SportInterface sportInterface = SportClient.getApiService();
Call<SportNews> call = sportInterface.getArticles();
call.enqueue(new Callback<SportNews>() {
#Override
public void onResponse(Call<SportNews> call, Response<SportNews> response) {
sportNews = response.body();
if(sportNews != null && sportNews.getArticles() != null){
articleList.addAll(sportNews.getArticles());
}
articleAdapter = new ArticleAdapter( articleList, sportNews);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(articleAdapter);
}
#Override
public void onFailure(Call<SportNews> call, Throwable t) {
}
});
}
}
your problem is in that line
articleAdapter = new ArticleAdapter( articleList, sportNews);
should be replaced with this
articleList=sportNews.getArticles();
articleAdapter = new ArticleAdapter( articleList, sportNews);
try this. i think your adapter is wrong.
public class ArticleAdapter extends RecyclerView.Adapter<ArticleAdapter.CustomViewHolder> {

how to set a path param using retrofit

how to get ID position in call retrofit
GET https://api.themoviedb.org/3/movie/{movie_id}/credits?api_key=<>
i need to get position id send to server in loadCast function
and in MovieService that's retrofit call i need send postion id befor credits
i don't know how to do that if any one can help me thanks so much for that <3
//this my call retrofit server
public interface MovieService {
#GET("popular?" + Common.API_KEY + "&language=en-US")
Call<MoviesList> getPopular(#Query("api_key") String api_key);
#GET( ListMovieAdapter.SELECTED_MOVIE +"/credits?" + Common.API_KEY +
"&language=en-US")
Call<MovieCast> getCast(
#Query("api_key") String api_key);
----------------------------------------------------------------
package com.example.android.movie;
/**
* Created by yuyu on 12-Nov-18.
*/
public class MovieDetails extends YouTubeBaseActivity {
Result selectedMovie;
private ArrayList<Cast> cast;
private RecyclerView.LayoutManager mLayoutManager;
private RecyclerView mRecyclerView;
private CastMovieAdapter castMovieAdapter;
private TextView name;
private ImageView imageMovie;
private TextView date;
private TextView rating;
private ArrayList<Result> results;
MovieService mService;
private static final String YT_API_KEY = "###";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.movie_details);
selectedMovie =
getIntent().getParcelableExtra(ListMovieAdapter.SELECTED_MOVIE);
mRecyclerView = (RecyclerView) findViewById(R.id.cast_recycler);
mLayoutManager = new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL, false);
mRecyclerView.setLayoutManager(mLayoutManager);
cast = new ArrayList<>();
castMovieAdapter = new CastMovieAdapter(cast, MovieDetails.this);
mRecyclerView.setAdapter(castMovieAdapter);
results = new ArrayList<>();
mService = Common.getMovieService();
loadTriler();
loadMovies();
loadCast();
}
this function to load movie
private void loadMovies() {
mService.getPopular(Common.API_KEY).enqueue(new Callback<MoviesList>()
{
#Override
public void onResponse(Call<MoviesList> call, Response<MoviesList>
response) {
results.clear();
results.addAll(response.body().getResults());
name = (TextView) findViewById(R.id.name_movie);
rating = (TextView) findViewById(R.id.rating);
date = (TextView) findViewById(R.id.date_det);
imageMovie = (ImageView) findViewById(R.id.imageView);
date.setText(selectedMovie.getReleaseDate());
name.setText(selectedMovie.getTitle());
rating.setText(String.valueOf(selectedMovie.getVoteAverage()));
final String image = Common.IMAGE_LOAD +
selectedMovie.getPosterPath();
Picasso.with(MovieDetails.this)
.load(image)
.into(imageMovie);
}
#Override
public void onFailure(Call<MoviesList> call, Throwable t) {
Log.d("===LoadMovies", "onResponse: " + t);
}
});
}
//i have proplem here in send ID postion
private void loadCast() {
mService.getCast(
ListMovieAdapter.SELECTED_MOVIE+Common.API_KEY).enqueue(new
Callback<MovieCast>() {
#Override
public void onResponse(Call<MovieCast> call, final
Response<MovieCast> response) {
cast.clear();
cast.addAll(response.body().getCast());
mRecyclerView.getAdapter().notifyDataSetChanged();
}
#Override
public void onFailure(Call<MovieCast> call, Throwable t) {
}
});
}
}
package com.example.android.movie.Adapter;
/**
* Created by yuyu on 11-Nov-18.
*/
public class ListMovieAdapter extends
RecyclerView.Adapter<ListMovieAdapter.MyViewHolder> {
private ArrayList<Result> mMovies;
private Context context;
public static final String SELECTED_MOVIE = "selected_movie";
private int lastPosition = -1;
public ListMovieAdapter(ArrayList<Result> mMovies, Context context) {
this.mMovies = mMovies;
this.context = context;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.list_views, parent, false);
return new MyViewHolder(view);
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
//Animation Scroll
Animation animation = AnimationUtils.loadAnimation(context,
(position > lastPosition) ? R.anim.up_from_bottom
: R.anim.down_from_top);
holder.itemView.startAnimation(animation);
lastPosition = position;
holder.nameMovie.setText(mMovies.get(position).getTitle());
final String image = Common.IMAGE_LOAD +
mMovies.get(position).getPosterPath();
Picasso.with(context)
.load(image)
.into(holder.imageMovie);
holder.rating.setText(String.valueOf(
mMovies.get(position).getVoteAverage()));
holder.dateMovie.setText(mMovies.get(position).getReleaseDate());
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onClick(View view, int position) {
Intent intent = new Intent(context, MovieDetails.class);
Result result = mMovies.get(position);
intent.putExtra(SELECTED_MOVIE, result);
context.startActivity(intent);
}
});
}
#Override
public int getItemCount() {
return mMovies.size();
}
class MyViewHolder extends RecyclerView.ViewHolder implements
View.OnClickListener {
ImageView imageMovie;
TextView nameMovie;
TextView rating;
TextView dateMovie;
ItemClickListener itemClickListener;
public MyViewHolder(View itemView) {
super(itemView);
this.imageMovie = (ImageView)
itemView.findViewById(R.id.image_movie);
this.nameMovie = (TextView) itemView.findViewById(R.id.name_movie);
this.rating = (TextView) itemView.findViewById(R.id.rating);
this.dateMovie = (TextView) itemView.findViewById(R.id.date);
itemView.setOnClickListener(this);
}
public void setItemClickListener(ItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
#Override
public void onClick(View v) {
itemClickListener.onClick(v, getAdapterPosition());
}
}
}
From the Retrofit documentation:
URL MANIPULATION A request URL can be updated dynamically using
replacement blocks and parameters on the method. A replacement block
is an alphanumeric string surrounded by { and }. A corresponding
parameter must be annotated with #Path using the same string.
#GET("group/{id}/users")
Call<List<User>> groupList(#Path("id") int groupId);
https://square.github.io/retrofit/

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

RecyclerView OnClick to take to another Fragment

I am stuck with this error for a long time now, I am new to JAVA.
I want to click an item on the RecyclerView (currently on a fragment) that got populated from Firebase. Once I click on it, it should take me to the next fragment by parcing some data and also the position of the item.
Here is my adapter, CustomAdapter.java
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> {
public CustomAdapter(ArrayList<Userpost> data) {
this.data = data;
}
public interface OnItemClickListener{
void onItemClick(Userpost userpost, int activityNumber);
}
private ArrayList<Userpost> data;
private static final int ACTIVITY_NUM = 4;
private OnItemClickListener listener;
public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
TextView textViewName;
TextView textViewVersion;
SquareImageView imageView;
private final Context context;
public View mCardView;
public MyViewHolder(View itemView) {
super(itemView);
context = itemView.getContext();
this.textViewName = (TextView) itemView.findViewById(R.id.textViewName);
this.textViewVersion = (TextView) itemView.findViewById(R.id.textViewVersion);
this.imageView = (SquareImageView) itemView.findViewById(R.id.imageView);
this.mCardView = itemView.findViewById(R.id.card_view);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Toast.makeText(context, "Position is " +getAdapterPosition(),Toast.LENGTH_SHORT).show();
}
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
Log.d(TAG, "MyViewHolder: setting up adapter for profile fragment");
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cards_layout, parent, false);
MyViewHolder myViewHolder = new MyViewHolder(itemView);
return myViewHolder;
}
#Override
public void onBindViewHolder(final MyViewHolder holder, final int Position) {
Log.d(TAG, "onBindViewHolder: setting up adapter for profile fragment");
TextView textViewName = holder.textViewName;
TextView textViewVersion = holder.textViewVersion;
final ImageView imageView = holder.imageView;
textViewName.setText(data.get(Position).getPheading());
textViewVersion.setText(data.get(Position).getDescriptionpost());
Picasso.with(holder.imageView.getContext()).load(data.get(Position).getImage_path()).into(holder.imageView);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(view.getContext(), "Recycle Click" + Position, Toast.LENGTH_SHORT).show();
listener.onItemClick(data.get(Position), ACTIVITY_NUM);
}
});
}
#Override
public int getItemCount() {
return data.size();
}
}
Here's fragment, ProfileFragment.java
public class ProfileFragment extends Fragment {
private static final String TAG = "ProfileFragment";
private static final int ACTIVITY_NUM = 4;
//firebase stuff
private FirebaseAuth mAuth;
private FirebaseAuth.AuthStateListener mAuthListener;
private FirebaseDatabase mFirebaseDatabase;
private DatabaseReference myRef;
private FirebaseMethods mFirebaseMethods;
// Recycler View Widgets
private static RecyclerView.Adapter adapter;
private RecyclerView.LayoutManager layoutManager;
private static RecyclerView recyclerView;
private static ArrayList<Userpost> data;
private static ArrayList<Integer> removedItems;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_profile, container, false);
gridView = (GridView) view.findViewById(R.id.gridView);
recyclerView = (RecyclerView) view.findViewById(R.id.my_recycler_view);
cardView = (CardView) view.findViewById(R.id.card_view);
toolbar = (Toolbar) view.findViewById(R.id.profileToolBar);
bottomNavigationView = (BottomNavigationViewEx) view.findViewById(R.id.bottomNavViewBar);
mContext = getActivity();
mFirebaseMethods = new FirebaseMethods(getActivity());
//Recycler View class
super.onCreate(savedInstanceState);
data = new ArrayList<Userpost>();
recyclerView = (RecyclerView) view.findViewById(R.id.my_recycler_view);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
adapter = new CustomAdapter(data);
recyclerView.setAdapter(adapter);
updateArrayList();
private void updateArrayList() {
Log.d(TAG, "updateArrayList: setting up for profile fragment");
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference
.child(getString(R.string.dbname_user_posts))
.child(FirebaseAuth.getInstance().getCurrentUser().getUid());
query.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Log.d(TAG, "onChildAdded: explore fragment");
data.add(dataSnapshot.getValue(Userpost.class));
adapter.notifyDataSetChanged();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
Userpost model = dataSnapshot.getValue(Userpost.class);
final int index = getItemIndex(model);
data.set(index, model);
adapter.notifyItemChanged(index);
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private int getItemIndex(Userpost user) {
Log.d(TAG, "getItemIndex: setting up for profile fragment");
int index = -1;
for (int i = 0; i < data.size(); i++) {
if (data.get(i).image_path.equals(user.image_path)) {
index = i;
break;
}
}
return index;
}
Userpost.java is the model here.
And here is the logcat:
java.lang.NullPointerException: Attempt to invoke interface method 'void sahhaj.com.myapp.CustomAdapter$OnItemClickListener.onItemClick(myap.com.myapp.models.Userpost, int)' on a null object reference
at sahhaj.com.sahhajapp.CustomAdapter$1.onClick(CustomAdapter.java:112)
at android.view.View.performClick(View.java:5721)
at android.view.View$PerformClick.run(View.java:22620)
Your OnItemClickListener listener attribute is never set, so it is Null.
Check where you initialize it, if ever.
Change your RecyclerView array adapter class constructor like below.
public CustomAdapter(ArrayList<Userpost> data, OnItemClickListener listener) {
this.data = data;
this.listener = listener;
}
And in your Fragment change the RecyclerView array adapter object initializing like below.
adapter = new CustomAdapter(data, new CustomAdapter.OnItemClickListener() {
#Override
public void onItemClick(Userpost userpost, int activityNumber) {
// do whatever you want to do
}
});
And that's it. Now run the code you'll get your desired output.
**Call in Get Api **
implementation "com.android.support:cardview-v7:28.0.0"
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
<uses-permission android:name="android.permission.INTERNET" />
android:usesCleartextTraffic="true"
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:id="#+id/customRecyclerView"
android:layout_height="match_parent"
/>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/coverImage"
android:layout_width="80dp"
android:layout_height="80dp" />
<TextView
android:id="#+id/title"
android:textSize="15dp"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
public interface ApiInterface
{
#GET("/photos")
Call<List<RetroPhoto>> getAllPhotos();
}
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class RestApiClient {
private static Retrofit retrofit;
private static final String BASE_URL = "https://jsonplaceholder.typicode.com";
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
public class RetroPhoto {
#SerializedName("albumId")
private Integer albumId;
#SerializedName("id")
private Integer id;
#SerializedName("title")
private String title;
#SerializedName("url")
private String url;
#SerializedName("thumbnailUrl")
private String thumbnailUrl;
public RetroPhoto(Integer albumId, Integer id, String title, String url, String thumbnailUrl) {
this.albumId = albumId;
this.id = id;
this.title = title;
this.url = url;
this.thumbnailUrl = thumbnailUrl;
}
public Integer getAlbumId() {
return albumId;
}
public void setAlbumId(Integer albumId) {
this.albumId = albumId;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getThumbnailUrl() {
return thumbnailUrl;
}
public void setThumbnailUrl(String thumbnailUrl) {
this.thumbnailUrl = thumbnailUrl;
}
}
private CustomAdapter adapter;
private RecyclerView recyclerView;
ProgressDialog progressDoalog;
progressDoalog = new ProgressDialog(MainActivity.this);
progressDoalog.setMessage("Loading....");
progressDoalog.show();
/*Create handle for the RetrofitInstance interface*/
ApiInterface service = RestApiClient.getRetrofitInstance().create(ApiInterface.class);
Call<List<RetroPhoto>> call = service.getAllPhotos();
call.enqueue(new Callback<List<RetroPhoto>>() {
#Override
public void onResponse(Call<List<RetroPhoto>> call, Response<List<RetroPhoto>> response) {
progressDoalog.dismiss();
generateDataList(response.body());
}
#Override
public void onFailure(Call<List<RetroPhoto>> call, Throwable t) {
progressDoalog.dismiss();
Toast.makeText(MainActivity.this, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
}
});
}
/*Method to generate List of data using RecyclerView with custom adapter*/
private void generateDataList(List<RetroPhoto> photoList) {
recyclerView = findViewById(R.id.customRecyclerView);
adapter = new CustomAdapter(this, photoList);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(MainActivity.this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
}
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Picasso;
import java.util.List;
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.CustomViewHolder> {
private List<RetroPhoto> dataList;
private Context context;
public CustomAdapter(Context context,List<RetroPhoto> dataList){
this.context = context;
this.dataList = dataList;
}
class CustomViewHolder extends RecyclerView.ViewHolder {
public final View mView;
TextView txtTitle;
private ImageView coverImage;
CustomViewHolder(View itemView) {
super(itemView);
mView = itemView;
txtTitle = mView.findViewById(R.id.title);
coverImage = mView.findViewById(R.id.coverImage);
}
}
#Override
public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
View view = layoutInflater.inflate(R.layout.custom_row, parent, false);
return new CustomViewHolder(view);
}
#Override
public void onBindViewHolder(CustomViewHolder holder, int position) {
holder.txtTitle.setText(dataList.get(position).getTitle());
Picasso.get().load(dataList.get(position).getThumbnailUrl()).into(holder.coverImage);
// Picasso.Builder builder = new Picasso.Builder(context);
// builder.downloader(new OkHttp3Downloader(context));
// builder.build().load(dataList.get(position).getThumbnailUrl())
// .placeholder((R.drawable.ic_launcher_background))
// .error(R.drawable.ic_launcher_background)
// .into(holder.coverImage);
}
#Override
public int getItemCount() {
return dataList.size();
}
}

Categories