I'm writing an Android application which requires the user to login. I have a "username" and "password" EditText fields and also a "Submit" button.
When testing in the emulator (and on a phone), the app appears to 'lock up' when the user hits "Submit". It hasn't actually crashed or anything like that, it's just locked whilst the connection to the server is made (and then it advances the user to the next view if their login is correct).
This isn't very cosmetically pleasing as some users may think the app has locked up if their connection is slow and the login doesn't process for a few seconds..
To avoid this I want to have a ProgressBar which will appear just to let the user know something is happening and the app hasn't locked up!
Here's my code:
private OnClickListener listenerOne = new OnClickListener() {
public void onClick(View v) {
Button submitButton = (Button)findViewById(R.id.submit);
submitButton.setVisibility(8); //Make submit button invisible
ProgressBar progressBar = (ProgressBar)findViewById(R.id.progressbar);
progressBar.setVisibility(0); //Make progress bar visible. It's in the same position as the submit button
login(); // do the login server stuff
// the problem is that thenew visibility doesn't happen until the login() is called...
}
};
I've ordered the code so that it makes the submit invisible, then makes the progress bar visible, then does the login (so the progress bar will be there twirling around whilst the app connects to the login server). However, it's not working out how I intended - it's seemingly skipping over the setVisibility code and just calling the login method. It must be setting the visibility of the submit and progress bar items but it doesn't happen before the login method does its stuff as it just locks up like usual and the items never actually get hidden/shown until the login method has completed!!
Any help would be much appreciated. Sorry for the essay!
You need to hand control back to the UI thread after changing the ProgressBar visibility and do your login work on another thread. The best way to do this is via AsyncTask.
This answer has a code sample for showing a ProgressDialog while doing a task in the background. You can modify it to call setVisibility on your ProgressBar instead.
The login part is still taking over the UI thread despite being "after" your UI elements.
You should try running it in a separate thread or AsyncTask. Try this for starters (replace your login() call with it), then make it prettier if it works:
new Thread(new Runnable() {
public void run() {
login();
}
}).start();
Any particular reason you are using the actual ints as opposed to the flags available for setting visibility? Seems like it would be easier to read like this:
progressBar.setVisibility(ProgressBar.VISIBLE);
Related
I have an activity in an Android application that includes both native UI elements and a WebView. The WebView is normally hidden (Visibility.GONE), and it performs occasional work "in the background" on its JavaScript loop. On a particular button click, the WebView is made visible and the user can see the web page. On a subsequent button click, the WebView is hidden again. The user can repeat this process.
I added a call to WebView.postVisualStateCallback when the user presses the button to make the WebView visible. I only make the WebView visible during the VisualStateCallback.onComplete. This works great the first time the user clicks the button and I make the WebView visible. However, after the user dismisses the WebView and I make it hidden again, I cannot repeat this process. Any subsequent call to WebView.postVisualStateCallback never results in another call to VisualStateCallback.onComplete.
mWebView.postVisualStateCallback(++mWebViewVisualStateCallback, new WebView.VisualStateCallback() {
#Override
public void onComplete(long requestId) {
if (requestId == mWebViewVisualStateCallback) {
mWebView.setVisibility(View.VISIBLE);
}
}
});
I am not navigating to new web pages in the WebView. The web page is essentially a long-lived single-page app. The DOM may be changing in the WebView while it is in the background, which is why I'm trying to subsequently call WebView.postVisualStateCallback. I am testing on an emulator and Pixel 2 with Oreo 8.1/API 27.
Is it possible to use WebView.postVisualStateCallback multiple times on the same main frame? Why would WebView.postVisualStateCallback only work once?
Quoted from android website, I think you might need to consider these situations when using postVisualStateCallback()
To guarantee that the WebView will successfully render the first frame
after the VisualStateCallback#onComplete method has been called a set
of conditions must be met:
If the WebView's visibility is set to VISIBLE then the WebView must be attached to the view hierarchy.
If the WebView's visibility is set to INVISIBLE then the WebView must be attached to the view hierarchy and must be made VISIBLE from
the VisualStateCallback#onComplete method.
If the WebView's visibility is set to GONE then the WebView must be attached to the view hierarchy and its LayoutParams's width and height
need to be set to fixed values and must be made VISIBLE from the
VisualStateCallback#onComplete method.
Hope this is helpful~
My app requires people to log in with Facebook. Once they have done so, the Facebook token is checked each time they open the app so that we do not ask them to sign in again - we redirect them straight to the MainActivity.
Note that this is an 'empty view' activity - I have not used setContentView to set it to a view, it is purely there for decision making.
public class DecisionActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FacebookSdk.sdkInitialize(getApplicationContext());
if (AccessToken.getCurrentAccessToken() != null) {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
} else {
Intent startIntent = new Intent(this, SignUpActivity.class);
startActivity(startIntent);
finish();
};
}
}
This is my MainActivity code. Notice that I call my network operations in onCreate because I do not want to call them each time I minimize my app and maximize my app when the activity onResumes. It must be called once when I create my activity.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//show my progress bar
//CALL MY API TO GET SOME DATA FROM THE SERVER
//hide my progress bar after data is received.
}
}
This works perfectly. If the user has signed in, he is redirected to my MainActivity everytime. If the user hasn't signed in, he goes to SignUpActivity.
However, there is one nasty side effect from this code that I discovered today. Scenario 1 on onResuming my app works the way I want it to work.
Scenario 2 on onResuming my app does not work the way I want it to work.
Scenario 1:
If you are in your MainActivity and you minimize your app and press the square button, find your app and maximize again, the MainActivity onCreate method will not be called as the activity simply onResumes therefore no network operations is performed, progress bar is not shown, which is what I want.
Scenario 2:
However, if you minimize your app and decide to click on the app icon on your phone, DecisionActivity will be launched which will decide that MainActivity needs to be launch as the user has logged in already and the token exists. Because MainActivity is relaunched, onCreate is called and network activities are performed and the progress bar is shown, which is not what I want.
How do I stop this from happening when I click on my app icon on my phone?
I checked popular apps like Facebook now to see if they have the same issue by testing Scenario 1 and Scenario 2 on them and they don't seem to encounter this problem which makes me think whether the setup I have used to check whether someone has logged into my app under DecisionActivity can be done in a better way.
I'm sure a more elegant way exists, but this is what I have off the top of my head:
Try using SharedPreferences. So, when your app is minimized, the onPause() method is called. In this method, set the SharedPreference to false, which means that you don't wanna run the progress bar right now. Check for that SharedPreference in your MainActivity's onCreate() method. When the app is resumed, set the SharedPreference to true.
So this means that whenever the user went through the onPause() method, the progress bar won't run either if he goes through the Scenario 1 (because then he will hit onResume(), which won't show the progress bar) or if he goes through Scenario 2 (because your SharedPreference is false, and you check for its value beforehand in MainActivity's onCreate()).
But, now you also have to use the onFinish() or the onDestroy() method, and change the value of your SharedPreference to true, which will make the progress bar to appear when the app is launched next time.
The only flaw I can think of is that I'm not sure whether the onDestroy() method would be called if the user closes the app from the Recents Menu, or if Android mamory cleaner closes the app to free up memory, so do try it and tell me if it works.
And I agree this is but more of a hack and not a proper solution, but if it works, it is good enough ;)
Here is my problem - I want to create an activity and a dialog (with text field and OK button). I want to do the following:
Show the AlertDialog (on creation of the activity, on clicking a button, or some other actions);
Fill the text in the AlertDialog, and click the OK button;
Continue doing the main thread of the activity;
Something like this:
public String getText() {
String result = null;
// Showing the new window with the text box and the button, and after
// the button is clicked to move to the return statement below;
return result;
}
I tried using "runOnUiThread" and "AsyncTask", but the actions on the field "result" are done only in the "protected void onPostExecute(Void result)" method, and meanwhile the main program is still executing, without waiting for my input.
Is there anyway this to be done (I am sure it has, because saw such apps) to solve this problem? I know that is really impudent to ask for such help - but is is possible to write some code example, just to see how it is really happening, because more than 3 days, I can' do it. If not please give some suggestions, and will continue trying and trying :)
THANKS A LOT!
Whatever the operations u want to perform after click ,write in asynctask .When dialog button clicked execute the asynctask.Thats it
Well that's pretty much how dialogs work anyway.
http://developer.android.com/guide/topics/ui/dialogs.html#CustomDialog
At the bottom it shows how to create a custom dialog.
However, a lot of the time the text you need to take in is also displayed on the activity anyway, could you not embed an EditText on your activity and simplify this task?
I have code like this
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
boolean autoLogin = false;
autoLogin = checkAutoLogin();
if(autoLogin) {
showProgress();// Show progress dialog
if(login(savedUserName,savedPassword)) {
//call home activity using startActivity();
}
// login(savedUserName,savedPassword), this function access the server and return true if username and password correct- this works properly
}
}
Now the question is, i get display of home activity without displaying main activity and its progress dialog, during the authentication time of login(savedUserName,savedPassword)(this function take countable time because of server authentication) function, I got only a black screen, during this time i want show main activity and progress dialog.
Note:If i click back button in home activity i can get main activity and progress dialog
You should not do the network operation on UI thread,you can do it in separate thread and then you can call the home activity using Handler object,it iwll solve your problem
Do your Time Consuming Task in the AsynchTask. this class is designed exactly for the kind of work you are looking for.Use doInBackground() method to accomplish the task and onPreExecute you can show a progress Dialog.
Depending on what your showProgress() method contains, I'd guess that showProgress runs, sees that there is no active login attempt happening, and dismisses itself, then the login() method is called.
What you want to do is start login() asynchronously and then start the progress dialog that will check to see if login() is finished.
This is just a guess from what I can see of your code.
Could you post some more of it perhaps?
Try putting some logcat logging into the showProgress() method to see if it is in fact being created and destroyed quickly.
I have buttons in my app that do various things. A problem i am running into is that a button can be pressed multiple times before what that button does is enabled/processed/calculated.
Example
when i press a button { an integer should have 1 added to it unless it is at it maximum value.
when i press a button { a dialog should show (only once).
in either case if i press slowly i have no problems, but if i press rapidly the integer will pass its maximum or multiple dialogs will show.
Can someone point me in the right direction to deal with this.
It sounds as though you could simply set a boolean value when the button handler is entered to signify that the task is being performed. If you enter the function and the value is already true then simply return (or just disable the button until the operation is complete).
I don't know a lot about android, and I don't know if you have the task running in a different thread or if multiple clicks are being queued up, in which case the boolean wouldn't help as it would all be happening in serial. In that case, as I suggested earlier, just disable the button while the task is in progress (probably a good idea in any case).
I would suggest disabling is not that user friendly, i see the user is selecting button and has a lot of time in between before the next operation happens and tats why he ends up clicking multiple times. In this case as soon as soon capture the click you can show circular progress dialog , that shows user something is in happening and he wont be able to click button also.
Dismiss the dialog once you have set the counter
or second case about to open the dialog ProgressDialog dialog = ProgressDialog.show(MyActivity.this, "",
"Loading. Please wait...", true); then dialog.dismiss() once ur done