I am testing my application on an LG Eve phone. I have an application that tries to download something from the web, and when it throws an exception, it is supposed to launch an alertdialog saying that there was an error. When the phone has no wifi signal, the program crashes at builder.create() (see code below). However, when there is wifi signal, and the exception is thrown by something else (for instance, a typo in the url), the dialog launches the way it's supposed to. Any clue as to why this could be?
Code for onCreateDialog:
#Override
protected Dialog onCreateDialog(int id){
Dialog d = null;
switch (id){
case DIALOG_DATA_ERROR_ID:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(getResources().getString(R.string.error_data));
builder.setCancelable(false);
builder.setNeutralButton("OK", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface d, int id){
d.cancel();
}
});
d = builder.create();
break;
}
return d;
}
Code for AsyncTask that calls showDialog:
private static class DownloadJSONTask extends AsyncTask<String, Void, String>{
private ProgressDialog dialog;
private Activity parent;
private JSONParserInterface jsonParser;
public DownloadJSONTask(Activity parent, JSONParserInterface jsonParser){
this.parent = parent;
this.jsonParser = jsonParser;
}
protected void onPreExecute(){
dialog = ProgressDialog.show(parent, "Loading", "Please Wait...", true);
}
protected String doInBackground (String... urls){
try {
return HttpHelper.getResponse(urls[0]);
}catch (Exception e){
dialog.cancel();
parent.showDialog(BoomSetListActivity.DIALOG_DATA_ERROR_ID);
}
return null;
}
protected void onPostExecute(String json){
dialog.cancel();
if (jsonParser != null) jsonParser.parse(json);
}
}
Do not show dialog at doInBackground. The method doesn't run on UI thread. Try showing error dialog at onPostExecute or onProgressUpdate.
Related
In an Android application, by clicking a button, in a fragment, I want to show an AlertDialog using AsynTask() method. I have put, in onPreExecute(), the function which called the AlertDialog. In doInBackground(), there is a task running, and in onPostExecute(), I dismiss the AlertDialog.
The crash occurs just when I click the button. And it refers to line code in the LoadingDialog class, which is dialog.show();. I have tried many suggestions given on the site, but, the issue occurs again.
Could anyone help me?
This is the LoadingDialog.java
public class LoadingDialog {
private Activity activity;
private AlertDialog dialog;
LoadingDialog(Activity myActivity){
activity = myActivity;
}
public void startLoadingDialog(){
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
LayoutInflater inflater = activity.getLayoutInflater();
builder.setView(inflater.inflate(R.layout.custom_dialog, null));
builder.setCancelable(false);
dialog = builder.create();
dialog.show();
}
public void dismissDialog(){
dialog.dismiss();
}
}
This is my Fragment class
public class MyFragment extends Fragment {
View view ;
private Button btn_;
private Activity activity;
private AlertDialog dialog;
private LoadingDialog loadingDialog;
public MyFragment(){
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
this.view = inflater.inflate(R.layout.fragment_, container, false);
loadingDialog = new LoadingDialog(getActivity());
btn_ = this.view.findViewById(R.id._button);
eventListnerReinitialiser();
return this.view;
}
public void eventListnerReinitialiser() {
this.btn_.setOnClickListener(v -> {
new ShowDialogAsyncTask().execute();
});
}
public class ShowDialogAsyncTask extends AsyncTask<Void, Void, Void> {
int s = 0;
#Override
protected void onPreExecute() {
loadingDialog.startLoadingDialog();
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
for(int i=0;i<1000000;i++)
s = s + i;
Toast.makeText(view.getContext(), "Valeur de s = "+ s, Toast.LENGTH_LONG).show() ;
return null;
}
#Override
protected void onPostExecute(Void result) {
loadingDialog.dismissDialog();
super.onPostExecute(result);
}
}
}
And I have this error log in my console of Android studio
E/WindowManager: android.view.WindowLeaked: Activity com.example.myproject.Menu2Activity has leaked window DecorView#96c506[] that was originally added here
at android.view.ViewRootImpl.<init>(ViewRootImpl.java:511)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:338)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93)
at android.app.Dialog.show(Dialog.java:322)
You are showing a toast in the doInBackground() of the AsyncTask, and this cannot be done. You can only update the Ui in the main thread.
Showing the toast in the doInBackground() which is running in a background thread throws a exception and your fragment is forced to shutdown at that moment but the dialog is still open which caused the exception.
So try calling the Toast.makeText(view.getContext(), "Valeur de s = "+ s, Toast.LENGTH_LONG).show() ; in the onPostExecute of AsyncTask.
Here is how to do the AsyncTask part.
public class ShowDialogAsyncTask extends AsyncTask<Void, Void, Void> {
int s = 0;
#Override
protected void onPreExecute() {
loadingDialog.startLoadingDialog();
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
for(int i=0;i<100_000_000;i++)
s = s + i;
return null;
}
#Override
protected void onPostExecute(Void result) {
Toast.makeText(MainActivity.this, "Valeur de s = "+ s, Toast.LENGTH_LONG).show() ;
loadingDialog.dismissDialog();
super.onPostExecute(result);
}
}
In addition to what Vivek said also:
Change the ShowDialogAsyncTask to static class
pass the dialog as WeakReference then use weakReference.get() in each place where it is
used
To show dialog pass context.getApplicationContext() as weak reference.
Currently your Activity is leaking through AsyncTask.
I created this AsyncTask inner class and now I want to make it outer. Here is the code:
private class DownloadDataFromServer extends AsyncTask<String, Integer, String> {
ProgressDialog dialog;
boolean connErr = false;
boolean soErr = false;
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(HomePage.this); !!!!PROBLEM!!!!
dialog.setIndeterminate(false);
dialog.setMax(100);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setCancelable(false);
dialog.setTitle("Download");
dialog.setMessage("Updating...");
dialog.show();
super.onPreExecute();
}
#Override
protected String doInBackground(String... urls) {
// do something
}
protected void onProgressUpdate(Integer... progress) {
// Update the progress
dialog.setProgress(progress[0]);
}
#Override
protected void onPostExecute(String result) {
if (connErr || soErr) {
String msg = "Bad connection";
AlertDialog.Builder builder;
builder = new AlertDialog.Builder(HomePage.this); !!!!PROBLEM!!!!
builder.setCancelable(false);
builder.setTitle("Connection timeout");
builder.setMessage(msg);
builder.setPositiveButton("Retry", new DialogInterface.OnClickListener(){
#Override
public void onClick(DialogInterface dialog, int which)
{
dialog.dismiss();
new DownloadDataFromServer().execute(new String[] { "http://www.example.com" });
}
});
builder.setNegativeButton("Exit", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
finish(); !!!!PROBLEM!!!!
}
});
AlertDialog dialog = builder.create();
dialog.show();
} else {
if (Integer.parseInt(result) <= 0) {
Toast.makeText(getBaseContext(), "Error!", Toast.LENGTH_SHORT).show(); !!!!PROBLEM!!!!
} else {
Toast.makeText(getBaseContext(), "OK!", Toast.LENGTH_SHORT).show(); !!!!PROBLEM!!!!
}
}
dialog.dismiss();
}
}
Please note "!!!!PROBLEM!!!!" strings in the above code: there are all the errors that I get. I tried to apply some workarounds but finally I could not make it working. In addition I also have to use
private Database db = new Database(this);
but I do not know what to put in place of "this". Please help me to convert this inner class in the right way.
You should make one argument constructor to DownloadDataFromServer class and pass Context as argument like
Context mCon;
public DownloadDataFromServer(Context con){
this.mCon=con;
}
and used this mCon context to anywhere in your DownloadDataFromServer like so
builder = new AlertDialog.Builder(mCon);
and at last called DownloadDataFromServer from any Activity like
new DownloadDataFromServer(your_Activity.this).execute(......);
Make yout DownloadDataFromServer have a constructor accepting HomeScreen, save the home screen in a field in the constructor and then use that field everywhere instead of HomeScreen.this.
You may have to make some of your private fields of HomeScreen public (or provide accessors) because of that.
You do not want to do all that though, what's the advantage?
I have a splash screen that runs an asyncTask that downloads data from an API. On that task's OnPostExecute I run the next asyncTask to send stored emails. Once that is complete I need an AlertDialog to popup with an ok button so the user knows the downloads are complete. I used this SO question to get as far as I have:
Android AlertDialog inside AsyncTask
Now I'm getting a NullPointerException when I attempt to add properties to the dialog:
public class JSONParser extends AsyncTask<String, String, JSONObject> {
Context c;
public JSONParser(int api,Context c) {
this.api= api;
this.c = c;
}
...
protected void onPostExecute(JSONObject result) {
JSONObject output = new JSONEmailParser(c).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, new String[] {null,null,null,null}).get();
}
}
public class JSONEmailParser extends AsyncTask<String, String, JSONObject> {
Context c;
AlertDialog.Builder builder;
public JSONEmailParser(Context c){
this.c = c;
}
protected void onPreExecute(int api){
builder = new AlertDialog.Builder(SplashScreen.this);
}
...
protected void onPostExecute(JSONObject result) {
setLastUpdate();
builder.setTitle("Sales Toolkit");
builder.setCancelable(false);
builder.setMessage("Download Complete");
builder.setPositiveButton("Continue", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
dialog.dismiss();
endSplash();
}
});
builder.show();
}
}
The error is coming up on builder.setTitle("Sales Toolkit");
AsyncTask#onPreExecute() doesn't take an int argument. Since your method has the wrong signature, it is likely never being called, and therefore builder is never set. This is a classic example of why you should use #Override annotations.
Do not use a .get() to execute an AsyncTask as it will not be async anymore. And onPreExecute will not be called?
It seems like the onPreExecute() method is not being called. If you don't really need to use the builder anywhere before the onPostExecute() method, I would suggest just moving
builder = new AlertDialog.Builder(SplashScreen.this);
into the onPostExecute() method.
I have a fully functional asynctask in my android app, but when I'm not connected it causes my app to crash in the Error message within my Activity (in AlertDialog.Builder) stemming from the Async not connecting. I pass Context to my async, so that may have something to do with it, but not sure.
Below is the code from Async class and Activity. LogCat is telling me error is occurring in the AlertDialog alert builder.create(). How can I solve?
From Async class:
InputsRecapUploadTask extends AsyncTask<String, Void, Integer> {
public InputsRecapUploadTask(InputsRecap activity,
ProgressDialog progressDialog, Context ctx) {
this.activity = activity;
this.myCtx = ctx;
this.progressDialog = progressDialog;
}
#Override
protected void onPreExecute() {
progressDialog.show();
}
}
#Override
protected Integer doInBackground(String... arg0) {
//// http code
responseCode = 1;
}
}
} catch (Exception e) {
e.printStackTrace();
progressDialog.dismiss();
activity.showLoginError("");
}
return responseCode;
}
#Override
protected void onPostExecute(Integer headerCode) {
progressDialog.dismiss();
if (headerCode == 1)
activity.login(id);
else
activity.showLoginError("");
}
Activity Class:
public void showLoginError(String result) {
AlertDialog.Builder builder = new AlertDialog.Builder(InputsRecap.this);
builder.setPositiveButton("okay",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
builder.setMessage("unable to upload database");
AlertDialog alert = builder.create();
alert.setCancelable(true);
alert.show();
}
If an exception is thrown in your doInBackground method these two lines:
progressDialog.dismiss();
activity.showLoginError("");
Will cause Exception - you can not modify the UI from within the doInBackground method. Instead set a flag and show the error dialog in the onPostExecute which is executed in the main thread.
Check the link below especially the topic under heading The 4 steps.
http://developer.android.com/reference/android/os/AsyncTask.html
Hi it's my first question in stackoverflow sorry if i do something wrong.
My problem is that when i start the app for very first time i need to write the SQL data in the database. If i do that in onCreate() while it's writing the sql it's not showing the View so it's like freezing. And if i make loader there it's not showed because first of all ti want's to finish all the oncreate and after that to show the View. Then i made AlertDialog to run if SQL is empty to inform the user that in needs "instalation" and after confirm i wanted to make loading box while it's running inserting the SQL...
So my question is : How to make loading onCreate... at running of the activity... can u give me some good idea... here is the code i made:
private DatabaseHandler db = new DatabaseHandler(this);
Context context;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = this;
if(db.getWordsCount() == 0)
{
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Instalation needed");
builder.setMessage("Database need to be installed");
builder.setPositiveButton("Ok", dialogClickListener);
builder.setNegativeButton("Close", dialogClickListener);
builder.show();
}
}
DialogInterface.OnClickListener dialogClickListener = new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
switch (which){
case DialogInterface.BUTTON_POSITIVE:
ProgressDialog progress = new ProgressDialog(context);
progress.setTitle("Instalation");
progress.setMessage("Please wait...");
progress.show();
db.insertWords(db);
progress.cancel();
break;
case DialogInterface.BUTTON_NEGATIVE:
finish();
break;
}
}
};
There is a lots of example for same :
http://ashwinrayaprolu.wordpress.com/2011/03/15/android-database-example-database-usage-asynctask-database-export/
private class InsertDataTask extends AsyncTask {
private final ProgressDialog dialog = new ProgressDialog(
DatabaseActivity.this);
// can use UI thread here
protected void onPreExecute() {
this.dialog.setMessage("Inserting data...");
this.dialog.show();
}
// automatically done on worker thread (separate from UI thread)
protected Void doInBackground(final String... args) {
DatabaseActivity.this.application.getDataHelper().insert(args[0]);
return null;
}
// can use UI thread here
protected void onPostExecute(final Void unused) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
// reset the output view by retrieving the new data
// (note, this is a naive example, in the real world it might make sense
// to have a cache of the data and just append to what is already there, or such
// in order to cut down on expensive database operations)
new SelectDataTask().execute();
}
}