Unboxing of hashmap.get() is producing a NullPointerException - java

I'm using a hashmap to get data from another class. I check the logcat and the data for hashmap has been set and it contains the key. But when I try to get the hashmap from the other class I'm getting NullPointerException and when I try to check if the map contains the key it doesn't
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.continueItem:
CustomAdapter a = new CustomAdapter();
CustomAdapter.InputTextListener i = a.new InputTextListener();
HashMap<String, Integer> hashMap = i.getHashMap();
inputTime = hashMap.get("EDITTEXT VALUE");
Log.d(TAG, "onOptionsItemSelected: " + hashMap.get("EDITTEXT VALUE"));
Log.d(TAG, "onOptionsItemSelected: " + hashMap.containsKey("EDITTEXT VALUE"));
retrieveInputTime(inputTime);
break;
}
return super.onOptionsItemSelected(item);
}
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
private static final String TAG = "CustomAdapter";
private ArrayList<Integer> mWorkTW = new ArrayList<>();
private ArrayList<Integer> mWorkET = new ArrayList<>();
private ArrayList<Integer> mRestTW = new ArrayList<>();
private ArrayList<Integer> mRestET = new ArrayList<>();
private Context mContext;
private int numberOfIntervals;
public CustomAdapter() {
}
public CustomAdapter(Context context, ArrayList<Integer> mWorkTW, ArrayList<Integer> mWorkET, ArrayList<Integer> mRestTW, ArrayList<Integer> mRestET, int numberOfIntervals) {
this.mWorkTW = mWorkTW;
this.mWorkET = mWorkET;
this.mRestTW = mRestTW;
this.mRestET = mRestET;
this.mContext = context;
this.numberOfIntervals = numberOfIntervals;
//this.inputTimeIntegerWET = inputTimeIntegerWET;
Log.d(TAG, "CustomAdapter: " + numberOfIntervals);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View customView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.time_row, viewGroup, false);
ViewHolder holder = new ViewHolder(customView, new InputTextListener());
return holder;
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder viewHolder, final int i) {
Log.d(TAG, "onBindViewHolder: called");
viewHolder.workTextView.setText(R.string.work_text_view);
viewHolder.restTextView.setText(R.string.rest_text_view);
viewHolder.workEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus)
viewHolder.workEditText.setHint("");
else
viewHolder.workEditText.setHint(mWorkET.get(viewHolder.getAdapterPosition()));
}
});
viewHolder.restEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus)
viewHolder.restEditText.setHint("");
else
viewHolder.restEditText.setHint(mRestET.get(viewHolder.getAdapterPosition()));
}
});
}
#Override
public int getItemCount() {
Log.d(TAG, "" + numberOfIntervals);
return numberOfIntervals;
}
public class ViewHolder extends RecyclerView.ViewHolder {
public InputTextListener inputTextListener;
TextView workTextView;
EditText workEditText;
TextView restTextView;
EditText restEditText;
ConstraintLayout parentLayout;
public ViewHolder(#NonNull View itemView, InputTextListener inputTextListener) {
super(itemView);
workTextView = itemView.findViewById(R.id.workTextView);
workEditText = itemView.findViewById(R.id.workEditText);
restTextView = itemView.findViewById(R.id.restTextView);
restEditText = itemView.findViewById(R.id.restEditText);
parentLayout = itemView.findViewById(R.id.parentLayout);
this.inputTextListener = inputTextListener;
workEditText.addTextChangedListener(inputTextListener);
}
}
class InputTextListener implements TextWatcher {
String inputTimeString;
int inputTime;
HashMap<String, Integer> hashMap = new HashMap<String, Integer>();
public HashMap<String, Integer> getHashMap() {
return hashMap;
}
public InputTextListener() {
}
public void setHashMap(HashMap<String, Integer> hashMap) {
this.hashMap = hashMap;
}
/*public int getInputTime() {
return inputTime;
}*/
public void setInputTime(int inputTime) {
this.inputTime= inputTime;
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
try {
Log.d(TAG, "onTextChanged: I've made it to here!");
inputTimeString = s.toString().trim();
inputTime = Integer.parseInt(inputTimeString);
setInputTime(inputTime);
hashMap.put("EDITTEXT VALUE", inputTime);
Log.d(TAG, "onTextChanged: " + inputTime);
int bla = inputTime + 2;
Log.d(TAG, "onTextChanged: " + bla);
Log.d(TAG, "onTextChanged: " + hashMap.containsKey("EDITTEXT VALUE"));
Log.d(TAG, "onTextChanged: " + hashMap.get("EDITTEXT VALUE"));
setHashMap(hashMap);
} catch (NumberFormatException NFE) {
mWorkET = null;
}
}
#Override
public void afterTextChanged(Editable s) {
}
}
}
I'm expecting for the hashmap being able to access the data from the other class.

Here is some of the code you posted:
CustomAdapter a = new CustomAdapter();
CustomAdapter.InputTextListener i = a.new InputTextListener();
HashMap<String, Integer> hashMap = i.getHashMap();
What this is going to do is create a new instance of your CustomAdapter class, then create a new instance of your InputTextListener class, and finally retrieve the HashMap stored inside the text listener.
Again, this is all happening with new instances of these classes. Therefore, the HashMap is empty (since nothing has populated it).
You are probably assuming that i would be the "same" listener instance as you're using elsewhere in your app. This is not the case. You will need to access that listener somehow rather than creating a new instance.
Looking at your code, this doesn't really seem feasible. Each ViewHolder has its own instance of InputTextListener... how will your options menu know which ViewHolder you're trying to interact with?
Chances are good that you're going to need to go back to the drawing board and come up with a different way to solve whatever problem you're attempting.

Related

Inconsistency: Invalid view holder adapter when using FirestorePagingAdapter with custom wrapper

I wrote a wrapper around FirestorePagingAdapter. This works fine most of the times. But there are occasions where this crashes with
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter
I will show you the complete wrapper. Also the last log message I see before the crash is
[Paging adapter] Data loading finished.
I also noticed, when I slowly scroll the list it works fine. Only if I scroll the list fast it crashes eventually.
So here is the code. I cannot figure out where the problem is. Any help is highly appreciated
public abstract class PagingAdapter<T extends RecyclerItem> extends FirestorePagingAdapter<T, RecyclerViewHolder<T, ? extends ViewBinding>> implements Function1<CombinedLoadStates, Unit> {
protected final String TAG = this.getClass().getSimpleName();
private final SnapshotParser<T> mParser;
private SortedList<T> mListItems;
private int mTryCount;
private boolean mReverseFill = false;
private PagingAdapter(#NonNull FirestorePagingOptions<T> options, PagingAdapterCallback<T> callback) {
super(options);
mListItems = new SortedList(RecyclerItem.class, new SortedListAdapterCallback<T>(this) {
#Override
public int compare(T o1, T o2) {
return callback.compare(o1, o2);
}
#Override
public boolean areContentsTheSame(T oldItem, T newItem) {
return callback.areContentsTheSame(oldItem, newItem);
}
#Override
public boolean areItemsTheSame(T item1, T item2) {
return callback.areContentsTheSame(item1, item2);
}
});
mParser = options.getParser();
this.mTryCount = 0;
}
public void setReverseFill(boolean reverseFill) {
this.mReverseFill = reverseFill;
}
#Override
public int getItemViewType(int position) {
return getList().get(position).getRecyclerItemType().getId();
}
public SortedList<T> getList() {
return mListItems;
}
#NonNull
#Override
public RecyclerViewHolder<T, ? extends ViewBinding> onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
RecyclerViewHolder<T, ? extends ViewBinding> viewHolder = onCreateViewHolder(parent, RecyclerItemType
.get(viewType));
if (viewHolder == null) {
throw new NullPointerException("Your list contains items for that you did not specify a view holder for");
}
return viewHolder;
}
public abstract RecyclerViewHolder<T, ? extends ViewBinding> onCreateViewHolder(#NonNull ViewGroup parent, RecyclerItemType itemType);
#Override
public void onBindViewHolder(RecyclerViewHolder<T, ? extends ViewBinding> holder, int position) {
try {
//and trigger the paging to load around with the correct "position"
super.onBindViewHolder(holder, getPagingPosition(position)); //<--Needed to page the list, be we do not really use it (see below)
} catch (Exception ignore) {
//If this fails, because there are less items in the list, do not crash, this is fine
Log.d(TAG, "onBindViewHolder: ");
}
holder.bind(getList().get(position));
}
protected int getPagingPosition(int requestedPosition) {
return requestedPosition;
}
#Override
protected void onBindViewHolder(#NonNull RecyclerViewHolder<T, ? extends ViewBinding> holder, int position, #NonNull T model) {
//We do not use this method
}
#Override
public int getItemCount() {
return getList().size();
}
#Override
public Unit invoke(CombinedLoadStates states) {
LoadState refresh = states.getRefresh();
LoadState append = states.getAppend();
if (refresh instanceof LoadState.Error || append instanceof LoadState.Error) {
//The previous load (either initial or additional) failed
Log.d(TAG, "[Paging adapter] An error occurred while loading the data");
if (mTryCount < 3) {
mTryCount += 1;
retry();
}
}
if (refresh instanceof LoadState.Loading) {
Log.d(TAG, "[Paging adapter] Loading initial data");
}
if (append instanceof LoadState.Loading) {
Log.d(TAG, "[Paging adapter] Loading more data");
}
if (append instanceof LoadState.NotLoading) {
LoadState.NotLoading notLoading = (LoadState.NotLoading) append;
if (notLoading.getEndOfPaginationReached()) {
Log.d(TAG, "[Paging adapter] No further documents");
mTryCount = 0;
return null;
}
if (refresh instanceof LoadState.NotLoading) {
Log.d(TAG, "[Paging adapter] Data loading finished");
mTryCount = 0;
List<T> items = new ArrayList<>();
if (mReverseFill) {
for (int i = snapshot().size() - 1; i >= 0; i--) {
T currentItem = mParser.parseSnapshot(snapshot().get(i));
if (getList().indexOf(currentItem) == SortedList.INVALID_POSITION)
items.add(currentItem);
}
} else {
for (DocumentSnapshot snapshot : snapshot()) {
T currentItem = mParser.parseSnapshot(snapshot);
if (getList().indexOf(currentItem) == SortedList.INVALID_POSITION)
items.add(currentItem);
}
}
addAll(items);
return null;
}
}
return null;
}
public void addAll(Collection<T> items) {
getList().beginBatchedUpdates();
getList().addAll(items);
getList().endBatchedUpdates();
}
public abstract static class PagingAdapterCallback<T extends RecyclerItem> {
public abstract int compare(T o1, T o2);
public abstract boolean areContentsTheSame(T oldItem, T newItem);
public abstract boolean areItemsTheSame(T item1, T item2);
}
}
Just in case you wonder. These are the other two wrapper:
public abstract class RecyclerViewHolder<T extends RecyclerItem, E extends ViewBinding> extends RecyclerView.ViewHolder {
public final String TAG = this.getClass().getSimpleName();
protected final E b;
private final Context mContext;
protected RecyclerViewHolder(#NonNull E b) {
super(b.getRoot());
this.b = b;
this.mContext = b.getRoot().getContext();
}
public abstract void bind(T item);
protected Context getContext() {
return mContext;
}
protected Context requireContext() {
return getContext();
}
protected String getString(int resId) {
return mContext.getString(resId);
}
protected String getString(int resId, Object... args) {
return mContext.getString(resId, args);
}
}
and
public interface RecyclerItem {
#NonNull
RecyclerItemType getRecyclerItemType();
default void setRecyclerItemType(RecyclerItemType type){
//Does not do anything per default
}
}

how display string array content through recycleview adapter

I have this structure of json api:
{
seasons: [
{
seasonstitle: "Season 1",
titles: "S1E1; S1E2; S1E3",
},
{
seasonstitle: "Season 2",
titles: "S2E1; S2E2; S2E3",
},
]
}
and I'm trying to display the values of these two keys: seasonstitle and titles but as you see the titles key has multiple values so I parsing the json like this:
ParsingClass:
public final class JsonDetailSeries {
public static ArrayList<SeriesItem> getSimpleMovieStringsFromJson(Context context, String moviesJsonString)
throws JSONException {
final String SEASONS = "seasons";
final String SEASONTITLE = "seasonstitle";
final String TITLES = "titles";
ArrayList<SeriesItem> parsedMovieData = new ArrayList<>();
JSONObject moviesObject = new JSONObject(moviesJsonString);
JSONArray moviesArray = moviesObject.getJSONArray(SEASONS);
for (int i = 0; i < moviesArray.length(); i++) {
String seasontitle;
String titles;
moviesObject = moviesArray.getJSONObject(i);
seasontitle = moviesObject.getString(SEASONTITLE);
titles = moviesObject.getString(TITLES);
String[] titlesArrray = titles.split(Pattern.quote(";"));
for (int j=0; j<titlesArrray.length; j++) {
Log.i("titles ", "=" + titlesArrray[j]);
}
parsedMovieData.add(new SeriesItem(seasontitle, titlesArrray));
}
return parsedMovieData;
}
}
when I saw it in log cat it splits correctly like this:
titles = S1E1
titles = S1E2
titles = S1E3
and so on, in my custom arraylist class which I return the data for it:
public class SeriesItem implements Parcelable {
private String seasontitle;
private String[] titlesArrray;
public SeriesItem(String seasontitle, String[] titlesArrray) {
this.seasontitle = seasontitle;
this.titlesArrray = titlesArrray;
}
#Override
public void writeToParcel(Parcel out, int flags) {
out.writeString(seasontitle);
out.writeStringArray(titlesArrray);
}
private SeriesItem(Parcel in) {
this.seasontitle = in.readString();
this.titlesArrray = in.createStringArray();
}
public SeriesItem() {
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<SeriesItem> CREATOR = new Creator<SeriesItem>() {
#Override
public SeriesItem createFromParcel(Parcel in) {
return new SeriesItem(in);
}
#Override
public SeriesItem[] newArray(int i) {
return new SeriesItem[i];
}
};
public String getSeasontitle() {
return seasontitle;
}
public String[] gettitlesArrray() {
return titlesArrray;
}
}
when I debug this class the data of titlesArrray recevied well each title split from the other one
so I'm trying to display this data in recyleview like this way:
Season1
S1E1
S1E2
S1E3
Season2
S2E1
S2E2
S2E3
so this is my adapter of recycleview:
public class SeriesAdapter extends RecyclerView.Adapter<SeriesAdapter.RecyclerViewHolder> {
ArrayList<SeriesItem> mMoviesItems;
private Context context;
private final SeriesAdapterOnClickHandler mClickHandler;
public interface SeriesAdapterOnClickHandler {
void onClick(SeriesItem movie);
}
public SeriesAdapter(SeriesAdapterOnClickHandler clickHandler) {
mClickHandler = clickHandler;
}
class RecyclerViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final TextView seasontitle;
public final ListView titlesArray;
public RecyclerViewHolder(View view) {
super(view);
seasontitle = (TextView)itemView.findViewById(R.id.seasontitle);
titlesArray = (ListView) itemView.findViewById(R.id.titlesArray);
view.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int adapterPosition = getAdapterPosition();
SeriesItem movie = mMoviesItems.get(adapterPosition);
mClickHandler.onClick(movie);
}
}
#Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
context = viewGroup.getContext();
int layoutIdForListItem = R.layout.series_list_item;
LayoutInflater inflater = LayoutInflater.from(context);
boolean shouldAttachToParentImmediately = false;
View view = inflater.inflate(layoutIdForListItem, viewGroup, shouldAttachToParentImmediately);
return new RecyclerViewHolder(view);
}
#Override
public void onBindViewHolder(RecyclerViewHolder holder, int position) {
holder.seasontitle.setText(String.valueOf(mMoviesItems.get(position).getSeasontitle()));
holder.titlesArray.setText(String.valueOf(mMoviesItems.get(position).gettitlesArrray()));
}
#Override
public int getItemCount() {
if (null == mMoviesItems)
return 0;
else {
return mMoviesItems.size();
}
}
public void setMovieData(ArrayList<SeriesItem> movieData) {
mMoviesItems = movieData;
notifyDataSetChanged();
}
}
I tried to include a listview to display the titlesArray inside this recycleview and the problem is with this line:
holder.titlesArray.setText(String.valueOf(mMoviesItems.get(position).gettitlesArrray()));
I can't use setText for ListView so how can to display the titlesArray content inside this recycleview?
I tried to include a listview to display the titlesArray inside this recycleview
Do not do that.
What you want to do is handle two different types, the season and the episode. This question that will help you with that.
How to create RecyclerView with multiple view type?
Use Gson to parse Json instead of the native, it is much easier to implement.

onTextChangedListener goes into loop, but only on first ListView element, any following elements don't loop

I have a moneyConversion class which converts strings as I type them into an EditText which there are multiple of due to being contained in a listview. The conversion works fine for the EditText, but for some reason, the first list item always goes into a loop and hangs when typing something in, where as all other identical EditText boxes work absolutely fine and format without issue.
Here's my adapter.
public class DietyAmountAdapter extends ArrayAdapter {
Context context;
int layoutResourceId;
ArrayList<Dieties> data = null;
int counterTotal;
int currentlyActive;
public DietyAmountAdapter(Context context, int layoutResourceId, ArrayList<Dieties> data){
super(context, layoutResourceId, data);
this.context = context;
this.layoutResourceId = layoutResourceId;
this.data = data;
}
public void addViews(){
SharedPreferences sharedPref = ((Activity) context).getPreferences(Context.MODE_PRIVATE);
currentlyActive = 0;
this.clear();
for(int i = 1; i <= counterTotal; i++) {
boolean a = sharedPref.getBoolean(Integer.toString(i), false);
if (a) {
currentlyActive = currentlyActive + 1;
}
}
}
public View getView(int position, View convertView, ViewGroup parent) {
View ListItem = convertView;
Holder holder;
final Dieties Diety = data.get(position);
if (ListItem == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
ListItem = inflater.inflate(layoutResourceId, parent, false);
holder = new Holder();
holder.banner = (ImageView) ListItem.findViewById(R.id.DietyBanner);
holder.title = (TextView) ListItem.findViewById(R.id.titleText);
holder.text1 = (EditText) ListItem.findViewById(R.id.text1Amount);
holder.text2 = (EditText) ListItem.findViewById(R.id.text2Amount);
holder.text1Text = (TextView) ListItem.findViewById(R.id.text1Text);
holder.text2Text = (TextView) ListItem.findViewById(R.id.text2Text);
ListItem.setTag(holder);
} else {
holder = (Holder) ListItem.getTag();
}
MyTextWatcher text2Watcher = (new MyTextWatcher() {
public Holder holder;
public void setView(Holder newHolder){
holder = newHolder;
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (holder.text2.isFocused()) {
holder.text2.removeTextChangedListener(this);
String raw = moneyConversion.unformatToString(s.toString());
double text1Value = moneyConversion.gettext1Value(Double.parseDouble(raw));
holder.text2.setText(moneyConversion.formatLive(raw));
holder.text1.setText(moneyConversion.format(text1Value));
holder.text2.addTextChangedListener(this);
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
MyTextWatcher text1Watcher = (new MyTextWatcher() {
public Holder holder;
public void setView(Holder newHolder){
holder = newHolder;
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (holder.text1.isFocused()) {
holder.text1.removeTextChangedListener(this);
String text1Value = moneyConversion.unformatToString(s.toString());
String formattedValue = moneyConversion.formatLive(text1Value);
double text2Value = moneyConversion.gettext2Value(Double.parseDouble(text1Value));
holder.text1.setText(formattedValue);
holder.text2.setText(moneyConversion.format(text2Value));
holder.text1.addTextChangedListener(this);
}
}
#Override
public void afterTextChanged(Editable s) {
}
});
HolderOnFocusChangeListener text1FocusListener = new HolderOnFocusChangeListener() {
public DietyAmountAdapter.Holder holder;
public void setHolder(Holder newHolder){
holder = newHolder;
}
#Override
public void onFocusChange(View v, boolean hasFocus) {
// Timer timer = new Timer();
// TimerTask t1 = new TimerTask() {
// #Override
// public void run() {
// holder.text1.clearFocus();
// }
// };
if (hasFocus){
holder.text1.setBackgroundColor(Color.parseColor("#5aa0ce"));
holder.text1Text.setBackgroundColor(Color.parseColor("#5aa0ce"));
holder.text1.setSelection(holder.text1.getText().length());
}
if (!hasFocus) {
if (!holder.text1.getText().toString().isEmpty()) {
holder.text1.setSelection(holder.text1.getText().length());
// holder.text2.setText(moneyConversion.format());
}
holder.text1.setBackgroundColor(Color.parseColor("#424242"));
holder.text1Text.setBackgroundColor(Color.parseColor("#424242"));
// timer.scheduleAtFixedRate(runOnUiThread(t1), 1, 500);
}
}
};
HolderOnFocusChangeListener text2FocusListener = new HolderOnFocusChangeListener() {
public DietyAmountAdapter.Holder holder;
public void setHolder(Holder newHolder){
holder = newHolder;
}
#Override
public void onFocusChange(View v, boolean hasFocus) {
// Timer timer = new Timer();
// TimerTask t2 = new TimerTask() {
// #Override
// public void run() {
// holder.text2.clearFocus();
// }
// };
if (hasFocus){
holder.text2.setBackgroundColor(Color.parseColor("#5aa0ce"));
holder.text2Text.setBackgroundColor(Color.parseColor("#5aa0ce"));
holder.text2.setSelection(holder.text2.getText().length());
}
if (!hasFocus) {
if (!holder.text2.getText().toString().isEmpty()) {
holder.text2.setSelection(holder.text2.getText().length());
}
holder.text2.setBackgroundColor(Color.parseColor("#424242"));
holder.text2Text.setBackgroundColor(Color.parseColor("#424242"));
}
}
};
text2FocusListener.setHolder(holder);
text1FocusListener.setHolder(holder);
text1Watcher.setView(holder);
text2Watcher.setView(holder);
holder.text2.addTextChangedListener(text2Watcher);
holder.text1.addTextChangedListener(text1Watcher);
holder.text2.setOnFocusChangeListener(text2FocusListener);
holder.text1.setOnFocusChangeListener(text1FocusListener);
holder.title.setText(Diety.title);
holder.banner.setImageResource(Diety.banner);
return ListItem;
}
static class Holder {
ImageView banner;
TextView title;
EditText text1;
EditText text2;
TextView text2Text;
TextView text1Text;
}
}
Here's my moneyConversion class:
public class moneyConversion {
public int currentlyActive;
public int counterTotal;
Context context;
public static double gettext1Value(double value){
double newValue = (value / 1.05);
return newValue;
}
public static double gettext2Value(double value){
double newValue = (value * 1.05);
return newValue;
}
public static String format(double value){
DecimalFormat df = new DecimalFormat();
df.applyPattern("###,###,###,###.##");
String formattedValue = df.format(value);
Log.d(TAG, formattedValue);
return formattedValue;
}
public static String formatLive(String s) {
if (s.endsWith(".")) {
return s;
}
DecimalFormat df = new DecimalFormat();
df.applyPattern("###,###,###,###.##");
Double value = Double.parseDouble(s);
String formattedValue = df.format(value);
// Log.d(TAG, formattedValue);
return formattedValue;
}
public static double unformat(String s){
if (s != null && s.isEmpty() ){
return 0;
}
String string = s.replace(",", "");
if (string.isEmpty()) {
return 0;
}
// if (string.equals(".")){
// return Double.parseDouble("0");
// }
return Double.parseDouble(string);
}
public static String unformatToString(String s){
if (s != null && s.isEmpty() ){
return "0";
}
String string = s.replace(",", "");
if (string.isEmpty()) {
return "0";
}
// if (string.equals(".")){
// return Double.parseDouble("0");
// }
return string;
}
}
Write your textchangeListener inside if (ListItem == null) { condition block, it will work.
What actually happening in your case is whenever you scroll your listview on change listener will call for each and every row that is visible.

Android List(RecyclerView Adapter) is changing when Edittext On Text change

İ have a problem about RecyclerView filter.
İ am using edittext on text change method for filter text query in recyclerview but when i filter my Product List is changing.
Note : all of that in fragment and fragment in viewpager.
My problem is that : when i write something it is working but at the same time my product list's elements are changing to result of filter.
So in example at first
MyList Has 40 items
FilteredDataList is empty
After i write "a" in edittext after that FilteredDataList is has 30 items but MyList has same 30 items. But i have not set anything to Mylist
My Data List ,i get it from sqlite
productList = new ArrayList<>();
productList = handler.getAllProduct();
My Filter Method
private List<Product> filter(List<Product> models, String query) {
query = query.toLowerCase();
List<Product> filteredModelList = new ArrayList<>();
filteredModelList.clear();
for (Product model : models) {
final String text = model.get_ProductName().toLowerCase();
if (text.contains(query)) {
filteredModelList.add(model);
}
}
return filteredModelList;
}
My Edittext OnChange Metod
searchEdt.addTextChangedListener(new TextWatcher() {
#Override
public void afterTextChanged(Editable s) {
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (s.length() != 0) {
List<Product> filteredModelList = filter( productList, s.toString());
rcAdapter.animateTo(filteredModelList);
pager_recycler_view.scrollToPosition(0);
} else {
rcAdapter.animateTo(productList);
pager_recycler_view.scrollToPosition(0);
}
}
});
My AdapterClass
public class ProductRecyclerViewAdapter extends RecyclerView.Adapter< ProductRecyclerViewHolder > {
private List<Product> itemList;
private Context context;
public ProductRecyclerViewAdapter(Context context, List<Product> itemList) {
this.itemList = itemList;
this.context = context;
}
#Override
public ProductRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View layoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.product_card_single_item, null);
ProductRecyclerViewHolder rcv = new ProductRecyclerViewHolder(layoutView);
return rcv;
}
#Override
public void onBindViewHolder(ProductRecyclerViewHolder holder, int position) {
holder.productName.setText(itemList.get(position).get_ProductName());
holder.productWatCode.setText("%" +itemList.get(position).get_ProductWatCode());
holder.productPOR.setText("%" +itemList.get(position).get_ProductPOR());
holder.productRSP.setText("£" +itemList.get(position).get_ProductRSP());
holder.productDescription.setText(itemList.get(position).get_ProductDescription());
holder.productSKU.setText(itemList.get(position).get_ProductSKU());
holder.productPrice.setText("£" + itemList.get(position).get_ProductPrice());
// holder.productCountCart.setText("");
Picasso.with(context)
.load( "http://firmabayi.com/images/ilanK/" +itemList.get(position).get_ProductPhoto())
.placeholder(R.drawable.add_icon)
.error(R.drawable.minus_icon)
.into(holder.productPhoto);
// holder.countryPhoto.setImageResource(itemList.get(position).get_ProductName());
}
#Override
public int getItemCount() {
return this.itemList.size();
}
public void animateTo(List<Product> itemList) {
applyAndAnimateRemovals(itemList);
applyAndAnimateAdditions(itemList);
applyAndAnimateMovedItems(itemList);
}
private void applyAndAnimateRemovals(List<Product> newModels) {
for (int i = itemList.size() - 1; i >= 0; i--) {
final Product model = itemList.get(i);
if (!newModels.contains(model)) {
removeItem(i);
}
}
}
private void applyAndAnimateAdditions(List<Product> newModels) {
for (int i = 0, count = newModels.size(); i < count; i++) {
final Product model = newModels.get(i);
if (!itemList.contains(model)) {
addItem(i, model);
}
}
}
private void applyAndAnimateMovedItems(List<Product> newModels) {
for (int toPosition = newModels.size() - 1; toPosition >= 0; toPosition--) {
final Product model = newModels.get(toPosition);
final int fromPosition = itemList.indexOf(model);
if (fromPosition >= 0 && fromPosition != toPosition) {
moveItem(fromPosition, toPosition);
}
}
}
public Product removeItem(int position) {
final Product model = itemList.remove(position);
notifyItemRemoved(position);
return model;
}
public void addItem(int position, Product model) {
itemList.add(position, model);
notifyItemInserted(position);
}
public void moveItem(int fromPosition, int toPosition) {
final Product model = itemList.remove(fromPosition);
itemList.add(toPosition, model);
notifyItemMoved(fromPosition, toPosition);
}
}
i solved my problem it is only about adapter class one line :(
in adapter class
instead of
this.itemList = itemList;
use that
this.itemList = new ArrayList<>(itemList);
It is about your productList.
When you create a object like doing this;
Class a = b();
You are cloning your object. In deep, they are the same object.
So when you filtered object named a, b is being effected from this.
In short, don't do this. Instead of cloning object you should add each items to a from b by one by.
Like this;
productList = new ArrayList<>();
for( int i = 0 ; i <arrayFromSource.size() ; i++ )
{
productList.add(arrayFromSource.get(i));
}

Converting custom ArrayList to LinkedHashSet

I have a custom ArrayAdapter<Summary> which holds a list of events. There are duplicate values in the List<Summary>, so I'm trying to put the values of List<Summary> to LinkedHashSet<Summary> but this displays a blank page.
How do I convert custom ArrayList to LinkedHashSet to get unique data?
Main.java:
LinkedHashSet<Summary> listToSet = new LinkedHashSet<Summary>();
final List<Summary> summaries = new ArrayList<Summary>();
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.events_summary, container, false);
.......
setListView(month, year, date_value);
summaryAdapter = new SummaryAdapter(this.getActivity().getApplicationContext(), R.layout.listview_item_row, listToSet);
calendarSummary = (ListView) v.findViewById(R.id.calendarSummary);
calendarSummary.setAdapter(summaryAdapter);
return v;
}
public void setListView(int month, int year, int dv) {
events = new HolidayEvents();
_calendar = Calendar.getInstance(Locale.getDefault());
int totalDays = _calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
for(int i = 1; i <= totalDays; i++){
if(isHoliday(i, month, year, dv))
{
date = i + " " + getMonthForInt(month-1) + " " + year;
for (Event event : events.eventDetails(this, month, i))
{
summaries.add(new Summary(date, event.eventdetails));
listToSet.addAll(summaries);
}
}
}
}
ArrayAdapter.java:
public class SummaryAdapter extends ArrayAdapter<Summary>{
Context context;
int layoutResourceId;
LayoutInflater mInflater;
LinkedHashSet<Summary> list = null;
List<Summary> data = null;
public SummaryAdapter(Context context, int layoutResourceId, LinkedHashSet<Summary> summaries) {
super(context, layoutResourceId);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.list = summaries;
data = new ArrayList<Summary>(list); //converting LinkedHashSet to List
mInflater = LayoutInflater.from(context);
}
....rest of the code retrieving data by using data.get(position) ...
You need to ensure that the class you are putting into Set properly overrides Equals and hashCode functions.
Lets have a look at case where hashCode is not overriden:
import java.util.*;
public class Example {
public static class Abc {
protected String s;
public Abc(String s) {
this.s = s;
}
#Override
public boolean equals(Object other) {
if (other instanceof Abc) {
return ((Abc) other).s.equals(this.s);
}
return false;
}
#Override
public int hashCode() {
return (int) (Math.random() * Integer.MAX_VALUE);
}
public String toString() {
return "Abc: " + this.s;
}
}
public static void main(String[] args) {
ArrayList<Abc> ar = new ArrayList<>();
ar.add(new Abc("a"));
ar.add(new Abc("a"));
ar.add(new Abc("a"));
LinkedHashSet<Abc> lhs = new LinkedHashSet<>(ar);
System.out.println("ar: " + ar);
System.out.println("LinkedHashSet: " + lhs);
}
}
This will produce:
ar: [Abc: a, Abc: a, Abc: a]
LinkedHashSet: [Abc: a, Abc: a, Abc: a]
even though equals are properly implemented.
I believe you may want to double-check proper implementation of both HashCodes and Equals.

Categories

Resources