I've isolated an issue I am having when showing a ProgressDialog while an AsyncTask is executing and then trying to show an AlertDialog when onPostExecute is executed.
The steps to reproduce are:
1-Run the task
2-Before the task has finished press Home button
3-When you assume the task is finished return to the app
4-AlertDialog is not shown and a low bright (like disabled) screen is shown.
I've discovered that moving the dialog.dismiss() line to the end of the onPostExecute method fixes the problem... But this is weird, isn't it?
Source code:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClickButton(View view) {
new MyAsyncTask(this).execute();
}
private class MyAsyncTask extends AsyncTask<Void, Void, Void>
{
ProgressDialog dialog;
Context ctx;
public MyAsyncTask(Context ctx) {
this.ctx = ctx;
}
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(ctx);
dialog.setMessage("Loading");
dialog.show();
}
#Override
protected Void doInBackground(Void... params) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void value) {
dialog.dismiss();
AlertDialog.Builder alertbox = new AlertDialog.Builder(ctx);
alertbox.setNeutralButton("OK", null);
alertbox.setMessage("Message");
alertbox.setIcon(android.R.drawable.ic_dialog_alert);
alertbox.show();
// dialog.dismiss(); If I remove it from above and put this line here, it will work ok
}
}
}
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 have a big process called that will be called when I execute http-request and move to other activity or fragment,
The problem is, the process isn't finished yes then the display going to be blank and after that it move to another activity.
Question is, how we can set the timer and the timeout and where I can put the line code.
This is my current code
public class BigProccess extends AsyncTask<Void, Integer, Void> {
private Context mContext;
ProgressDialog mProgress;
private int mProgressDialog=0;
public BigProccess(Context context, int progressDialog){
this.mContext = context;
this.mProgressDialog = progressDialog;
}
#Override
public void onPreExecute() {
mProgress = new ProgressDialog(mContext);
mProgress.setMessage("Loading...");
// if (mProgressDialog== ProgressDialog.STYLE_HORIZONTAL){
mProgress.setIndeterminate(false);
mProgress.setMax(100);
mProgress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgress.setCancelable(false);
// }
mProgress.show();
}
#Override
protected void onProgressUpdate(Integer... values) {
// if (mProgressDialog== ProgressDialog.STYLE_HORIZONTAL){
mProgress.setProgress(values[0]);
// }
}
#Override
protected Void doInBackground(Void... values) {
try {
//This is to simulate there is a heavy process is running
//and we make it slow down by 500 ms for each number
for (int i =1; i<=10;i++){
publishProgress(i*10);
Thread.sleep(500);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
mProgress.dismiss();
// Toast.makeText(mContext,"Done!!!",Toast.LENGTH_LONG).show();
}
}
I've tried modified the thread.Sleep to 15000ms but it won't work.
Any help would be appreciated.
I have a class that takes care of performing background tasks.
public class BackgroundTask extends AsyncTask<Void, Void, Void>
{
private ProgressDialog dialog;
public BackgroundTask(AppCompatActivity activity)
{
dialog = new ProgressDialog(activity);
}
#Override
protected void onPreExecute()
{
dialog.setMessage("Doing something, please wait.");
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setCancelable(false);
dialog.setProgress(0);
dialog.setMax(100);
dialog.show();
}
#Override
protected void onPostExecute(Void result)
{
if (dialog.isShowing())
{
dialog.dismiss();
}
}
#Override
protected Void doInBackground(Void... params)
{
try
{
// How can I call non-static method of MyActivity here?
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return null;
}
}
In my activity MyActivity (derived from AppCompatActivity) whenever there are time consuming task, I call it like this:
BackgroundTask task = new BackgroundTask(MyActivity.this);
task.execute();
And then displays waiting animation in dialog which is perfectly fine. I like to know: How can I pass non static method (that consumes time) which belongs to MyActivity (and any other activities) to this BackgroundTask so that I can call it from `doInBackground' ?
Thanks in advance.
public class BackgroundTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog dialog;
private MyActivity activity;
public BackgroundTask(MyActivity activity) {
this.activity = activity;
dialog = new ProgressDialog(activity);
}
...
#Override
protected Void doInBackground(Void... params) {
try {
activity.callWhatYouNeed();
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
But take care about what you call inside doInBackground, becasue this method executes on non-main thread, so you can't do anything with Views. If you need do something with views, make call like this
public class BackgroundTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog dialog;
private MyActivity activity;
private Handler uiHandler;
public BackgroundTask(MyActivity activity) {
this.activity = activity;
dialog = new ProgressDialog(activity);
uiHandler = new Handler(Looper.getMainLooper());
}
...
#Override
protected Void doInBackground(Void... params) {
try {
mHandler.post(new Runnable() {
#Override
public void run() {
activity.callWhatYouNeed();
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
UPDATE: if you want use AsyncTask with other activities, you should use inheritance and create one BaseActivity with callWhatYouNeed()
public abstract class BaseActivity extends AppCompatActivity {
public abstract void callWhatYouNeed();
}
extends from BaseActivity:
public class MyActivity extends BaseActivity {
#Override
public void callWhatYouNeed() {
//Implementation
}
}
and change AsyncTask
public class BackgroundTask extends AsyncTask<Void, Void, Void>
{
private ProgressDialog dialog;
private BaseActivity activity;
public BackgroundTask(BaseActivity activity)
{
this.activity = activity;
dialog = new ProgressDialog(activity);
}
#Override
protected Void doInBackground(Void... params) {
try {
activity.callWhatYouNeed();
}
catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
Or you can check activity with instanceof operator:
public class BackgroundTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog dialog;
private AppCompatActivity activity;
public BackgroundTask(AppCompatActivity activity) {
this.activity = activity;
dialog = new ProgressDialog(activity);
}
...
#Override
protected Void doInBackground(Void... params){
try {
if (activity instanceof MyActivity) {
((MyActivity) activity).callWhatYouNeed();
} else if (acitivty instanceof SeocndActivity) {
((SecondActivity) activity).secondCall();
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
But it is bad practice to use instanceof, so i strongly recommend use inheritance.
BackgroundTask task = new BackgroundTask(MyActivity.this);
task.execute();
When you call above code in MyActivity class at that time You have passed the instance on class in a constructer. So You can get any non-static method from MyActivity class. for example
public class BackgroundTask extends AsyncTask<Void, Void, Void>{
private ProgressDialog dialog;
private MyActivity activity;
public BackgroundTask(MyActivity activity)
{
this.activity = activity;
dialog = new ProgressDialog(activity);
}
#Override
protected void onPreExecute()
{
dialog.setMessage("Doing something, please wait.");
dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
dialog.setCancelable(false);
dialog.setProgress(0);
dialog.setMax(100);
dialog.show();
}
#Override
protected void onPostExecute(Void result)
{
if (dialog.isShowing())
{
dialog.dismiss();
}
}
#Override
protected Void doInBackground(Void... params)
{
try
{
activity.callyourmethod();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return null;
}
}
I have a huge database (40MB) on an SDCard. I need fetch data, with LIKE in query, which is very slow.
DB request takes about 5 seconds. Therefore, I need to do it asynchronously and with ProgressDialog.
I tried it with AsyncTask, but problem is with ProgressDialog. It was implemented this way:
private class GetDataFromLangDB extends AsyncTask<String, String, String> {
private final ProgressDialog dialog = new ProgressDialog(TranslAndActivity.this);
#Override
protected void onPreExecute() {
super.onPreExecute();
urDBCursor.close();
curDBCursor = null;
scaAdapter = null;
this.dialog.setMessage("Loading data...");
this.dialog.show();
}
#Override
protected String doInBackground(String... whatSearch) {
String result = "";
if (myDatabaseAdapter != null) {
curDBCursor = myDatabaseAdapter.fetchAll(whatSearch[0]);
}
return result;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
prepareListView();
}
}
The problem is that ProgressDialog is not shown during the DB request.
After finished database query, it flash on screen for a short time. When user tries
to tap on screen during database request, UI is freezed, and after DB request
message about 'not responding' is shown.
I tried it with a thread this way:
public void startProgress(View view, final String aWhatSearch) {
final ProgressDialog dialog = new ProgressDialog(MyActivity.this);
if (curDBCursor != null){
curDBCursor.close();
curDBCursor = null;
}
dialog.setMessage("Loading data...");
dialog.show();
Runnable runnable = new Runnable() {
public void run() {
curDBCursor = myDatabaseAdapter.fetchAll(aWhatSearch);
// dirty trick
try {
Thread.sleep(250); // it must be here to show progress
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
public void run() {
if (dialog.isShowing()) {
dialog.dismiss();
}
prepareListView();
}
});
}
};
new Thread(runnable).start();
}
The result was the same, but when I used the trick with Thread.sleep(250);
ProgressDialog was shown during the database request. But it is not spinning,
it looks freezed during the DB request.
DB stuff is called this way (after tap on search button):
btnSearchAll.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// AsyncTask
new GetDataFromLangDB().execute(edtTextToSearch.getText().toString());
// or Thread
//startProgress(null, edtTextToSearch.getText().toString());
}
});
I found a lot of problems like this in SO, but nothing was useful for me.
Could it be that DB is on SD Card?
I put the definition of the dialog into the AsyncTask Class and it works fine for me.
Take a look at this exampel (You have to change NAMEOFCLASS in the name of your CLASS:
private class doInBackground extends AsyncTask<Integer, Integer, Void> {
final ProgressDialog dialog = new ProgressDialog(NAMEOFCLASS.this) {
#Override
protected void onPreExecute() {
dialog.setCancelable(false);
dialog.setTitle(getString(R.string.daten_wait_titel));
dialog.setIcon(R.drawable.icon);
dialog.setMessage(getString(R.string.dse_dialog_speichern));
dialog.show();
}
#Override
protected void onCancelled() {
dialog.cancel();
}
....
#Override
protected void onProgressUpdate(Integer... values) {
// DO YOUR UPDATE HERE
}
#Override
protected void onPostExecute(Void result) {
dialog.dismiss();
}
}
Maybe this SO answer could help you. It looks like similar problem. Try to use AsyncQueryHandler for querying your database
declare you Dialog box on Class (Activity) level like this
private ProgressDialog dialog = null;
show the progress dialog and call the AsyncTask class when you want to start you Busy work..like onButton click or any
dialog = ProgressDialog.show(this,"Sending Email to your account please! wait...", true);
SendingEmailTask task = new SendingEmailTask();
String s = "";
task.execute(s);
create your inner class like
private class SendingEmailTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... urls) {
//do your work here..
// like fetching the Data from DB or any
return null;
}
#Override
protected void onPostExecute(String str) {
//hide progress dialog here
dialog.dismiss();
}
}
let me know if this help!!
I have a tabgroup having multiple activities. In one of the tabs i have two activities between whom i want to place a progress dialog.For this i am using Asynk Task. Following is my AsynkTask class which i have made an inner class for AboutUs activity:
private class TheTask extends AsyncTask<Void, Void, Void>{
#Override
protected void onPreExecute() {
progDialog = ProgressDialog.show(AboutUs.this.getParent(), "Loading... ",
"please wait....", true);
}
#Override
protected Void doInBackground(Void... params) {
final Intent aboutusIntent = new Intent(getParent(), Departments.class);
final TabGroupActivity parentActivity = (TabGroupActivity)getParent();
parentActivity.startChildActivity("Departments", aboutusIntent);
return null;
}
#Override
protected void onPostExecute(Void result) {
if(progDialog.isShowing())
{
progDialog.dismiss();
}
}
}
I am calling this class in my AboutUs activity :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.aboutus);
.
.
.
.
/* Button for going to Departments */
Button ourdepbtn = (Button) findViewById(R.id.departmentsbutton);
ourdepbtn.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
//ourDepartments();
new TheTask().execute();
return false;
}
});
}
However this does'nt start a new activity i.e. Departments. The progress dialog appears and then disappears but activity never loads.
Any suggestions..??
First, you cannot start an activity from a non GUI thread (which Async doInBackground() is). Just start directly inside your Button.onClick() (why you use onTouch?) listener.
If you want to show up a ProgressDialog for the new Activity as soon as possible, you need to create it in the new (child) Activity onCreate(), as your ProgressDialog is connected to the new (child) activity (is it?). Take care about the order of creating layouts (create the ProgressDialog after calling setContentView()).
I am not very sure why you want to show that ProgressDialog. Is there something which delays the display of the childActivity? You loading some data? Then, the Dialog should be related to that loading task (Async I guess).
private class TheTask extends AsyncTask{
Context con;
Intent aboutusIntent;
TabGroupActivity parentActivity;
private TheTask(Context context)
{
this.con=context;
}
#Override
protected void onPreExecute() {
progDialog = ProgressDialog.show(con, "Loading... ",
"please wait....", true);
}
#Override
protected Void doInBackground(Void... params) {
aboutusIntent = new Intent(con, Departments.class);
parentActivity = (TabGroupActivity)getParent();
return null;
}
#Override
protected void onPostExecute(Void result) {
if(progDialog.isShowing())
{
progDialog.dismiss();
}
parentActivity.startChildActivity("Departments", aboutusIntent);
}
}
Thanks for your suggestions Oliver :)