Android activity unresponsive until back button is pressed - java

Below is the oncreate to my activity. My issue is that when the activity is started it is completely unresponsive until I press the back button. Once I press the back button it works perfectly.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_packs);
count = 0;
Bundle extras = getIntent().getExtras();
if(extras != null || !equals("")){
name = extras.getString("name");
}
else{name="PackActivity";}
//getActionBar().setTitle(name);
ActionBar actionBar = getActionBar();
//actionBar.setBackgroundDrawable(R.drawable.navigation_bar_colour_image);
//actionBar.setHomeButtonEnabled(true);
actionBar.setTitle(name);
actionBar.setDisplayHomeAsUpEnabled(false);
//actionBar.hide();
database = new DataObjectDataSource(this.getApplicationContext());
//load all the packs from the DB
packs = loadPacks();
//make the request for GetPacks
sortArrayById();
if(isOnline(this)) {
HTTPRequest.getHTTPRequest(HTTPRequest.getPacksURL, this);
}
else{
dialog("No internet connection available","their is limited functionality available in offline mode",1);
}
gridView = (GridView) findViewById(R.id.packGrid);
adapter = new PackGridAdapter(this, getApplicationContext(), packs);
gridView.setAdapter(adapter);
gridView.setOnItemClickListener(this);
System.out.println(" pack_ids ");
}
I have included the dialog function as the unresponsiveness comes after it have been dismissed.
public boolean dialog(String mes,String message,int type){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
// Add the buttons
if(type==2){
builder.setMessage(message)
.setTitle(mes);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
});
}
// Create the AlertDialog
final AlertDialog dialog = builder.create();
dialog.show();
if(type==2){
final Timer t = new Timer();
t.schedule(new TimerTask() {
public void run() {
dialog.dismiss();
// when the task active then close the dialog
t.cancel(); // also just top the timer thread, otherwise, you may receive a crash report
}
}, 5000);
}
return true;
}

2 Things:
1st confirm that your ActionBar code is working (comment the actionbar part to make sure that is not culprit here) to see if the activity is responsive or not
If the 1st doesn't work, and even after commenting ActionBar activity is unresponsive .. then
2nd comment these lines:
if(isOnline(this)) {
HTTPRequest.getHTTPRequest(HTTPRequest.getPacksURL, this);
}
else{
dialog("No internet connection available","their is limited functionality available in offline mode",1);
}
I suspect you're doing some network operation on your UI Thread, that could be the cause of Activity not Responding or it must have something to do with the dialog method you're using. If you show that method code, it could lead further to diagnose.

Related

Crash in ViewRootImpl.java line XXX on Android 7 despite catching all Toast related errors [duplicate]

From my main activity, I need to call an inner class and in a method within the class, I need to show AlertDialog. After dismissing it, when the OK button is pressed, forward to Google Play for purchase.
Things work perfectly for most of the times, but for few users it is crashing on builder.show() and I can see "android.view.WindowManager$BadTokenException: Unable to add window" from crash log. Please suggest.
My code is pretty much like this:
public class classname1 extends Activity{
public void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.<view>);
//call the <className1> class to execute
}
private class classNamename2 extends AsyncTask<String, Void, String>{
protected String doInBackground(String... params) {}
protected void onPostExecute(String result){
if(page.contains("error"))
{
AlertDialog.Builder builder = new AlertDialog.Builder(classname1.this);
builder.setCancelable(true);
builder.setMessage("");
builder.setInverseBackgroundForced(true);
builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton){
dialog.dismiss();
if(!<condition>)
{
try
{
String pl = "";
mHelper.<flow>(<class>.this, SKU, RC_REQUEST,
<listener>, pl);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
});
builder.show();
}
}
}
}
I have also seen the error in another alert where I am not forwarding to any other activity. It's simple like this:
AlertDialog.Builder builder = new AlertDialog.Builder(classname1.this);
builder.setCancelable(true);
//if successful
builder.setMessage(" ");
builder.setInverseBackgroundForced(true);
builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton){
// dialog.dismiss();
}
});
builder.show();
}
android.view.WindowManager$BadTokenException: Unable to add window"
Problem :
This exception occurs when the app is trying to notify the user from
the background thread (AsyncTask) by opening a Dialog.
If you are trying to modify the UI from background thread (usually
from onPostExecute() of AsyncTask) and if the activity enters
finishing stage i.e.) explicitly calling finish(), user pressing home
or back button or activity clean up made by Android then you get this
error.
Reason :
The reason for this exception is that, as the exception message says,
the activity has finished but you are trying to display a dialog with
a context of the finished activity. Since there is no window for the
dialog to display the android runtime throws this exception.
Solution:
Use isFinishing() method which is called by Android to check whether
this activity is in the process of finishing: be it explicit finish()
call or activity clean up made by Android. By using this method it is
very easy to avoid opening dialog from background thread when activity
is finishing.
Also maintain a weak reference for the activity (and not a strong
reference so that activity can be destroyed once not needed) and check
if the activity is not finishing before performing any UI using this
activity reference (i.e. showing a dialog).
eg.
private class chkSubscription extends AsyncTask<String, Void, String>{
private final WeakReference<login> loginActivityWeakRef;
public chkSubscription (login loginActivity) {
super();
this.loginActivityWeakRef= new WeakReference<login >(loginActivity)
}
protected String doInBackground(String... params) {
//web service call
}
protected void onPostExecute(String result) {
if(page.contains("error")) //when not subscribed
{
if (loginActivityWeakRef.get() != null && !loginActivityWeakRef.get().isFinishing()) {
AlertDialog.Builder builder = new AlertDialog.Builder(login.this);
builder.setCancelable(true);
builder.setMessage(sucObject);
builder.setInverseBackgroundForced(true);
builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton){
dialog.dismiss();
}
});
builder.show();
}
}
}
}
Update :
Window Tokens:
As its name implies, a window token is a special type of Binder token
that the window manager uses to uniquely identify a window in the
system. Window tokens are important for security because they make it
impossible for malicious applications to draw on top of the windows of
other applications. The window manager protects against this by
requiring applications to pass their application's window token as
part of each request to add or remove a window. If the tokens don't
match, the window manager rejects the request and throws a
BadTokenException. Without window tokens, this necessary
identification step wouldn't be possible and the window manager
wouldn't be able to protect itself from malicious applications.
 A real-world scenario:
When an application starts up for the first time,
the ActivityManagerService creates a special kind of window token
called an application window token, which uniquely identifies the
application's top-level container window. The activity manager gives
this token to both the application and the window manager, and the
application sends the token to the window manager each time it wants
to add a new window to the screen. This ensures secure interaction
between the application and the window manager (by making it
impossible to add windows on top of other applications), and also
makes it easy for the activity manager to make direct requests to the
window manager.
I had dialog showing function:
void showDialog(){
new AlertDialog.Builder(MyActivity.this)
...
.show();
}
I was getting this error and i just had to check isFinishing() before calling this dialog showing function.
if(!isFinishing())
showDialog();
The possible reason is the context of the alert dialog. You may be finished that activity so its trying to open in that context but which is already closed.
Try changing the context of that dialog to you first activity beacause it won't be finished till the end.
e.g
rather than this.
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
try to use
AlertDialog alertDialog = new AlertDialog.Builder(FirstActivity.getInstance()).create();
first you cannot extend AsyncTask without override doInBackground
second try to create AlterDailog from the builder then call show().
private boolean visible = false;
class chkSubscription extends AsyncTask<String, Void, String>
{
protected void onPostExecute(String result)
{
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setCancelable(true);
builder.setMessage(sucObject);
builder.setInverseBackgroundForced(true);
builder.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton)
{
dialog.dismiss();
}
});
AlertDialog myAlertDialog = builder.create();
if(visible) myAlertDialog.show();
}
#Override
protected String doInBackground(String... arg0)
{
// TODO Auto-generated method stub
return null;
}
}
#Override
protected void onResume()
{
// TODO Auto-generated method stub
super.onResume();
visible = true;
}
#Override
protected void onStop()
{
visible = false;
super.onStop();
}
I am creating Dialog in onCreate and using it with show and hide. For me the root cause was not dismissing onBackPressed, which was finishing the Home activity.
#Override
public void onBackPressed() {
new AlertDialog.Builder(this)
.setTitle("Really Exit?")
.setMessage("Are you sure you want to exit?")
.setNegativeButton(android.R.string.no, null)
.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
Home.this.finish();
return;
}
}).create().show();
I was finishing the Home Activity onBackPressed without closing / dismissing my dialogs.
When I dismissed my dialogs the crash disappeared.
new AlertDialog.Builder(this)
.setTitle("Really Exit?")
.setMessage("Are you sure you want to exit?")
.setNegativeButton(android.R.string.no, null)
.setPositiveButton(android.R.string.yes,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog,
int which) {
networkErrorDialog.dismiss() ;
homeLocationErrorDialog.dismiss() ;
currentLocationErrorDialog.dismiss() ;
Home.this.finish();
return;
}
}).create().show();
I try this it solved.
AlertDialog.Builder builder = new AlertDialog.Builder(
this);
builder.setCancelable(true);
builder.setTitle("Opss!!");
builder.setMessage("You Don't have anough coins to withdraw. ");
builder.setMessage("Please read the Withdraw rules.");
builder.setInverseBackgroundForced(true);
builder.setPositiveButton("OK",
(dialog, which) -> dialog.dismiss());
builder.create().show();
In my case I refactored code and put the creation of the Dialog in a separate class. I only handed over the clicked View because a View contains a context object already. This led to the same error message although all ran on the MainThread.
I then switched to handing over the Activity as well and used its context in the dialog creation
-> Everything works now.
fun showDialogToDeletePhoto(baseActivity: BaseActivity, clickedParent: View, deletePhotoClickedListener: DeletePhotoClickedListener) {
val dialog = AlertDialog.Builder(baseActivity) // <-- here
.setTitle(baseActivity.getString(R.string.alert_delete_picture_dialog_title))
...
}
I , can't format the code snippet properly, sorry :(
I got this error, but mine was coming from the Toasts, not a Dialog.
I have Activity and Fragments in my layout. Code for the Toast was in the Activity class. Fragments gets loaded before the Activity.
I think the Toast code was hit before the Context/Activity finished initializing. I think it was the getApplicationContext() in the command Toast.makeText(getApplicationContext(), "onMenutItemActionCollapse called", Toast.LENGTH_SHORT).show();
Try this :
public class <class> extends Activity{
private AlertDialog.Builder builder;
public void onCreate(Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.<view>);
builder = new AlertDialog.Builder(<class>.this);
builder.setCancelable(true);
builder.setMessage(<message>);
builder.setInverseBackgroundForced(true);
//call the <className> class to execute
}
private class <className> extends AsyncTask<String, Void, String>{
protected String doInBackground(String... params) {
}
protected void onPostExecute(String result){
if(page.contains("error")) //when not subscribed
{
if(builder!=null){
builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton){
dialog.dismiss();
if(!<condition>)
{
try
{
String pl = "";
mHelper.<flow>(<class>.this, SKU, RC_REQUEST,
<listener>, pl);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
});
builder.show();
}
}
}
}
with this globals variables idea,
I saved MainActivity instance in onCreate();
Android global variable
public class ApplicationController extends Application {
public static MainActivity this_MainActivity;
}
and Open dialog like this. it worked.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Global Var
globals = (ApplicationController) this.getApplication();
globals.this_MainActivity = this;
}
and in a thread, I open dialog like this.
AlertDialog.Builder alert = new AlertDialog.Builder(globals.this_MainActivity);
Open MainActivity
Start a thread.
Open dialog from thread -> work.
Click "Back button" ( onCreate will be called and remove first MainActivity)
New MainActivity will start. ( and save it's instance to globals )
Open dialog from first thread --> it will open and work.
: )

Capturing user input from an actionbar menu item

I am creating a gym app in Android Studio and the first feature I'm trying to implement is to have the user create a workout by clicking on an option in the action bar to add it. Clicking this button brings up an alert dialog with an EditText field to type in the workout name. Later, I will use the input to create a list view with the different workouts added, but for now I am just concerned about capturing the input from this EditText field.
Here is what should happen.. on this screen I click the + button and it brings up an alert dialog box with an EditText field. I want to capture this input in the java main activity file.
Here is the java MainActivity File. I want the input from the EditText field to be stored in the m_Text variable.
public class MainActivity extends AppCompatActivity {
private String m_Text;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu,menu);
return super.onCreateOptionsMenu(menu);
}
#Override
//Clicking add workout button in the action bar
//stackoverflow.com/questions/13143006/alert-dialog-from-within-onooptionsitemselected-android
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.action_add_workout:
//final EditText mAddWorkout = (EditText)R.layout.userinput;
//Creating the dialog box for entering the workout name
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Enter the workout name");
//Create the user input xml file into a java object; capturing the user input from the dialog box
//inflate means "fill"
View view = LayoutInflater.from(this).inflate(R.layout.userinput,null);
final EditText mAddWorkout = (EditText)view.findViewById(R.id.workout_name_input);
builder.setView(R.layout.userinput);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
m_Text = mAddWorkout.getText().toString();
boolean brkpt = true;
}
}); //Second parameter pass in which event listener should trigger when the button is clicked
builder.setNegativeButton("Cancel",null);
builder.show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
Here is the xml for my actionbar menu item for adding the workout name (main_menu.xml)
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/action_add_workout"
android:icon="#drawable/ic_add"
android:title="#string/add_workout"
app:showAsAction="always"/>
</menu>
Last, the xml for the EditText (userinput.xml)
<EditText xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/workout_name_input"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hint="name..">
</EditText>
When I debug my code, the m_Text variable is always empty if I enter a workout name in the EditText field. I have been stuck on this for days now and I have combed youtube and SO for an answer and haven't found much relating to my issue.
Any insight is greatly appreciated. Thank you.
EDIT: Updated code for MainActivity. I can get control pass to the custom clicker but the input is still not saved. Thanks
public class MainActivity extends AppCompatActivity {
private EditText mAddWorkout;
public class CustomClickListener implements View.OnClickListener {
private final Dialog dialog;
CustomClickListener(Dialog dialog) {
this.dialog = dialog;
}
#Override
public void onClick(View v) {
String editTextValue= mAddWorkout.getText().toString();
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu,menu);
return super.onCreateOptionsMenu(menu);
}
#Override
//Clicking add workout button in the action bar
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
case R.id.action_add_workout:
//final EditText mAddWorkout = (EditText)R.layout.userinput;
//Creating the dialog box for entering the workout name
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Enter the workout name");
//Create the user input xml file into a java object; capturing the user input from the dialog box
//inflate means "fill"
View view = LayoutInflater.from(this).inflate(R.layout.userinput,null);
mAddWorkout = (EditText)view.findViewById(R.id.workout_name_input);
builder.setView(R.layout.userinput);
builder.setPositiveButton("OK",null);
builder.setNegativeButton("Cancel",null);
AlertDialog alertDialog = builder.create();
alertDialog.show();
Button saveWorkout = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
saveWorkout.setOnClickListener(new CustomClickListener(alertDialog));
builder.show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
******FINAL EDIT*******
I've since finished the entire app and thought I would post my alert dialog code in case it helps someone else out. It turns out that this issue with alert dialogs was the only major issue I had, once I got used to android studio and java things really took off. Anyways my gymapp is a nice little app that uses SQLlite to track workouts, exercises, and sets.. I've actually used it in the gym :)
#Override
//Clicking add workout button in the action bar
public boolean onOptionsItemSelected(MenuItem item) {
//Creating the dialog box for entering the workout name
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final EditText input = new EditText(this);
builder.setTitle("Enter the workout name").setView(input).setView(input);
builder.setPositiveButton("OK",new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Workout workout = new Workout(input.getText().toString());
long workout_key = myDb.createWorkout(workout);
populateWorkouts();
}
});
builder.setNegativeButton("Cancel",new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.show();
return super.onOptionsItemSelected(item);
}
In my case, I use the input to create a workout object and insert it to my database. And obviously you would need a switch statement if you had more than one option in your action bar menu.
Thanks again to the 2 guys that tried to help me.
Here is how you should do this:
Create a customer click listener
private class CustomClickListener implements View.OnClickListener {
private final Dialog dialog;
CustomClickListener(Dialog dialog) {
this.dialog = dialog;
}
#Override
public void onClick(View v) {
String editTextValue= mAddWorkout.getText().toString();
}
}
You should make mAddWorkout value class-level so you can access it easily!
Then :
Set this click listener to your dialog like this
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Enter the workout name");
//Create the user input xml file into a java object; capturing the user input from the dialog box
//inflate means "fill"
View view = LayoutInflater.from(this).inflate(R.layout.userinput,null);
final EditText mAddWorkout = (EditText)view.findViewById(R.id.workout_name_input);
builder.setView(R.layout.userinput);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
boolean brkpt = true;
}
}); //Second parameter pass in which event listener should trigger when the button is clicked
AlertDialog alertDialog = builder.create();
alertDialog .show();
Button saveWorkout = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
saveWorkout .setOnClickListener(new CustomClickListener(alertDialog));
This is the solution that I use for my own code and works fine; you can do validation inside the onClick method of the click listener and alert the user accordingly!
Good luck!
private android.app.AlertDialog mAlert;
private EditText mAddWorkout;
//Creating the dialog box for entering the workout name
AlertDialog.Builder builder = new AlertDialog.Builder(this);
View view = LayoutInflater.from(this).inflate(R.layout.userinput,null);
builder.setTitle("Enter the workout name");
mAlert = builder.create();
mAlert.setCancelable(true);
mAlert.setView(view, 10, 10, 10, 10);
if (mAlert != null && !mAlert.isShowing()) {
mAlert.show();
}
mAddWorkout = (EditText) mAlert.findViewById(R.id.workout_name_input);
m_Text = mAddWorkout.getText().toString();
Hope this solves your problem
A bit late, but I had run into the same problem, and found yet another answer. The solution that works for me is...
binding.myEditText.setOnEditorActionListener { _, action, key ->
if (actionId == EditorInfo.IME_ACTION_SEARCH ||
actionId == EditorInfo.IME_ACTION_DONE ||
key == null ||
key.keyCode == KeyEvent.KEYCODE_ENTER) {
// Put your actions here
true
} else {
false
}
}
I have only been writing kotlin for a month or so, so I cannot promise this follows best practice, but maybe someone else can improve this.
This task is hard because we had only one control, so it is harder to trap focus changes. If we had a page full of buttons, we might have a [Reset] and a [Save] button. We have one function that loads all the parameters into the EditTexts (used on entry and Reset); and one function that updates all the parameters with the EditText text (used on Save). Then all is easy. But I was going to get one parameter going before adding th fancy stuff, which is why I fell into this hole.

How do you prevent the back button from closing an application from the main activity?

I am having a problem with my activity closing when i am trying to display a fragment. I am trying to have my application ask the user to rate my application when they press the back button to exit my application from the main screen. This is supposed to display a fragment asking to rate it now or later. The fragment appears for about 1 second then the application closes before the user can make a choice. How do I fix this?
This is the solution I came up with:
I am going to show you what I did to implement the fragment and how I prevented it from closing the activity bypassing the fragment.
In my main activity I added:
#Override
public void onBackPressed() {
final DialogFragment rate = new RateMe();
rate.show(getSupportFragmentManager(), "Rate");
}
Be sure to remove the super statement from the Override to stop the button push from CLOSING OUT YOUR APPLICATION completely when the back button is pushed.
I created a blank fragment activity with an xml called "RateMe". I left the xml blank after removing the "Hllo World" but be sure to double check your tools:context= . This was a mistake I made and it did not match my package. Simple fix. Just change it to your package name.
Then in the fragment i put:
public class RateMe extends DialogFragment {
public static RateMe newInstance(int title) {
RateMe frag = new RateMe();
Bundle args = new Bundle();
// args.putInt("title", title);
frag.setArguments(args);
return frag;
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setCancelable(false);
builder.setTitle("Rate Me");
builder.setMessage(R.string.Rate);
//Create a string in your res values strings.xml file. This will be your //R.string that appears on your fragment^^^^ Then continue by adding......
builder.setPositiveButton("Yes, I Will", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
Uri uri = Uri.pa(RateMe.this);rse("market://details?id=****PUT YOUR GOOGLE PLAY URL INFO HERE");
Intent myAppLinkToMarket = new Intent(Intent.ACTION_VIEW, uri);
myAppLinkToMarket.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY |
Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
try {
startActivity(myAppLinkToMarket);
} catch (ActivityNotFoundException e) {
Toast.makeText(getContext(), " unable to find market app", Toast.LENGTH_LONG).show();
}
}
});
builder.setNegativeButton("Not Now", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
System.exit(0); //this will close the application
}
});
return builder.create();
}
}
This worked perfectly for me. Hope this can help someone.

Android AlertDialog crashes with BadTokenException?

this is my first post so please bear with me.
I'm a high school developer and recently released an Android app on the play store. I'm using Crashlytics to capture exceptions, and for this some reason it throws this error.
Fatal Exception: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy#1989547c is not valid; is your activity running?
It was reported specifically on the LG D855, Nexus 5, and the Huawei PLK AL10 occurring on versions 5.0, 5.0.2, 5.1.1 and 6.0.1. I've looked online, and have found that this occurs when an activity does not exist. This error occurs on the initial startup of the app.
The following is the code I use for an Alert Dialog which simply asks if the user wants to see a tutorial (y/n)
public void showTutorialDialog() {
AlertDialog tutorialDialog = new AlertDialog.Builder(this)
.setTitle(R.string.tutorial_question_title)
.setCancelable(false)
.setMessage(R.string.tutorial_question)
.setPositiveButton(getResources().getString(R.string.tutorial_question_pos), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// Take to tutorial
// Assume isn't backer for now..
finish();
Intent i = new Intent(StartupActivity.this, TutorialActivity.class);
i.putExtra("from", "StartupActivity");
startActivity(i);
}
})
.setNegativeButton(getResources().getString(R.string.tutorial_question_neg), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// No tutorial, ask if they are a backer
showBackerDialog();
}
}).show();
Upon the initial start of the app, I load the users purchase details using IabHelper in a separate class. This class, called PurchaseRetriever, retrieves the content of users purchases asynchronously and stores it in an ArrayList. This is how my code works.
if (mManager.isUserFirstTime()) {
// Initialize purchase retriever.
// The rest will be done when the observer reports that purchase data has been retrieved.
mPurchases = PurchaseRetriever.getInstance(StartupActivity.this);
mPurchases.addObserver(new FirstStartupObserver(this));
StartupManager.FIRST = true;
loadImageContent();
It runs using the Observer pattern, so when the purchase details are queried it calls the update() method in FirstStartupObserver, which then by a reference to StartupActivity, calls startupActivity.showTutorialDialog();where the error occurs.
I've tested it on multiple devices I and my friends own personally (Nexus 6, Nexus 5, Nexus 7 tablet, Samsung Galaxy Tab, various devices on Samsung Remote Lab) yet it works fine on my end...
Any advice appreciated, thanks.
Edit: Here is StartupActivity.
/**
* Main startup activity. Determines which activity to launch.
* Puts the user in one place or another depending on if they are a backer.
*/
public class StartupActivity extends AppCompatActivity {
private StartupManager mManager;
private ProgressBar bar;
// --- Used if first time app loading to query purchase info
private PurchaseRetriever mPurchases;
#Override
protected void onCreate(Bundle savedInstanceState) {
// Used in either cases
// If first time, displayed, if not, hidden//
//hideNavBar();
User.init(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_startup);
bar = (ProgressBar)this.findViewById(R.id.progressBar);
mManager = new StartupManager(this);
// Returns true if data was corrupt before
if (mManager.isDataCorrupt()) {
bar.setVisibility(View.VISIBLE);
loadImageContent();
// Reset watch to default black
// Internally starts NewMainActivity
ErrorManager.fixCorruptData(bar, this);
} else {
// Stays true until user selects watch
if (mManager.isUserFirstTime()) {
// Initialize purchase retriever.
// The rest will be done when the observer reports that purchase data has been retrieved.
mPurchases = PurchaseRetriever.getInstance(StartupActivity.this);
mPurchases.addObserver(new FirstStartupObserver(this));
StartupManager.FIRST = true;
loadImageContent();
} else {
// NOT first time starting app.
mPurchases = PurchaseRetriever.getInstance(StartupActivity.this);
mPurchases.addObserver(new AfterFirstStartupObserver(this));
loadImageContent();
}
}
}
// Two main dialogs used
public void showTutorialDialog() {
AlertDialog tutorialDialog = new AlertDialog.Builder(this)
.setTitle(R.string.tutorial_question_title)
.setCancelable(false)
.setMessage(R.string.tutorial_question)
.setPositiveButton(getResources().getString(R.string.tutorial_question_pos), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// Take to tutorial
// Assume isn't backer for now..
finish();
Intent i = new Intent(StartupActivity.this, TutorialActivity.class);
i.putExtra("from", "StartupActivity");
startActivity(i);
}
})
.setNegativeButton(getResources().getString(R.string.tutorial_question_neg), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// No tutorial, ask if they are a backer
showBackerDialog();
}
}).show();
tutorialDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(Color.RED);
tutorialDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(Color.RED);
}
private void showBackerDialog() {
// Show AlertDialog ask if they are kickstarter backer
AlertDialog askDialog = new AlertDialog.Builder(this)
.setTitle(getResources().getString(R.string.startup_dialog_title))
.setCancelable(false)
.setMessage(getResources().getString(R.string.startup_dialog_message))
.setPositiveButton(getResources().getString(R.string.startup_dialog_pos), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// User is a backer, take to watch chooser screen, then it takes to login screen
// Also look at Timer with TimerTask
new Thread(new Runnable() {
#Override
public void run() {
try {
Intent i = new Intent(StartupActivity.this, WatchChooserActivity.class);
i.putExtra("from", "StartupActivityBacker");
startActivity(i);
} finally {
finish();
}
}
}).start();
}
})
.setNegativeButton(getResources().getString(R.string.startup_dialog_neg), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// User is not a backer, take to MainActivity
new Thread(new Runnable() {
#Override
public void run() {
try {
Intent i = new Intent(StartupActivity.this, WatchChooserActivity.class);
i.putExtra("from", "StartupActivityNonBacker");
startActivity(i);
} finally {
finish();
}
}
}).start();
}
}).show();
askDialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextColor(Color.RED);
askDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextColor(Color.RED);
}
Here is the code for FirstStartupObserver.'
public class FirstStartupObserver implements Observer {
private StartupActivity startupActivity;
public FirstStartupObserver(StartupActivity startupActivity) {
this.startupActivity = startupActivity;
}
// Called when the observable is done loading purchase detail
// (Only called when user runs app first time)
#Override
public void update(Observable observable, Object data) {
// Set default first-time watch
// Query product data (the Watchfaces purchased in the form of a WatchFace object)
PurchaseRetriever mPurchases = PurchaseRetriever.getInstance(startupActivity);
if (mPurchases.hasSuccess()) {
ArrayList<DynamicLoader.WatchFace> facesOwned = mPurchases.getPurchasedFaces();
for (DynamicLoader.WatchFace f : facesOwned) {
f.setPurchased(true);
}
// Check if coming from v1.4
if (UpgradeManager.isUpgrading(startupActivity)) {
// Then it calls the code below, but after the async task.
String accessCode = UpgradeManager.getOldAccessCode(startupActivity);
String accessToken = UpgradeManager.getOldAccessToken(startupActivity);
UpgradeManager.migrateBacker(startupActivity, accessCode, accessToken);
} else {
// Ask if they want to see tutorial.
// This is when the exception occurs!!!
startupActivity.showTutorialDialog();
}
return;
} else {
Log.d("TAG", "Showing fail dialog");
DialogUtils.showIabFailDialog(startupActivity, this);
}
}
}
token android.os.BinderProxy#1989547c is not valid; is your activity
running?
This means that you're trying to show your popup while your activity is being destroyed or after it's destroyed.
You can check if your activity isDestroyed like below:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && !isDestroyed()) {
showTutorialDialog();
}
If you're supporting below api 17 devices you can try to use isFinishing in else case. I did not test if it's working as expected. (If i'm wrong please correct me.)
else {
if (!isFinishing()) {
showTutorialDialog();
}
}
Or for a quick fix you can surround with try catch
This is usually caused by doing something in an AsyncTask or other background task which holds a reference to the Activity and tries to display the dialog when the work is done. In this case, it sounds like your FirstStartupObserver is holding a reference to the activity and trying to show a dialog, but the activity may have been destroyed by the time PurchaseRetriever completes its work.
Don't try to test the activity state, and don't catch the BadTokenException. That just masks the problem. The simplest solution would be to cancel the PurchaseRetriever when the activity is paused. If you want the background work to survive configuration changes like rotations but still be restricted to the user-perceived lifetime of the activity, do the work in a retained fragment. Finally, if the background work should continue when the user navigates between activities or puts the app in the background, do the work in a Service and save the result where the activity can retrieve it.
token android.os.BinderProxy#1989547c is not valid; is your activity
running?
You are trying to load the AlertDialog too early, when the Activity doesn't exist! In my apps I load a little tutorial when the activity lifecycle is completed:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_screen);
...
...
...
showTutorialDialog();
}

Showing a message without closing actual dialog in Android

I've to do a pair of fixes to an Android app although I don't really know about Android, but I'm getting problems in something that I don't think should be that difficult, I just want that when an OK button is pressed and some conditions haven't been fulfilled it displays a message and keeps on the same screen until data is correct or the user cancels, but I've tried it for some time and whatever I try it always displays the message and after that a white screen appears, even trying to search for examples on the internet.
This is my code:
final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
LinearLayout layout = new LinearLayout(this);
LinearLayout.LayoutParams parms = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
layout.setOrientation(LinearLayout.VERTICAL);
layout.setLayoutParams(parms);
layout.setGravity(Gravity.CLIP_VERTICAL);
layout.setPadding(2, 2, 2, 2);
TextView tv = new TextView(this);
tv.setText("Es necesario rellenar los datos solicitados a continuación para poder realizar su primer canje");
tv.setPadding(40, 40, 40, 40);
tv.setGravity(Gravity.CENTER);
tv.setTextSize(20);
EditText et = new EditText(this);
String etStr = et.getText().toString();
TextView tv1 = new TextView(this);
tv1.setText("Nombre completo");
EditText et2 = new EditText(this);
String etStr2 = et2.getText().toString();
TextView tv2 = new TextView(this);
tv2.setText("Teléfono");
final EditText et3 = new EditText(this);
String etStr3 = et3.getText().toString();
TextView tv3 = new TextView(this);
tv3.setText("Correo electrónico");
LinearLayout.LayoutParams tv1Params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
tv1Params.bottomMargin = 5;
layout.addView(tv1,tv1Params);
layout.addView(et, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
layout.addView(tv2,tv1Params);
layout.addView(et2, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
layout.addView(tv3,tv1Params);
layout.addView(et3, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
alertDialogBuilder.setView(layout);
alertDialogBuilder.setTitle("hola");
// alertDialogBuilder.setMessage("Input Student ID");
alertDialogBuilder.setCustomTitle(tv);
// alertDialogBuilder.setMessage(message);
alertDialogBuilder.setCancelable(true);
// Setting Negative "Cancel" Button
alertDialogBuilder.setNegativeButton("Cancel",new DialogInterface.OnClickListener() {
alertDialogBuilder.setNegativeButton("Cancel",new DialogInterface.OnClickListener() {
[more code here]
alertDialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
matcher = pattern.matcher(et3.getText().toString());
if (matcher.matches())
{
[more code here]
}
else
{
Toast.makeText( contexto, "Por favor, introduzca un e-mail válido", Toast.LENGTH_LONG).show();
}
Hope you can help me with this thing, as I would find pretty annoying to have to learn android from the beginning to make something that I've been able to do in another programming languages in 5 minutes or less without knowing them at all.
Create two instance variables or class varibles like this
private Toast toast;
private boolean stop = false;
Write a method called this
private void showInfiniteToast() {
stop = false;
Thread t = new Thread() {
public void run() {
try {
while (true) {
if (!stop) {
toast.show();
} else {
toast.cancel();
return;
}
sleep(1850);
}
} catch (Exception e) {
Log.e("Infinite Toast", "Error "+ e.getLocalizedMessage());
}
}
};
t.start();
}
Now in the oncreate create the toast and call this method
toast = Toast.makeText(getApplicationContext(), "Test", Toast.LENGTH_LONG);
showInfiniteToast();
Now if you want to change the toast message use this
toast.setText("message");
To stop the toast call any of these
//Call anyone of them
stop = true;
toast.cancel();
To implement your own custom view use this
View mView;
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mView = inflater.inflate(R.layout.mylayout, null);
toast.setView(mView);
Here is the complete file
public class MainActivity extends Activity implements OnClickListener {
Button btnChange, btnStop, btnShow;
private Toast toast;
private boolean stop = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnShow = (Button) findViewById(R.id.btnShow);
btnShow.setOnClickListener(this);
btnChange = (Button) findViewById(R.id.btnChange);
btnChange.setOnClickListener(this);
btnStop = (Button) findViewById(R.id.btnStop);
btnStop.setOnClickListener(this);
toast = Toast.makeText(getApplicationContext(), "Test",
Toast.LENGTH_LONG);
showInfiniteToast();
}
private void showInfiniteToast() {
stop = false;
Thread t = new Thread() {
public void run() {
try {
while (true) {
if (!stop) {
toast.show();
} else {
toast.cancel();
return;
}
sleep(1850);
}
} catch (Exception e) {
Log.e("Infinite Toast", "Error "+ e.getLocalizedMessage());
}
}
};
t.start();
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnShow:
showInfiniteToast();
break;
case R.id.btnChange:
toast.setText("Added");
break;
case R.id.btnStop:
stop = true;
toast.cancel();
break;
default:
break;
}
}
}
First of all create your layouts using xml and inflate the view like this:
LayoutInflater li = (LayoutInflater) <ACTIVITY_NAME>.this
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = li.inflate(R.layout.<LAYOUT_NAME>, parent, false);
or
View view = li.inflate(R.layout.<LAYOUT_NAME>, null);
If there is no parent view to attach the inflated view to. Then you can edit objects in your view by doing:
EditText edit = (EditText) findViewById(R.id.edit1);
edit.setText("example");
Doing so just makes your code much more cleaner.
The methods: setPositiveButton, setNeutralButton and setNegativeButton are coded so that when they are pressed, the dialog will close after it has finished executing the code in the listener.
If your Android app is running on the main thread for over 5 seconds then the app will throw an error saying that the app is no longer responding. If you wished to do a long action then you should use an AsyncTask or a Service.
I believe you are wanting to have a progress bar of some kind. I will link you to a
tutorial that will show you how to acheive that side of things. Check here
Hopefully this points you in the right direction.
create a dialogBuilder, and override the negative and positive buttons, and on the click listeners do whatever you want. This will prevent the dialog from closing.
Like this:
Create the builder, intialize it, set it for eg:
builder.setView(view);
builder.setCancelable(false);
override the ondismiss listener, and onshow listener like:
builder.setOnDismissListener(new OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
if(!errorFlag) {
dialog.dismiss();
}
}
});
builder.setOnShowListener(new OnShowListener() {
#Override
public void onShow(DialogInterface dialog) {
Button b = builder.getButton(AlertDialog.BUTTON_POSITIVE);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// write the logic here, and maintain a flag.
// if the flag is true then only dismiss the dialog else show another one
}
Override the negative button also.
show the builder using builder.show()

Categories