ViewPager offsets cursor position - android

I have a situation similar to this ViewPager. Getting wrong cursor in SimpleCursorAdapter and this ViewPager Cursor positon but the questions had no
applicable answer.
Situation
I am loading the views in my viewpager from a database (cursor). When I set the text for the items (Buttons, TextViews etc) it does this with the correct cursor (in the expected position).
But when i try to button.getText() it shows me the text from the next position in the database (same with buttons etc). If the user swipes forward, the cursor returns values in the next position and if the user swipes backward, it returns values in the previous position
So at position x swiping forward returns cursor at position x + 1 and swiping backwards returns cursor at postion x - 1.
How can i solve this? This is my PagerAdapter.instantiateItem
public Object instantiateItem(View view, int position) {
cursor.moveToPosition(position);
int cus = cursor.getPosition();
Log.d(DBHelper.TAG, Integer.toString(cus) + " current cursor position ");
final ViewPager pager = (ViewPager) view.findViewById(R.id.pager_nav);
ScrollView layout = (ScrollView) inflater.inflate(R.layout.question_activity, null);
if (cursorCategory != null && cursorCategory.moveToFirst()){
String s = cursorCategory.getString(cursorCategory.getColumnIndex("name"));
((TextView)layout.findViewById(R.id.text_category)).setText(s);
}
Typeface tpf = Typeface.createFromAsset(context.getAssets(), "Roboto-Light.ttf");
String text = cursor.getString(cursor.getColumnIndex("question_text"));
TextView question_text = (TextView)layout.findViewById(R.id.text_question);
question_text.setText(text);
Log.d("question_text", question_text.getText() + " " + position + " " + text);
question_text.setTypeface(tpf);
final String qPos = Integer.toString(position + 1) + ".";
TextView question_position = (TextView) layout.findViewById(R.id.text_position);
question_position.setText(qPos);
question_position.setTypeface(tpf);
this.rightAnswer = cursor.getString(cursor.getColumnIndex(DBHelper.RIGHT_ANSWER));
this.wrongAnswer1 = cursor.getString(cursor.getColumnIndex(DBHelper.WRONG_ANSWER1));
this.wrongAnswer2 = cursor.getString(cursor.getColumnIndex(DBHelper.WRONG_ANSWER2));
optionsArray = new ArrayList<String>();
optionsArray.clear();
optionsArray.add(this.rightAnswer);
optionsArray.add(this.wrongAnswer1);
optionsArray.add(this.wrongAnswer2);
Collections.shuffle(optionsArray);
option1 = (Button) layout.findViewById(R.id.button_option1);
option1.setText((CharSequence) this.optionsArray.get(0));
option2 = (Button) layout.findViewById(R.id.button_option2);
option2.setText((CharSequence) this.optionsArray.get(1));
option3 = (Button) layout.findViewById(R.id.button_option3);
option3.setText((CharSequence) this.optionsArray.get(2));
if (this.optionsArray.get(0).equalsIgnoreCase(this.rightAnswer)) {
this.option1.setTag(DBHelper.RIGHT_ANSWER);
} else if (!this.rightAnswer.equalsIgnoreCase((String) this.optionsArray.get(0))) {
this.option1.setTag("wrong");
}
if (this.rightAnswer.equalsIgnoreCase((String) this.optionsArray.get(1))) {
this.option2.setTag(DBHelper.RIGHT_ANSWER);
} else if (!this.rightAnswer.equalsIgnoreCase((String) this.optionsArray.get(1))) {
this.option2.setTag("wrong");
}
if (this.rightAnswer.equalsIgnoreCase((String) this.optionsArray.get(2))) {
this.option3.setTag(DBHelper.RIGHT_ANSWER);
} else if (!this.rightAnswer.equalsIgnoreCase((String) this.optionsArray.get(2))){
this.option3.setTag("wrong");
}
private int getItem(int i) {
return i += pager.getCurrentItem();
}
});
option1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
String Tag = option1.getTag().toString();
Toast.makeText(context, Tag + " " + option1.getText(), Toast.LENGTH_SHORT).show();
}
});
option2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
String Tag = option2.getTag().toString();
Toast.makeText(context, Tag + " " + option2.getText(), Toast.LENGTH_SHORT).show();
}
});
option3.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
String Tag = option3.getTag().toString();
Toast.makeText(context, Tag + " " + option3.getText(), Toast.LENGTH_SHORT).show();
}
});
}
And my onLoadFinished()
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
switch (loader.getId()) {
case QUESTION_TEXT:
Log.d(" Selection Position", " Selection Position" + selcectionPosition );
Log.d(" Activity Position", cursor.getPosition() + " Activity Position");
mAdapter.swapCursor(cursor);
mAdapter.notifyDataSetChanged();
pager.setCurrentItem(selcectionPosition, true);
break;
}
}
Hoping to get some help.

Disclaimer: It might not be the solution to your problem.
I faced the same problem.
So after reading what you wrote, I searched around for something that would help us.
I solved it by using this: How do you get the current page number of a ViewPager for Android?
On my project, I had a button on each page, that on click would trigger a dialog, this dialog would then get a string from the current position of a cursor.
The position on the cursor didn't match the current page being displayed, because, ViewPager changes the cursor's position to get data to preload pages.
So you need to force the the cursor to move to the correct position, the one you're viewing.
To do that, you use cursor.moveToPosition(viewpager.getCurrentItem()).
To make sure the cursor follows what you are viewing.
I hope this helps you.

Related

RecyclerView item showing inconsistent data

While debugging my app, I noticed that my RecyclerView display is inconsistent with the data provided, i.e.
If I set an alarm (TextView in RecyclerView has date set) then scroll my RecyclerView, the date shows up in the wrong positions e.g If I set the date on the 4th item, then the 3rd item also has the date set as well for some reason
I also noticed that at times, e.g. Only the 3rd and 5th -last items in the data set plays an animation while the 4th does not. I checked the logs, and it appears that onBindViewHolder() is not called for the 4th item, only 3rd and 5th. Am I doing something wrong here?
I have looked at the documentation, but am not sure how to patch accordingly. Can you help me?
My onBindViewHolder:
#Override
public void onBindViewHolder(final RecyclerVH recyclerVH, final int position) {
currentNote = data.get(position);
final String currentTitle = currentNote.getTitle();
final String currentContent = currentNote.getContent();
final int currentPosition = currentNote.getPosition();
String currentAlarmDate = currentNote.getAlarm();
Log.d("RecyclerView", "onBindVH called: " + currentTitle);
Log.d("RecyclerView", "Position at: " + currentPosition + " and Adapter Position at: " + recyclerVH.getAdapterPosition());
// final Info currentObject = data.get(position);
// Current Info object retrieved for current RecyclerView item - USED FOR DELETE
recyclerVH.listTitle.setText(currentTitle);
recyclerVH.listContent.setText(currentContent);
Log.d("RecyclerAdapter", "currentAlarmDate is: '" + currentAlarmDate + "'");
if (currentAlarmDate != null && !currentAlarmDate.equals(" ")) {
Log.d("RecyclerAdapter", "Current Alarm set for: " + currentAlarmDate);
recyclerVH.alarm.setText(currentAlarmDate);
}
recyclerVH.pencil.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("User Interface", "updateNoteInfo called!");
// Opens Dialog to update Note and Alarm
// TODO Open Activity instead
//final View updateButton;
// NEEDS TO BE DECLARED AT TOP, SO IT IS SEEN EVERYWHERE
updateDialog = new MaterialDialog.Builder(context)
.title(R.string.rewrite_note)
.customView(R.layout.note_update_screen, false)
.positiveText(R.string.update)
.negativeText(R.string.nevermind)
.forceStacking(false)
.cancelable(false)
.canceledOnTouchOutside(false)
.onPositive(new MaterialDialog.SingleButtonCallback() {
#Override
public void onClick(MaterialDialog dialog, DialogAction which) {
updatedTitle = updateTitle.getText().toString();
updatedContent = updateContent.getText().toString();
updateNote(updatedTitle, updatedContent, recyclerVH.getAdapterPosition());
}
})
.build();
//noinspection ConstantConditions
updateTitle = (EditText) updateDialog.getCustomView().findViewById(R.id.updateNoteTitle);
updateContent = (EditText) updateDialog.getCustomView().findViewById(R.id.updateNoteContent);
// Set the text for the title using current info
updateTitle.setText(currentTitle);
updateTitle.setSingleLine(false);
updateTitle.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
updateContent.setText(currentContent);
updateContent.setSingleLine(false);
updateContent.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
updateButton = updateDialog.getActionButton(DialogAction.POSITIVE);
// TODO Use do-while loop for onTextChanged?
// TODO Use Thread?
updateDialog.show();
// updateButton.setEnabled(false);
}
});
runEnterAnimation(recyclerVH.itemView, position);
}
since RecyclerView reuses or recycles the views, you must always add an else condition to make sure that it works properly. So, add an else block along with your if block.
Remove the setOnClickListener() from onBindViewHolder and set the setOnClickListener() inside your ViewHolder RecyclerVH. To get the position of the clicked item or row call the method getAdapterPosition(). Example:
public class ReservationViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
// each data item is just a string in this case
CardView cardView;
public ReservationViewHolder(View v) {
super(v);
cardView = (CardView) v.findViewById(R.id.cv);
cardView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
int position = getAdapterPosition();
// do what you want...
}
}

Calling notifyDataSetChanged in my onFocusChangedListener causes focus to freak out in my ListView

I have a ListView which has multiple EditTexts per item. When I change an EditText on one item, I'd like it to affect the text on the next item. I'm using an onFocusChanged listener and I can successfully update the underlying data, but My actual focus is lost (and my cursor ends up in weird places). Please review my code and offer any insight. I've been banging my head about this for a while.
Note:
I am not recycling items using a holder, as this was giving me odd behavior and my performance is not suffering. Every time I've tried re-enabling the recycling, things get messier.
I have overriden hasStableIds to return true, but it doesn't seem to make any difference.
Assigning the Listener:
MyFocusChangeListener myFocusListener = new MyFocusChangeListener(myItem, position);
holder.et_min.setOnFocusChangeListener(myFocusListener);
Defining the Listener:
private class MyFocusChangeListener implements View.OnFocusChangeListener{
private EditText et;
private EditText curView;
private ScaleItem item;
private Integer pos;
public MyFocusChangeListener(ScaleItem item, Integer pos){
this.item = item;
this.pos = pos;
}
#Override
public void onFocusChange(View v, boolean hasFocus){
if(!hasFocus){
et = (EditText) v;
System.out.println("EditText lost focus on row: " + et.getText().toString() + " et id: " + et.getId());
if(pos < data.size()){
data.get(pos + 1).setMax(Double.valueOf(et.getText().toString()));
notifyDataSetChanged();
System.out.println("Updated dataset and called notifyDataSetChanged()");
}
} else {
et = (EditText) v;
if(et != null)
System.out.println("EditText just RECEIVED focus on row : " + et.getText().toString() + " et id: " + et.getId());
}
}
}
This is the console output I get, if I enter the activity, click field A, and then click field B.
Notice:
Each EditText (regardless of row) has the same ID (I think this is expected)
The only change I'm making is to the underlying data. In fact, I have the same issue if I change nothing but call notifyDataSetChanged.
The target field loses focus, I've no idea why.
TL;DR - Calling notifyDataSetChanged() in my onFocusChangedListener causes focus to freak out in my ListView.
See? The cursor is drunk.
If you focus a EditText in ListView get position value, after updating ListView redrawn and automatically it will select last position.
Step 1:
if (_Curserposition == position) {
holder.textViewStake.setFocusableInTouchMode(true);
//holder.textViewStake.clearFocus();
holder.textViewStake.requestFocus();
holder.textViewStake.setSelection(holder.textViewStake.getText().toString().length());
}
Step 2:
holder.textViewStake.setOnFocusChangeListener(new View.OnFocusChangeListener() {
#Override
public void onFocusChange(View v, boolean hasFocus) {
_Curserposition = position;
Log.d(">>>", "setOnFocusChangeListener" + _Curserposition);
/*
//showVirtualKeyboard(con_text, v);
// holder.textViewStake.requestFocus();
InputMethodManager imm = (InputMethodManager) activityContext.getSystemService(Context.INPUT_METHOD_SERVICE);
if (hasFocus) {
imm.showSoftInput(holder.textViewStake, InputMethodManager.SHOW_FORCED);
} else {
imm.hideSoftInputFromWindow(holder.textViewStake.getWindowToken(), 0);
}*/
}
});
Step 3:
holder.textViewStake.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
betlist_view.setFocusable(false);
if (s.length() > 0) {
try {
if (Integer.parseInt(holder.textViewStake.getText().toString()) > 0) {
int _Stackamt = Integer.parseInt(holder.textViewStake.getText().toString());
int _picknumber = arrayDailyGameDrawList.get(position).getID();
//Log.d(">>>", "_picknumber" + position + "-" + arrayDailyGameDrawList.get(position).getBetNumberID() + "-" + Common.DrawId + "-" + _Stackamt + "-" + arrayDailyGameDrawList.get(position).getBetNumberID());
AddUpdateDailyGameNumberIntoList(
position,
2,
arrayDailyGameDrawList.get(position).getBetNumberID(),
Common.DrawId,
_Stackamt,
arrayDailyGameDrawList.get(position).getBetNumberID()
);
/* new Handler().postDelayed(new Runnable() {
#Override
public void run() {
}
}, 3000);*/
}
} catch (Exception e) {
}
} else {
holder.textViewStake.setText("0");
}
}
#Override
public void afterTextChanged(Editable s) {
}
});

OnClickListener in a while loop on custom objects

I'm setting up a CardView layout (with the libary) but I've got a problem.
I can setup a onClickListener (which works) in this way:
mCardView = (CardUI) getView().findViewById(R.id.cardsview);
mCardView.setSwipeable(true);
MyCard b = new MyCard("Hi", "Hi", 15);
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
System.out.println(v.toString());
Toast.makeText(getActivity(),"werkt",Toast.LENGTH_LONG).show();
}
});
mCardView.addCard(b);
But when I try to do it in a loop I can't seem to get the ID of the cards.
My cards do have a unique ID (just a int as ID).
I'm adding them like this:
int id = 0;
while(!c.isAfterLast()){
String description = "";
System.out.println("Opmerking: " + c.getString(3));
if(!c.getString(3).equals("")){
description = "Opmerkingen: " + c.getString(3);
}
if(recreate){
MyCard a = new MyCard(c.getString(2)+" "+c.getString(1), description, id);
cards.add(a);
mCardView.addCard(a);
a.setOnClickListener(new OnClickListener());
}
c.moveToNext();
id++;
}
And the onClickListener is this:
private class OnClickListener implements View.OnClickListener {
#Override
public void onClick(View view) {
switch (view.getId()){
case 1:
Toast.makeText(getActivity(), "werkt", Toast.LENGTH_LONG).show();
break;
default: Toast.makeText(getActivity(), "werkt niet", Toast.LENGTH_LONG).show(); break;
}
}
}
But everytime when I click one which has a onClickListener of the while loop I get 'werkt niet' which is the default item of the switch.
The card ID is a int in the MyCard object.
If anyone could help me it would be greatly appreciated.
Edit: The MyCard object is a object which needs this libary: http://nadavfima.com/cardsui-view-library/
That is because your view.getId() is never equals 1. Try adding
System.out.println("view.getId() -->> "+view.getId());
inside the default case..
You will get your problem then and there...

Get values of multiple checkboxes on Android

I have one of these for each day of the week:
mondayRadioButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (mondayRadioButton.isChecked()){
deleteAppointmentsLayout.removeAllViews();
daySelected = 1;
for(Iterator<Appointment> i = appointments.iterator(); i.hasNext();){
Appointment item = i.next();
if(item.getDay() == 1){
checkBox = new CheckBox(DeleteAppointmentActivity.this);
System.out.println("fucken did work");
id = item.getId();
time = item.getTime();
duration = item.getDuration();
description = item.getDescription();
boxText = time + ", " + duration + ", " + description;
checkBox.setText(boxText);
checkBox.setTextSize(12);
checkBox.setId((int) id);
deleteAppointmentsLayout.addView(checkBox);
}
else {
System.out.println("fucken didnt work");
}
}
}
}
});
When an onclick for a button is activated I want to retrieve the information for each of the selected checkboxes for the currently selected day (checkboxes are generated programmatically). How can I check which ones are selected when the onclick for the Delete button is activated?
Create a member variable Array like
public class MyClass extends Activity
{
ArrayList<CheckBox> cbArray = new ArrayList<CheckBox>();
then when you create a checkbox add it to the ArrayList. Now when you click the delete Button use a for loop to iterate over the ArrayList and call isChecked() on each one.
Then delete or add that to a checked Array to do whatever you need with it
for (int i=0; i<cbArray.size(); i++)
{
if (cbArray.get(i).isChecked())
{
// do whatever here

DialogFragment OnClickListener strange Cursor behavior

I am using the code below in a class extending DialogFragment.
Before adding the buttons I move a cursor to a certain position (see setDataFromCursor()) The strange thing is, that the position has changed when trying to get the position again in the OnClickListener of the positive button.
I added some Log output which proves that. Does anybody know why that happens?
Thanks for your help!
Edit: In the debugger it is visible too. I step forward a few steps and the cursor position changes without calling moveToPosition.
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Log.v(TAG, "onCreateDialog");
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
LayoutInflater inflater = getActivity().getLayoutInflater();
view = inflater.inflate(R.layout.query_tab_dialog_add_operation,
null);
name = (TextView) view.findViewById(R.id.editTextOPName);
cimclass = (TextView) view.findViewById(R.id.editTextCIMclass);
setDataFromCursor();
builder.setView(view)
.setTitle(
R.string.querytabfragment_dialog_editOperation_title)
.setPositiveButton(R.string.apply,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
nameStr = name.getText().toString();
cimclassStr = cimclass.getText().toString();
Log.d(TAG,
"cursor position: "
+ cursor.getPosition());
int id = cursor.getInt(0);
Log.d(TAG, "cursor on item: " + id);
// update affected row
queryDBHelper.editCIMQuery(id, nameStr,
cimclassStr);
Log.d(TAG, "query edited. id: " + id
+ " name: " + nameStr
+ " cimclass: " + cimclassStr);
cursor.requery();
}
})
.setNegativeButton(R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,
int which) {
EditOperationDialogFragment.this
.getDialog().cancel();
}
});
return builder.create();
}
private void setDataFromCursor() {
cursor.moveToPosition(cursorPosition);
name.setText(cursor.getString(1));
cimclass.setText(cursor.getString(2));
}
The code that you posted doesn't change the Cursor's position anywhere else.
However, if cursor references the same Cursor used in a CursorAdapter bound to a ListView then when the Dialog is drawn it probably obscures part of a ListView forcing the ListView to redraw. This definitely changes the position.
Solution: Either use moveToPosition() again in the OnClickListener or fetch an independent Cursor.

Categories

Resources