This question is very similar to questions that have been asked in the past but please bear with me as it is still a unique question. Basically, I have a class that gets application permissions, and if the user does not have internet running, then when the auto login screen comes, it is stuck in loading. So what I want to do is show a dialog message, and the user will click ok to close the app. For dialogs, I need the context, and I must run on the main thread. I have posted an image of the code because I want to show you that runOnUIThread is red. Here is the error I get form Android Studio
Cannot resolve method runOnUIThread.
Here is what I had
Problem: For some reason, runOnUIThread is not usable. Does anyone have a counter proposal, or a reason as to why I am having this problem?
Here is the code:
public void alert() {
new Thread()
{
public void run()
{
application.runOnUiThread(new Runnable() // application is the context of my current activity.
{
public void run() //I display my alert Dialog here.
{
AlertDialog build= new AlertDialog.Builder(application.getApplicationContext())
.setTitle("Error")
.setMessage("Sorry there seems to be a problem with the service. Please check to make sure you have a stable internet connection. ")
.setPositiveButton("Ok, I understand.", (dialog, which) -> System.exit(0))
.show();
build.setCancelable(false);
Button positive= build.getButton(DialogInterface.BUTTON_POSITIVE);
positive.setTextColor(application.getResources().getColor(R.color.buttonPrimaryColor));
positive.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
}
});
}
}.start();
Here is how I have made it work with a Toast in the past.
public void shortToast(String msg) {
Observable.just(msg)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(message -> {
Toast.makeText(application, message, Toast.LENGTH_SHORT).show();
});
}
// In the main method
shortToast("Sorry an error occured");
For some reason, runOnUIThread is not usable
The method that you are trying to invoke is runOnUiThread(). That is a method on Activity. Whatever application is, it is not an Activity.
Does anyone have a counter proposal
Move this code into an Activity. Generally, pop-ups (dialogs, snackbars, etc.) should be displayed by an Activity. And only an Activity can show a Dialog, such as an AlertDialog.
Try to use an activity to run on UI, not application
Related
In my project, I have an activity called "ExamMenuActivity" where I can choose between "Addition, Subtraction, Multiplication and Division" activities.
In Addition activity (called ExamAdditionActivity) I have a handler method to regenerate the question form after a given answer. Everything seems working fine, I can generate the question and give an answer and after giving an answer, a new question is generated in 2 seconds.
The issue I am having is, after I give a correct or a wrong answer to the question, within 2 seconds, if I quickly press on the back button of the phone and don't wait for the question to regenerate, I come back to the Exam Menu page as I wanted (back to ExamMenuActivity) but the screen changes back to ExamAdditionActivity and I see a new generated question again.
So I want to be able to come back to Exam Menu activity again when I press on the back button of the phone before the question regenerates and I don't want to face back the ExamAdditionActivity again with a new generated question (say I changed my mind after giving an answer to an addition question and I wanted to choose another activity from the menu and I didn't wait for at least 2 seconds).
I have tried overriding the activity with onBackPressed method:
#Override
public void onBackPressed() {
super.onBackPressed();
finish();
}
but unfortunately that didn't work.
Here is how I regenerate the question. I basically restart the same activity in two seconds with a handler ( there was a runnable within my handler code but since it was showing anonymous, android studio offered me to change it to a lambda function) :
private void regenerateQuestion() {
new Handler().postDelayed(() -> {
Intent restartExamAdditionActivity = new Intent(ExamAdditionActivity.this, ExamAdditionActivity.class);
overridePendingTransition(0, 0);
startActivity(restartExamAdditionActivity);
finish();
overridePendingTransition(0, 0);
}, TIME_OUT);
}
Even though I am not sure but I think I am having the problem in button listeners area since I give an answer to the question and call regenetate() method there under each button.
I hope there can be an answer to my issue. Thank you so much for stopping by to check on my post!
Create your Handler as a member variable of your class, like this:
Handler myHandler = new Handler();
Create your Runnable as a member variable of your class, like this:
Runnable myRunnable = new Runnable() {
#Override
public void run() {
Intent restartExamAdditionActivity = new Intent(ExamAdditionActivity.this, ExamAdditionActivity.class);
overridePendingTransition(0, 0);
startActivity(restartExamAdditionActivity);
finish();
overridePendingTransition(0, 0);
}
};
Post the Runnable using the new variable:
myHandler.postDelayed(myRunnable, TIME_OUT);
When you want to cancel the regeneration, do this:
myHandler.removeCallbacks(myRunnable);
I am making an android app in java in which I need to trigger some database requests whenever an activity is completely destroyed which would probably happen if the user presses the back button or leaves the app itself... But the onDestroy() function in my app is randomly getting triggered even when the user is still on the activity... I guess the probable reason for this is configuration changes but I am not able to figure out a proper solution for this.
Is there a way we could exactly detect when an activity is left by a user avoiding any in-page configuration changes??
The onDestroy() that I am using is this:
#Override
protected void onDestroy() {
/// do smthng
super.onDestroy();
}
Any help would be appreciated!!
Solved:
Thank you for the answer guys... For me onStop() worked out perfectly and it is working in every case whether it might be pressing the back button or exiting the activity or the app itself!!
If you want to check if the user ended the activity, meaning pressed back, do this:
#override
public void onBackPressed(){
//do something before we finish the activity
super.onBackPressed();
}
If you want to check when user, goes to next activity, then resturns to the same activity:
#override
public void onResume(){
//do something when return back to this activity
super.onResume();
}
#override
public void onPause(){
//do something before going to another activity
super.onPause();
}
onDestroy is called when the activity is destroyed or finished and not guaranteed to be called always, don't depend on it
We can check on whether our application is foreground or background based on the activity entering and exiting the foreground by implementing ActivityLifecycleCallbacks.
Good reference : https://medium.com/#iamsadesh/android-how-to-detect-when-app-goes-background-foreground-fd5a4d331f8a
Quoting from the above article,
#Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}
and,
#Override
public void onActivityStopped(Activity activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}
by which we can make sure that our app is in foreground or not. Here you always have the control of what activity is in foreground based on which you can check and execute the logic.
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage(message)
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
login(activity);
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
activity.finish();
}
});
AlertDialog alert = builder.create(); // Crash
alert.show();
The app runs fine and shows the alert dialog when I run it normally, but when I run it in an instrumented test, it crashes in builder.create at the first line:
final AlertDialog dialog = new AlertDialog(P.mContext, mTheme);
with this exception:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
This closes the app and then the test fails because there isn't any activity:
android.support.test.espresso.NoActivityResumedException: No activities in stage RESUMED. Did you forget to launch the activity. (test.getActivity() or similar)?
This is a thread problem, but that's not what I expected based on an answer here:
To verify if dialog appears you can simply check if View with a text that present inside the dialog is shown:
onView(withText("dialogText")).check(matches(isDisplayed()));
I don't understand how I'm supposed to check if the text is displayed if the app crashes before the dialog is created.
EDIT:
mActivityRule.launchActivity(intent);
mActivityRule.getActivity().showOptionDialog();
onView(withText(mActivityRule.getActivity().getString(R.string.dialogText))).check(matches(isDisplayed()));
A couple things that will likely help you...
Calling mActivityRule.getActivity().showOptionDialog(); in an Espresso test is not the 'Espresso' way. Unless your test is properly annotated, it's not running on the UI Thread, so this is a case where you are calling something that should be done on the UI Thread from the Instrumentation Thread. You can get around this by doing something like:
rule.runOnUiThread(new Runnable() {
#Override
public void run() {
mActivityRule.getActivity().showOptionDialog();
}
});
Doing this may require you to build out your own synchronization logic to make sure that future Espresso statements are not run before this occurs.
The better way to test this using Espresso is to use an onView(XXX).perform(click()) on the UI control that would normally invoke showOptionsDialog().
Additionally, you don't need to resolve the string that you pass to withText() yourself, you can just use the string resource id, but this isn't the cause of the issue that you are seeing.
Hey guys I'm trying to make a function that quit my application when onClick on a Button but it doesn't work.
Would you take a look and let me now what's wrong with the code please ?
Here is the code :
public void addListenerOnButtonLeave()
{
quitButton = (ImageView) findViewById(R.id.quitButton);
quitButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
finish();
moveTaskToBack(true);
}
});
}
I put this function into the overrided onCreate().
Thanks for your help guys.
You may also use finishActivity (int requestCode)
Force finish another activity that you had previously started with
startActivityForResult(Intent, int).
Probably some of your activities are running in background. When you have switched between activities, you have not finished them.
First finish those activities by adding
ActivityName.this.finish()
just before you sail to another activity, and then use
getActivity().finish();
System.exit(0);
to quit the app triggered where needed.
I have "MainMenuActivity" in my application, from which I want to log out. After pressing the back button, this activity should start "Logout activity", which does some logout stuff and then finishes the application.
Method called onBackPressed() from MainMenuActivity:
public static void logoutAction(final AbstractActivity activity) {
Builder dialog = new AlertDialog.Builder(activity);
dialog.setPositiveButton(R.string.dialog_btn_yes, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Intent i = new Intent();
i.setClass(activity, iess.student.login.LogoutActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
activity.startActivity(i);
activity.finish();
}
});
dialog.show();
}
Then, "LogoutActivity" executes AsyncTask, which at the end of its work calls finish() on LogoutActivity.
My problem is, that if other activities were launched before MainMenuActivity, i.e. A -> B -> MainMenuActivity, then after pressing back button Logout activity does its work, finishes, but instead of closing the application, activity B comes to front. I tried to launch MainMenuActivity from activity B with FLAG_ACTIVITY_CLEAR_TOP and then call finish() on B, but in that case A came to front. I also tried to set:
<activity android:name="abc.def.LogoutActivity" android:clearTaskOnLaunch="true"></activity>
But the result was the same as before. Could you please help me what should I do?
OK, so I finally managed it. After creating an activity, I register it in static ArrayList<Activity>. After "LogoutActivity" does its work; it just calls finish() on each Activity registered in ArrayList. It works, but I guess it's not really nice. But I haven't figured out how to do this with FLAG_ACTIVITY_CLEAR_TOP.
As #sandrstar says in the comment:
from API 11 you can use FLAG_ACTIVITY_CLEAR_TASK
It works very well for me, as it removes all Activities, not just the ones on top.