I've an activity in which I use a RecyclerView. In the Adaptater I modify the content of an ArrayList. How can I retrieve my modified ArrayList in my first activity
Thank you very much for your help
Best regards
Georges
holder.imageClick.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (laPlateaux.get(position).Cat.equals("U7")) {
keyPlateau = "PlatU7" + "-" + zdte + "-" + laPlateaux.get(position).AccueilNum;}
else {
keyPlateau = "PlatU9" + "-" + zdte + "-" + laPlateaux.get(position).AccueilNum; }
if (laPlateaux.get(position).Cat.equals("U7")) {
if (laPlateaux.get(position).Select.equals("N")){
mDatabase.child("PlateauxU7").child(keyPlateau).child("Selected").setValue("Y");
holder.imageClick.setImageDrawable(holder.itemView.getContext().getDrawable(R.drawable.valoknew));
laPlateaux.get(position).Select = "Y";
notifyDataSetChanged();}
else {
mDatabase.child("PlateauxU7").child(keyPlateau).child("Selected").setValue("N");
holder.imageClick.setImageDrawable(holder.itemView.getContext().getDrawable(R.drawable.valnoknew));
laPlateaux.get(position).Select = "N";
notifyDataSetChanged();}}
else {
if (laPlateaux.get(position).Select.equals("N")){
mDatabase.child("PlateauxU9").child(keyPlateau).child("Selected").setValue("Y");
holder.imageClick.setImageDrawable(holder.itemView.getContext().getDrawable(R.drawable.valoknew));
laPlateaux.get(position).Select = "Y";
notifyDataSetChanged();}
else {
mDatabase.child("PlateauxU9").child(keyPlateau).child("Selected").setValue("N");
holder.imageClick.setImageDrawable(holder.itemView.getContext().getDrawable(R.drawable.valnoknew));
laPlateaux.get(position).Select = "N";
notifyDataSetChanged();}}} }); }
#Override
public int getItemCount() {
return laPlateaux.size();
}
I guess you must just implement the public getter in your adapter, that's all.
In the Adapter
public List<PlaceholderItem> getKeyPlateau() {
return keyPlateau;
}
In the activity
ArrayList<String> keyPlateau = adapter.getKeyPlateau();
Related
I am using my CustomAlertDialog in order to delete a record from database, when I delete one successfully and I attempt to insert a new row into database, the AlertDialog appears again notwithstanding I didn't even call it and when I click the delete button it deletes one record until all the records are deleted and app crashes.
I call it on my AdapterClass =>
#Override
public void onClick(View view) {
E04Object obj = object.get(getAdapterPosition()) ;
id = obj.getId() ;
if (view == deleteBtn) {
int position = id ;
if (position != RecyclerView.NO_POSITION) {
activityReference.ShowDialog(position);
}
clicked = false ;
} }
and I initialize it in my FragmentClass =>
#Override
public void ShowDialog(int position) {
DialogObject dialogObject = new DialogObject() ;
CustomDialogView customDialogView = new CustomDialogView(getActivity() , dialogObject) ;
dialogObject.setListener(new DialogListener() {
#Override
public void onPositive() {
dbConnector.get().execSQL(
" DELETE FROM " + db.Tables.MYDB + " WHERE " + db.MYDB.ID + " = " + position );
customDialogView.hide();
list.remove(MyAdapter.cardId) ;
adapter.notifyDataSetChanged();
}
#Override
public void onNegative() {
customDialogView.hide();
}
});
customDialogView.setCancelable(true);
customDialogView.show();
}
#Override
public void ShowDialog(int position) {
DialogObject dialogObject = new DialogObject() ;
CustomDialogView customDialogView = new CustomDialogView(getActivity() , dialogObject) ;
dialogObject.setListener(new DialogListener() {
#Override
public void onPositive() {
dbConnector.get().execSQL(
" DELETE FROM " + db.Tables.MYDB + " WHERE " + db.MYDB.ID + " = " + position );
customDialogView.dismiss();
list.remove(MyAdapter.cardId) ;
adapter.notifyDataSetChanged();
}
#Override
public void onNegative() {
customDialogView.dismiss();
}
});
customDialogView.setCancelable(true);
customDialogView.show();
}
customDialogView.hide();
replace code with this
customDialogView.dismiss();
I have a "favourite" button for each row of my recyclerview which the user clicks when the like the image (obviously). Each row is a cardview that I only want to "flip" when the user opens the fragment.
When the user clicks the button I update my database with "Y" or "N".
My problem is that my recyclerview refreshes even though the list hasn't changed. When it refreshes all my cards flip which I do not want. How can I stop the recyclerview from updating when the button is clicked?
Here is my adapter class
#Override
public void onBindViewHolder(#NotNull final ClothesViewHolder holder, final int position) {
String image;
if (flip) {
holder.flipView.flipTheView();
}
ClothingItem current = mClothingItems.get(position);
holder.itemNameView.setText(current.getItem());
holder.categoryNameView.setText(current.getCategory());
holder.seasonNameView.setText(current.getSeason());
Integer yesCount = current.getYesCount();
Integer noCount = current.getNoCount();
if (current.getFavourite().equalsIgnoreCase("N")) {
holder.animationView.setProgress(0);
}
else {
holder.animationView.setProgress(1);
}
holder.yesTextView.setText(String.valueOf(yesCount));
holder.noTextView.setText(String.valueOf(noCount));
image = current.getPhotoPath();
Glide.with(holder.cardView)
.load(image)
.into(holder.pictureView);
flip = false;
} catch (NullPointerException e) {
Log.e("Picture","onBindViweHolder: Null Point:" + e.getMessage());
}
holder.animationView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.onFavouriteClick(position);
}
});
public interface clickButtons {
void onFavouriteClick(int position);
}
Fragment Class
#Override
public void onFavouriteClick(int position) {
RecyclerView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(position);
LottieAnimationView animationView = holder.itemView.findViewById(R.id.favouriteAnimation);
ClothingItem item = springList.get(position);
final Long id = item.getId();
if (animationView.getProgress() > 0) {
animationView.setProgress(0);
mClothingViewModel.updateFavourite(id.intValue(), "N");
adapter.notifyItemChanged(position,"favourite");
} else if (animationView.getProgress() == 0) {
animationView.playAnimation();
mClothingViewModel.updateFavourite(id.intValue(),"Y");
}
}
I tried to use onBindViewHolder with payloads but I get the same result. I think I'm not calling this properly
adapter.notifyItemChanged(position,"favourite");
Adapter class
#Override
public void onBindViewHolder(final ClothesViewHolder holder ,final int position, final List<Object> payloads){
String image;
if(!payloads.isEmpty()) {
ClothingItem current = mClothingItems.get(position);
holder.itemNameView.setText(current.getItem());
holder.categoryNameView.setText(current.getCategory());
holder.seasonNameView.setText(current.getSeason());
Integer yesCount = current.getYesCount();
Integer noCount = current.getNoCount();
if(yesCount == null) {
yesCount = 0;
}
if (noCount == null) {
noCount = 0;
}
if (current.getFavourite() == null || current.getFavourite().equalsIgnoreCase("N")) {
holder.animationView.setProgress(0);
}
else {
holder.animationView.setProgress(1);
}
// Log.d("Counting","Yes count " + yesCount + " no count " + noCount);
holder.yesTextView.setText(String.valueOf(yesCount));
holder.noTextView.setText(String.valueOf(noCount));
image = current.getPhotoPath();
Glide.with(holder.cardView)
.load(image)
.into(holder.pictureView);
} else {
onBindViewHolder(holder,position);
}
}
Fragment
#Override
public void onFavouriteClick(int position) {
RecyclerView.ViewHolder holder = recyclerView.findViewHolderForAdapterPosition(position);
LottieAnimationView animationView = holder.itemView.findViewById(R.id.favouriteAnimation);
ClothingItem item = springList.get(position);
final Long id = item.getId();
if (animationView.getProgress() > 0) {
animationView.setProgress(0);
mClothingViewModel.updateFavourite(id.intValue(), "N");
adapter.notifyItemChanged(position,"favourite");
} else if (animationView.getProgress() == 0) {
animationView.playAnimation();
mClothingViewModel.updateFavourite(id.intValue(),"Y");
adapter.notifyItemChanged(position,"favourite");
}
}
Recyclerview is updated or refreshed when notifiydataSetChanged is called.
try to remove notifiyDataSetChanged in the click event maybe
I want to write a validator for multiple editText's using TextWatcher.
I already have method to validate if the data written by user is correct.
And also added validation to check if editText is empty. But here is where it's not working as I would like to.
This TextWatcher is also activated when phone changes orientation and I don't want this to happen. I want it work only when user deletes data from editText.
Here is the code:
#Override
final public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
#Override
final public void onTextChanged(CharSequence s, int start, int before, int count) {}
#Override
final public void afterTextChanged(Editable s) {
String text = textView.getText().toString();
if(textView.getText().toString().isEmpty()){
textView.setError("Can't be empty");
ParametersFrag.isCorrect = false;
} else {
validate(textView, text);
}
}
And the validate part in fragment look like this:
editText2_5.addTextChangedListener(new ParameterValidator(editText2_5) {
#Override
public void validate(TextView textView, String text) {
double parDouble = Double.parseDouble(Tab2Fragment.editText2_5.getText().toString());
if (parDouble < sth_min) {
textView.setError(getString(R.string.err_min_value) + " " + sth_min);
ParametersFrag.isCorrect = false;
} else if (parDouble > sth_max) {
textView.setError(getString(R.string.err_max_value) + " " + sth_max);
ParametersFrag.isCorrect = false;
} else {
ParametersFrag.isCorrect = true;
}
}
});
Question is how can I make it not triggering on orientation change?
Thank You
try this:
#Override
public void onConfigurationChanged(#NotNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
switch (newConfig.orientation) {
case Configuration.ORIENTATION_LANDSCAPE:
editText2_5.addTextChangedListener(null);
break;
case Configuration.ORIENTATION_PORTRAIT:
// editText2_5.addTextChangedListener(null);
// ============= OR =============
// editText2_5.addTextChangedListener(new ParameterValidator(editText2_5) {
// #Override
// public void validate(TextView textView, String text) {
// double parDouble = Double.parseDouble(Tab2Fragment.editText2_5.getText().toString());
// if (parDouble < sth_min) {
// textView.setError(getString(R.string.err_min_value) + " " + sth_min);
// ParametersFrag.isCorrect = false;
// } else if (parDouble > sth_max) {
// textView.setError(getString(R.string.err_max_value) + " " + sth_max);
// ParametersFrag.isCorrect = false;
// } else {
// ParametersFrag.isCorrect = true;
// }
// }
// });
break;
default:
break;
}
}
private var doesDeviceTitled = false
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
doesDeviceTitled = when (newConfig.orientation) {
Configuration.ORIENTATION_LANDSCAPE -> {
true
}
else -> {
false
}
}
}
Note: The above code was in Kotlin
then after wrap validation using this boolean variable.
editText2_5.addTextChangedListener(new ParameterValidator(editText2_5) {
#Override
public void validate(TextView textView, String text) {
if(!doesDeviceTitled){
//Your validation code here.
}
}});
Happy Coding :)
OK, so now as I think, you need to declare android:configChanges="orientation" in your <activity> tag in AndroidManifest.xml and remove this:
public void onConfigurationChanged(#NotNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
switch (newConfig.orientation) {
case Configuration.ORIENTATION_LANDSCAPE:
editText2_5.addTextChangedListener(null);
break;
case Configuration.ORIENTATION_PORTRAIT:
// editText2_5.addTextChangedListener(null);
// ============= OR =============
// editText2_5.addTextChangedListener(new ParameterValidator(editText2_5) {
// #Override
// public void validate(TextView textView, String text) {
// double parDouble = Double.parseDouble(Tab2Fragment.editText2_5.getText().toString());
// if (parDouble < sth_min) {
// textView.setError(getString(R.string.err_min_value) + " " + sth_min);
// ParametersFrag.isCorrect = false;
// } else if (parDouble > sth_max) {
// textView.setError(getString(R.string.err_max_value) + " " + sth_max);
// ParametersFrag.isCorrect = false;
// } else {
// ParametersFrag.isCorrect = true;
// }
// }
// });
break;
default:
break;
}
}
I'm inflating RecyclerView with data received from server call. Now I want to add one more item to this RecyclerView from local storage(i.e. one drawable and one string manually). Let me show few of my code and tried methods which have not worked for me yet.
FragmentCategoryList.java:
CategoryAdapter adapter;
ArrayList<CatDataItem> dataItems;
ArrayList<ExtraDataItem> extraItems;
void getCategories() {
ApiGetCategories.getInstance().setListener(this);
}
#Override
public void onGetCategories(CategoriesModel categoriesModel) {
isLoading = false;
dataItems = categoriesModel.getData();
setAdapter();
}
void setAdapter() {
if (adapter == null) {
//tried method dataItems.addAll(dataItems.size()+1, extraItems);
adapter = new CategoryAdapter(dataItems, getActivity());
recyclerCategory.setAdapter(adapter);
setLayoutManager();
} else {
//tried method dataItems.addAll(dataItems.size() +1, extraItems);
adapter.updateList(dataItems);
setLayoutManager();
}
}
....
CategoryAdapter.java extends RecyclerView.Adapter:
private ArrayList<CatDataItem> dataItems;
public CategoryAdapter(ArrayList<CatDataItem> dataItems, Context context) {
this.dataItems = dataItems;
this.context = context;
}
public void updateList(ArrayList<CatDataItem> dataItems) {
this.dataItems = dataItems;
notifyDataSetChanged();
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_raw_category, parent, false);
return new MyViewHolder(v);
}
#Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
holder.tvCategory.setText(dataItems.get(position).getName());
Glide.with(AppController.getInstance())
.setDefaultRequestOptions(new RequestOptions()
.placeholder(R.mipmap.ic_launcher)
.error(R.mipmap.ic_launcher))
.load(ApiClient.IMAGE_URL + dataItems.get(position).getImg() + ".png")
.into(holder.ivCategory);
holder.mainContainer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (onCategoryClick != null) {
onCategoryClick.onClickCategory(position);
}
}
});
}
#Override
public int getItemCount() {
return dataItems.size();
}
....
CatDataItem.java:
This is getter setter class and used com.google.gson.annotations.SerializedName;
...
#Override
public String toString() {
return
"DataItem{" +
"id = '" + id + '\'' +
",name = '" + name + '\'' +
",img = '" + img + '\'' +
",description = '" + description + '\'' +
"}";
}
...
CategoriesModel:
#SerializedName("data")
private ArrayList<CatDataItem> data;
#SerializedName("message")
private String message;
public void setData(ArrayList<CatDataItem> data) {
this.data = data;
}
public ArrayList<CatDataItem> getData() {
return data;
}
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
#Override
public String toString() {
return
"CategoriesModel{" +
"data = '" + data + '\'' +
",message = '" + message + '\'' +
"}";
}
ExtraDataItem extends CatDataItem:
I had set static values to id, name, img and description parameter. Everything is same as CatDataItem.
Everything works fine and inflates very beautiful view having 3x* grid.
But now I wants to add one more item at the beginning of the first item. So want to move all items to one index further. Also the extra item is from local storage while all other data is coming from remote server API call.
So I'm not able to trace out perfect way to add one string and image to first position in RecyclerView.
Finally after trying many methods, I have got perfect answer for this question.
First Declare DataItems element:
CatDataItem ee;
Then inside onCreateView add some values to this element.
ee = new CatDataItem();
ee.setId("0");
ee.setName("Add");
ee.setImg("animals_pets");
ee.setDescription("desc");
And finally add that element to position 0 in DataItems:
#Override
public void onGetCategories(CategoriesModel categoriesModel) {
isLoading = false;
dataItems = categoriesModel.getData();
dataItems.add(0, ee);
setAdapter();
}
Thank You.
Hope this might help lots of people who wants to mix local and online data.
Probably you want to jump to Update 2 and check the code if needed
I am building a barcode scanner and having difficulty in passing data that I have captured from an inner class that extends BroadcastReceiver to MainActivity class, I do understand the difference between static and non static objects, but I got stuck.
Cant invoke my logic method from the inner class.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
protected void onCreate(Bundle savedInstanceState){...}
public void Logic(String result){// Do something...}
//Inner Class
public static class ScanResultReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {...
// data here captured fine!
// Here I want to send my data to MainActivity Logic(result)
Logic(result);
}
}
If I make "Logic()" as Static method, I get a lot of errors regards to calling non static from static method from Toaster/variables..etc
Update
This method is inside MainActivity, I do want to call it from the inner class
public void Logic(String result) throws Exception {
//prepare the results
if (mDecodeResult.decodeValue.substring(0, 1).equals("{") && mDecodeResult.decodeValue.substring(mDecodeResult.decodeValue.length() - 1).equals("}")) {
if (!(mDecodeResult.decodeValue.equals("SCAN AGAIN"))) {
mDecodeResult.decodeValue = mDecodeResult.decodeValue.substring(1);
mDecodeResult.decodeValue = mDecodeResult.decodeValue.substring(0, mDecodeResult.decodeValue.length() - 1);
}
}
if (mDecodeResult.decodeValue.equals("SCAN AGAIN")) {
Toast toast = Toast.makeText(getApplicationContext(),
"No scan data received! Please Scan Again", Toast.LENGTH_SHORT);
toast.show();
} else if (mDecodeResult.decodeValue != null && tourFlag) {
String formattedDate = getTime();
String scanContent = mDecodeResult.decodeValue;
boolean found = false;
if (ForcedOrRandom.equals("Random")) {
String[] b;
for (String l : ToBeScanned) {
b = l.split(":");
if (scanContent.equals(b[0])) {
Log.d("remove", "scanned: " + scanContent);
Log.d("remove", "remove : " + b[0]);
found = true;
}
}
} else if (ForcedOrRandom.equals("Forced")) {
String[] b;
for (String I : FTobeScannedNext) {
b = I.split(":");
if (scanContent.equals(b[0])) {
Log.d("remove", "scanned: " + scanContent);
Log.d("remove", "remove : " + b[0]);
found = true;
}
}
}// end Skip/Forced
if (listLoaded && found) {
theResult[resultCount].setTourID(currentTourId);
theResult[resultCount].setBarcode(scanContent);
BarcodeObject a = getBarcodeInfo(scanContent);
if (ForcedOrRandom.equals("Random")) {
} else {
if (myTimer != null) {
myTimer.cancel();
Timer = (TextView) findViewById(R.id.timertext);
Timer.setText("");
PlayOrPause.setVisibility(View.INVISIBLE);
}
boolean isTimed = a.getForceNextBarCode().equals("");
if (!(isTimed)) {
PlayOrPause = (ImageButton) findViewById(R.id.PlayPause);
PlayOrPause.setVisibility(View.VISIBLE);
PlayOrPause.setImageResource(R.drawable.pause);
final AlertDialog.Builder timealert = new AlertDialog.Builder(this);
PlayOrPause.setEnabled(true);
long duration = Integer.parseInt(a.getForceNextBarCode());
duration = duration * 60000;
myTimer = new CountDownTimer(duration, 1000) {
#Override
public void onTick(long millisuntilFinished) {
int seconds = (int) (millisuntilFinished / 1000) % 60;
int minutes = (int) ((millisuntilFinished / (1000 * 60)) % 60);
Timer = (TextView) findViewById(R.id.timertext);
Timer.setText(minutes + ":" + seconds);
timeLeft = millisuntilFinished;
}
String value = "";
#Override
public void onFinish() {
Timer = (TextView) findViewById(R.id.timertext);
theResult[resultCount].setScanstatus(scanStatusTimeElapsed);
timealert.setTitle("Site Secure");
timealert.setMessage("Time Elapsed! Enter reason");
// Set an EditText view to get user input
final EditText input = new EditText(MainActivity.this);
timealert.setView(input);
timealert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
value = input.getText().toString();
// Do something with value!
while (value.equals("")) {
timealert.setView(input);
timealert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
value = input.getText().toString();
}
});
}
theResult[resultCount].setComments(value);
}
});
timealert.setIcon(android.R.drawable.ic_dialog_alert);
timealert.show();
Timer.setText(R.string.Time_Elapsed);
}
};
myTimer.start();
}
}
theResult[resultCount].setBarcodeID(a.getBarCodeId());
theResult[resultCount].setDateScanned(formattedDate);
theResult[resultCount].setSkipped(getResources().getString(R.string.Scanned));
}// end big if listLoaded && found
contentTxt.setText(scanContent);
Toaster(getResources().getString(R.string.TScan_Complete));
if (mainScanCounter == 0) {
if (tourDecider(scanContent)) {//tour decider is called to determine if this is boolJanamScanner random or forced tour
tourId = scanContent;
if (!(readFileOffline(siteSecurePath + "/doneTourNumber.txt").equals(""))) {
SYNC.setEnabled(true);
}
}
} else if (mainScanCounter > 0) {
if (ForcedOrRandom.equals("Random")) {
ListManager(scanContent);
} else {
ForcedListManager(scanContent);
}
}
} else if (mDecodeResult.decodeValue != null && officerScanFlag) {
TextView officertextview = (TextView) findViewById(R.id.officerid);
UserObject theofficer = getUserInfo(mDecodeResult.decodeValue);
if (theofficer == null) {
popUps("Error", "Invalid Officer ID, Please Rescan", "TITLE");
officerScan.setEnabled(true);
} else if (theofficer != null) {
// officer ID found need to store it for backup
officerId = theofficer.getOfficerid();
makeFileOffline(officerId, "officerID");
officertextview.setText(theofficer.getUsername());
officerScanFlag = false;
startTimersOfficerID = getTime();
tourBtn.setEnabled(true);
}
}
if (mDecodeResult.decodeValue != null && exceptionFlag) {
Log.d("check", "exception was clicked");
String ex_result = mDecodeResult.decodeValue;
for (int i = 0; i < theExceptions.length; i++) {
if (!(theExceptions[i].getBarcode().equals(ex_result))) {
String refnum = theExceptions[i].getRefNum();
i = theExceptions.length;
theResult[resultCount - 1].setException(refnum);
}
}
exceptionFlag = false;
Toaster(getResources().getString(R.string.TScan_Complete));
}
} // Logic Ends
Update 2
Not sure if I need to have another thread for this but I will put what I have found, my issue have narrowed to the following:
I am waiting on an intent called
<action android:name="device.scanner.USERMSG" />
with a permission
android:permission="com.permission.SCANNER_RESULT_RECEIVER"
now my issue
if a user tap button and released in less than .5 second onKeyup() event will be fired before my onReceive() that is inside the static class which is extends BroadcastReceiver, and that causes problem because Logic() will be invoked before updating the String inside onReceive()
if user hold the button long enough, onReceive will be invoked and everything is good and happy.
How can I make sure that onReceive() always invoked first?
public boolean onKeyUp(int keycode, KeyEvent event) {
if (keycode == 221 || keycode == 220 || keycode == 222) {
Logic(result);
}
return true;
}
Move this line of code:
public void Logic(String result){// Do something...}
inside your class ScanResultReceiver and it will work for sure. Your code should look like this:
public static class ScanResultReceiver extends BroadcastReceiver {
public ScanResultReceiver() {
//empty constructor
}
#Override
public void onReceive(Context context, Intent intent) {...
// data here captured fine!
// Here I want to send my data to MainActivity Logic(result)
Logic(result);
}
public void Logic(String result){/* ... */}
}