ArrayAdapter and ListView bug - android

I'm facing a bug while displaying some data through ListView with ArrayAdapter.
I have Order instances in my data defined by its ID.
The ListView displays it through a TextView with the ID.
The problem is that the first (and always the first) instance has its ID written 3 times.
ex:
Order n°111
Order n°2
Order n°3
It's not my first experience with ListViews and adapters and I've never had such a disagreement.
public class OrderAdapter extends ArrayAdapter<Order> {
public OrderAdapter(Context context, ArrayList<Order> orders) {
super(context, 0, orders);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Order order = getItem(position);
if(convertView == null){
convertView = LayoutInflater.from(getContext()).inflate(R.layout.order, parent, false);
}
TextView orderCheckedTextView = (TextView)convertView.findViewById(R.id.orderCheckedTextView);
System.out.println("###"+order.getId());
orderCheckedTextView.setText(orderCheckedTextView.getText()+Integer.toString(order.getId()));
return convertView;
}}
Here the print returns:
###1 ###1 ###1 ###2
Then I create 3 Orders add it to the data set and set the adapter to the listView:
Order order1 = new Order(Type.LIVRAISON,State.PREPARATION, PaymentType.CB, articleList, null);
Order order2 = new Order(Type.EMPORTE,State.PREPARATION, PaymentType.TICKET, articleList, null);
Order order3 = new Order(Type.EMPORTE,State.PREPARATION, PaymentType.TICKET, articleList, null);
parentActivity.model.getOrderlist().addOrder(order1);
parentActivity.model.getOrderlist().addOrder(order2);
parentActivity.model.getOrderlist().addOrder(order3);
this.inProgressOrderAdapter = new OrderAdapter(parentActivity.getApplicationContext(), parentActivity.model.getOrderlist().getInProgressOrderList());
final ListView inProgressOrderListView = (ListView)parentActivity.findViewById(R.id.inProgressOrderListView);
inProgressOrderListView.setAdapter(inProgressOrderAdapter);
public class Order {
private OrderList orderList= null;
private static int staticID = 0;
private int id = 0;
private Type type = null;
private PaymentType paymentType = null;
private State state = null;
private Date time = null;
private ArrayList<Object> articleList = new ArrayList<>();
private double totalPrice = 0;
private Deliver deliver = null;
public Order(Type type, State state, PaymentType paymentType, ArrayList<Object> articleList, Deliver deliver) {
staticID++;
this.id = staticID;
this.type = type;
this.state = state;
this.paymentType = paymentType;
this.articleList = articleList;
this.deliver = deliver;
for(Object article:articleList){
if(article instanceof Article){
totalPrice += ((Article)article).getPrice();
}
else if(article instanceof Menu){
totalPrice += ((Menu)article).getPrice();
}
}
}
public OrderList getOrderList() {
return orderList;
}
public void setOrderList(OrderList orderList) {
this.orderList = orderList;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
if(state.equals(State.LIVRE) || state.equals(State.PREPARE))
this.orderList.switchOrderList(this);
}
public PaymentType getPaymentType() {
return paymentType;
}
public void setPaymentType(PaymentType paymentType) {
this.paymentType = paymentType;
}
public Date getTime() {
return this.time;
}
public ArrayList<Object> getArticleList() {
return articleList;
}
public void setArticleList(ArrayList<Object> articleList) {
this.articleList = articleList;
}
public void addArticle(Object article){
if(article instanceof Article || article instanceof Menu){
Boolean removed = this.articleList.add(article);
if(article instanceof Article && removed){
this.totalPrice += ((Article) article).getPrice();
}
else if(article instanceof Menu && removed){
this.totalPrice += ((Menu) article).getPrice();
}
}
}
public void removeArticle(Object article){
if(article instanceof Article || article instanceof Menu){
Boolean removed = this.articleList.remove(article);
if(article instanceof Article && removed){
this.totalPrice -= ((Article) article).getPrice();
}
else if(article instanceof Menu && removed){
this.totalPrice -= ((Menu) article).getPrice();
}
}
}
public double getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(double totalPrice) {
this.totalPrice = totalPrice;
}
public Deliver getDeliver() {
return deliver;
}
public void setDeliver(Deliver deliver) {
this.deliver = deliver;
}}
public enum PaymentType {
INTERNET, CB, ESPECE, TICKET;}
Thanks

Problem is with line where you declared your private static int staticID = 0;
for each object creation of Order class and instance of order is created with all its memeber variable and static variable so for each order object this staticId = 0 at the time of object creation. Suppose your created first object Order1 here staticId = 0; and in custructor you incremented it to 1 so for order1 id= 1
2- Now for order2 Object created again this instance have staticId value = 0 not 1 (if you think i incremented it to 1 at the time of first order creation than you are taking static as wrong understanding bcs when ever a new object created all its member variable again created with it) so for order2 objects constructor you increment it 0 to 1 so for order2 id is again set to 1 not 2.
3- order3 continue same as order2.
Now solution is pass your id value in the constructor at the time of object creation like below:
Order order1 = new Order(1,Type.LIVRAISON,State.PREPARATION, PaymentType.CB, articleList, null);
Order order2 = new Order(2,Type.EMPORTE,State.PREPARATION, PaymentType.TICKET, articleList, null);
Order order3 = new Order(3,Type.EMPORTE,State.PREPARATION, PaymentType.TICKET, articleList, null);
parentActivity.model.getOrderlist().addOrder(order1);
parentActivity.model.getOrderlist().addOrder(order2);
parentActivity.model.getOrderlist().addOrder(order3);
And increase one parameter in Order Constructor:
public Order(int **orderid**,Type type, State state, PaymentType paymentType, ArrayList<Object> articleList, Deliver deliver) {
staticID++; **// dont use this staticId**
this.id = orderid;
this.type = type;
this.state = state;
this.paymentType = paymentType;
this.articleList = articleList;
this.deliver = deliver;
for(Object article:articleList){
if(article instanceof Article){
totalPrice += ((Article)article).getPrice();
}
else if(article instanceof Menu){
totalPrice += ((Menu)article).getPrice();
}
}
}

Related

Pass Cursor objects through intents to another activity in Android

I have a recyclerview adapter that displays data in a list view which data were populated via cursor. I would like to extend further by setting a click to each list item and pass an intent of values to another Activity like a detail activity.
Adapter.class
public class RecyclerAdapter extends
RecyclerView.Adapter<RecyclerAdapter.Holder> {
/* ViewHolder for each insect item */
public class Holder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView friendlyName, scientificName, dangerLevel;
ImageView image;
public Holder(View itemView) {
super(itemView);
friendlyName = (TextView) itemView.findViewById(R.id.friendlyName);
scientificName = (TextView) itemView.findViewById(R.id.scientificName);
dangerLevel = (TextView) itemView.findViewById(R.id.text1);
}
#Override
public void onClick(View v) {
}
}
private Cursor mCursor;
private Context mContext;
public RecyclerAdapter(Context context, Cursor cursor) {
this.mContext = context;
this.mCursor = cursor;
}
#Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.bugs_list_item, parent, false);
return new Holder(view);
}
#Override
public void onBindViewHolder(Holder holder, int position) {
int insectname = mCursor.getColumnIndex(BugsContract.BugsEntry.COLUMN_FRIENDLYNAME);
int scienceName = mCursor.getColumnIndex(BugsContract.BugsEntry.COLUMN_SCIENTIFICNAME);
int id = mCursor.getColumnIndex(BugsContract.BugsEntry._ID);
int dangerlevel = mCursor.getColumnIndex(BugsContract.BugsEntry.COLUMN_DANGERLEVEL);
int insectImage = mCursor.getColumnIndex(BugsContract.BugsEntry.COLUMN_IMAGEASSET);
mCursor.moveToPosition(position);
String insectRName = mCursor.getString(insectname);
String scienceRName = mCursor.getString(scienceName);
String insectRImage = mCursor.getString(insectImage);
int dangerlevelInt = mCursor.getInt(dangerlevel);
String dangerString = "" + dangerlevelInt;
holder.dangerLevel.setText(dangerString);
holder.friendlyName.setText(insectRName);
holder.scientificName.setText(scienceRName);
}
private int getDangerColor(int danger) {
int priorityColor = 0;
int[] colorDangerarray = mContext.getResources().getIntArray(R.array.dangerColors);
switch(danger) {
case 1: priorityColor = ContextCompat.getColor(mContext, colorDangerarray[0]);
break;
case 2: priorityColor = ContextCompat.getColor(mContext, colorDangerarray[1]);
break;
case 3: priorityColor = ContextCompat.getColor(mContext, colorDangerarray[2]);
break;
default: break;
}
return priorityColor;
}
#Override
public int getItemCount() {
return mCursor.getCount();
}
/**
* Return the {#link Insect} represented by this item in the adapter.
*
* #param position Adapter item position.
*
* #return A new {#link Insect} filled with this position's attributes
*
* #throws IllegalArgumentException if position is out of the adapter's bounds.
*/
public Insect getItem(int position) {
if (position < 0 || position >= getItemCount()) {
throw new IllegalArgumentException("Item position is out of adapter's range");
} else if (mCursor.moveToPosition(position)) {
return new Insect(mCursor);
}
return null;
}
}
A model class that implements parceleable
public class Insect implements Parcelable {
private static final String TAG = Insect.class.getSimpleName();
//Common name
public int id;
public String name;
//Latin scientific name
public String scientificName;
//Classification order
public String classification;
//Path to image resource
public String imageAsset;
//1-10 scale danger to humans
public int dangerLevel;
/**
* Create a new Insect from discrete values
*/
public Insect(String name, String scientificName, String classification, String imageAsset, int dangerLevel) {
this.name = name;
this.scientificName = scientificName;
this.classification = classification;
this.imageAsset = imageAsset;
this.dangerLevel = dangerLevel;
}
/**
* Create a new Insect from a database Cursor
*/
public Insect(Cursor cursor) {
//TODO: Create a new insect from cursor
this.name = cursor.getString(cursor.getColumnIndex(BugsContract.BugsEntry.COLUMN_FRIENDLYNAME));
this.scientificName = cursor.getString(cursor.getColumnIndex(BugsContract.BugsEntry.COLUMN_SCIENTIFICNAME));
this.classification = cursor.getString(cursor.getColumnIndex(BugsContract.BugsEntry.COLUMN_CLASSIFICATION));
this.imageAsset = cursor.getString(cursor.getColumnIndex(BugsContract.BugsEntry.COLUMN_IMAGEASSET));
this.dangerLevel = Integer.parseInt(cursor.getString(cursor.getColumnIndex(BugsContract.BugsEntry.COLUMN_DANGERLEVEL)));
}
public Insect() {
}
/**
* Create a new Insect from a data Parcel
*/
protected Insect(Parcel in) {
this.name = in.readString();
this.scientificName = in.readString();
this.classification = in.readString();
this.imageAsset = in.readString();
this.dangerLevel = in.readInt();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeString(scientificName);
dest.writeString(classification);
dest.writeString(imageAsset);
dest.writeInt(dangerLevel);
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<Insect> CREATOR = new Creator<Insect>() {
#Override
public Insect createFromParcel(Parcel in) {
return new Insect(in);
}
#Override
public Insect[] newArray(int size) {
return new Insect[size];
}
};
}
I would like to know how to declare an intent that houses the data to another activity and how to get data from the intent in the next activity
As long as you've implemented parcelable on your model class you can easily pass your object around like you usually would passing primitive data via putExtra() method.
For the sender activity:
Intent receiverIntent = new Intent(this, Receiver.class);
receiverIntent.putExtra("key", ParcelableObject);
startActivity(receiverIntent);
As for the receiver class, you just make an intent object to get the parcelableExtra in the onCreate() method.
Intent i = getIntent();
ParcelableClass parcelableObject;
parcelableObject = i.getParcelableExtra("key");
voila, that should do.

How to instantiate interface from asynctask inside fragment

I have an Interface implemented in ProductListAdapter class which is a list adapter. Items in this list have three input fields. to keep track of those values I have implemented a class MyCustomEditTextListener which extends a TextWatcher class. This class simply create array list of edited data. I want to get reference to array list every time it changes from fragment which contains list view. For that I have implemented DataChangedListener
ProductListAdapter.java
public class ProductListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private LayoutInflater inflater;
private ArrayList<Products> listData;
private ArrayList<Products> editedData;
private Context context;
private DataChangedListener dataChangedListener;
private static final int ITEM = 0;
private static final int LOADING = 1;
private static final int QUANTITY = 5;
private static final int FREE_QUANTITY = 10;
private static final int DISCOUNT = 15;
public ProductListAdapter(ArrayList<Products> listData, ArrayList<Products> editedData, Context context) {
this.listData = listData;
this.context = context;
this.editedData = editedData;
inflater = LayoutInflater.from(this.context);
}
public void updateData(ArrayList<Products> data) {
this.listData = data;
notifyDataSetChanged();
}
public void setDataChangedListener(DataChangedListener listener) {
this.dataChangedListener = listener;
}
#Override
public int getItemViewType(int position) {
return listData.get(position) == null ? LOADING : ITEM;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder viewHolder = null;
switch (viewType) {
case ITEM:
viewHolder = getViewHolder(parent, inflater);
break;
case LOADING:
View v2 = inflater.inflate(R.layout.list_footer, parent, false);
viewHolder = new LoadingVH(v2);
break;
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Products productObject = listData.get(position);
switch (getItemViewType(position)) {
case ITEM:
for(int i=0; i<editedData.size(); i++){
if(productObject.getProductId().equals(editedData.get(i).getProductId())){
productObject.setQuantity(editedData.get(i).getQuantity());
productObject.setFreeQuantity(editedData.get(i).getFreeQuantity());
productObject.setDiscount(editedData.get(i).getDiscount());
}
}
String productName = productObject.getProductName();
String quantityValue = productObject.getQuantity();
String freeQuantityValue = productObject.getFreeQuantity();
String discountValue = productObject.getDiscount();
String quantityInHand = productObject.getQuantityInHand();
String price = productObject.getWholeSalePrice();
ContentViewHolder movieVH = (ContentViewHolder) holder;
movieVH.productName.setText(productName);
movieVH.stock.setText(quantityInHand);
movieVH.price.setText("Rs."+price);
movieVH.quantityEditTextListener.updatePosition(movieVH.getLayoutPosition());
movieVH.quantity.setText(quantityValue);
movieVH.freeQuantityEditTextListener.updatePosition(movieVH.getLayoutPosition());
movieVH.freeQuantity.setText(freeQuantityValue);
movieVH.discountEditTextListener.updatePosition(movieVH.getLayoutPosition());
movieVH.discount.setText(discountValue);
movieVH.quantity.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
return false;
}
});
break;
case LOADING:
//Do nothing
break;
}
}
#Override
public int getItemCount() {
return listData == null ? 0 : listData.size();
}
#NonNull
private RecyclerView.ViewHolder getViewHolder(ViewGroup parent, LayoutInflater inflater) {
RecyclerView.ViewHolder viewHolder;
View view = inflater.inflate(R.layout.custom_product_list_item, parent, false);
viewHolder = new ContentViewHolder(view, new MyCustomEditTextListener()
, new MyCustomEditTextListener(), new MyCustomEditTextListener());
return viewHolder;
}
/**
* View holder for main container
*/
public class ContentViewHolder extends RecyclerView.ViewHolder{
private TextView productName;
private EditText quantity;
private EditText freeQuantity;
private EditText discount;
private TextView stock;
private TextView price;
private MyCustomEditTextListener quantityEditTextListener;
private MyCustomEditTextListener freeQuantityEditTextListener;
private MyCustomEditTextListener discountEditTextListener;
public ContentViewHolder(View itemView, MyCustomEditTextListener textListener
, MyCustomEditTextListener textListener2, MyCustomEditTextListener textListener3) {
super(itemView);
productName = (TextView) itemView.findViewById(R.id.product_name_data);
quantity = (EditText) itemView.findViewById(R.id.quantity_1_edit_text);
freeQuantity = (EditText) itemView.findViewById(R.id.quantity_2_edit_text);
discount = (EditText) itemView.findViewById(R.id.quantity_3_edit_text);
stock = (TextView) itemView.findViewById(R.id.quantity_in_hand_value);
price = (TextView) itemView.findViewById(R.id.price_value);
quantityEditTextListener = textListener;
quantityEditTextListener.setEditTextType(QUANTITY);
freeQuantityEditTextListener = textListener2;
freeQuantityEditTextListener.setEditTextType(FREE_QUANTITY);
discountEditTextListener = textListener3;
discountEditTextListener.setEditTextType(DISCOUNT);
this.quantity.addTextChangedListener(quantityEditTextListener);
this.freeQuantity.addTextChangedListener(freeQuantityEditTextListener);
this.discount.addTextChangedListener(discountEditTextListener);
}
}
/**
* View holder to display loading list item
*/
protected class LoadingVH extends RecyclerView.ViewHolder {
public LoadingVH(View itemView) {
super(itemView);
}
}
/**
* textWatcher for to keep track of changed data.
*/
private class MyCustomEditTextListener implements TextWatcher {
private int position;
private int type;
public void updatePosition(int position) {
this.position = position;
}
public void setEditTextType(int type) {
this.type = type;
}
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
// no op
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
if (type == QUANTITY) {
listData.get(position).setQuantity(charSequence.toString());
} else if (type == FREE_QUANTITY) {
listData.get(position).setFreeQuantity(charSequence.toString());
} else if (type == DISCOUNT) {
listData.get(position).setDiscount(charSequence.toString());
}
}
#Override
public void afterTextChanged(Editable s) {
boolean matchFound = false;
if(s.toString().length()>0){
for (int i=0;i<editedData.size();i++){
if(editedData.get(i).getProductId()
.equals(listData.get(position).getProductId())){
matchFound = true;
if (type == QUANTITY) {
editedData.get(i).setQuantity(s.toString());
} else if (type == FREE_QUANTITY) {
editedData.get(i).setFreeQuantity(s.toString());
} else if (type == DISCOUNT) {
editedData.get(i).setDiscount(s.toString());
}
}
}
if(!matchFound){
editedData.add(listData.get(position));
}
if(dataChangedListener!=null){
dataChangedListener.onDataChanged(editedData);
}
}
}
}
public interface DataChangedListener{
void onDataChanged(ArrayList<Products> editedData);
}
In my OrderEditFragment i'm trying to implement that interface to do necessary calculations.
OrderEditFragment.java
public class OrderEditFragment extends Fragment implements ProductListAdapter.DataChangedListener {
private LinearLayoutManager layoutManager;
private RecyclerView productRecyclerView;
private static ProductListAdapter productListAdapter;
private String employeeId;
private static ArrayList<Products> editedData;
private static ArrayList<Products> productsData;
private SharedPreferences sharedpreferences;
private final static OkHttpClient client = new OkHttpClient();
public OrderEditFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View inflate = inflater.inflate(R.layout.fragment_order_edit, container, false);
initComponents(inflate);
return inflate;
}
private void initComponents(View view) {
productRecyclerView = (RecyclerView) view.findViewById(R.id.product_edit_recycler_view);
progressView = (CircularProgressView) view.findViewById(R.id.progress_view);
layoutManager = new LinearLayoutManager(getContext());
sharedpreferences = getActivity().getSharedPreferences("dgFashionPref", Context.MODE_PRIVATE);
employeeId = sharedpreferences.getString("employee_id","");
productsData = new ArrayList<>();
editedData = new ArrayList<>();
isLoading = false;
isLastPage = false;
isFirstLoad = true;
isSearch = false;
new GetProductListGetRequest(getContext(), productRecyclerView, layoutManager)
.execute(RestConnection.PRODUCT_LIST_GET
+ RestConnection.CUSTOMER_ID_FOR_NAME + employeeId);
}
#Override
public void onDataChanged(ArrayList<Products> editedData) {
Log.d(TAG,editedData.toString());
}
/**
* AsyncTask class which handel the GET request to get product list
**/
public static class GetProductListGetRequest extends AsyncTask<String, Void, String>{
private WeakReference<Context> ActivityWeakReference;
private WeakReference<RecyclerView> recyclerViewWeakReference;
private WeakReference<RecyclerView.LayoutManager> layoutManagerWeakReference;
public GetProductListGetRequest(Context activity, RecyclerView recyclerView
, RecyclerView.LayoutManager layoutManager) {
ActivityWeakReference = new WeakReference<>(activity);
recyclerViewWeakReference = new WeakReference<>(recyclerView);
layoutManagerWeakReference = new WeakReference<>(layoutManager);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String urlEndPoint = params[0];
Request request = new Request.Builder()
.url(RestConnection.API_BASE + urlEndPoint)
.build();
try {
Response response = client.newCall(request).execute();
return response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String response) {
if( productsData.size()>0){
productsData.remove(productsData.size() - 1);
}
JSONArray responseBody;
try {
if (response != null && ActivityWeakReference.get() != null) {
responseBody = new JSONArray(response);
for (int i = 0; i < responseBody.length(); i++) {
JSONObject row = responseBody.getJSONObject(i);
String productId = row.getString("ProductID");
String productName = row.getString("Name");
String unit = row.getString("Unit");
String wholeSalePrice = row.getString("WSalePrice");
String packSize = row.getString("PackSize");
String retailPrice = row.getString("RetailPrice");
String costPrice = row.getString("CostPrice");
String qtyInHand = row.getString("QtyInHand");
Products productObj = new Products();
productObj.setProductName(productName);
productObj.setProductId(productId);
productObj.setUnit(unit);
productObj.setWholeSalePrice(wholeSalePrice);
productObj.setPackSize(packSize);
productObj.setRetailPrice(retailPrice);
productObj.setCostPrice(costPrice);
productObj.setQuantityInHand(qtyInHand);
productsData.add(productObj);
}
productListAdapter = new ProductListAdapter(productsData, editedData, ActivityWeakReference.get());
productListAdapter.setDataChangedListener(ActivityWeakReference.get());
recyclerViewWeakReference.get().setAdapter(productListAdapter);
recyclerViewWeakReference.get().setLayoutManager(layoutManagerWeakReference.get());
recyclerViewWeakReference.get().addItemDecoration(new RecyclerViewDivider(2));
} else {
Toast.makeText(ActivityWeakReference.get(), "Can't connect to the server", Toast.LENGTH_LONG).show();
}
} catch (JSONException e)
{
Log.d(TAG, "Get customer details onPostExecute :" + e.getLocalizedMessage());
}
}
}
/**
* A class that define space between list items
*/
private static class RecyclerViewDivider extends RecyclerView.ItemDecoration {
int space;
public RecyclerViewDivider(int space) {
this.space = space;
}
#Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.bottom = space;
if (parent.getChildLayoutPosition(view) == 0) {
outRect.top = space;
}
}
}
}
As you can see I'm trying to instantiate interface inside AsyncTask class soon after created productListAdapter object by calling setDataChangedListener(DataChangedListener listener); method. But it did not take ActivityWeakReference.get() as a valid parameter. I have done slimier thing before with list adapter to bring custom created onListItemClick event to activity. In those cases ActivityWeakReference.get() works fine. I think this is happening because I'm in a fragment, But I can't figure out which object I should pass. I need to create Adapter inside AsyncTask because i have implemented pagination for list view. I remove those codes to make this post short. Please help.
Found the solution. You need to pass fragment object to interface not the activity.
Here's my fragment class now.
/**
* AsyncTask class which handel the GET request to get product list
**/
public static class GetProductListGetRequest extends AsyncTask<String, Void, String>{
private WeakReference<OrderEditFragment> fragmentWeakReference;
private WeakReference<RecyclerView> recyclerViewWeakReference;
private WeakReference<RecyclerView.LayoutManager> layoutManagerWeakReference;
public GetProductListGetRequest(OrderEditFragment fragment, RecyclerView recyclerView
, RecyclerView.LayoutManager layoutManager) {
fragmentWeakReference = new WeakReference<>(fragment);
recyclerViewWeakReference = new WeakReference<>(recyclerView);
layoutManagerWeakReference = new WeakReference<>(layoutManager);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
String urlEndPoint = params[0];
Request request = new Request.Builder()
.url(RestConnection.API_BASE + urlEndPoint)
.build();
//Log.d(TAG,RestConnection.API_BASE + urlEndPoint);
try {
Response response = client.newCall(request).execute();
return response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String response) {
if( productsData.size()>0){
productsData.remove(productsData.size() - 1);
}
JSONArray responseBody;
//Log.d(TAG,response);
try {
if (response != null && fragmentWeakReference.get() != null) {
responseBody = new JSONArray(response);
for (int i = 0; i < responseBody.length(); i++) {
JSONObject row = responseBody.getJSONObject(i);
String productId = row.getString("ProductID");
String productName = row.getString("Name");
String unit = row.getString("Unit");
String wholeSalePrice = row.getString("WSalePrice");
String packSize = row.getString("PackSize");
String retailPrice = row.getString("RetailPrice");
String costPrice = row.getString("CostPrice");
String qtyInHand = row.getString("QtyInHand");
Products productObj = new Products();
productObj.setProductName(productName);
productObj.setProductId(productId);
productObj.setUnit(unit);
productObj.setWholeSalePrice(wholeSalePrice);
productObj.setPackSize(packSize);
productObj.setRetailPrice(retailPrice);
productObj.setCostPrice(costPrice);
productObj.setQuantityInHand(qtyInHand);
productsData.add(productObj);
}
/** if lower limit and upper limit change, change responseBody.length()<10 respectively **/
if (responseBody.length() == 0 || responseBody.length() < 10) {
isLastPage = true;
}
if (isFirstLoad) {
progressView.setVisibility(View.GONE);
recyclerViewWeakReference.get().setVisibility(View.VISIBLE);
productListAdapter = new ProductListAdapter(productsData, editedData, fragmentWeakReference.get().getContext());
productListAdapter.setDataChangedListener(fragmentWeakReference.get());
recyclerViewWeakReference.get().setAdapter(productListAdapter);
recyclerViewWeakReference.get().setLayoutManager(layoutManagerWeakReference.get());
recyclerViewWeakReference.get().addItemDecoration(new RecyclerViewDivider(2));
isFirstLoad = false;
} else {
productListAdapter.updateData(productsData);
isLoading = false;
}
} else {
Toast.makeText(fragmentWeakReference.get().getContext(), "Can't connect to the server", Toast.LENGTH_LONG).show();
}
} catch (JSONException e)
{
Log.d(TAG, "Get customer details onPostExecute :" + e.getLocalizedMessage());
}
}
}
And create AsyncTask object like bellow.
new GetProductListGetRequest(this, productRecyclerView, layoutManager)
.execute(RestConnection.PRODUCT_LIST_GET
+ RestConnection.CUSTOMER_ID_FOR_NAME + employeeId);

Android recyclerView updata all list data still merge with old data

public RecyclerView.Adapter mAdapter;
public RecyclerView mMessagesView;
this is my list
public List<MessageList> Message_List = new ArrayList<MessageList>();
and this is my adapter
mAdapter = new MessageAdapter1(getApplicationContext(), Message_List);
mMessagesView = (RecyclerView) findViewById(R.id.messages);
mMessagesView.setLayoutManager(new LinearLayoutManager(this));
mMessagesView.setAdapter(mAdapter);
now i add some data on it
Message_List.add(messageList);
mAdapter.notifyItemInserted(Message_List.size() - 1);
its work without problems
now i want to change all Message_List data and show in in recyvlerView
i do this
public void swap(List<MessageList> datas){
Message_List.clear();
Message_List.addAll(datas);
mAdapter.notifyDataSetChanged();
}
here i replace all data in Message_List and notifyDataSetChanged now its shown new data of Message_List
empty Message_List show blank
but when i try add new item to list and notify adapter its shown to me some of old item i removed it from Message_List and in LOG i watch it no old data there
now this is image before update Message_List data
now change Message_List data and notify
like we see blank because there are no data on Message_List
now try add new item to Message_List and notify adapter
Message_List.add(balabala data);
mAdapter.notifyItemInserted(Message_List.size() - 1);
and result must be without old data
for more information this is my MessageList class
public class MessageList {
public static final int TYPE_MESSAGE_RIGHT = 0;
public static final int TYPE_MESSAGE_LEFT = 1;
public static final int TYPE_ACTION = 2;
public static final String TYPING = "typing";
private String message, thumbnailUrl;
private String date;
private int user_id;
private boolean status = false;
private String fname;
private String direction;
private ArrayList<String> messageList;
public MessageList() {
setMessageStatus(status);
}
public MessageList(String name, String thumbnailUrl, String date, String direction,
ArrayList<String> messageList, String fname, int user_id) {
this.message = name;
this.thumbnailUrl = thumbnailUrl;
this.date = date;
this.direction = direction;
this.messageList = messageList;
this.fname = fname;
this.user_id = user_id;
}
public String getMessage() {
return message;
}
public String getFname() {
return fname;
}
public void setMessage(String message) {
this.message = message;
}
public String getThumbnailUrl() {
return thumbnailUrl;
}
public void setThumbnailUrl(String thumbnailUrl) {
this.thumbnailUrl = thumbnailUrl;
}
public String getDate() {
return date;
}
public boolean getMessageStatus() {
return status;
}
public void setMessageStatus(boolean status) {
this.status = status;
}
public int getUser_id() {
return user_id;
}
public void setUser_id(int user_id) {
this.user_id = user_id;
}
public void setDate(String date) {
this.date = date;
}
public void setFname(String fname) {
this.fname = fname;
}
public String getDir() {
return direction;
}
public void setDir(String direction) {
this.direction = direction;
}
public ArrayList<String> getMessageList() {
return messageList;
}
public void setMessageList(ArrayList<String> messageList) {
this.messageList = messageList;
}
}
and this is my adapter
public class MessageAdapter1 extends RecyclerView.Adapter<MessageAdapter1.ViewHolder> {
private List<MessageList> mMessages;
private int[] mUsernameColors;
private Context context;
public MessageAdapter1(Context context, List<MessageList> messages) {
mMessages = messages;
this.context = context;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int layout = -1;
int type = -1;
if(mMessages.get(viewType).getDir().equals("left")) type = 1;
else if(mMessages.get(viewType).getDir().equals("right")) type = 0;
else if(mMessages.get(viewType).getDir().equals("typing")) type = 2;
switch (type) {
case MessageList.TYPE_MESSAGE_RIGHT:
layout = R.layout.right_message;
break;
case MessageList.TYPE_MESSAGE_LEFT:
layout = R.layout.left_message;
break;
case MessageList.TYPE_ACTION:
layout = R.layout.message_left;
break;
}
View v = LayoutInflater.from(parent.getContext()).inflate(layout, parent, false);
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
MessageList message = mMessages.get(position);
viewHolder.setGroupMessage(message);
}
#Override
public int getItemCount() {
return mMessages.size();
}
#Override
public int getItemViewType(int position) {
return position;
}
public class ViewHolder extends RecyclerView.ViewHolder {
private LinearLayout groupMessage;
//private ImageView typing;
public ViewHolder(View itemView) {
super(itemView);
groupMessage = (LinearLayout)itemView.findViewById(R.id.messages);
}
public void setGroupMessage(MessageList m) {
if (null == groupMessage) return;
int i = 0;
if(m.getMessageStatus() == false){
m.setMessageStatus(true);
for (String message : m.getMessageList()) {
//TextView text = new TextView(activity);
TextView text = new MyTextView(context);
LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
p.setMargins(0, 0, 0, 2);
if (m.getDir().equals("left")) {
text.setTextColor(Color.BLACK);
p.gravity = Gravity.LEFT;
if(m.getMessageList().size() == 1){
text.setBackgroundResource(R.drawable.message_left_default);
}
else if (i == 0) {
text.setBackgroundResource(R.drawable.message_left_first);
} else if (i + 1 == m.getMessageList().size()) {
text.setBackgroundResource(R.drawable.message_left_last);
} else {
text.setBackgroundResource(R.drawable.message_left);
}
} else{
p.gravity = Gravity.RIGHT;
text.setTextColor(Color.WHITE);
if(m.getMessageList().size() == 1){
text.setBackgroundResource(R.drawable.message_right_default);
}
else if (i == 0) {
text.setBackgroundResource(R.drawable.message_right_first);
} else if (i + 1 == m.getMessageList().size()) {
text.setBackgroundResource(R.drawable.message_right_last);
} else {
text.setBackgroundResource(R.drawable.message_right);
}
}
text.setLayoutParams(p);
text.setText(message);
text.setPadding(8, 8, 8, 8);
text.setTextSize(18f);
//text.setTextAppearance(context, android.R.style.TextAppearance_Large);
groupMessage.addView(text);
i++;
}
}
}
}
}
the problem is there is no connection between mMessages and Message_List. To achieve this, put swap() in the adapter class and call it from the activity or fragment.
public class MessageAdapter1 extends RecyclerView.Adapter<MessageAdapter1.ViewHolder> {
...
public void swap(List<MessageList> datas){
mMessages.clear();
mMessages.addAll(datas);
notifyDataSetChanged();
}
public void add(MessageList data){
mMessages.add(data);
notifyItemInserted(mMessages.size() - 1);
}
}
and from fragment or activity:
((MessageAdapter1) rv.getAdapter).add(data);
((MessageAdapter1) rv.getAdapter).swap(Message_List);

RecyclerView with multiple Adapters and SharedPreferences

I am using a RecyclerView inside a Fragment to display a list of categories ( as shown in the images). When a category is selected, a new Activity starts with a RecyclerView. Each item from the list has a TextView and an icon for favorite ( the star from the top-right corner ). Once the favorite icon is pressed, the TextView will be saved to another Activity called Favorites.
The problem: let's say that I select Category A and I press the favorite button for the first 2 items. Everything looks good, the items are saved to Favorites. If I select Category B, bamm, I find the first 2 items selected...I go to Category C, same thing!
So if I check the favorite button once, it checks for all Adapters, like they're communicating. Why is this happening?
Although the favorite buttons are checked, I can't find the TextView's from Category B or C in the Favorites activity.
The Activity that starts when a category item is selected:
public class CategoriesDetailActivity extends AppCompatActivity {
Adapter0 ca0;
RecyclerView recList;
public CategoriesDetailActivity() {
// Required empty public constructor
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.categories_detail_activity);
Bundle bundle = this.getIntent().getExtras();
// Bundle bundle = this.getArguments();
bundle.getInt("id");
int position = bundle.getInt("id");
if (bundle.containsKey("id")) {
position = bundle.getInt("id");
} else {
this.finish();
}
recList = (RecyclerView) findViewById(R.id.cardList);
recList.setHasFixedSize(true);
LinearLayoutManager llm = new LinearLayoutManager(this);
llm.setOrientation(LinearLayoutManager.VERTICAL);
recList.setLayoutManager(llm);
switch (position) {
case 0:
ca0 = new Adapter0(this, createList0(99));
recList.setAdapter(ca0);
break;
case 1:
ca0 = new Adapter0(this, createList1(80));
recList.setAdapter(ca0);
break;
...
}
}
private List<BeanSampleList> createList0(int size) {
List<BeanSampleList> result = new ArrayList<>();
for (int i = 0; i <= size; i++) {
BeanSampleList ci = new BeanSampleList();
ci.title = DataText.Text1[i];
ci.id = i;
result.add(ci);
}
return result;
}
private List<BeanSampleList> createList1(int size) {
List<BeanSampleList> result = new ArrayList<>();
for (int i = 0; i <= size; i++) {
BeanSampleList ci = new BeanSampleList();
ci.title = DataText.Text2[i];
ci.id = i;
result.add(ci);
}
return result;
}
#Override
public void onResume() {
super.onResume();
if (recList.getAdapter() == ca0) {
ca0.notifyDataSetChanged();
} if (recList.getAdapter() == ca1) {
ca1.notifyDataSetChanged();
} else {
// nothing
}
}
}
The Adapter class:
public class Adapter0 extends RecyclerView.Adapter<Adapter0 .ContactViewHolder> {
private Context context;
List<BeanSampleList> postBeanSampleList;
SharedPreference sharedPreference;
BeanSampleList beanSampleList;
public Adapter0 (Context context, List<BeanSampleList> postBeanSampleList) {
this.context = context;
this.postBeanSampleList = postBeanSampleList;
sharedPreference = new SharedPreference();
}
#Override
public int getItemCount() {
return postBeanSampleList.size();
}
public Object getItem(int position) {
return postBeanSampleList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public void onBindViewHolder(final ContactViewHolder holder,final int i) {
beanSampleList = (BeanSampleList) getItem(i);
holder.vName.setText(beanSampleList.getTitle());
if (checkFavoriteItem(beanSampleList)) {
holder.btnFavourite.setLiked(true);
holder.btnFavourite.setTag("active");
} else {
holder.btnFavourite.setLiked(false);
holder.btnFavourite.setTag("deactive");
}
}
#Override
public ContactViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View itemView = LayoutInflater.
from(viewGroup.getContext()).
inflate(R.layout.categories_detail_adapter, viewGroup, false);
return new ContactViewHolder(itemView);
}
public class ContactViewHolder extends RecyclerView.ViewHolder implements OnLikeListener {
protected TextView vName;
protected LikeButton btnFavourite;
public ContactViewHolder(View v) {
super(v);
vName = (TextView) v.findViewById(R.id.t1);
btnFavourite = (LikeButton) v.findViewById(R.id.favouritesToggle);
btnFavourite.setOnLikeListener(this);
}
#Override
public void liked(LikeButton likeButton) {
final int position = getAdapterPosition();
if (likeButton.getId() == btnFavourite.getId()) {
String tag = btnFavourite.getTag().toString();
if (tag.equalsIgnoreCase("deactive")) {
sharedPreference.addFavorite(context, postBeanSampleList.get(position));
btnFavourite.setTag("active");
btnFavourite.setLiked(true);
}
Snackbar snackbar = Snackbar
.make(likeButton, "Added to Favorites!", Snackbar.LENGTH_SHORT);
snackbar.show();
}
}
#Override
public void unLiked(LikeButton likeButton) {
final int position = getAdapterPosition();
if (likeButton.getId() == btnFavourite.getId()) {
sharedPreference.removeFavorite(context, postBeanSampleList.get(position));
btnFavourite.setTag("deactive");
btnFavourite.setLiked(false);
Snackbar snackbar = Snackbar
.make(likeButton, "Removed from Favorites!", Snackbar.LENGTH_SHORT);
snackbar.show();
}
}
}
public boolean checkFavoriteItem(BeanSampleList checkProduct) {
boolean check = false;
List<BeanSampleList> favorites = sharedPreference.loadFavorites(context);
if (favorites != null) {
for (BeanSampleList product : favorites) {
if (product.equals(checkProduct)) {
check = true;
break;
}
}
}
return check;
}
}
For the past 2 days I've been trying to fix this but I just can't figure out what's causing this. I also tried to use different Adapters for each position but with no success.
public class BeanSampleList {
public int id;
public String title;
public String subTitle;
public String bottomTitle;
public String imageView;
public BeanSampleList() {
super();
}
public BeanSampleList(int id, String title, String subTitle, String bottomTitle, String imageView) {
super();
this.id = id;
this.title = title;
this.subTitle = subTitle;
this.bottomTitle = bottomTitle;
this.imageView = imageView;
}
public String getSubTitle() {
return subTitle;
}
public void setSubTitle(String subTitle) {
this.subTitle = subTitle;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitleBottom() {
return bottomTitle;
}
public void setTitleBottom(String bottomTitle) {
this.bottomTitle = bottomTitle;
}
public String getImageView() {
return imageView;
}
public void setImageView(String imageView) {
this.imageView = imageView;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BeanSampleList other = (BeanSampleList) obj;
if (id != other.id)
return false;
return true;
}
}
Thank you so much and sorry for my english.
I think the error is in your id generation for BeanSampleList
private List<BeanSampleList> createList0(int size) {
List<BeanSampleList> result = new ArrayList<>();
for (int i = 0; i <= size; i++) {
BeanSampleList ci = new BeanSampleList();
ci.title = DataText.Text1[i];
ci.id = i;
result.add(ci);
}
return result;
}
private List<BeanSampleList> createList1(int size) {
List<BeanSampleList> result = new ArrayList<>();
for (int i = 0; i <= size; i++) {
BeanSampleList ci = new BeanSampleList();
ci.title = DataText.Text2[i];
ci.id = i;
result.add(ci);
}
return result;
}
You need to generate unique id for your BeanSamleList objects in createList* method. As in your current code the objects are the same from the equals method side (their id are from 0 to list_size range).
Or add some unique modifier to compare in equal, like add the position of parent list
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
BeanSampleList other = (BeanSampleList) obj;
if (id != other.id)
return false;
if (listId != other.listId)
return false;
return true;
}
You need to find a different way to uniquely identify each BeanSampleList element. Just matching id is not good enough. Perhaps you could also match the titles if you know they will be unique. Or generate unique Ids for each of these elements say by dividing the integer domain in different ranges e.g. 1 to 1000000 is for category 1, 1000001 to 2000000 for category 2 and so on.

Having trouble restoring state on listview

I have an app that allows the user to select an option and a certain list is displayed in a listview. I'm having issues with getting it to save and restore state. I have a list_mode that gets set depending on which option the user selects. so far I have it saving the state of the adapter but restoring it is causing an issue ( I know it's saving because when I examine customAdapter.onRestoreInstanceState(savedInstanceState) in the onCreate it's showing the right items based on selection but I'm having a hard time restoring it to the list view. It will crash on restore. It crashes on getAllItems.clear and .addAll. I have even hard coded this to one of the lists but it didn't work either. When I comment that line out then it crashes in the main activity. I'm a noob when it comes to Java and Android and am still learning. I do not know how close or how far off I am. Can anyone provide insight on what I'm doing wrong and how I can get it to work? Thanks
List Adapter:
public class ListAdapter extends BaseAdapter {
private static final String KEY_ADAPTER_STATE = "ListAdapter.KEY_ADAPTER_STATE";
public enum ListMode {
IMAGES_AND_TEXT,
IMAGES_ONLY,
TEXT_ONLY
}
private ListMode mListMode = ListMode.IMAGES_AND_TEXT;
private ArrayList<Item> mItems;
private ArrayList<Item> mImages;
private ArrayList<Item> mTexts;
#Override
public int getCount() {
switch (mListMode) {
case IMAGES_AND_TEXT:
return mItems == null ? 0 : mItems.size();
case IMAGES_ONLY:
return mImages == null ? 0 : mImages.size();
case TEXT_ONLY:
return mTexts == null ? 0 : mTexts.size();
}
return 0;
}
#Override
public Item getItem(int position) {
switch (mListMode) {
case IMAGES_AND_TEXT:
return mItems == null ? null : mItems.get(position);
case IMAGES_ONLY:
return mImages == null ? null : mImages.get(position);
case TEXT_ONLY:
return mTexts == null ? null : mTexts.get(position);
}
return null;
}
public ArrayList getAllItems() {
switch (mListMode) {
case IMAGES_AND_TEXT:
return mItems;
case IMAGES_ONLY:
return mImages;
case TEXT_ONLY:
return mTexts;
}
return null;
}
#Override
public long getItemId(int position) {
return position; // not really used
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = null;
TextView tn = null;
ImageView img = null;
if (convertView == null) {
LayoutInflater vi;
vi = LayoutInflater.from(parent.getContext());
v = vi.inflate(R.layout.list, null);
} else {
v=convertView;
}
Item p = getItem(position);
tn = (TextView) v.findViewById(R.id.tvText);
img = (ImageView) v.findViewById(R.id.thumbnail);
if (p.getmType().equals("image")) {
img.setVisibility(View.VISIBLE);
Picasso.with(parent.getContext()).load(p.getmData()).error((R.drawable.placeholder_error)).placeholder(R.drawable.placeholder).resize(90,0).into(img);
tn.setText("ID: " + p.getmID()+"\nTYPE: " + p.getmType() +"\nDate: " + p.getmDate()+ "\nImage URL: " + p.getmData());
} else {
img.setVisibility(View.GONE);
tn.setText("ID: " + p.getmID()+"\nTYPE: " + p.getmType() +"\nDate: " + p.getmDate()+ "\nText Data: " + p.getmData());
}
return v;
}
public void setListMode(ListMode listMode) {
mListMode = listMode;
notifyDataSetChanged();
}
public void setItems(JSONArray jsonArray) throws JSONException {
mItems = new ArrayList<>();
mImages = new ArrayList<>();
mTexts = new ArrayList<>();
for (int i = 0; i < jsonArray.length(); i++) {
Item item = new Item((JSONObject) jsonArray.get(i));
mItems.add(item);
if (item.getmType().equals("image")) {
mImages.add(item);
}
if (item.getmType().equals("text")) {
mTexts.add(item);
}
}
notifyDataSetChanged();
}
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putParcelableArrayList("list_items", getAllItems());
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
if (savedInstanceState.containsKey("list_items")) {
//ArrayList<Item> objects = savedInstanceState.getParcelableArrayList(KEY_ADAPTER_STATE);
//getAllItems().clear();
//getAllItems().addAll(objects);
//mImages.clear();
//mImages.addAll(objects);
}
}
}
Main Activity:
myListView = (ListView) findViewById(R.id.listViewID);
customAdapter = new ListAdapter();
if(savedInstanceState!=null) {
//When I put a breakpoint here I see it's getting the correct list
customAdapter.onRestoreInstanceState(savedInstanceState);
}
if (savedInstanceState != null && savedInstanceState.containsKey("list_items")) {
//When I remove the .clear and .addAll it then crashes on this line
myListView.onRestoreInstanceState(savedInstanceState.getParcelable("list_items"));
myListView.setAdapter(customAdapter);
}
else{
if (isNetworkAvailable()) {
getData theJsonData = new getData();
theJsonData.execute();
}
else{
Toast.makeText(getApplicationContext(), "No internet connection", Toast.LENGTH_SHORT).show();
tvNoInet.setVisibility(View.VISIBLE);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
//Not sure what I should put here or if what I have is right
customAdapter.onSaveInstanceState(savedInstanceState);
}
//This is the code that sets the list_mode when the user selects an option
if (id == R.id.all) {
item.setChecked(true);
customAdapter.setListMode(ListAdapter.ListMode.IMAGES_AND_TEXT);
myListView.setSelectionAfterHeaderView();
return true;
}
if (id == R.id.images) {
item.setChecked(true);
customAdapter.setListMode(ListAdapter.ListMode.IMAGES_ONLY);
myListView.setSelectionAfterHeaderView();
return true;
}
if (id == R.id.text) {
item.setChecked(true);
customAdapter.setListMode(ListAdapter.ListMode.TEXT_ONLY);
myListView.setSelectionAfterHeaderView();
return true;
}
And my Item class:
public class Item implements Parcelable{
private String mID;
private String mType;
private String mDate;
private String mData;
public Item(String mID,String mType, String mDate, String mData) {
this.mType = mType;
this.mID = mID;
this.mDate = mDate;
this.mData = mData;
}
public Item(JSONObject jsonItem) throws JSONException {
String itemID=null;
String itemType=null;
String itemDate=null;
String itemData=null;
if (jsonItem.has("id")) {
itemID=jsonItem.getString("id");
}
if (jsonItem.has("type")) {
itemType=jsonItem.getString("type");
}
if (jsonItem.has("date")){
itemDate=jsonItem.getString("date");
}
if (jsonItem.has("data")){
itemData=jsonItem.getString("data");
}
this.mID=itemID;
this.mType=itemType;
this.mDate=itemDate;
this.mData=itemData;
}
protected Item(Parcel in) {
String[] data = new String[4];
in.readStringArray(data);
this.mID = data[0];
this.mType = data[1];
this.mDate = data[2];
this.mData = data[3];
}
public static final Creator<Item> CREATOR = new Creator<Item>() {
#Override
public Item createFromParcel(Parcel in) {
return new Item(in);
}
#Override
public Item[] newArray(int size) {
return new Item[size];
}
};
public String getmID() {
return mID;
}
public String getmType() {
return mType;
}
public String getmDate() {
return mDate;
}
public String getmData() {
return mData;
}
#Override
public String toString() {
return "{" +
"ID='" + mID + '\'' +
", Type='" + mType + '\'' +
", Date='" + mDate + '\'' +
", Data='" + mData + '\'' +
'}';
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
String[] data = new String[4];
data[0] = mID;
data[1] = mType;
data[2] = mDate;
data[3] = mData;
dest.writeStringArray(data);
}
}
UPDATE: This is what the code looks like now. When I select a certain list and then rotate the screen it's working. It's staying on the currently selected list. Now the issue is when they select a new list after the device has been rotated the listview is completely blank
if(savedInstanceState!=null) {
customAdapter.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState.containsKey(KEY_LIST_VIEW_STATE)) {
myListView.onRestoreInstanceState(savedInstanceState.getParcelable(KEY_LIST_VIEW_STATE));
myListView.setAdapter(customAdapter);
}
}
else{
if (isNetworkAvailable()) {
getData theJsonData = new getData();
theJsonData.execute();
tvNoInet.setVisibility(View.GONE);
btnRetry.setVisibility(View.GONE);
} else {
Toast.makeText(getApplicationContext(), "No internet connection", Toast.LENGTH_SHORT).show();
tvNoInet.setVisibility(View.VISIBLE);
btnRetry.setVisibility(View.VISIBLE);
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
customAdapter.onSaveInstanceState(savedInstanceState);
savedInstanceState.putParcelable(KEY_LIST_VIEW_STATE, myListView.onSaveInstanceState());
}
and my updated list adapter:
private ListMode mListMode = ListMode.IMAGES_AND_TEXT;
private ArrayList<Item> mItems= new ArrayList<>();
private ArrayList<Item> mImages= new ArrayList<>();
private ArrayList<Item> mTexts= new ArrayList<>();
public void onSaveInstanceState(Bundle savedInstanceState) {
//savedInstanceState.putParcelableArrayList("list_items", getAllItems());
savedInstanceState.putParcelableArrayList(KEY_ADAPTER_STATE, getAllItems());
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
if (savedInstanceState.containsKey(KEY_ADAPTER_STATE)) {
ArrayList<Item> objects = savedInstanceState.getParcelableArrayList(KEY_ADAPTER_STATE);
getAllItems().clear();
getAllItems().addAll(objects);
//mImages.clear();
//mImages.addAll(objects);
}
}
And this is the code in the options menu that switches the list. If I haven't rotated the screen yet this works. When I rotate the screen and select a different list the listview is then blank. If I select "All" which should display All items then whatever list I had selected before if restored. So If I selected Images Only at first, rotate the screen everything is displayed right, if I rotate the screen back and select Text Only or Images Only again, the list is blank, if I select "All" then whatever list I picked the first time (in this case Images Only) is displayed
if (id == R.id.all) {
item.setChecked(true);
customAdapter.setListMode(ListAdapter.ListMode.IMAGES_AND_TEXT);
myListView.setSelectionAfterHeaderView();
return true;
}
if (id == R.id.images) {
item.setChecked(true);
customAdapter.setListMode(ListAdapter.ListMode.IMAGES_ONLY);
myListView.setSelectionAfterHeaderView();
return true;
}
if (id == R.id.text) {
item.setChecked(true);
customAdapter.setListMode(ListAdapter.ListMode.TEXT_ONLY);
myListView.setSelectionAfterHeaderView();
return true;
}
Well, since I got you into this mess.... :)
Something I do in situations like this is to pass in the saved instance state Bundle to the constructor for the adapter. Since you made your Item class Parcelable, everything else should be easy.
public ListAdapter(Bundle savedInstanceState) {
if (savedInstanceState != null) {
int ordinal = savedInstanceState.getInt("adapter_mode", 0);
mListMode = ListMode.values()[ordinal];
ArrayList<Item> items =
savedInstanceState.getParcelableArrayList(KEY_ADAPTER_STATE);
if (items != null) {
setItems(items);
}
}
}
public void onSaveInstanceState(Bundle outState) {
outState.putInt("adapter_mode", mListMode.ordinal());
outState.putParcelableArrayList(KEY_ADAPTER_STATE, mItems);
}
So with the saved instance state in the constructor, you don't need an explicit method to restore the adapter state.
public void setItems(JSONArray jsonArray) throws JSONException {
List<Item> items = new ArrayList<>();
for (int i = 0; i < jsonArray.length(); i++) {
items.add(new Item((JSONObject) jsonArray.get(i)));
}
setItems(items);
}
private void setItems(List<Item> items) {
for (Item item : items) {
mItems.add(item);
if (item.getmType().equals("image")) {
mImages.add(item);
}
if (item.getmType().equals("text")) {
mTexts.add(item);
}
}
notifyDataSetChanged();
}
Your app crashes if you call ListAdapter.getAllItems().clear() without calling ListAdapter.setItems() before
Cause: ListAdapter.getAllItems() may return null if mItems, mImages, mTexts are not initialized.
One workaround may be
public class ListAdapter extends ... {
...
private ArrayList<Item> mItems = new ArrayList<>();
private ArrayList<Item> mImages = new ArrayList<>();
private ArrayList<Item> mTexts = new ArrayList<>();
...
}

Categories

Resources