I am using spinner which get populated dynamically from data base
here is my code
<Spinner
android:id="#+id/spnOrdrPrdBrand"
style="#style/ButtonStyleSpinner"
android:layout_marginTop="5dp"
android:hint="#string/select"
android:paddingLeft="5dp" />
List<Brand> brandList = new ArrayList<Brand>();
if(!custId.equals("0")){
brandList = cCon.getBrandList(custId);
}
// Sorting
//Collections.sort(brandList);
//Brand Lst
ArrayAdapter<Brand> brandAdp = new ArrayAdapter<Brand>(this,android.R.layout.simple_spinner_item,brandList.toArray(new Brand[brandList.size()]));
brandAdp.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spnOrdrPrdBrand.setAdapter(brandAdp);
data is thr in brandList object
but while populating showing me object name instead actual brand name.
I am using
public class Brand implements Comparable<Brand>{
// private variables
protected int brandId;
protected String brandNm;
// Empty constructor
public Brand() {
}
// constructor
public Brand(int brandId, String brandNm) {
this.brandId = brandId;
this.brandNm = brandNm;
}
/**
* #return the brandId
*/
public int getBrandId() {
return brandId;
}
/**
* #param brandId the brandId to set
*/
public void setBrandId(int brandId) {
this.brandId = brandId;
}
/**
* #return the brandNm
*/
public String getBrandNm() {
return brandNm;
}
/**
* #param brandNm the brandNm to set
*/
public void setBrandNm(String brandNm) {
this.brandNm = brandNm;
}
#Override
public int compareTo(Brand another) {
if (this.brandNm.equals(another.brandNm)) {
return ((Integer.valueOf(this.brandId)).compareTo(Integer.valueOf(another.brandId)));
} else {
return this.brandNm.compareTo(another.brandNm);
}
}
}
so how to resolve for the same
What are you showing is the toString implementation of Object. If you do not want to have a custom adapter, you can override toString() in your Brand class and let it returns the String you want to show,
Related
I asked a question about parsing a JSON array a couple of days ago:
How do you parse a JSON Array w/o a defined array?
I'm downloading a list of 11 items(displayed in a vertical layout in an activity by a RecyclerView LinearLayoutManager). For some reason, two identical lists are being downloaded. I double checked the JSON data tested the Url in Postman and there are no duplicate values. Also, the API doesn't have a pagination parameter.
To moderator. I found a few threads on here about duplicate values in JSON. Again, there are no duplicate values in mine. Thank you in advance.
Remove Duplicate objects from JSON Array
remove duplicate values from json data
JSONUtils class from the above mentioned thread:
public class JSONUtils
{
/**
* Tag for the log messages
*/
private static final String LOG_TAG = JSONUtils.class.getSimpleName();
private static final String KEY_LINE_ID = "id";
private static final String KEY_LINE_NAME = "name";
public JSONUtils()
{
}
public static Lines extractFeatureFromJson (String linesJSON)
{
// If the JSON string is empty or null, then return early.
if (TextUtils.isEmpty(linesJSON)) {
return null;
}
Lines line = null;
try
{
// Create a JSONObject from the JSON file
JSONObject jsonObject = new JSONObject(linesJSON);
String id = "";
if (jsonObject.has("id"))
{
id = jsonObject.optString(KEY_LINE_ID);
}
String name = "";
if (jsonObject.has("name"))
{
name= jsonObject.optString(KEY_LINE_NAME);
}
line = new Lines(id, name);
}
catch (JSONException e)
{
// If an error is thrown when executing any of the above statements in the "try" block,
// catch the exception here, so the app doesn't crash. Print a log message
// with the message from the exception.
Log.e("QueryUtils", "Problem parsing lines JSON results", e);
}
// Return the list of lines
return line;
}
}
RecyclerViewAdapter class:
public class LinesAdapter extends RecyclerView.Adapter<LinesAdapter.LinesAdapterViewHolder>
{
private static final String TAG = LinesAdapter.class.getSimpleName();
private ArrayList<Lines> linesList = new ArrayList<Lines>();
private Context context;
private LinesAdapterOnClickHandler mLineClickHandler;
/**
* The interface that receives onClick messages.
*/
public interface LinesAdapterOnClickHandler
{
void onClick(Lines textLineClick);
}
/**
* Creates a Lines Adapter.
*
* #param lineClickHandler The on-click handler for this adapter. This single handler is called
* * when an item is clicked.
*/
public LinesAdapter(LinesAdapterOnClickHandler lineClickHandler, ArrayList<Lines> linesList, Context context)
{
mLineClickHandler = lineClickHandler;
this.linesList = linesList;
this.context = context;
}
/**
* Cache of the children views for a line list item.
*/
public class LinesAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
{
#BindView(R.id.line_name)
public TextView lineName;
public LinesAdapterViewHolder(View view)
{
super(view);
ButterKnife.bind(this, view);
view.setOnClickListener(this);
}
/**
* This gets called by the child views during a click.
*
* #param v The View that was clicked
*/
#Override
public void onClick(View v)
{
int adapterPosition = getAdapterPosition();
Lines textLineClick = linesList.get(adapterPosition);
mLineClickHandler.onClick(textLineClick);
}
}
#Override
public LinesAdapterViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType)
{
Context context = viewGroup.getContext();
int layoutIdForListItem = R.layout.line_list_item;
LayoutInflater inflater = LayoutInflater.from(context);
boolean shouldAttachToParentImmediately = false;
View view = inflater.inflate(layoutIdForListItem, viewGroup, shouldAttachToParentImmediately);
return new LinesAdapterViewHolder(view);
}
/**
* Cache of the children views for a line list item.
*/
#Override
public void onBindViewHolder(LinesAdapterViewHolder holder, int position)
{
//Binding data
final Lines lineView = linesList.get(position);
holder.lineName.setText(lineView.getLineName());
}
#Override
public int getItemCount()
{
return linesList.size();
}
public void setLinesList(ArrayList<Lines> mLinesList)
{
this.linesList.addAll(mLinesList);
notifyDataSetChanged();
}
}
This method look suspicious:
public void setLinesList(ArrayList<Lines> mLinesList)
{
this.linesList.addAll(mLinesList);
notifyDataSetChanged();
}
It has a name like a "setter", but it's not actually setting lines, it is adding lines. If you had code that called this twice with the same arguments, you'd wind up with duplicates.
Here are two ways to write this method so that it actually overwrites the list every time:
public void setLinesList(ArrayList<Lines> mLinesList)
{
this.linesList.clear();
this.linesList.addAll(mLinesList);
notifyDataSetChanged();
}
public void setLinesList(ArrayList<Lines> mLinesList)
{
this.linesList = new ArrayList<>(mLinesList);
notifyDataSetChanged();
}
Objective: I have a ListView with a BaseAdapter I want to populate with values from my Firebase Database.
This is my BaseAdapter I named MessagesAdapter.java:
public class MessagesAdapter extends BaseAdapter {
private Context context;
private List<Message> messages;
private LayoutInflater inflater;
boolean showMoreClicked = false;
public MessagesAdapter(Context context, List<Message> messages) {
this.context = context;
this.messages = messages;
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return messages.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
public View getView(final int position, final View convertView,final ViewGroup parent) {
View itemView = convertView;
MessagesAdapter.ViewHolder holder;
if (convertView == null) {
itemView = inflater.inflate(R.layout.item_message, null);
holder = new ViewHolder();
// set image based on selected text
holder.message = itemView.findViewById(R.id.tv_msg);
holder.showMoreBtn = itemView.findViewById(R.id.bt_show_more);
holder.datetime = itemView.findViewById(R.id.tv_ride_time);
itemView.setTag(holder);
} else
holder = (MessagesAdapter.ViewHolder) itemView.getTag();
final Message msg = messages.get(position);
/* editing item views */
holder.datetime.setText(msg.getDatetime());
holder.message.setText(msg.getContent());
holder.showMoreBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "All Message: "+msg.getContent(), Toast.LENGTH_SHORT).show();
showMoreClicked = !showMoreClicked;
}
});
DatabaseReference profileRef = FirebaseDatabase.getInstance().getReference("profile");
profileRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Profile sender = dataSnapshot.child(msg.getSender_id()+"").getValue(Profile.class);
ViewHolder h = new ViewHolder();
h.userImg = parent.getChildAt(position).findViewById(R.id.iv_profile_image);
h.userName = parent.getChildAt(position).findViewById(R.id.tv_sender_name);
h.userName.setText(sender.getFirstname()+" "+sender.getLastname()); /*** Error shows up here ***/
getImageFromDB(sender.getPicpath(), h.userImg);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return itemView;
}
private static class ViewHolder {
CircleImageView userImg;
TextView userName;
TextView datetime;
TextView message;
Button showMoreBtn;
}
private void getImageFromDB(String firebasePath, ImageView imageView) {
StorageReference mStorageRef = FirebaseStorage.getInstance()
.getReferenceFromUrl("gs://iveridemap.appspot.com")
.child(firebasePath);
// Load the image using Glide
Glide.with(context)
.using(new FirebaseImageLoader()) // cannot resolve method using!
.load(mStorageRef)
.into(imageView);
}
}
This adapter is used to fetch messages sent to the current user from firebase and show them in my ListView.
I instantiate this BaseAdapter and ListView inside a fragment I called MessagesFragment.java:
public class MessagesAdapter extends BaseAdapter {
private Context context;
private List<Message> messages;
private LayoutInflater inflater;
boolean showMoreClicked = false;
public MessagesAdapter(Context context, List<Message> messages) {
this.context = context;
this.messages = messages;
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return messages.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
public View getView(final int position, final View convertView,final ViewGroup parent) {
View itemView = convertView;
MessagesAdapter.ViewHolder holder;
if (convertView == null) {
itemView = inflater.inflate(R.layout.item_message, null);
holder = new ViewHolder();
// set image based on selected text
holder.message = itemView.findViewById(R.id.tv_msg);
holder.showMoreBtn = itemView.findViewById(R.id.bt_show_more);
holder.datetime = itemView.findViewById(R.id.tv_ride_time);
itemView.setTag(holder);
} else
holder = (MessagesAdapter.ViewHolder) itemView.getTag();
final Message msg = messages.get(position);
/* editing item views */
holder.datetime.setText(msg.getDatetime());
holder.message.setText(msg.getContent());
holder.showMoreBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(context, "All Message: "+msg.getContent(), Toast.LENGTH_SHORT).show();
showMoreClicked = !showMoreClicked;
}
});
DatabaseReference profileRef = FirebaseDatabase.getInstance().getReference("profile");
profileRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Profile sender = dataSnapshot.child(msg.getSender_id()+"").getValue(Profile.class);
ViewHolder h = new ViewHolder();
h.userImg = parent.getChildAt(position).findViewById(R.id.iv_profile_image);
h.userName = parent.getChildAt(position).findViewById(R.id.tv_sender_name);
h.userName.setText(sender.getFirstname()+" "+sender.getLastname());
getImageFromDB(sender.getPicpath(), h.userImg);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return itemView;
}
private static class ViewHolder {
CircleImageView userImg;
TextView userName;
TextView datetime;
TextView message;
Button showMoreBtn;
}
private void getImageFromDB(String firebasePath, ImageView imageView) {
StorageReference mStorageRef = FirebaseStorage.getInstance()
.getReferenceFromUrl("gs://iveridemap.appspot.com")
.child(firebasePath);
// Load the image using Glide
Glide.with(context)
.using(new FirebaseImageLoader()) // cannot resolve method using!
.load(mStorageRef)
.into(imageView);
}
}
Problem: When I scroll down my ListView my code returns a NullPointerException at the line:
h.userName.setText(sender.getFirstname()+" "+sender.getLastname());
In the BaseAdapter, I pointed it out in the code above. Apprently something is wrong with initiating my profile instance I fetch from Firebase.
More Info: This error doesn't show up when there is fewer items in the list and I don't have to scroll down..
I am ready to post more code upon demand, if anyone needs to see my XML file or database structure just say so!
Thanks alot for your time.
I recommend using a RecyclerView, to use firebase items there is some great libraries to make everything more simple
Here is a great library to parcel your items
compile 'org.parceler:parceler-api:1.1.9'
With parceler you can make your activity like this example
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.Menu;
import android.view.MenuItem;
import com.firebase.client.Firebase;
import com.firebase.client.Query;
import org.parceler.Parcels;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private final static String SAVED_ADAPTER_ITEMS = "SAVED_ADAPTER_ITEMS";
private final static String SAVED_ADAPTER_KEYS = "SAVED_ADAPTER_KEYS";
private Query mQuery;
private MyAdapter mMyAdapter;
private ArrayList<MyItem> mAdapterItems;
private ArrayList<String> mAdapterKeys;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handleInstanceState(savedInstanceState);
setupFirebase();
setupRecyclerview();
}
// Restoring the item list and the keys of the items: they will be passed to the adapter
private void handleInstanceState(Bundle savedInstanceState) {
if (savedInstanceState != null &&
savedInstanceState.containsKey(SAVED_ADAPTER_ITEMS) &&
savedInstanceState.containsKey(SAVED_ADAPTER_KEYS)) {
mAdapterItems = Parcels.unwrap(savedInstanceState.getParcelable(SAVED_ADAPTER_ITEMS));
mAdapterKeys = savedInstanceState.getStringArrayList(SAVED_ADAPTER_KEYS);
} else {
mAdapterItems = new ArrayList<MyItem>();
mAdapterKeys = new ArrayList<String>();
}
}
private void setupFirebase() {
Firebase.setAndroidContext(this);
String firebaseLocation = getResources().getString(R.string.firebase_location);
mQuery = new Firebase(firebaseLocation);
}
private void setupRecyclerview() {
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
mMyAdapter = new MyAdapter(mQuery, MyItem.class, mAdapterItems, mAdapterKeys);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(mMyAdapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return item.getItemId() == R.id.action_settings || super.onOptionsItemSelected(item);
}
// Saving the list of items and keys of the items on rotation
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(SAVED_ADAPTER_ITEMS, Parcels.wrap(mMyAdapter.getItems()));
outState.putStringArrayList(SAVED_ADAPTER_KEYS, mMyAdapter.getKeys());
}
#Override
protected void onDestroy() {
super.onDestroy();
mMyAdapter.destroy();
}
}
Here is the item Model
import org.parceler.Parcel;
#Parcel
public class MyItem {
String name;
long age;
public MyItem() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getAge() {
return age;
}
public void setAge(long age) {
this.age = age;
}
}
Here is the adapter
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.firebase.client.Query;
import java.util.ArrayList;
import java.util.List;
public class MyAdapter extends FirebaseRecyclerAdapter<MyAdapter.ViewHolder, MyItem> {
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView textViewName;
TextView textViewAge;
public ViewHolder(View view) {
super(view);
textViewName = (TextView) view.findViewById(R.id.textview_name);
textViewAge = (TextView) view.findViewById(R.id.textview_age);
}
}
public MyAdapter(Query query, #Nullable ArrayList<MyItem> items,
#Nullable ArrayList<String> keys) {
super(query, items, keys);
}
#Override public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item, parent, false);
return new ViewHolder(view);
}
#Override public void onBindViewHolder(MyAdapter.ViewHolder holder, int position) {
MyItem item = getItem(position);
holder.textViewName.setText(item.getName());
holder.textViewAge.setText(String.valueOf(item.getAge()));
}
#Override protected void itemAdded(MyItem item, String key, int position) {
Log.d("MyAdapter", "Added a new item to the adapter.");
}
#Override protected void itemChanged(MyItem oldItem, MyItem newItem, String key, int position) {
Log.d("MyAdapter", "Changed an item.");
}
#Override protected void itemRemoved(MyItem item, String key, int position) {
Log.d("MyAdapter", "Removed an item from the adapter.");
}
#Override protected void itemMoved(MyItem item, String key, int oldPosition, int newPosition) {
Log.d("MyAdapter", "Moved an item.");
}
}
And here is the adapter that is extending the main adapter so it can work with firebase
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.ViewGroup;
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.Query;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
/**https://firebase.google.com/support/guides/firebase-android.
* <p>
* This class is a generic way of backing an Android RecyclerView with a Firebase location.
* It handles all of the child events at the given Firebase location.
* It marshals received data into the given class type.
* Extend this class and provide an implementation of the abstract methods, which will notify when
* the adapter list changes.
* <p>
* This class also simplifies the management of configuration change (e.g.: device rotation)
* allowing the restore of the list.
*
* #param <T> The class type to use as a model for the data contained in the children of the
* given Firebase location
*/
public abstract class FirebaseRecyclerAdapter<ViewHolder extends RecyclerView.ViewHolder, T> extends RecyclerView.Adapter<ViewHolder> {
private Query mQuery;
private ArrayList<T> mItems;
private ArrayList<String> mKeys;
/**
* #param query The Firebase location to watch for data changes.
* Can also be a slice of a location, using some combination of
* <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>.
*/
public FirebaseRecyclerAdapter(Query query) {
this(query, null, null);
}
/**
* #param query The Firebase location to watch for data changes.
* Can also be a slice of a location, using some combination of
* <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>.
* #param items List of items that will load the adapter before starting the listener.
* Generally null or empty, but this can be useful when dealing with a
* configuration change (e.g.: reloading the adapter after a device rotation).
* Be careful: keys must be coherent with this list.
* #param keys List of keys of items that will load the adapter before starting the listener.
* Generally null or empty, but this can be useful when dealing with a
* configuration change (e.g.: reloading the adapter after a device rotation).
* Be careful: items must be coherent with this list.
*/
public FirebaseRecyclerAdapter(Query query,
#Nullable ArrayList<T> items,
#Nullable ArrayList<String> keys) {
this.mQuery = query;
if (items != null && keys != null) {
this.mItems = items;
this.mKeys = keys;
} else {
mItems = new ArrayList<T>();
mKeys = new ArrayList<String>();
}
query.addChildEventListener(mListener);
}
private ChildEventListener mListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
String key = dataSnapshot.getKey();
if (!mKeys.contains(key)) {
T item = getConvertedObject(dataSnapshot);
int insertedPosition;
if (previousChildName == null) {
mItems.add(0, item);
mKeys.add(0, key);
insertedPosition = 0;
} else {
int previousIndex = mKeys.indexOf(previousChildName);
int nextIndex = previousIndex + 1;
if (nextIndex == mItems.size()) {
mItems.add(item);
mKeys.add(key);
} else {
mItems.add(nextIndex, item);
mKeys.add(nextIndex, key);
}
insertedPosition = nextIndex;
}
notifyItemInserted(insertedPosition);
itemAdded(item, key, insertedPosition);
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
String key = dataSnapshot.getKey();
if (mKeys.contains(key)) {
int index = mKeys.indexOf(key);
T oldItem = mItems.get(index);
T newItem = getConvertedObject(dataSnapshot);
mItems.set(index, newItem);
notifyItemChanged(index);
itemChanged(oldItem, newItem, key, index);
}
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
String key = dataSnapshot.getKey();
if (mKeys.contains(key)) {
int index = mKeys.indexOf(key);
T item = mItems.get(index);
mKeys.remove(index);
mItems.remove(index);
notifyItemRemoved(index);
itemRemoved(item, key, index);
}
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
String key = dataSnapshot.getKey();
int index = mKeys.indexOf(key);
T item = getConvertedObject(dataSnapshot);
mItems.remove(index);
mKeys.remove(index);
int newPosition;
if (previousChildName == null) {
mItems.add(0, item);
mKeys.add(0, key);
newPosition = 0;
} else {
int previousIndex = mKeys.indexOf(previousChildName);
int nextIndex = previousIndex + 1;
if (nextIndex == mItems.size()) {
mItems.add(item);
mKeys.add(key);
} else {
mItems.add(nextIndex, item);
mKeys.add(nextIndex, key);
}
newPosition = nextIndex;
}
notifyItemMoved(index, newPosition);
itemMoved(item, key, index, newPosition);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e("FirebaseListAdapter", "Listen was cancelled, no more updates will occur.");
}
};
#Override
public abstract ViewHolder onCreateViewHolder(ViewGroup parent, int viewType);
#Override
public abstract void onBindViewHolder(ViewHolder holder, final int position);
#Override
public int getItemCount() {
return (mItems != null) ? mItems.size() : 0;
}
/**
* Clean the adapter.
* ALWAYS call this method before destroying the adapter to remove the listener.
*/
public void destroy() {
mQuery.removeEventListener(mListener);
}
/**
* Returns the list of items of the adapter: can be useful when dealing with a configuration
* change (e.g.: a device rotation).
* Just save this list before destroying the adapter and pass it to the new adapter (in the
* constructor).
*
* #return the list of items of the adapter
*/
public ArrayList<T> getItems() {
return mItems;
}
/**
* Returns the list of keys of the items of the adapter: can be useful when dealing with a
* configuration change (e.g.: a device rotation).
* Just save this list before destroying the adapter and pass it to the new adapter (in the
* constructor).
*
* #return the list of keys of the items of the adapter
*/
public ArrayList<String> getKeys() {
return mKeys;
}
/**
* Returns the item in the specified position
*
* #param position Position of the item in the adapter
* #return the item
*/
public T getItem(int position) {
return mItems.get(position);
}
/**
* Returns the position of the item in the adapter
*
* #param item Item to be searched
* #return the position in the adapter if found, -1 otherwise
*/
public int getPositionForItem(T item) {
return mItems != null && mItems.size() > 0 ? mItems.indexOf(item) : -1;
}
/**
* Check if the searched item is in the adapter
*
* #param item Item to be searched
* #return true if the item is in the adapter, false otherwise
*/
public boolean contains(T item) {
return mItems != null && mItems.contains(item);
}
/**
* ABSTRACT METHODS THAT MUST BE IMPLEMENTED BY THE EXTENDING ADAPTER.
*/
/**
* Called after an item has been added to the adapter
*
* #param item Added item
* #param key Key of the added item
* #param position Position of the added item in the adapter
*/
protected void itemAdded(T item, String key, int position) {
}
/**
* Called after an item changed
*
* #param oldItem Old version of the changed item
* #param newItem Current version of the changed item
* #param key Key of the changed item
* #param position Position of the changed item in the adapter
*/
protected void itemChanged(T oldItem, T newItem, String key, int position) {
}
/**
* Called after an item has been removed from the adapter
*
* #param item Removed item
* #param key Key of the removed item
* #param position Position of the removed item in the adapter
*/
protected void itemRemoved(T item, String key, int position) {
}
/**
* Called after an item changed position
*
* #param item Moved item
* #param key Key of the moved item
* #param oldPosition Old position of the changed item in the adapter
* #param newPosition New position of the changed item in the adapter
*/
protected void itemMoved(T item, String key, int oldPosition, int newPosition) {
}
/**
* Converts the data snapshot to generic object
*
* #param snapshot Result
* #return Data converted
*/
protected T getConvertedObject(DataSnapshot snapshot) {
return snapshot.getValue(getGenericClass());
}
/**
* Returns a class reference from generic T.
*/
#SuppressWarnings("unchecked")
private Class<T> getGenericClass() {
return (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
}
}
Useful links:
Generic Firebase recyclerview list for Android
Hope it helps
This question already has answers here:
Why does Gson fromJson throw a JsonSyntaxException: Expected BEGIN_OBJECT but was BEGIN_ARRAY?
(2 answers)
Closed 6 years ago.
good evening everyone, Ive been searching for a solution to an error android studio's log is sending using RecyclerView to show a JSON "product" list with retrofit.
I have already read the questions related to this error but im not able to find the right answer to my needs.
Android: RecyclerView: No adapter attached; skipping layout
No adapter attached; skipping layout recyclerview error
recyclerview No adapter attached; skipping layout
No adapter attached; skipping layout onCreateView()
This is de error log showed by android studio
RecyclerView: No adapter attached; skipping layout
RecyclerView: No adapter attached; skipping layout
Surface: getSlotFromBufferLocked: unknown buffer: 0xa3d9a700
OpenGLRenderer: endAllStagingAnimators on 0xa2b6bb00 (RippleDrawable) with handle 0xa200a310
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
For this proyect are been used this Classes and Layout files
"Producto" Class
public class Producto {
#SerializedName("id")
#Expose
private int id;
#SerializedName("name")
#Expose
private String name;
#SerializedName("status")
#Expose
private String status;
#SerializedName("price")
#Expose
private String price;
#SerializedName("regular_price")
#Expose
private String regularPrice;
#SerializedName("sale_price")
#Expose
private String salePrice;
#SerializedName("price_html")
#Expose
private String priceHtml;
#SerializedName("on_sale")
#Expose
private boolean onSale;
#SerializedName("total_sales")
#Expose
private int totalSales;
#SerializedName("purchase_note")
#Expose
private String purchaseNote;
#SerializedName("categories")
#Expose
private List<Category> categories;
#SerializedName("menu_order")
#Expose
private int menuOrder;
/**
*
* #return
* The id
*/
public int getId() {
return id;
}
/**
*
* #param id
* The id
*/
public void setId(int id) {
this.id = id;
}
/**
*
* #return
* The name
*/
public String getName() {
return name;
}
/**
*
* #param name
* The name
*/
public void setName(String name) {
this.name = name;
}
/**
*
* #return
* The status
*/
public String getStatus() {
return status;
}
/**
*
* #param status
* The status
*/
public void setStatus(String status) {
this.status = status;
}
/**
*
* #return
* The price
*/
public String getPrice() {
return price;
}
/**
*
* #param price
* The price
*/
public void setPrice(String price) {
this.price = price;
}
/**
*
* #return
* The regularPrice
*/
public String getRegularPrice() {
return regularPrice;
}
/**
*
* #param regularPrice
* The regular_price
*/
public void setRegularPrice(String regularPrice) {
this.regularPrice = regularPrice;
}
/**
*
* #return
* The salePrice
*/
public String getSalePrice() {
return salePrice;
}
/**
*
* #param salePrice
* The sale_price
*/
public void setSalePrice(String salePrice) {
this.salePrice = salePrice;
}
/**
*
* #return
* The priceHtml
*/
public String getPriceHtml() {
return priceHtml;
}
/**
*
* #param priceHtml
* The price_html
*/
public void setPriceHtml(String priceHtml) {
this.priceHtml = priceHtml;
}
/**
*
* #return
* The onSale
*/
public boolean isOnSale() {
return onSale;
}
/**
*
* #param onSale
* The on_sale
*/
public void setOnSale(boolean onSale) {
this.onSale = onSale;
}
/**
*
* #return
* The totalSales
*/
public int getTotalSales() {
return totalSales;
}
/**
*
* #param totalSales
* The total_sales
*/
public void setTotalSales(int totalSales) {
this.totalSales = totalSales;
}
/**
*
* #return
* The purchaseNote
*/
public String getPurchaseNote() {
return purchaseNote;
}
/**
*
* #param purchaseNote
* The purchase_note
*/
public void setPurchaseNote(String purchaseNote) {
this.purchaseNote = purchaseNote;
}
/**
*
* #return
* The categories
*/
public List<Category> getCategories() {
return categories;
}
/**
*
* #param categories
* The categories
*/
public void setCategories(List<Category> categories) {
this.categories = categories;
}
/**
*
* #return
* The menuOrder
*/
public int getMenuOrder() {
return menuOrder;
}
/**
*
* #param menuOrder
* The menu_order
*/
public void setMenuOrder(int menuOrder) {
this.menuOrder = menuOrder;
}
}
"Category" Class (which matches with the private List<Category> categories; property)
public class Category {
#SerializedName("id")
#Expose
private int id;
#SerializedName("name")
#Expose
private String name;
#SerializedName("slug")
#Expose
private String slug;
/**
*
* #return
* The id
*/
public int getId() {
return id;
}
/**
*
* #param id
* The id
*/
public void setId(int id) {
this.id = id;
}
/**
*
* #return
* The name
*/
public String getName() {
return name;
}
/**
*
* #param name
* The name
*/
public void setName(String name) {
this.name = name;
}
/**
*
* #return
* The slug
*/
public String getSlug() {
return slug;
}
/**
*
* #param slug
* The slug
*/
public void setSlug(String slug) {
this.slug = slug;
}
}
Both Containanied as Arrays in this class called "JSONproducts"
public class JSONproducts {
private Producto[] products;
private Category[] categories;
public Producto[] getProducts(){
return products;
}
public Category[] getCategories(){
return categories;
}
}
Then The Request Interface called "LecturaProductos"
public interface LecturaProductos {
#GET("Products")
Call<JSONproducts> ListarProductos();
}
The data Adapter for the Recycler View called "Adaptador"
public class Adaptador extends RecyclerView.Adapter<Adaptador.ViewHolder> {
private ArrayList<Producto> productos;
private ArrayList<Category> categoria;
public Adaptador(ArrayList<Producto> productos, ArrayList<Category> categoria){
this.productos = productos;
this.categoria = categoria;
}
#Override
public Adaptador.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.product_view, parent, false );
return new ViewHolder(view);
}
#Override
public void onBindViewHolder(Adaptador.ViewHolder holder, int position) {
holder.nom_pro_tv.setText(productos.get(position).getName());
holder.id_pro_tv.setText(productos.get(position).getId());
holder.cat_pro.setText(categoria.get(position).getName());
}
#Override
public int getItemCount() {
return productos.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
private TextView nom_pro_tv, id_pro_tv, cat_pro;
public ViewHolder(View itemView) {
super(itemView);
nom_pro_tv = (TextView)itemView.findViewById(R.id.nom_pro_tv);
id_pro_tv = (TextView)itemView.findViewById(R.id.id_pro_tv);
cat_pro = (TextView)itemView.findViewById(R.id.cat_pro_tv);
}
}
}
And the Activity Class "ListaProductos"
public class ListaProductos extends AppCompatActivity {
private RecyclerView recyclerView;
private ArrayList<Producto> product;
private ArrayList<Category> category;
private Adaptador adaptador;
public static final String BASE_URL= "https://mydomain.com.mx/wp-json/wc/v1/";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_lista_productos);
showView();
}
private void showView(){
recyclerView = (RecyclerView)findViewById(R.id.prod_recycler_view);
recyclerView.setHasFixedSize(true);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
cargarJSON();
}
private void cargarJSON(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
final LecturaProductos producto = retrofit.create(LecturaProductos.class);
Call<JSONproducts> productoCall = producto.ListarProductos();
productoCall.enqueue(new Callback<JSONproducts>() {
#Override
public void onResponse(Call<JSONproducts> call, Response<JSONproducts> response) {
JSONproducts jsonproducts = response.body();
product = new ArrayList<>(Arrays.asList(jsonproducts.getProducts()));
category = new ArrayList<>(Arrays.asList(jsonproducts.getCategories()));
adaptador = new Adaptador(product, category);
recyclerView.setAdapter(adaptador);
}
#Override
public void onFailure(Call<JSONproducts> call, Throwable t) {
Log.d("Error", t.getMessage());
}
});
}
}
And the Layout XML files that are been used
RecyclerView Layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_lista_productos"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="mx.com.corpcap.elrollorepartidor.ListaProductos">
<android.support.v7.widget.RecyclerView
android:id="#+id/prod_recycler_view"
android:layout_height="match_parent"
android:layout_width="match_parent"/></LinearLayout>
CardView Layout for the product list
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/nom_pro_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="16sp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"/>
<TextView
android:id="#+id/id_pro_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/cat_pro_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v7.widget.CardView>
Everything complies great and launches the app without an issue but when the information is tried to be accessed it sends the log messages quoted in the beginning of this question.
Thanks a Lot
A RecyclerView is not much use on it's own without an adapter providing the data it must display. So when a RecyclerView is initialized and placed in the layout but .setAdapter has not yet been called, the problem you're experiencing occurs. How about you take an empty list and use that to initialize the adapter and set it to your RecyclerView before you even send the network request. When you make the network request and get a response, simply clear the old values in the list, add new values and notify your adapter that the data in the list has changed. This should avoid the skipping layout problem, Alex.
Something like this:
private ArrayList<YourObjectClass> listOfYourObjects = new ArrayList<>();
.
.
.
SomeAdapter yourAdapter = new SomeAdapter(listOfYourObjects , context);
yourRecyclerView.setAdapter(yourAdapter);
.
.
.
onResponse:
list.clear();
//Let the adapter know the list is empty now
yourAdapter.notifyDataSetChanged();
//Fill in your list with values from server using a for/while loop etc.
//Again notify your adapter that the list has changed:
yourAdapter.notifyDataSetChanged();
Hope that helps.
Hello guys I'm still learning android things and this is my first time that I 'm building a list using retrofit to populate it from server. I receive no error, app doesn't crash, and my log show that I receive data from server.
My Adapter for listview:
public class TransactionsAdapter extends BaseAdapter {
ArrayList<Transactions> transactions;
public TransactionsAdapter(ArrayList<Transactions> transactions) {
this.transactions=transactions;
}
#Override
public int getCount() {
return 0;
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view=null;
ViewHolder viewHolder = null;
if(convertView == null)
{
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.izvjestaji_item,parent,false);
viewHolder = new ViewHolder(view);
view.setTag(viewHolder);
}
else{
view = convertView;
viewHolder= (ViewHolder) view.getTag();
}
Transactions transactions = (Transactions) getItem(position);
if(transactions != null) {
viewHolder.datum.setText(transactions.getPurchaseDate());
viewHolder.partner.setText(transactions.getMerchantName());
viewHolder.iznos.setText(transactions.getTransactionMoneyAmount().toString());
viewHolder.brojbodova.setText(transactions.getSalesAmount().toString());
}
return view;
}
private class ViewHolder{
TextView datum;
TextView partner;
TextView iznos;
TextView brojbodova;
public ViewHolder(View view) {
this.datum = (TextView) view.findViewById(R.id.izvjestaji_datum);
this.partner = (TextView) view.findViewById(R.id.izvjestaji_partner);
this.iznos = (TextView) view.findViewById(R.id.izvjestaji_iznos);
this.brojbodova=(TextView)view.findViewById(R.id.izvjestaji_brojbodova);
}
}
}
Model that server return generated via jsonschema2pojo.org
import javax.annotation.Generated;
#Generated("org.jsonschema2pojo")
public class Transactions {
private Integer Id;
private String PurchaseDate;
private Integer Month;
private Integer Year;
private Double SalesAmount;
private Object SpecialSalesActionId;
private Integer PosTerminalId;
private Integer CardId;
private String MerchantName;
private Integer TransactionPointsAmount;
private Double TransactionMoneyAmount;
private Boolean IsDeleted;
private Boolean IsVoucher;
private Integer LoyaltyLevel;
private Integer CategoryId;
private Object CardNo;
private Integer MerchantId;
/**
*
* #return
* The Id
*/
public Integer getId() {
return Id;
}
/**
*
* #param Id
* The Id
*/
public void setId(Integer Id) {
this.Id = Id;
}
/**
*
* #return
* The PurchaseDate
*/
public String getPurchaseDate() {
return PurchaseDate;
}
/**
*
* #param PurchaseDate
* The PurchaseDate
*/
public void setPurchaseDate(String PurchaseDate) {
this.PurchaseDate = PurchaseDate;
}
/**
*
* #return
* The Month
*/
public Integer getMonth() {
return Month;
}
/**
*
* #param Month
* The Month
*/
public void setMonth(Integer Month) {
this.Month = Month;
}
/**
*
* #return
* The Year
*/
public Integer getYear() {
return Year;
}
/**
*
* #param Year
* The Year
*/
public void setYear(Integer Year) {
this.Year = Year;
}
/**
*
* #return
* The SalesAmount
*/
public Double getSalesAmount() {
return SalesAmount;
}
/**
*
* #param SalesAmount
* The SalesAmount
*/
public void setSalesAmount(Double SalesAmount) {
this.SalesAmount = SalesAmount;
}
/**
*
* #return
* The SpecialSalesActionId
*/
public Object getSpecialSalesActionId() {
return SpecialSalesActionId;
}
/**
*
* #param SpecialSalesActionId
* The SpecialSalesActionId
*/
public void setSpecialSalesActionId(Object SpecialSalesActionId) {
this.SpecialSalesActionId = SpecialSalesActionId;
}
/**
*
* #return
* The PosTerminalId
*/
public Integer getPosTerminalId() {
return PosTerminalId;
}
/**
*
* #param PosTerminalId
* The PosTerminalId
*/
public void setPosTerminalId(Integer PosTerminalId) {
this.PosTerminalId = PosTerminalId;
}
/**
*
* #return
* The CardId
*/
public Integer getCardId() {
return CardId;
}
/**
*
* #param CardId
* The CardId
*/
public void setCardId(Integer CardId) {
this.CardId = CardId;
}
/**
*
* #return
* The MerchantName
*/
public String getMerchantName() {
return MerchantName;
}
/**
*
* #param MerchantName
* The MerchantName
*/
public void setMerchantName(String MerchantName) {
this.MerchantName = MerchantName;
}
/**
*
* #return
* The TransactionPointsAmount
*/
public Integer getTransactionPointsAmount() {
return TransactionPointsAmount;
}
/**
*
* #param TransactionPointsAmount
* The TransactionPointsAmount
*/
public void setTransactionPointsAmount(Integer TransactionPointsAmount) {
this.TransactionPointsAmount = TransactionPointsAmount;
}
/**
*
* #return
* The TransactionMoneyAmount
*/
public Double getTransactionMoneyAmount() {
return TransactionMoneyAmount;
}
/**
*
* #param TransactionMoneyAmount
* The TransactionMoneyAmount
*/
public void setTransactionMoneyAmount(Double TransactionMoneyAmount) {
this.TransactionMoneyAmount = TransactionMoneyAmount;
}
/**
*
* #return
* The IsDeleted
*/
public Boolean getIsDeleted() {
return IsDeleted;
}
/**
*
* #param IsDeleted
* The IsDeleted
*/
public void setIsDeleted(Boolean IsDeleted) {
this.IsDeleted = IsDeleted;
}
/**
*
* #return
* The IsVoucher
*/
public Boolean getIsVoucher() {
return IsVoucher;
}
/**
*
* #param IsVoucher
* The IsVoucher
*/
public void setIsVoucher(Boolean IsVoucher) {
this.IsVoucher = IsVoucher;
}
/**
*
* #return
* The LoyaltyLevel
*/
public Integer getLoyaltyLevel() {
return LoyaltyLevel;
}
/**
*
* #param LoyaltyLevel
* The LoyaltyLevel
*/
public void setLoyaltyLevel(Integer LoyaltyLevel) {
this.LoyaltyLevel = LoyaltyLevel;
}
/**
*
* #return
* The CategoryId
*/
public Integer getCategoryId() {
return CategoryId;
}
/**
*
* #param CategoryId
* The CategoryId
*/
public void setCategoryId(Integer CategoryId) {
this.CategoryId = CategoryId;
}
/**
*
* #return
* The CardNo
*/
public Object getCardNo() {
return CardNo;
}
/**
*
* #param CardNo
* The CardNo
*/
public void setCardNo(Object CardNo) {
this.CardNo = CardNo;
}
/**
*
* #return
* The MerchantId
*/
public Integer getMerchantId() {
return MerchantId;
}
/**
*
* #param MerchantId
* The MerchantId
*/
public void setMerchantId(Integer MerchantId) {
this.MerchantId = MerchantId;
}
}
Fragment in which I want to include list:
public class Izvjestaji extends Fragment {
ListView list;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
// Defines the xml file for the fragment
return inflater.inflate(R.layout.izvjestaji, parent, false);
}
// This event is triggered soon after onCreateView().
// Any view setup should occur here. E.g., view lookups and attaching view listeners.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
list=(ListView)view.findViewById(R.id.izvjestaji_list);
showList();
// Setup any handles to view objects here
// EditText etFoo = (EditText) view.findViewById(R.id.etFoo);
}
public void showList(){
NetworkSDK.getInstance().getTransactions(new Callback<List<Transactions>>() {
#Override
public void onResponse(Call<List<Transactions>> call, Response<List<Transactions>> response) {
if(response.isSuccess()){
Log.d("Data", String.valueOf(response.isSuccess()));
TransactionsAdapter transactionsAdapter=new TransactionsAdapter((ArrayList<Transactions>)response.body());
list.setAdapter(transactionsAdapter);
}
}
#Override
public void onFailure(Call<List<Transactions>> call, Throwable t) {
Log.d("Error","Def error");
}
});
}
}
2 xml files (one is from fragment and other is single item in list )
Fragment layout :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical" >
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/izvjestaji_list" />
</LinearLayout>
Item_Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Datum"
android:id="#+id/izvjestaji_datum"
android:gravity="center"
android:background="#a9a8a8"
android:layout_weight="1"
android:textSize="20dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/izvjestaji_partner"
android:text="Partner"
android:gravity="center"
android:background="#a9a8a8"
android:layout_weight="1"
android:textSize="20dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/izvjestaji_iznos"
android:text="Iznos"
android:background="#a9a8a8"
android:gravity="center"
android:layout_weight="1"
android:textSize="20dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/izvjestaji_brojbodova"
android:text="Broj Bodova"
android:gravity="center"
android:background="#a9a8a8"
android:layout_weight="1"
android:textSize="20dp" />
</LinearLayout>
In my preview I only get empty fragment
In TransactionAdapter class you have not implemented the overriding methods
use these
#Override
public int getCount() {
return transactions.size();
}
#Override
public Object getItem(int position) {
return transactions.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
Change to this
#Override
public int getCount() {
return transactions.size();
}
#Override
public Object getItem(int position) {
return transactions.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
I'm trying to populate a layout of mine by looping through some requested JSON (I use Retrofit).
When I try to populate the layout manually (like below), it displays fine:
Post post1 = new Post("1", "1", "This is a message.");
But if I try to populate it with the requested JSON data, the layout doesn't get populated nor does it display on my screen. Only the layout with "This is a message." is displayed.
Here is the code within my onCreateView() for my fragment:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
ListView listView = (ListView) view.findViewById(R.id.listview_posts);
final ArrayList<Post> arrayOfUsers = new ArrayList<Post>();
// This works fine. It populates the layout as it should.
Post post1 = new Post("1", "1", "This is a message.");
arrayOfUsers.add(post1);
final RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(BASE_URL)
.build();
final ApiEndpointInterface apiService = restAdapter.create(ApiEndpointInterface.class);
apiService.getJsonStuff(1, new Callback<PostData>() {
#Override
public void success(PostData postData, Response response) {
// This doesn't work either
Post post2 = new Post("1", "1", "This is a message2.");
arrayOfUsers.add(post2);
for (Post p : postData.data) {
// This does not work. The layout isn't populated nor does it display.
Post posty = new Post(p.getId(), p.getUserId(), p.getContent());
arrayOfUsers.add(posty);
// The JSON is being read correctly, since this prints out the right values.
Log.d("MESSAGE", p.getMessage());
}
}
#Override
public void failure(RetrofitError retrofitError) {
retrofitError.printStackTrace();
}
});
PostAdapter adapter = new PostAdapter(getActivity(), arrayOfUsers);
listView.setAdapter(adapter);
return view;
}
The callback:
void getJsonStuff(#Path("user_id") int userId, Callback<PostData> response);
Post model:
import java.util.ArrayList;
import java.util.List;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class Post {
#Expose
private String id;
#SerializedName("user_id")
#Expose
private String userId;
#Expose
private String content;
public Post(String id, String userId, String content) {
this.id = id;
this.userId = userId;
this.content = content;
}
/**
*
* #return
* The id
*/
public String getId() {
return id;
}
/**
*
* #param id
* The id
*/
public void setId(String id) {
this.id = id;
}
/**
*
* #return
* The userId
*/
public String getUserId() {
return userId;
}
/**
*
* #param userId
* The user_id
*/
public void setUserId(String userId) {
this.userId = userId;
}
/**
*
* #return
* The content
*/
public String getContent() {
return content;
}
/**
*
* #param content
* The content
*/
public void setContent(String content) {
this.content= content;
}
}
PostData model:
import java.util.ArrayList;
import java.util.List;
import com.google.gson.annotations.Expose;
public class PostData {
#Expose
public Boolean success;
#Expose
public List<Post> data = new ArrayList<Post>();
/**
*
* #return
* The success
*/
public Boolean getSuccess() {
return success;
}
/**
*
* #param success
* The success
*/
public void setSuccess(Boolean success) {
this.success = success;
}
/**
*
* #return
* The data
*/
public List<Post> getData() {
return data;
}
/**
*
* #param data
* The data
*/
public void setData(List<Post> data) {
this.data = data;
}
}
In the scenario that works for you -> you are doing the things sequentially: create the Post object - add it to the list - create the adapter based on the non-empty list - set the adapter on the list.
In the scenario that doesn't work, you are doing them asynchronously: create empty list - trigger request for data (but no data yet) - create adapter - set the adapter on the list - at some undetermined moment in the future data arrives. The problem is that in this case the adapter doesn't know that anything changed, so you need to notify it (at the end of your success callback):
adapter.notifyDataSetChanged()
Your getJsonStuff method should be declared something like...
getJsonStuff(int id, Callback<List<Post>> callback)