Populate ListView using Retrofit 2 - android

I'm trying to populate a ListView with a JSON from a server. I'm getting the data from the server but I can't seem to figure out how to put it in a ListView. The error I'm getting is in the onResponse.
It says: "Error:(84, 54) error: constructor JucatoriLiberiArrayAdapter in class JucatoriLiberiArrayAdapter cannot be applied to given types;
required: Context,ArrayList
found: FragmentActivity,Call>
reason: actual argument Call> cannot be converted to ArrayList by method invocation conversion"
I think I've tried almost every Alt+Enter fix there is. Also tried to change type from Call<ArrayList<FreePlayers> to just ArrayList<> or just Call<>.
This is my class:
#Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
final Retrofit builder = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.baseUrl(ROOT)
.build();
REST_CLIENT = builder.create(API.class);
final Call<FreePlayers> request = REST_CLIENT.getFreePlayers(1);
request.enqueue(new Callback<FreePlayers>() {
#Override
public void onResponse(final Call<FreePlayers> call, final Response<FreePlayers> response) {
ArrayList<FreePlayers> players = null;
players = call;
ListView lv = (ListView) getView().findViewById(android.R.id.list);
JucatoriLiberiArrayAdapter adapter = new JucatoriLiberiArrayAdapter(getActivity(),
players);
lv.setAdapter(adapter);
}
#Override
public void onFailure(final Call<FreePlayers> call, final Throwable t) {
}
});
}
My API interface:
public interface API {
#FormUrlEncoded
#POST("/fan-sport/app-test/")
Call<ArrayList<FreePlayers>> getFreePlayers(#Field("getFreePlayers") int freePlayers);
}
And this is my custom adapter:
public class JucatoriLiberiArrayAdapter extends BaseAdapter {
private Context context;
private ArrayList<FreePlayers> players;
public JucatoriLiberiArrayAdapter(Context context, ArrayList<FreePlayers> playersList) {
super();
this.context = context;
this.players = playersList;
}
#Override
public int getCount() {
return 0;
}
#Override
public Object getItem(final int position) {
return null;
}
#Override
public long getItemId(final int position) {
return 0;
}
#Override
public View getView(final int position, View convertView, final ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_view_jucatori_liberi, null);
TextView playerName = (TextView) convertView.findViewById(R.id.name);
playerName.setText((CharSequence) players.get(position));
}
return convertView;
}
}

In your onResponse() you receive a Call object wheras your adapter expects a List<FreePlayers>, the response argument is the list of players you want to give to your adapter.
Try this code:
final Call<List<FreePlayers>> request = REST_CLIENT.getFreePlayers(1);
request.enqueue(new Callback<List<FreePlayers>>() {
#Override
public void onResponse(final Call<List<FreePlayers>> call, final Response<List<FreePlayers>> response) {
ArrayList<FreePlayers> players = null;
players = response.body();
ListView lv = (ListView) getView().findViewById(android.R.id.list);
JucatoriLiberiArrayAdapter adapter = new JucatoriLiberiArrayAdapter(getActivity(),
players);
lv.setAdapter(adapter);
}
#Override
public void onFailure(final Call<FreePlayers> call, final Throwable t) {
}
});

call is assgined to players, but players type is ArrayList<FreePlayers> and call type is Call<List<FreePlayers>. Not the same. The adapter expects ArrayList<FreePlayers>.

You're declaring
Call<FreePlayers>,
but expect to receive
Call<ArrayList<FreePlayers>>.
Also, you're Adapter is broken. These methods should look something like:
#Override
public int getCount() {
if (players == null) return 0;
return players.size();
}
#Override
public Object getItem(final int position) {
if (players == null || players.size() == 0) return null;
return players.get(position);
}
#Override
public long getItemId(final int position) {
return getItem(position).getId(); // or something like an id that suits you.
}

Related

Recycleview not populated with JSON and Retrofit?

I am making a simple app in which the user will able to search for books by its name, with google.com book api. For now, I wish to present a list of books with android in their name. I am doing it with Retrofit2 and RecycleView, but nothing is showing.
MainActivity:
public class MainActivity extends AppCompatActivity {
RecyclerView recyclerView;
KnjigaAdapter knjigaAdapter;
List<KnjigaModel> listaKnjiga;
public static final String BASE_URL = "https://www.googleapis.com/books/";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
uzmiKomentare();
}
public void uzmiKomentare() {
Gson gson = new GsonBuilder().serializeNulls().create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
KnjigaApi knjigaApi = retrofit.create(KnjigaApi.class);
final Call<KnjigaModel> pozivZaListuKnjiga = knjigaApi.getKnjige("android");
pozivZaListuKnjiga.enqueue(new Callback<KnjigaModel>() {
#Override
public void onResponse(Call<KnjigaModel> call, Response<KnjigaModel> response) {
if (!response.isSuccessful()) {
return;
}
//generateRecycleView(WHAT TO PUT HERE!!!!);
}
#Override
public void onFailure(Call<KnjigaModel> call, Throwable t) {
Log.d("MainActivity:", t.getMessage());
}
});
}
private void generateRecycleView(List<KnjigaModel> knjige) {
listaKnjiga = new ArrayList<>();
recyclerView = findViewById(R.id.recycleview);
knjigaAdapter = new KnjigaAdapter(this, knjige);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(knjigaAdapter);
if (knjigaAdapter.getItemCount() == 0){
Log.i("List is empty: ","YES");
}
else {
Log.i("list is empty: ","No");
}
}
}
api inteface:
public interface KnjigaApi {
#GET("v1/volumes")
Call<KnjigaModel> getKnjige(#Query("q") String knjiga);
}
model class:
public class KnjigaModel {
#SerializedName("title")
#Expose
private String imeKnjige;
#SerializedName("authors")
#Expose
private String imeAutora;
#SerializedName("thumbnail")
#Expose
private String slikaKnjige;
public KnjigaModel(String imeKnjige, String imeAutora,String slikaKnjige) {
this.imeKnjige = imeKnjige;
this.imeAutora = imeAutora;
this.slikaKnjige = slikaKnjige;
}
public String getImeKnjige() {
return imeKnjige;
}
public String getImeAutora() {
return imeAutora;
}
public String getSlikaKnjige() {
return slikaKnjige;
}
}
and my adapter:
public class KnjigaAdapter extends RecyclerView.Adapter<KnjigaAdapter.KomentariViewHolder> {
private List<KnjigaModel> listaKnjiga;
private LayoutInflater inflater;
private Context context;
public KnjigaAdapter(Context context, List<KnjigaModel> listaKnjiga) {
this.listaKnjiga = listaKnjiga;
this.context = context;
}
#Override
public KomentariViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
inflater = LayoutInflater.from(context);
// Inflate the custom layout
View postView = inflater.inflate(R.layout.single_item, parent, false);
// Return a new holder instance
return new KomentariViewHolder(postView);
}
#Override
public void onBindViewHolder(KomentariViewHolder holder, int position) {
KnjigaModel knjige = listaKnjiga.get(position);
holder.naslovKnjige.setText(knjige.getImeKnjige());
holder.imeAutora.setText(knjige.getImeAutora());
Glide.with(context)
.load(knjige.getSlikaKnjige())
.into(holder.slikaKnjige);
}
#Override
public int getItemCount() {
return listaKnjiga.size();
}
public class KomentariViewHolder extends RecyclerView.ViewHolder {
private TextView naslovKnjige;
private TextView imeAutora;
private ImageView slikaKnjige;
public KomentariViewHolder(View itemView) {
super(itemView);
naslovKnjige = itemView.findViewById(R.id.ime_knjige);
imeAutora = itemView.findViewById(R.id.autor_knjige);
slikaKnjige = itemView.findViewById(R.id.sika_korica);
}
}
}
my JSON format:
https://www.googleapis.com/books/v1/volumes?q=android
First of all, I strongly recommend to use RxJava for asynchronous requests, though it's totally optional.
Your Problem:
Your "getKnjige" Method returns only ONE Model, though the endpoint is named volumes (plural), you need to wrap your KnjigaModel in a class like
data class KnjigaResponse(val items: List<KnjigaModel>)
(Kotlin for simplicity, you can also generate a Java class with a single member volumes member that holds a list of KnjigaModel)
In addition, your model is wrong. authors is not a string, but a List of Strings, and "thumbnail" is wrapped in an "imageLinks" Object, and title is wrapped in a volumeInfo Object.
Your retrofit interface then would look like this:
public interface KnjigaApi {
#GET("v1/volumes")
Call<KnjigaResponse> getKnjige(#Query("q") String knjiga);
Request:
final Call<KnjigaResponse> pozivZaListuKnjiga = knjigaApi.getKnjige("android");
pozivZaListuKnjiga.enqueue(new Callback<KnjigaResponse>() {
#Override
public void onResponse(Call<KnjigaResponse> call, Response<KnjigaResponse> response) {
if (!response.isSuccessful()) {
return;
}
generateRecycleView(response.items);
}
#Override
public void onFailure(Call<KnjigaResponse> call, Throwable t) {
Log.d("MainActivity:", t.getMessage());
}
});

Pass multiple parameters to RecyclerView

In my current code, I'm able to pass and display one value to the RecyclerView. I'm not sure what I'm missing or if I have to completely change my code.
Here's my Adapter Class:
public class TechSkillsAdapter extends RecyclerView.Adapter<TrainingViewHolder> {
Context c;
ArrayList<String> trainings;
public TechSkillsAdapter(Context c, ArrayList<String> trainings) {
this.c = c;
this.trainings = trainings;
}
#Override
public TrainingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(c).inflate(R.layout.cv_traininglist, parent, false);
return new TrainingViewHolder(v);
}
#Override
public void onBindViewHolder(TrainingViewHolder holder, int position) {
holder.date_txt.setText(trainings.get(position));
}
#Override
public int getItemCount() {
return trainings.size();
}
}
I'm retrieving the list using retrofit then passing the values to a method that displays them to the recyclerview.
Here's how I'm retrieving the trainings:
private void getTraining(final String id, String tid){
com.trendmicro.projectlara.apis.ApiServiceTraining apiService = ApiClient.getClient().create(ApiServiceTraining.class);
Call<List<Training>> call = apiService.getMyTraining(id, tid);
call.enqueue(new Callback<List<Training>>() {
#Override
public void onResponse (Call<List<Training>> call, Response<List<Training>> response) {
List<Training> training = response.body();
for(Training t: training){
fillTrainings(t.getTraining_title().toString(), t.getTraining_date().toString());
}
}
Here's my fillTrainings method.
I'm passing two values but I'm only able to display one value:
private void fillTrainings(String title, String date) {
training.add(title);
adapter = new TechSkillsAdapter(getContext(), training);
rv.setAdapter(adapter);
progressDialog.dismiss();
}
Here's what I'm trying to fix,I'm not sure how to display the date as well since the way I'm adding the values is: training.add(title);
Any help or tip is much appreciated. Thanks!
This is because you're recreate the adapter each time you have an item with this code:
#Override
public void onResponse (Call<List<Training>> call, Response<List<Training>> response) {
List<Training> training = response.body();
for(Training t: training){
// here you're only send one time
fillTrainings(t.getTraining_title().toString(), t.getTraining_date().toString());
}
}
You can fix it by sending all the list to your method by changing the method to this:
private void fillTrainings(List<Training> trainList) {
for(Training train: trainList) {
training.add(train.getTraining_title().toString());
}
adapter = new TechSkillsAdapter(getContext(), training);
rv.setAdapter(adapter);
progressDialog.dismiss();
}
then you can use it with:
#Override
public void onResponse (Call<List<Training>> call, Response<List<Training>> response) {
List<Training> training = response.body();
fillTrainings(training);
}
You are receiving a List of Training, but for some reason your adapter is backed by List of String. Why is that?
Modify your adapter to hold Trainings and then bind both the title and the date to the view.
public class TechSkillsAdapter extends RecyclerView.Adapter<TrainingViewHolder> {
Context c;
ArrayList<Training> trainings;
public TechSkillsAdapter(Context c, ArrayList<Training> trainings) {
this.c = c;
this.trainings = trainings;
}
#Override
public TrainingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(c).inflate(R.layout.cv_traininglist, parent, false);
return new TrainingViewHolder(v);
}
#Override
public void onBindViewHolder(TrainingViewHolder holder, int position) {
holder.title_txt.setText(trainings.get(position).getTraining_title().toString());
holder.date_txt.setText(trainings.get(position).getTraining_date().toString());
}
#Override
public int getItemCount() {
return trainings.size();
}
}
And then in your onResponse just do:
#Override
public void onResponse (Call<List<Training>> call, Response<List<Training>> response) {
List<Training> training = response.body();
adapter = new TechSkillsAdapter(getContext(), training);
rv.setAdapter(adapter);
progressDialog.dismiss();
}
This should work, but you can improve this if you create and set your adapter once (in onCreate) and pass it some list, and then in onResponse just update that list and do adapter.notifyDataSetChanged() Sort of like this:
//Activity
List<Training> mTrainingsList = new ArrayList<Training>();
//onCreate
adapter = new TechSkillsAdapter(getContext(), mTrainingsList);
...
}
#Override
public void onResponse (Call<List<Training>> call, Response<List<Training>> response) {
List<Training> training = response.body();
mTrainingList.clear();
mTrainingList.addAll(training);
adapter.notifyDatasetChanged();
progressDialog.dismiss();
}
EDIT: Also, please note that in your code you're going over the list of trainings and you recreate the adapter for each item! Try to avoid this in the future.

iam using Retrofit library to fetch data from Database to recyclerview

am trying to Fetch the movies data from Mysql DB and show it to Recycler view
but when i run the app nothing shows
here is code i am using Retrofite Library
but i can't parse the Data to the Recycler view
i've made Adapter and Model Class normally like the Json
MainActivity.class
public class MainActivity extends AppCompatActivity {
private static final String url="http://192.168.1.109/stu/";
RecyclerView recyclerViewMovies;
List<MovieListsModels> movies;
MoviesAdapter adapter;
TextView Errortxt;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Errortxt = (TextView)findViewById(R.id.txterror);
recyclerViewMovies = (RecyclerView)findViewById(R.id.recyclerview);
recyclerViewMovies.setHasFixedSize(true);
recyclerViewMovies.setLayoutManager(new LinearLayoutManager(this));
movies = new ArrayList<>();
loadDatafromServer();
}
private void loadDatafromServer() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build();
Api api = retrofit.create(Api.class);
Call<MovieListsModels> call = api.ShowMoviesData();
call.enqueue(new Callback<MovieListsModels>() {
#Override
public void onResponse(Call<MovieListsModels> call, Response<MovieListsModels> response) {
try {
MovieListsModels movie = response.body();
adapter = new MoviesAdapter(MainActivity.this, (List<MovieListsModels>) movie);
recyclerViewMovies.setAdapter(adapter);
}
catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<MovieListsModels> call, Throwable t) {
Errortxt.setText(t.getMessage().toString());
}
});
}
this is the interface of the methods
Api.class Interface
public interface Api {
#GET("config.php")
Call<MovieListsModels> ShowMoviesData();
}
MovieLists.class
public class MovieListsModels {
public MovieListsModels() {
}
int id;
String movie_name;
String movie_image;
String movie_genre;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMovie_name() {
return movie_name;
}
public void setMovie_name(String movie_name) {
this.movie_name = movie_name;
}
public String getMovie_image() {
return movie_image;
}
public void setMovie_image(String movie_image) {
this.movie_image = movie_image;
}
public String getMovie_genre() {
return movie_genre;
}
public void setMovie_genre(String movie_genre) {
this.movie_genre = movie_genre;
}
public MovieListsModels(int id, String movie_name, String movie_image, String movie_genre) {
this.id = id;
this.movie_name = movie_name;
this.movie_image = movie_image;
this.movie_genre = movie_genre;
}
}
MovieAdapter.class
public class MoviesAdapter extends RecyclerView.Adapter<MoviesAdapter.MovieHolderView> {
private Context mContext;
private List<MovieListsModels> MovieList = new ArrayList<>();
public MoviesAdapter(Context mContext, List<MovieListsModels> movieList) {
this.mContext = mContext;
MovieList = movieList;
}
#NonNull
#Override
public MovieHolderView onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_item,parent,false);
MovieHolderView holder = new MovieHolderView(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull MovieHolderView holder, int position) {
MovieListsModels list = MovieList.get(position);
holder.txtName.setText(list.getMovie_name());
holder.txtGenre.setText(list.getMovie_genre());
Picasso.get()
.load(list.getMovie_image())
.into(holder.imgMovie);
}
#Override
public int getItemCount() {
return MovieList.size();
}
public class MovieHolderView extends RecyclerView.ViewHolder {
TextView txtName,txtGenre;
ImageView imgMovie;
public MovieHolderView(View itemView) {
super(itemView);
txtName =(TextView)itemView.findViewById(R.id.movieName);
txtGenre =(TextView)itemView.findViewById(R.id.movieGenre);
imgMovie =(ImageView)itemView.findViewById(R.id.movieImg);
}
}
}
If you receive a list of movies is better because you expect a list, I suppose
public void onResponse(Call<MovieListsModels> call, Response<MovieListsModels> response) {
try {
List<MovieListsModels> movie = response.body();
adapter = new MoviesAdapter(MainActivity.this, movies);
And I believe that not executing the notifyDataSetChanged, you can added like that:
private Context mContext;
private List<MovieListsModels> MovieList = new ArrayList<>();
public MoviesAdapter(Context mContext, List<MovieListsModels> movieList) {
this.mContext = mContext;
MovieList = movieList;
notifiyDataSetChanged();
If you are having json response of the form {..}, you are having an object response and you should expect an object as you have done i.e, Call<YourObject>
If you are having json response of the form [..], you are having an array response and you should expect an array i.e, Call<List<YourObject>>
In your case, i hope its an array(second case), So make changes as per the above answer done by #Guillodacosta
First don't forget to add the internet permission in your manifest file
<uses-permission android:name="android.permission.INTERNET" />
Second try this
Picasso.with(mContext).load(list.getMovie_image()).into(holder.imgMovie);

onCreateView wait queries result

I need to execute a query to my DB to get some IDs and then use those IDs to execute another query to Realm DB and return the result to the Adapter which is used to create UI. My problem is that the adapter is created in onCreatView (main thread) and i need to let that wait queries result. Do you know how can i do? Really thanks :)
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Realm realm = Realm.getDefaultInstance();
cardList = new ArrayList(realm.where(Card.class).findAll().sort("rarity"));
View rootView = inflater.inflate(R.layout.inventory_fragment_layout, null);
RecyclerView recyclerView = rootView.findViewById(R.id.inventory_recycler);
recyclerView.setLayoutManager(new GridLayoutManager(this.getContext(), 2));
adapter = new inventoryFragmentRecyclerAdapter(this.getContext(), getCards()); <----- getCards() is used here.
adapter.setClickListener(this);
recyclerView.setAdapter(adapter);
TextView topText = rootView.findViewById(R.id.inv_topText);
topText.setTypeface(Typeface.createFromAsset(getActivity().getAssets(), "fonts/Square.ttf"));
return rootView;
}
.
.
.
.
.
.
public List<Card> getCards() { //It is used when adapter is created, and it need to contain all cards to display
//Realm realm = Realm.getDefaultInstance();
String urlToGet = "myurl";
String user_name = settings.getString("username", null);
OkHttpClient client = new OkHttpClient();
RequestBody formBody = new FormBody.Builder()
.add("user_name", user_name)
.build();
Request request = new Request.Builder()
.url(urlToGet)
.post(formBody)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
responseCardInInventory = response.body().string();
handler.post(new Runnable() {
#Override
public void run() {
List<CardInInv> cardListInInv = new ArrayList<>();
Gson gson = new Gson();
CardInInventory civ = gson.fromJson(responseCardInInventory, CardInInventory.class);
cardListInInv = getCards(civ);
//HERE I NEED TO USE REALM TO EXECUTE A QUERY USING cardListInInv
}
});
}
});
//HERE I NEED TO RETURN THE RESULT OF THE QUERY EXECUTED BEFORE
return cardsIninv;
}
EDIT 1: Hre is my adapter code
public class inventoryFragmentRecyclerAdapter extends RecyclerView.Adapter<inventoryFragmentRecyclerAdapter.ViewHolder> {
private List<Card> dataCard = new ArrayList<>();
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
// data is passed into the constructor
public inventoryFragmentRecyclerAdapter(Context context, List<Card> data) {
this.mInflater = LayoutInflater.from(context);
this.dataCard = data;
}
// inflates the cell layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.inventory_rw, parent, false);
return new ViewHolder(view);
}
// binds the data to the in each cell
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.cardImage.setImageBitmap(BitmapFactory.decodeByteArray(dataCard.get(position).getCardImage(), 0, dataCard.get(position).getCardImage().length));
}
// total number of cells
#Override
public int getItemCount() {
return dataCard.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
ImageView cardImage;
//instanzio le componenti della pagina
ViewHolder(View itemView) {
super(itemView);
cardImage = itemView.findViewById(R.id.inv_rw_cardimage);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// convenience method for getting data at click position
Card getItem(int id) {
return dataCard.get(id);
}
// allows clicks events to be caught
public void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
Move your query to your adapter and start your adapter with an empty list. Make your query call at the end of your constructor. When you've successfully finished your query, notify your adapter that it has changed and let it handle the changes with your new data at the end of your queries finishing successfully. So after doing that your adapter would look something like this.
public inventoryFragmentRecyclerAdapter(Context context, List<Card> data) {
this.mInflater = LayoutInflater.from(context);
getCards();
}
public void getCards() { //It is used when adapter is created, and it need to contain all cards to display
//Realm realm = Realm.getDefaultInstance();
String urlToGet = "myurl";
String user_name = settings.getString("username", null);
OkHttpClient client = new OkHttpClient();
RequestBody formBody = new FormBody.Builder()
.add("user_name", user_name)
.build();
Request request = new Request.Builder()
.url(urlToGet)
.post(formBody)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
responseCardInInventory = response.body().string();
handler.post(new Runnable() {
#Override
public void run() {
List<CardInInv> cardListInInv = new ArrayList<>();
Gson gson = new Gson();
CardInInventory civ = gson.fromJson(responseCardInInventory, CardInInventory.class);
cardListInInv = getCards(civ);
//use realm to do all your card inventory stuff to get your resulting object
dataCard = yourObjectListAfterUsingRealm;
notifyDataSetChanged();
}
});
}
});
}
move This line adapter = new inventoryFragmentRecyclerAdapter(context, yourList);
inside onResponse() and pass the list directly without the getCards();
Edit:
initialize your adapter when your data is ready.where ? this is based on your needs.
or initialize it with empty list and call adapter.notifyDataSetChanged() when something changed (added or removed from the list or a brand new list is initialized)
Create your adapter with empty list
adapter = new inventoryFragmentRecyclerAdapter(this.getContext(), new ArrayList<Card>());
and then in your adapter create a method like this
public void updateCardList(List<Card> cardList) {
this.mCards = cardList;
notifyDataSetChanged();
}
and call this function in the
#Override
public void onResponse(Call call, final Response response)

How can I put the data to RecyclerView from okhttp and Asynctask

I've get some Json data from server by okhttp ,and I want to show them in a
recycleview inside of a fragment using a custom adapter and receiving the following error.
when I run this code,the logcat tell me the followeing msg:
java.lang.NullPointerException: Attempt to invoke virtual method 'int java.util.ArrayList.size()' on a null object reference
I print the list in the logcat ,it shows null.
but I can get some json data from the IE.Do anyone help me,please?
public class customer extends AppCompatActivity {
private static final String TAG = "MyDebug______ " ;
private RecyclerView cutomerRecyclerView;
private customerAdapter mAdapter;
private ArrayList<custModal> list;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_customer);
Toolbar toolbar = (Toolbar)findViewById(R.id.custom_toolbar);
setSupportActionBar(toolbar);
new getHttpData().execute();
Log.d(TAG, "the list is :" +list);
mAdapter = new customerAdapter(this,list);
cutomerRecyclerView = (RecyclerView)findViewById(R.id.customer_list);
cutomerRecyclerView.setLayoutManager(new LinearLayoutManager(this));
cutomerRecyclerView.setAdapter(mAdapter);
cutomerRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration(){
#Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state){
super.onDraw(c,parent,state);
c.drawColor(R.color.colorDevider);
}
#Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.offset(0,1);
}
});
}
public class customerAdapter extends RecyclerView.Adapter<customerAdapter.customerViewHolder>{
private Context mcontext;
private ArrayList<custModal> mlist;
// private LayoutInflater inflater;
class customerViewHolder extends RecyclerView.ViewHolder{
private TextView name,mem,cust_id;
public customerViewHolder(View view){
super(view);
cust_id = (TextView )view.findViewById(R.id.cust_id);
name = (TextView)view.findViewById(R.id.cust_name);
mem = (TextView)view.findViewById(R.id.cust_mem);
}
}
public customerAdapter(Context context,ArrayList<custModal> list){
this.mcontext = context;
this.mlist = list;
}
#Override
public customerViewHolder onCreateViewHolder(ViewGroup parent,int viewType){
customerViewHolder holder = new customerViewHolder(LayoutInflater.from(
customer.this).inflate(R.layout.customer_item,parent,false));
return holder;
}
#Override
public void onBindViewHolder(customerViewHolder holder,int position){
holder.cust_id.setText(mlist.get(position).getId());
holder.name.setText(mlist.get(position).getName());
holder.mem.setText(mlist.get(position).getMobiphone());
}
#Override
public int getItemCount(){ return mlist.size();}
}
class custModal {
private String id;
private String name;
private String gender;
private String mobiphone;
private String creat_time;
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getGender() {
return gender;
}
public void setMobiphone(String mobiphone) {
this.mobiphone = mobiphone;
}
public String getMobiphone() {
return mobiphone;
}
public void setCreat_time(String creat_time) {
this.creat_time = creat_time;
}
public String getCreat_time() {
return creat_time;
}
}
public class getHttpData extends AsyncTask<String,Integer,ArrayList<custModal> >{
//private ArrayList<custModal> custlist;
#Override
// protected void onPreExecute(){}
#Override
protected ArrayList<custModal> doInBackground(String... params){
String url = "http://aaaa.bbbbb.cn/index.php/mobi/customer/app_getlist";
try{
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
Log.d(TAG, "doInBackground: "+ responseData);
if(responseData != null){
//return getCustFromJson(responseData);
Gson gson = new Gson();
ArrayList<custModal> custlist = gson.fromJson(responseData,
new TypeToken<List<custModal>>() {}.getType()
);
return custlist;
}else{
return null;
}
}catch (IOException I){
I.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(ArrayList<custModal> custlist){
if(!custlist.isEmpty()){
super.onPostExecute(custlist);
list = custlist;
mAdapter.notifyDataSetChanged();
}
}
}
}
make sure initialize adapter, array list of adapter and attaching adapter to recycler in onCreate
You have to then add the new yourAsyncTask().execute where you need to to http call.
In your onBackground add items to the array list and in postExecute simply call notify data change method
Your list is in a null state when you pass it via adapter constructor therefore any operations on the list return null.
You could add a callback to your okhttp request and construct the adapter on the response? One way or another though you need to update the list before you can perform any operations on it.
I put the following code into the Method onPostExecute,it worked.But I think it is not a right solution.like this:
protected void onPostExecute(ArrayList<custModal> custlist){
Log.d(TAG, "onPostExecute(Result result) called");
Log.d(TAG, "onPostExecute: "+custlist);
mAdapter = new customerAdapter(customer.this,custlist);
cutomerRecyclerView = (RecyclerView)findViewById(R.id.customer_list);
cutomerRecyclerView.setLayoutManager(new LinearLayoutManager(customer.this));
cutomerRecyclerView.setAdapter(mAdapter);
}

Categories

Resources