Removing item from RecyclerView not working well - java

I didn't customize anything on RecyclerView so there's default animation on item added/removed. While I found the animation isn't working as I expected. When I removed item by the following code:
mComments.remove(position);
notifyItemRemoved(position);
I see on UI it always remove the wrong one, and the one should be removed already keeps showing up and overlay the others.
new CountDownTimer(60000, 1000) {
#Override
public void onTick(long l) {
for (int i = 0; i < mComments.size(); i++) {
RoomMessage item = mComments.get(i);
item.timeRemaining -= 1000;
if (item.timeRemaining <= 0) {
Log.v(TAG, "Going to remove no." + i + ". And the content = " + mComments.get(i).text);
removeAt(i);
}
}
}
#Override
public void onFinish() {
start();
}
}.start();
According to log, I did remove the right one. See as below.
02-16 15:26:38.274 21861-21861/com.xxxx.android V/ChatsAdapter: Going to remove no.0. And the content = 1
02-16 15:26:41.284 21861-21861/com.xxxx.android V/ChatsAdapter: Going to remove no.0. And the content = 2
02-16 15:26:42.284 21861-21861/com.xxxx.android V/ChatsAdapter: Going to remove no.0. And the content = 3
What did I do wrong?
btw I've set setisRecyclable(false)

Use only notifyItemRemoved(position);.You are using both. notifyItemRemoved which is for notifying that items previously located at position has been removed from the data set. While notifyItemRangeChanged(int positionStart, int itemCount) is used only when notify any registered observers that the itemCount items starting at position positionStart have changed. If you are adding single item use notifyItemInserted. If you have added more then one new items then use notifyItemRangeInserted(int positionStart, int itemCount). Any method ending with Changed states that the value or values of that particular item or row has changed.

Related

android studio 30 min interval on time picker(spinner)

I'm using a time picker spinner. I would like to implement 30 min intervals.
The code I'm using outputs this effect as shown in the below image.
Here's the code:
picker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
#Override
public void onTimeChanged(TimePicker view, int hour, int min) {
timeoutput.setText(String.format("%02dh%02d", hour, min));
}
});
back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(Schedule.this, choosewalk.class);
startActivity(intent);
}
});
#SuppressLint("DefaultLocale")
private void TimeInterval(TimePicker picker) {
try {
int Interval = 30;
NumberPicker minute = (NumberPicker) picker.findViewById(Resources.getSystem().getIdentifier(
"minute", "id", "android"));
minute.setMinValue(0);
minute.setMaxValue((60 / Interval) - 1);
List<String> displayedValue = new ArrayList<String>();
for (int i = 0; i < 60; i += Interval) {
displayedValue.add(String.format("%02d", i));
}
minute.setDisplayedValues(displayedValue.toArray(new String[0]));
} catch (Exception e) {
e.printStackTrace();
}
}
I know that that there are similar questions, but for this specific problem, I'm struggling. I know the method works for intervals of 5, 10, 15, etc. It's altering the code for 30 min intervals that's problematic.
Ok, here's your problem. You want a wheel with 00 and 30 on it, and you want to be able to infinitely scroll it, so it ticks over from 30 to 00 and increments the hour wheel each time, right? Which is basically how the TimePicker works by default.
The issue is this, from NumberPicker:
Note: If the number of items, i.e. the range ( getMaxValue() - getMinValue()) is less than the number of items shown on the selector wheel, the selector wheel will not wrap.
the max - min thing is an extremely awkward way of expressing this (the number of items is actually that + 1) - but basically the spinner shows three items on-screen at a time, and you need to have more than three items (so at least one is off-screen) for wrapping to work. That's why is works for your other intervals (15 mins gives you four items, so that wraps)
Unfortunately I don't think there's a lot you can do about it - the lack of wrapping is hardcoded behaviour in NumberPicker. You could fake it by having four items, 00, 30, 00, 30 but internally that's still values 0 to 3, one rotation of the wheel, not two. And the TimePicker uses those values, comparing to minValue and maxValue to check when the wheel has wrapped and the hour needs to automatically change.
The listener that handles this (in TimePickerSpinnerDelegate) can't be read, so you can't wrap it in a listener that pretends it's going 0 1 0 1 instead. The listener also refers to a bunch of internal private variables and methods, so you can't just copy it into your own code and make the tweaks. You'd have to reimplement the whole widget and its related classes by the looks of things
If it works for you, you could just throw two NumberPickers together and remake it yourself. You'll lose things like the AM/PM functionality, probably accessibility, it depends if you care or not. This basically works:
public class MainActivity extends AppCompatActivity implements NumberPicker.OnValueChangeListener {
private NumberPicker mMinuteSpinner;
private NumberPicker mHourSpinner;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMinuteSpinner = findViewById(R.id.minPicker);
mHourSpinner = findViewById(R.id.hourPicker);
mMinuteSpinner.setMinValue(0);
mMinuteSpinner.setMaxValue(3);
mMinuteSpinner.setDisplayedValues(new String[]{"00", "30", "00", "30"});
mMinuteSpinner.setOnValueChangedListener(this);
mHourSpinner.setMinValue(0);
mHourSpinner.setMaxValue(23);
String[] hours = new String[24];
for (int i = 0; i < 24; i++) {
hours[i] = Integer.toString(i + 1);
}
mHourSpinner.setDisplayedValues(hours);
}
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
boolean advanced = (newVal == 0 && oldVal == 3) || (newVal == 2 && oldVal == 1);
boolean regressed = (newVal == 3 && oldVal == 0) || (newVal == 1 && oldVal == 2);
if (advanced) {
mHourSpinner.setValue(mHourSpinner.getValue() + 1);
} else if (regressed) {
mHourSpinner.setValue(mHourSpinner.getValue() - 1);
}
}
}
Haven't touched Java in a while! There might be a better way to do that. But yeah, the listener is just checking to see if it's passing between the two rollover points on the four-item list (where it goes from 30 to 00 scrolling one way, or vice versa scrolling the other way). This is basically how the TimePicker works

how to remove the last digit to the left of the cursor in EditText

I am was making a DEL button which would delete 1 char at a time. I recently added cursor movement to delete in between bud don't know how
I used substrings for deleting normally. It would crash if the number of chars was 0 or 1 before pressing it. I added if statement to fix it.
Here is my delete method
public void delete(View view){
if(textArea.length()==0){
return;
}else if(textArea.length()==1){
if(textArea.getSelectionStart()==textArea.length()){
textArea.setText("");
}else{
return;
}
}else {
int selection = textArea.getSelectionStart();
textArea.setText(textArea.getText().delete(Math.max(0, selection - 1), selection));
}
}
Please Tell How I could Do This To Delete the Char immediately left to the cursor.
I edited the code for the answerer
You can use delete method of Editable class like this
public void delete(View view){
int selection = textArea.getSelectionStart();
textArea.setText(textArea.getText().delete(Math.max(0, selection - 1), selection));
}

ArrayList elemsts to be viewed evenly on the same view

I am trying to view list elements on the same view however 6 at a time. To start with, a cursor is called which in turn populates an array list with all the items.
if (cursor.moveToFirst())
{
try {
do {
items.add(ChecklistItem.fromCursor(cursor));
} while (cursor.moveToNext());
} catch (Exception e) {
e.printStackTrace();
}
}
Then that list is given to an adapter, which in turn handles vieweing the items on the current view.
if (items.size() > 0) {
if (mAdapter == null)
{
mAdapter = new RecipeDetailAdapter(this, items, this);
mRecyclerView.setAdapter(mAdapter);
}
else
{
mAdapter.updateItems(items);
}
}
On the view, there is a next button, which when clicked takes you to another view.
public void onClick(View view) {
switch (view.getId()) {
case R.id.next_button:
startActivity(new Intent(RecipeDetailActivity.this, RecipeTasksActivity.class)
.putExtra(RecipeTasksActivity.RECIPE_KEY, mRecipe.getRecipeId()));
finish();
break;
}
}
At the moment the view shows whatever items are in the list, could be 10, 30, 50, etc.
What I am trying to achieve is, assuming the list has 18 items, view the first 6 items in that list, then when the button "next" is clicked, view the other 6, and then when next is clicked, view the rest of the 6. Keeping in mind that I need to check if the list has 6 items or less, if less, view all of them, if more, spread them on two instances of the same view.
Any suggestions on how to approach this?
Yes you can do that by using the OFFSET & LIMIT in your query.
db.rawQuery("SELECT * FROM " + TABLE_NAME + " ORDER BY " + ORDER_BY + " LIMIT 0, 20", NULL);
Note : On above 0 is your OFFSET & 20 is your limit. in your case LIMIT would be 6. You can maintain offset by k * Limit where k would your pager number.

Assertion Failure while trying to assert amount of textviews in a list

Why is my assertion failing when I am trying to assert the amount of textviews in a list ?
#Test
public void testDeleteNote() throws Exception {
int count= getNoOfTextViews();
// Checking if count is greater than 0.
if (count > 0) {
// Iterating count times
for (int i = 0; i < count; i++)
{
// Checking if count is even or odd.
if (i % 2 == 0) {
solo.clickInList(0);
deleteNote();
} else {
// Clicking Long on the 1st item in the Notes List.
solo.clickLongInList(0);
// Clicking on Delete String.
solo.clickOnText(solo.getString(R.string.menu_delete));
}
}
count = getNoOfTextViews();
// Asserting all the text views are deleted.
assertEquals(0, count);
}
public int getNoOfTextViews() {
// Getting the count of text views in the activity.
ArrayList<TextView> textView = solo.getCurrentViews(TextView.class,
solo.getCurrentViews(ListView.class).get(0));
return textView.size();
}
The failure I am seeing is:
junit.framework.AssertionFailedError: expected:<0> but was:<1>
UPDATE:
I am seeing that this passes when i debugg, it fails only when i run the test case.
Your count variable is calculated once at the beginning of your program and then never updated. This means, when you are comparing it with 0 at the end, it still contains the old value.
All you have to do is update your count variable by calling the method again:
count = getNoOfTextViews();
Or simply
assertEquals(0, getNoOfTextViews());
Added a wait for list view before taking the count. This helped me solve the problem.
Thanks all.
public int getNoOfTextViews() {
solo.waitForView(ListView.class,0,1000);
// Getting the count of text views in the activity.
ArrayList<TextView> textView = solo.getCurrentViews(TextView.class,
solo.getCurrentViews(ListView.class).get(0));
return textView.size();
}

I need advice with making "Secret Friend" on java for Android

I'm trying to make this app for android, but here's the problem, I fill 2 lists, then I shuffle them, then I make a for to mix them and make the "couples", but before this I made a while to see if the final list(the list with the couples), is the same size as the original list (if this is true so everything is ok, since the couples will be the same size as the people playing), ALWAYS if the app goes to the while, it crashes, only if never goes to the while, I get the couples, here's my code:
protected void onCreate(Bundle savedInstanceState) { //when the app starts
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_amigo__secreto);
spinner1 = (Spinner) findViewById(R.id.spinner);
lista = new ArrayList<String>();
AdminSQLiteOpenHelper admin = new AdminSQLiteOpenHelper(this, "amigoS", null, 1);
this.llenarLista();
this.llenarLista2();
if (lista.size() > 1){ //if there are more than 2 people do this
Collections.shuffle(lista);
Collections.shuffle(lista2);
reproductor = MediaPlayer.create(this, R.raw.cancion);
reproductor.setLooping(true);
reproductor.start();
sorteo(); //here is the problem, look
}
}
public int sorteo() {
do {
listaParejas.clear();
listaSalidos.clear();
int start2;
for (int i = 0; i < lista.size(); i++) {
start2 = random.nextInt(lista2.size() - 0) + 0;
if (lista2.get(start2).equals(lista.get(i))) { if the person who receives is equals to the one who gives, continue
continue;
} else { //here I add who gives and receives
listaParejas.add(lista.get(i) + "->" + lista2.get(start2));
listaSalidos.add(lista2.get(start2));
lista2.remove(start2); //And remove the person who receives so that he'll never get out again
}
}
} while (listaParejas.size() != lista.size());
return 0;
}
Please any advice, I don't know what to do next, I've trying and trying, but I have no idea why always in the while, the app fails... Thanks
I think your process is based on the luck of your random factor to make the process to finish. This is not ok at all, specially because you are doing it in the main thread. What I would do is:
Take the first list, make a copy and shuffle it using a random sort. See for example Collections.shuffle(list).
Take the first list and make the couples using the following logic:
Take the first element of the first list and couple it with the first element of the second list.
If the element from the first list is the same as the element in the second, take the next one.
Remove the elements from both lists.
Repeat until the lists are empty.
This is also ensuring you have the same number of elements and that they are not the same. You can also use a queue or a stack to make your life easier.

Categories