Android: call a method after a textView is changed - java

a simple issue here, but one I haven't been able to find a simple solution for. My Android app has a button that calls a calculations-heavy method which may take a while to return results. I want the user to know that the app is working, not frozen, so upon hitting that button I want to display a textView with a loading message, then call the method and load its results to another textView (while also hiding the first one). How can I make sure the method is started only AFTER the loading message becomes visible, because the code below fires the method when it's still not visible?
buttonCalculate.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
loadingMessage.setVisibility(View.VISIBLE);
findSolution();
}
});

you are looking for a Progress Bar, it's a an android feature that android made for you.
Here is a link for the official google site: https://developer.android.com/reference/android/widget/ProgressBar

I usually would just throw a Toast message to let them know they should wait, without having to use progress bar, for example when button is clicked it will display a message saying"please wait,loading"
inside the button Toast.makeText(this, "Loading,Please Wait", Toast.LENGTH_SHORT).show();
and you then can change the lenght of how long it should appear, lenghtshort is just 2 seconds

Related

Confirm before dismissing DialogFragment in Android

I have defined a method for my DialogFragment which will pop another (alert) dialog, where I confirm that the user wants to dismiss the DialogFragment. If that is the case, then I call DialogFragment.dismiss(). If not, the dismissal of the DialogFragment should simply be ignored and the user should return to it as was before.
This method (say, confirmCancel()) is used for the 'Cancel' button at the bottom of the DialogFragment. Since I also want this to appear when the user presses the back button, or when they touch outside the DialogFragment, I have set confirmCancel as its onCancelListener (of course, I have also used getDialog().setCanceledOnTouchOutside(true) too).
This is the code for confirmCancel():
public void confirmCancel()
{
(new AlertDialog.Builder(getActivity())
.setIcon(R.drawable.ic_baseline_warning_24)
.setTitle("Discard changes")
.setMessage("Are you sure you want to discard changes and go back?")
.setPositiveButton("Yes", ( dialogInterface, i ) -> dismiss())
.setNegativeButton("No", ( dialogInterface, i ) -> {})
.show()).setCanceledOnTouchOutside(true);
}
This works almost perfectly, except for the fact that by the time the AlertDialog is shown on screen, the DialogFragment is already dismissed, and the actions taken in the AlertDialog are of no use at all.
So what I need now is a way to 'cancel' the dismissal of the DialogFragment, or a method that is called before the its dismissal. How do I solve this?
P.S.: getDialog().setCancelable(false) is not helpful to me since I do want the dialog to be cancelled; it's just that I want it cancelled conditionally.
Neither DialogFragment nor Dialog offer a condition that is checked before a cancel/dismiss event, that you can set.
They only offer listeners that are notified after said events have been fired, when the damage has already been done.
I have combed through the source code and have determined their is no way to force it into a state to ignore the first cancel/dismiss call but still allow the listeners to fire so you can catch the event, I have considered reflection to mess with fields, but it got to messy. I also tried forcing exceptions, to create invalid states, but there are no invalid states that would allow the functionality you want.
Here are the two sources.
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/Dialog.java
https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-activity-release/fragment/fragment/src/main/java/androidx/fragment/app/DialogFragment.java
You could play with the containing Activity's Window to handle touch events and send them back to the DialogFragment using a FragmentResultListener, ie the DialogFragment is set to non-cancelable and when the user touches the outside the
Activity picks it up and calls setFragmentResult to send it back to the DialogFragment. This may or may not work depending on how dialogs detect/receive outside touch events, does it consume them or let them fall through, when its non-cancalable.
The easiest solution by far is to copy the source code above, probably just the DialogFragment and make your own to solve this problem.
OR OR OR
I'm totally missing the most obvious solution.

Activity not paused quickly enough

In my AppCompatActivity, I am showing an AlertDialog at a specific event.
Once the AlertDialog is shown, the user should not be able to click on anything in my AppCompatActivity anymore.
I tried to disable the activity in onPause(): getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
And to check whether it is not paused: getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)
But it seems that onPause() is not called quickly enough for that.
I could set a static boolean to true whenever I pause the AppCompatActivity, set it on false in onResume() and check it in every single onClickListener/onTouchListener etc., but is there a better way to do it?
Every help is appreciated!
Edit:
Thanks for your comments! I found out, that when I am clicking on the screen while the UI thread is started (for opening the AlertDialog), the click is put in a queue. That's why the click event is executed while the AlertDialog is running. Do I need to save the AlertDialog and check if it is running or is there a better way?
I believe that you should let us know more about your code. However, I think that I can guess what you're saying. There is a setEnabled(false) method for every view component in android, and if you call it on a view component java object, it'll be disabled and no longer clickable. So you can simply disable your components whenever you want to show the AlertDialog and then enable them again by calling setEnabled(true) if you wish. I'm pretty sure pausing the activity is not what you should do. Because doing it manually, is not best practice anyway, at all.
I ended up saving an instance and writing a method to check if the Activity should not be active:
private void canRun() {
return (dialog == null || !dialog.isShowing()) && getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED);
}

RX java/Android how to i achieve This toast on every click using debounce operator

I have this ImageView which on clicked should Show toast and also making api on click of the image View, so I decided to use Debounce operator in Rx
but now thost is not visible on every click. below is the code
cartSubscriptionDecrement = RxView.clicks(holder.databinding
.cartQuantityLayout.ivDecreaseQuantity)
.debounce(1000, TimeUnit.MILLISECONDS)
.subscribe { next ->
cartQuantityEvent.onCartQuantityDecremented(cartSubscriptionDecrement!!)
}
I need to show toast on every single click of imageView.
I tried to have a separate onclick method for Image View but during debugging I found that the control is never coming to onclick method this is my another onclick method
How do I achieve this toast on every click while not making an api call in every click (make use of Debounce operator).
There are multiple ways to do what you're asking. I've included the simplest below, but will need to think more about potential side effects from using doOnNext.
The code for this example lives on Github here if you're interested in running the app. Just realized the package name is wrong, but the example will run just fine.
The most relevant code to the example is below. The key is that you'll need to debounce after you show the Toast rather than before.
RxView.clicks(image1)
.doOnNext(imageClickedEvent -> {
// Show toast every time onNext is called (this will also log to LogCat)
showToast();
})
.debounce(1000, TimeUnit.MILLISECONDS)
.subscribe(clickEvent -> {
makeApiCall();
});
I tried to have a separate onclick method for Image View but during debugging I found that the control is never coming to onclick method this is my another onclick method
I believe this is the case because RxClicks sets a listener on the ImageView, and that occurs after the framework sets the onClick listener and you can only have one OnClickListener on a View if I recall correctly. So what's happening is the RxView.clicks(imageView) is receiving the click event rather than the method you created separately.
You have to apply ".subscribeOn(AndroidSchedulers.mainThread())" to all RxBinding events, such as "RxView.clicks()"

Android onClick() tasks all happen at once

I'm trying to develop a feature for my app that pulls a string of text off of the internet (sort of like twitter, but a lot more basic) and displays it on the screen in a permeanent window. The user sees a large box with a refresh button next to it, and a small space below both where I would like to have a little progress monitor (just a TextView) which displays "Refreshing..." as soon as the refresh button is clicked, and then "Refresh successful!" once the string of text has been successfully pulled from the internet and displayed. This is just to reassure the user that something is actually happening when they press the button.
After a lot of research I've come to the conclusion that the way to update the TextView is to use a handler to execute a runnable which will update the text in the TextView. So my code looks like this:
refreshbutton.setOnClickListener(new View.OnClickListener()
{
public void onClick(View abc)
{
//display "Refreshing..."
refreshhandler.post(refreshingmsg);
/*Code to pull the string of text from the internet goes here (not shown)*/
//display "Refresh successul!"
successfulhandler.post(successfulmsg);
//clear the "Refresh successful" message after 2 seconds
clearhandler.postDelayed(clearmsg, 2000);
}
});
I hope that sort of makes sense. My issue is that these things all happen at once: I want the "Refreshing..." message to display, THEN for the phone to connect to the internet to find the string of text for the update, and THEN for the "Refresh Successful" message to display once the internet string has been successfully displayed. But what actually happens is that none of the commands in the onClick method actually happen until the phone has already pulled the message from the internet so the "Refreshing..." message isn't displayed at all. So what actually happens when the user clicks the button is that nothing happens for a second or two (presumably because the phone is busy pulling the string from the internet), then the string from the internet is suddenly displayed along with the message saying "Refresh Successful!".
So why is this happening? Is onClick supposed to work this way? If so, is there a workaround? I haven't posted my runnable and handler statements because I'm not sure it'll make any difference... but if it would help then I can post them!
Also, you can probably tell from this that I haven't been doing android (or indeed java) for very long, but I'm trying my best so please be gentle! Thanks :)
What is happening is that your code is locking on the network communication and doesn't let your app update itself with the handler value.
You should create an AsyncTask to that work for you.
On the OnPreExecute method, change your UI to show the user that you are refreshing your content. Reading your code it appears that you are updating an image, do that here.
On the doInBackground method do your actual network communication, an optional step is to use onProgressUpdate(Progress...) to update your UI to notify the user that the operation is progressing.
On the onPostExecute method you them update your UI to reflect the new content.
For more info check the documentation in AsyncTask, you can also search StackOverflow, there's a lot of good questions about it here.
As a side note, I don't recommend that you use handlers at all, AsyncTasks are easier to use and the code looks better.

android locking eventListener and even handling

I have a simple button onClickListener in my android application, and all it does is write some stuff to the database. It looks something like this
private void setEventListeners(){
mSpecialViewClass.getSubmitButton().setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
handleSubmitClick();
}
});
}
private void handleSubmitClicks(){
if (counter<0){
writeCounterToDb();
} else {
//do some stuff
closeDatabase();
}
}
now this works nicely, but if I tap the button fast enough, I get a closed DB error
java.lang.IllegalStateException: database not open
How can I prevent the key listener from doing anything, before the previous key event has been handeled?
Edit: some user suggested closing my database on Activity.onDestroy() which is quite nice, and he deleted the answer. That is a nice workaround for my problem, but still not the solution I am looking for.
I also tried disabling the button and enabling the button on various positions, and the problem remains. It seems I can always achieve that the function gets called one too many times, if I tap the button too fast.
A good UI trick, that you could possibly use here, is to disable the button once the user clicks. Just do something like this:
#Override
public void onClick(View arg0) {
arg0.setEnabled(false);
handleSubmitClick();
}
You can of course enable the button at the end of your onClick function if you need to.
While the button is disabled the user won't be able to click on it, so you will never get two onClick events. What is more, the style of the button changes, so the user will know that clicking won't do anything.
This technique is used all over the place (Gmail's send button for instance) and I consider it good UI design.
Now if you want to permit your user to press a button multiple times, really really fast and never loose or skip a single press, you'll need to implement some sort of a queuing mechanism. But I can only imagine this being necessary in games where there is a matter of life and death :)

Categories