Transformations.distinctUntilChanged() not working with equals() override - android

My Aim: I would like to use the Transformations.distinctUntilChanged() method to create an application which shows a toast message every time a LiveData object is updated. The LiveData object is a simple custom Integer object (MyInteger) that increments by one every time a button is clicked. The application should stop showing the toast message when myInteger exceeds 5. To implement this >5 condition, the application must override the equals() method of MyInteger class (the equals() method is called in the distinctUntilChanged() class).
The Problem: In the below code, the currentValue and previousValue fields are always the same (except for first time button is clicked). Hence onChanged is not called in MainActivity and the Toast message does not show from the second click onwards. See below for current result vs. what i expect should happen.
Please help. Again the application must use distinctUntilChanged() and overridden equals() methods together.
Current result:
First time button clicked: currentValue=1 and previousValue=null, Toast Message shows.
Second time button clicked: currentValue=2 and previousValue=2, Toast Message does not show.
Third time button clicked: currentValue=3 and previousValue=3, Toast Message does not show.
Fourth time button clicked: currentValue=4 and previousValue=4, Toast Message does not show.
and so on...
Desired result:
First time button clicked: currentValue=1 and previousValue=null, Toast Message shows.
Second time button clicked: currentValue=2 and previousValue=1, Toast Message shows.
Third time button clicked: currentValue=3 and previousValue=2, Toast Message shows.
Fourth time button clicked: currentValue=4 and previousValue=3, Toast Message shows.
and so on...
Blockquote
public class MainActivity extends AppCompatActivity {
private MainActivityViewModel mMainActivityViewModel;
Button button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = findViewById(R.id.my_button);
MyInteger myInteger = new MyInteger(0);
mMainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myInteger.incrementByOne();
mMainActivityViewModel.getLiveData().setValue(myInteger);
}
});
Transformations.distinctUntilChanged(mMainActivityViewModel.getLiveData()).observe(this, new Observer<MyInteger>() {
#Override
public void onChanged(MyInteger myInteger) {
Log.wtf("Transformations onChanged:", String.valueOf(myInteger.integer));
Toast.makeText(MainActivity.this, "Transformations onChanged:"+String.valueOf(myInteger.integer), Toast.LENGTH_SHORT).show();
}
});
}
}
Blockquote
public class MainActivityViewModel extends AndroidViewModel {
public MutableLiveData<MyInteger> myIntegerMutableLiveData;
public MainActivityViewModel(#NonNull Application application) {
super(application);
}
public MutableLiveData<MyInteger> getLiveData() {
if (myIntegerMutableLiveData == null) {
myIntegerMutableLiveData = new MutableLiveData<>();
}
// MediatorLiveData transformedLiveData = (MediatorLiveData) Transformations.distinctUntilChanged(myIntegerMutableLiveData);
return myIntegerMutableLiveData;
}
}
Blockquote
public class MyInteger {
public int integer;
public MyInteger(Integer integer) {
this.integer = integer;
}
public void incrementByOne() {
integer++;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyInteger myInteger = (MyInteger) o;
if ((myInteger.integer <= 5) && (integer == myInteger.integer)) {return true;}
if ((myInteger.integer <= 5) && (integer != myInteger.integer)) {return false;}
return (myInteger.integer > 5);
}
#Override
public int hashCode() {
return Objects.hash(integer);
}
}

Related

Showing results for a quiz app (Android Studio)

I have a quiz app that is working properly, but the thing is the user must answer all questions correctly in order to win the game(if the player gets it wrong the game will be over) .
What I wanted to do is have the questions answered and then at the end there will be an activity that will show how many the player has answered then there will be the options to retry and go back to menu
This is the code for the maingameactivity
public class MainGameActivity extends AppCompatActivity {
FButton buttonA, buttonB, buttonC, buttonD;
TextView questionText, triviaQuizText, timeText, resultText, coinText;
TriviaQuizHelper triviaQuizHelper;
TriviaQuestion currentQuestion;
List<TriviaQuestion> list;
int qid = 0;
int timeValue = 20;
int coinValue = 0;
CountDownTimer countDownTimer;
Typeface tb, sb;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game_main);
//Initializing variables
questionText = (TextView) findViewById(R.id.triviaQuestion);
buttonA = (FButton) findViewById(R.id.buttonA);
buttonB = (FButton) findViewById(R.id.buttonB);
buttonC = (FButton) findViewById(R.id.buttonC);
buttonD = (FButton) findViewById(R.id.buttonD);
triviaQuizText = (TextView) findViewById(R.id.triviaQuizText);
timeText = (TextView) findViewById(R.id.timeText);
resultText = (TextView) findViewById(R.id.resultText);
coinText = (TextView) findViewById(R.id.coinText);
//Setting typefaces for textview and buttons - this will give stylish fonts on textview and button etc
tb = Typeface.createFromAsset(getAssets(), "fonts/TitilliumWeb-Bold.ttf");
sb = Typeface.createFromAsset(getAssets(), "fonts/shablagooital.ttf");
triviaQuizText.setTypeface(sb);
questionText.setTypeface(tb);
buttonA.setTypeface(tb);
buttonB.setTypeface(tb);
buttonC.setTypeface(tb);
buttonD.setTypeface(tb);
timeText.setTypeface(tb);
resultText.setTypeface(sb);
coinText.setTypeface(tb);
//Our database helper class
triviaQuizHelper = new TriviaQuizHelper(this);
//Make db writable
triviaQuizHelper.getWritableDatabase();
//It will check if the ques,options are already added in table or not
//If they are not added then the getAllOfTheQuestions() will return a list of size zero
if (triviaQuizHelper.getAllOfTheQuestions().size() == 0) {
//If not added then add the ques,options in table
triviaQuizHelper.allQuestion();
}
//This will return us a list of data type TriviaQuestion
list = triviaQuizHelper.getAllOfTheQuestions();
//Now we gonna shuffle the elements of the list so that we will get questions randomly
Collections.shuffle(list);
//currentQuestion will hold the que, 4 option and ans for particular id
currentQuestion = list.get(qid);
//countDownTimer
countDownTimer = new CountDownTimer(22000, 1000) {
public void onTick(long millisUntilFinished) {
//here you can have your logic to set text to timeText
timeText.setText(String.valueOf(timeValue) + "\"");
//With each iteration decrement the time by 1 sec
timeValue -= 1;
//This means the user is out of time so onFinished will called after this iteration
if (timeValue == -1) {
//Since user is out of time setText as time up
resultText.setText(getString(R.string.timeup));
//Since user is out of time he won't be able to click any buttons
//therefore we will disable all four options buttons using this method
disableButton();
}
}
//Now user is out of time
public void onFinish() {
//We will navigate him to the time up activity using below method
timeUp();
}
}.start();
//This method will set the que and four options
updateQueAndOptions();
}
public void updateQueAndOptions() {
//This method will setText for que and options
questionText.setText(currentQuestion.getQuestion());
buttonA.setText(currentQuestion.getOptA());
buttonB.setText(currentQuestion.getOptB());
buttonC.setText(currentQuestion.getOptC());
buttonD.setText(currentQuestion.getOptD());
timeValue = 20;
//Now since the user has ans correct just reset timer back for another que- by cancel and start
countDownTimer.cancel();
countDownTimer.start();
//set the value of coin text
coinText.setText(String.valueOf(coinValue));
//Now since user has ans correct increment the coinvalue
coinValue++;
}
//Onclick listener for first button
public void buttonA(View view) {
//compare the option with the ans if yes then make button color green
if (currentQuestion.getOptA().equals(currentQuestion.getAnswer())) {
buttonA.setButtonColor(ContextCompat.getColor(getApplicationContext(),R.color.lightGreen));
//Check if user has not exceeds the que limit
if (qid < list.size() - 1) {
//Now disable all the option button since user ans is correct so
//user won't be able to press another option button after pressing one button
disableButton();
//Show the dialog that ans is correct
correctDialog();
}
//If user has exceeds the que limit just navigate him to GameWon activity
else {
gameWon();
}
}
//User ans is wrong then just navigate him to the PlayAgain activity
else {
gameLostPlayAgain();
}
}
//Onclick listener for sec button
public void buttonB(View view) {
if (currentQuestion.getOptB().equals(currentQuestion.getAnswer())) {
buttonB.setButtonColor(ContextCompat.getColor(getApplicationContext(),R.color.lightGreen));
if (qid < list.size() - 1) {
disableButton();
correctDialog();
} else {
gameWon();
}
} else {
gameLostPlayAgain();
}
}
//Onclick listener for third button
public void buttonC(View view) {
if (currentQuestion.getOptC().equals(currentQuestion.getAnswer())) {
buttonC.setButtonColor(ContextCompat.getColor(getApplicationContext(),R.color.lightGreen));
if (qid < list.size() - 1) {
disableButton();
correctDialog();
} else {
gameWon();
}
} else {
gameLostPlayAgain();
}
}
//Onclick listener for fourth button
public void buttonD(View view) {
if (currentQuestion.getOptD().equals(currentQuestion.getAnswer())) {
buttonD.setButtonColor(ContextCompat.getColor(getApplicationContext(),R.color.lightGreen));
if (qid < list.size() - 1) {
disableButton();
correctDialog();
} else {
gameWon();
}
} else {
gameLostPlayAgain();
}
}
//This method will navigate from current activity to GameWon
public void gameWon() {
Intent intent = new Intent(this, GameWon.class);
startActivity(intent);
finish();
}
//This method is called when user ans is wrong
//this method will navigate user to the activity PlayAgain
public void gameLostPlayAgain() {
Intent intent = new Intent(this, PlayAgain.class);
startActivity(intent);
finish();
}
//This method is called when time is up
//this method will navigate user to the activity Time_Up
public void timeUp() {
Intent intent = new Intent(this, Time_Up.class);
startActivity(intent);
finish();
}
//If user press home button and come in the game from memory then this
//method will continue the timer from the previous time it left
#Override
protected void onRestart() {
super.onRestart();
countDownTimer.start();
}
//When activity is destroyed then this will cancel the timer
#Override
protected void onStop() {
super.onStop();
countDownTimer.cancel();
}
//This will pause the time
#Override
protected void onPause() {
super.onPause();
countDownTimer.cancel();
}
//On BackPressed
#Override
public void onBackPressed() {
Intent intent = new Intent(this, HomeScreen.class);
startActivity(intent);
finish();
}
//This dialog is show to the user after he ans correct
public void correctDialog() {
final Dialog dialogCorrect = new Dialog(MainGameActivity.this);
dialogCorrect.requestWindowFeature(Window.FEATURE_NO_TITLE);
if (dialogCorrect.getWindow() != null) {
ColorDrawable colorDrawable = new ColorDrawable(Color.TRANSPARENT);
dialogCorrect.getWindow().setBackgroundDrawable(colorDrawable);
}
dialogCorrect.setContentView(R.layout.dialog_correct);
dialogCorrect.setCancelable(false);
dialogCorrect.show();
//Since the dialog is show to user just pause the timer in background
onPause();
TextView correctText = (TextView) dialogCorrect.findViewById(R.id.correctText);
FButton buttonNext = (FButton) dialogCorrect.findViewById(R.id.dialogNext);
//Setting type faces
correctText.setTypeface(sb);
buttonNext.setTypeface(sb);
//OnCLick listener to go next que
buttonNext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//This will dismiss the dialog
dialogCorrect.dismiss();
//it will increment the question number
qid++;
//get the que and 4 option and store in the currentQuestion
currentQuestion = list.get(qid);
//Now this method will set the new que and 4 options
updateQueAndOptions();
//reset the color of buttons back to white
resetColor();
//Enable button - remember we had disable them when user ans was correct in there particular button methods
enableButton();
}
});
}
//This method will make button color white again since our one button color was turned green
public void resetColor() {
buttonA.setButtonColor(ContextCompat.getColor(getApplicationContext(),R.color.white));
buttonB.setButtonColor(ContextCompat.getColor(getApplicationContext(),R.color.white));
buttonC.setButtonColor(ContextCompat.getColor(getApplicationContext(),R.color.white));
buttonD.setButtonColor(ContextCompat.getColor(getApplicationContext(),R.color.white));
}
//This method will disable all the option button
public void disableButton() {
buttonA.setEnabled(false);
buttonB.setEnabled(false);
buttonC.setEnabled(false);
buttonD.setEnabled(false);
}
//This method will all enable the option buttons
public void enableButton() {
buttonA.setEnabled(true);
buttonB.setEnabled(true);
buttonC.setEnabled(true);
buttonD.setEnabled(true);
}
}
Edited
Just remove the wrapper if else inside all the buttons better to keep it as, don't repeat the code. I am assuming the screen that shows result is handled inside gameWon and you have implemented functionality for inCorrectDialog
public void buttonA(View view) {
Button button = (Button) view;
buttonPressed(button);
}
public void buttonB(View view) {
Button button = (Button) view;
buttonPressed(button);
}
public void buttonC(View view) {
Button button = (Button) view;
buttonPressed(button);
}
public void buttonD(View view) {
Button button = (Button) view;
buttonPressed(button);
}
public void buttonPressed(Button button) {
button.setButtonColor(ContextCompat.getColor(getApplicationContext(), R.color.lightGreen));
if (qid < list.size() - 1) {
disableButton();
if (currentQuestion.getOptA().equals(currentQuestion.getAnswer())) {
correctDialog();
} else {
inCorrectDialog();
}
} else {
gameWon();
}
}

How to update Activity's textview when returning from another Activity's RecyclerView?

Hello (First of all excuse my English if something is wrong, it's not my first language), I'm developing an app with the IMDB API to keep up to date with your favorite series (no links or anything illegal).
I'm gonna focus on the two activities in which the problem is: The first Activity, ActivitySerieJson contains a recycled view filled with all the seasons in card view. Each card view contains season thumbnail, season number and the users completed view percentage:
ActivitySerieJson.
The second activity, ActivityTemporadaJSON contains another recyclerview, this one is filled with chapters name, thumbnail and an eye-shaped button that, when pressed, marks the chapter as seen on DB. The problem is that when I go back to previous activity the completed view percentage TextView is not being refreshed.
ActivityTemporadaJSon
This is my code:
RecyclerAdapterTemporada
public void bindPhoto(Temporada mtemporada, String idSerie, String tipo) {
temporada = mtemporada;
String Nombre = temporada.getNombreTemporada();
if(Nombre.length() >= 25)
{
Nombre = Nombre.substring(0,22);
Nombre = Nombre + "...";
}
AQuery androidAQuery=new AQuery(mItemImage.getContext());
androidAQuery.id(mItemImage).image(temporada.getPoster(), true, true, 150,0);
//Picasso.with(mItemImage.getContext()).load(mserie.getPoster()).into(mItemImage);
mItemDate.setText(Nombre);
mItemidTMDB.setText(idSerie);
mItemNumTemp.setText(Integer.toString(temporada.getNumeroTemporada()));
mItemNumEps.setText(Integer.toString(temporada.getNumeroEpisodios()));
//THIS CODE SECTION CALCULATES PERCENTAGE
if(tipo.equalsIgnoreCase("SQL"))
{
int porcen=1;
int numEps = temporada.getNumeroEpisodios();
if(numEps == 0){
numEps = 1;
}
porcen = (temporada.getEpisodiosVsitos() * 100) / numEps;
mNumEpsVistoVal.setText(Integer.toString(porcen) + "%");
}
else
{
mNumEpsVisto.setVisibility(View.INVISIBLE);
mNumEpsVistoVal.setVisibility(View.INVISIBLE);
}
}
}
}
RecyclerAdapterEpisodio
public class RecyclerAdapterEpisodio extends
RecyclerView.Adapter<RecyclerAdapterEpisodio.EpisodioHolder> {
private ArrayList<Episodio> mEpisodio;
private int IdSerie;
private RecyclerAdapterEpisodio miAdaptador;
private String Tipo;
private View v;
//5
#Override
public void onClick(View v) {
/*Context context = itemView.getContext();
Intent showPhotoIntent = new Intent(context, Pelicula.class);
showPhotoIntent.putExtra(PHOTO_KEY, peli);
context.startActivity(showPhotoIntent);*/
}
public void bindPhoto(final Episodio mEpisodio, final int mIdSerie, String tipo) {
episodio = mEpisodio;
if (tipo.equalsIgnoreCase("SQL")) {
if(episodio.isVisto()){
mBoton.setBackgroundResource(R.drawable.ojoabierto);
}else{
mBoton.setBackgroundResource(R.drawable.ojocerrado);
}
mBoton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (episodio.isVisto()) {
//mBoton.setBackgroundResource(R.drawable.ojoabierto);
DBHelper mydb = new DBHelper(v.getContext());
mydb.CancelVerEpisodio(episodio.getIdEpisodio());
v.setBackgroundResource(R.drawable.ojocerrado);
episodio.setVisto(false);
} else//else
{
//mBoton.setBackgroundResource(R.drawable.ojocerrado);
DBHelper mydb = new DBHelper(v.getContext());
mydb.VerEpisodio(episodio.getIdEpisodio());
mBoton.setBackgroundResource(R.drawable.ojoabierto);
episodio.setVisto(true);
}
}
});
}
else
{
mBoton.setVisibility(View.INVISIBLE);
}
in your fist activity do the loading inside OnResume(). so that when you comeback to the activity . onResume() method will be first called and you will get the updated data. This is when you have all your other block codes functioning well but you have problem with refreshing your page.
move your loading method from onCreate() to onResume() in the first activity

How to refresh DialogFragment after dismiss of another DialogFragment

I have an AppCompatActivity that, at some point, display a DialogFragment. In this dialog, there are items for which I ask confirmation before deleting them. That confirmation is asked through another Yes/No DialogFragment. When the user clicks Yes in that second dialog, I want the first dialog to refresh its ListView (just need to update the adapter and call its notifyDataSetChanged method). The problem is that I don't know when to update the listview.
Because that delete functionality is called from various sources, I implement a listener Interface at the activity level and call an "onDeleteRequest" event from that interface whenever I need an item to be deleted, and that's the activity who opens up the confirmation dialog and perform the actual delete.
Since I don't care much about refreshing the ListView in unnecessary situations, I tried to update the list in the onResume event, but the event is not called when I come back to the first dialog after the confirmation one is dismissed.
So my question is: how can I know when a dialog B displayed on top of a dialog A has been dismissed so I can refresh dialog A accordingly?
EDIT : A bit of code to support my question:
My activity class:
public class MonthActivity
extends AppCompatActivity
implements OnEditCalendarsDialogListener
{
...
//That's where dialog A is shown
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
...
if (id == R.id.action_select_calendar) {
final CalendarSelection currentSelection = mCalendarSelectionAdapter.getCurrentCalendarSelection();
if (currentSelection != null) {
EditCalendarsDialogFragment dialogFragment = EditCalendarsDialogFragment.newInstance(currentSelection);
dialogFragment.show(getSupportFragmentManager());
}
return true;
}
return super.onOptionsItemSelected(item);
}
...
//OnEditCalendarsDialogListener interface implementation
//That's where Dialog B is shown over Dialog A
#Override
public void onEditCalendarsDialogDelete(long calendarID) {
final Repository repository = Repository.getInstance(this);
final Calendar calendar = repository.fetchOneByID(Calendar.class, calendarID);
if (calendar != null) {
YesNoDialog yesNoDialog = YesNoDialog.newInstance(this, R.string.yes_no_dialog_confirmation, R.string.yes_no_dialog_calendar_delete);
setCurrentOnDecisionClickListener(new OnPositiveClickListener() {
#Override
public boolean onPositiveClick(DialogInterface dialog) {
//Delete calendar
repository.delete(calendar);
//That's where I'd like to notify Dialog A that it needs to be refreshed
return true;
}
});
yesNoDialog.show(getSupportFragmentManager());
}
}
}
My dialog class
public class EditCalendarsDialogFragment
extends DialogFragment
{
private OnEditCalendarsDialogListener mDialogListener;
public static EditCalendarsDialogFragment newInstance(CalendarSelection calendarSelection) {
EditCalendarsDialogFragment dialog = new EditCalendarsDialogFragment();
Bundle arguments = new Bundle();
if (calendarSelection != null) {
arguments.putLong(KEY_ID, calendarSelection.getID());
}
else {
arguments.putLong(KEY_ID, 0L);
}
dialog.setArguments(arguments);
return dialog;
}
...
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mDialogListener = (OnEditCalendarsDialogListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnCalendarSelectionDialogListener");
}
}
...
private View getLayoutView() {
View rootView = getActivity().getLayoutInflater().inflate(R.layout.calendar_list, null, false);
if (rootView != null) {
mCalendars = (ListView) rootView.findViewById(R.id.calendars);
if (mCalendars != null) {
//Create adaptor
mCalendarAdapter = new ArrayAdapter<Calendar>(
getContext(),
android.R.layout.simple_list_item_2,
android.R.id.text1,
new ArrayList<Calendar>()
) {
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View view = super.getView(position, convertView, parent);
final Calendar calendar = getItem(position);
if (calendar != null && calendar.hasID()) {
...
view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mDialogListener != null) {
//That's where I request delete from calling activity
mDialogListener.onEditCalendarsDialogDelete(calendar.getID());
}
return true;
}
});
}
return view;
}
};
mCalendars.setAdapter(mCalendarAdapter);
refreshCalendarList();
}
}
return rootView;
}
}
Use EventBus.
Register your dialog A to listen to events. When you dismiss dialog B post an event and pass the listitem's adapter position or whatever data you want to use to identify which item is to be deleted. Inside your dialog A write a function to receive this event inside which you delete the item.
OK, so I finally used the "over-abusive-callback" method.
I created the following interface:
public interface OnDeletedListener {
void onDeleted();
}
Updated the OnEditCalendarsDialogListener interface so that the callback has a callback to this interface too:
public interface OnEditCalendarsDialogListener {
void onEditCalendarsDialogDelete(long calendarID, OnDeletedListener onDeletedListener);
}
Implemented the OnDeletedListener interface in "Dialog A" class:
public class EditCalendarsDialogFragment
extends DialogFragment
implements OnDeletedListener
{
...
//OnDeletedListener interface implementation
#Override
public void onDeleted() {
//That's where I'm called back after item is deleted
refreshCalendarList();
}
...
private View getLayoutView() {
...
view.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mDialogListener != null) {
//That's where I request delete from calling activity, asking to call me back once deleted
mDialogListener.onEditCalendarsDialogDelete(calendar.getID(), EditCalendarsDialogFragment.this);
}
return true;
}
});
...
}
}
And finally, call the callback when delete is accepted and performed:
public class MonthActivity
extends AppCompatActivity
implements OnEditCalendarsDialogListener
{
//OnEditCalendarsDialogListener interface implementation
//That's where Dialog B is shown over Dialog A
#Override
public void onEditCalendarsDialogDelete(long calendarID, final OnDeletedListener onDeletedListener) {
final Repository repository = Repository.getInstance(this);
final Calendar calendar = repository.fetchOneByID(Calendar.class, calendarID);
if (calendar != null) {
YesNoDialog yesNoDialog = YesNoDialog.newInstance(this, R.string.yes_no_dialog_confirmation, R.string.yes_no_dialog_calendar_delete);
setCurrentOnDecisionClickListener(new OnPositiveClickListener() {
#Override
public boolean onPositiveClick(DialogInterface dialog) {
//Delete calendar
repository.delete(calendar);
//That's where I notify Dialog A that it needs to be refreshed
if (onDeletedListener != null) {
onDeletedListener.onDeleted();
}
return true;
}
});
yesNoDialog.show(getSupportFragmentManager());
}
}
}
Works smoothly!

Android: Update ListView from EditText

friends.
I have an app module that implements State pattern. Idea is:
1. User enter the Date -->
2. Screen changes to a ne state: dynamically inflates ListView and asks user to fill the list with some data
Problem is that when I call notifyDataSetChange() from update method 2nd time, EditText view doens't want to do its functions anymore.
This is a string from a logcat, that I think contains key of my problem.
09-10 10:33:38.937 26954-26954/com.example.android.turtleinfo D/ListView: change accessibility focus position = 0
Here are codes for everything.
1. My State Pattern Super Class
public abstract class ScreenState
{
public BuilderActivity activity;
public ScreenState(BuilderActivity activity) {
this.activity = activity;
//initializeScreen(activity);
}
public abstract void initializeScreen(Activity activity);
public abstract void switchState();
public abstract void updateText(View view);
public void addTextWatcher(EditText text) {
text.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
activity.state.updateText(v);
return true;
}
return false;
}
});
}
}
2. Implementation of initialize screen and updateData methods
#Override
public void initializeScreen(Activity activity) {
((BuilderActivity) activity).editText.setHint("Name");
addTextWatcher(((BuilderActivity) activity).editText);
textView = (TextView)activity.getLayoutInflater().inflate(R.layout.schedule_text_style, null);
textView.setHeight(100);
screenText = "End Date: " + new SimpleDateFormat("MMMM dd, yyyy", Locale.ENGLISH).format(((BuilderActivity) activity).data.getEndDate())+"\n\n";
textView.setText(screenText+"\n");
((BuilderActivity) activity).scheduleLayout.addView(textView);
((BuilderActivity) activity).data.setNames(new ArrayList<String>());
lv = (ListView)activity.getLayoutInflater().inflate(R.layout.listview_text_style, null);
listItems = new ArrayList<>();
adapt = new ArrayAdapter<>(super.activity, R.layout.schedule_text_style, listItems);
lv.setAdapter(adapt);
((BuilderActivity) activity).scheduleLayout.addView(lv);
}
#Override
public void updateText(View view) {
String text = activity.editText.getText().toString();
if (text.length() >= 2) {
if (!activity.data.names.contains(text)) {
activity.data.addToList(text);
listItems.add(text);
adapt.notifyDataSetChanged();
activity.editText.setText("");
counter++;
activity.editText.setText("");
} else {
Toast.makeText(activity, "same names are not allowed",
Toast.LENGTH_LONG).show();
((BuilderActivity) activity).editText.setText("");
}
}
else
{
Toast.makeText(activity, "name should contain 2 or more symbols",
Toast.LENGTH_LONG).show();
((BuilderActivity) activity).editText.setText("");
}
}
This is how it looks on device.
1. First insertion is ok
2. And second and further insertionas are impossible. OK softkeyboard button switches first to NEXT button
3. If I click next, EditText looses focus, nothing happens, but NEXT button Switches to '/n' button.
So, please, if anyone know, what am I doing worng, help!
Thanks in advance!
Your problem is in
public void addTextWatcher(EditText text)
function.
Look at the android:imeActionId and android:imeOptions attributes, plus the setOnEditorActionListener() method, all on TextView/Edittext.
You can also change the text of the keyboard button by using this.
mEditText.setImeActionLabel("Your text", KeyEvent.KEYCODE_ENTER);

Custom Listener on Button click in ListView Item

I have created a Custom Listener interface for Button click in Adapter class, i followed this tutorial: http://www.c-sharpcorner.com/UploadFile/9e8439/create-custom-listener-on-button-in-listitem-listview-in-a/
Adapter:
holder.btnQtyIncrease.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (customListner != null) {
customListner.onButtonClickListner(position);
}
cart = cartArrayList.get(position);
holder.textViewQuantity.setTag(cart);
if(cart.getQuantity() == 9) {
Toast.makeText(context, "Already reached", Toast.LENGTH_LONG).show();
return ;
}
else
{
cart.setQuantity(cart.getQuantity() + 1);
holder.textViewQuantity.setText(String.valueOf(cart.getQuantity()));
totalPrice = cart.getQuantity() * cart.getPrice();
CartArrayList.cartArraylist.get(position).setTotal(totalPrice);
holder.textViewTotal.setText(cart.getTotal());
}
}
});
.....
return convertView;
}
And I have implemented Listener in Activity like this:
public class CartActivity extends Activity implements customButtonListener {
......
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("CartActivity-onCreate", "onCreate");
setContentView(R.layout.activity_cart);
......
}
#Override
public void onResume()
{
super.onResume();
Log.d("CartActivity-onResume", "onResume");
}
#Override
public void onButtonClickListner(int position) {
totalPrice = CartArrayList.cartArraylist.get(position).getQuantity() * CartArrayList.cartArraylist.get(position).getPrice();
CartArrayList.cartArraylist.get(position).setTotal(totalPrice);
subTotal = subTotal + totalPrice;
}
}
As you can see inside for loop i am setting and getting total of each and every list item, and then calculating subTotal of ArrayList items...
But whenever i do tap on btnQtyIncrease it makes change in total of list item price, but it would not effect on subTotal amount
You should change you logic in some way that it calculates the subTotal in adapter only and then just pass the final value to interface which will simply set it in then textview
So your code should look like:
holder.btnQtyIncrease.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
cart = cartArrayList.get(position);
holder.textViewQuantity.setTag(cart);
if(cart.getQuantity() == 9) {
Toast.makeText(context, "Already reached", Toast.LENGTH_LONG).show();
return ;
}
else
{
cart.setQuantity(cart.getQuantity() + 1);
holder.textViewQuantity.setText(String.valueOf(cart.getQuantity()));
totalPrice = cart.getQuantity() * cart.getPrice();
CartArrayList.cartArraylist.get(position).setTotal(totalPrice);
holder.textViewTotal.setText(cart.getTotal());
}
}
// calculate total here
if (customListner != null) {
customListner.onButtonClickListner(getTotalValue());
}
});
Define a method getTotalValue in adapter which will iterate through the array and find the subTotal value.
And then simply set it in the textView
#Override
public void onButtonClickListner(float subTotal ) {
txtView.setText(String.valueOf(subTotal));
}
Accordingly, change the interface signature as :
public void onButtonClickListner(float total);
How to update value in Activity when do change in Adapter class
To update data in Activity on btnQtyIncrease Button click. create custom event listener using interface which will trigger in Activity when any change made in Quantity.
See following example for creating custom Listener :
How to create our own Listener interface in android?

Categories

Resources