ReNa
ReNa

Reputation: 1124

AsyncTask onPreExecute progressdialog

I have an AsyncTask when onPreExecute function executes it gives me an exception

** java.lang.IllegalStateException: View com.android.internal.policy.impl.PhoneWindow$DecorView@44ea0e20 has already been added to the window manager.**

when progressDialog's show() method is called.

My Activity

public class TopNewsActivity extends ListActivity {

public static final String LOG_TAG = "Infra";
private ProgressDialog progressDialog;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.listplaceholder);
    new BackgroundAsyncTask().execute();
}

public class BackgroundAsyncTask extends AsyncTask<String, Integer, ArrayList<HashMap<String, String>>> {

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        progressDialog = new ProgressDialog(TopNewsActivity.this);
        progressDialog.setCancelable(true);
        progressDialog.setMessage("Loading...");
        progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        progressDialog.setProgress(0);
        progressDialog.show();
    }

    @Override
    protected ArrayList<HashMap<String, String>> doInBackground(String... paths) {
        ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();

        String xml = XMLfunctions.getTopNewsXML();
        Document doc = XMLfunctions.XMLfromString(xml);

        int numResults = XMLfunctions.numResults(doc);
        Log.d(LOG_TAG, "Number of Results: " + numResults);
        if ((numResults <= 0)) {
            Toast.makeText(TopNewsActivity.this, "No Result Found",Toast.LENGTH_LONG).show();
            finish();
        }

        NodeList nodes = doc.getElementsByTagName("result");

        for (int i = 0; i < nodes.getLength(); i++) {
            HashMap<String, String> map = new HashMap<String, String>();

            Element e = (Element) nodes.item(i);
            map.put("id", XMLfunctions.getValue(e, "id"));
            map.put("title", XMLfunctions.getValue(e, "title"));
            mylist.add(map);
        }
        return mylist;
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);
    }

    protected void onPostExecute(ArrayList<HashMap<String, String>> result) {
        ListAdapter adapter = new SimpleAdapter(TopNewsActivity.this, result, R.layout.list_item, new String[] { "title" }, new int[] { R.id.item_title });
        setListAdapter(adapter);
        progressDialog.dismiss();

        final ListView lv = getListView();

        lv.setTextFilterEnabled(true);  
        lv.setOnItemClickListener(new OnItemClickListener() {
            @SuppressWarnings("unchecked")
            @Override
            public void onItemClick(AdapterView<?> a, View view, final int position, long id) {

                    HashMap<String, String> o = (HashMap<String, String>) lv.getItemAtPosition(position);

                    Intent i = new Intent(TopNewsActivity.this, NewsDetails.class);
                    i.putExtra("content_id", o.get("id"));
                    i.putExtra("title", o.get("title"));
                    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

                    View v = TopNewsGroup.group.getLocalActivityManager().startActivity("ShowNews", i).getDecorView();

                    // Again, replace the view
                    TopNewsGroup.group.setContentView(v);

            }
        });

    }

}

public class MySimpleAdapter extends SimpleAdapter {
     public MySimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) {
        super(context, data, resource, from, to);
        // TODO Auto-generated constructor stub
}

}
}

Please Help!!!!!

Upvotes: 7

Views: 33707

Answers (7)

Shouheng Wang
Shouheng Wang

Reputation: 648

Take the Dialog for example.

Judge from the Android source code, let's watch what happened when you called method Dialog#show() method. The code can be simplified as below:

    public void show() {
        if (mShowing) {
            // ...
            return;
        }
        // ...
        mDecor = mWindow.getDecorView();
        mWindowManager.addView(mDecor, l);
        // ...
        mShowing = true;
        // ...
    }

The mDecor field was got from mWidnow, the mWindow field was got from Dialog's construcor:

    Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        // ...
        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        // ...
    }

So that means one Dialog has one mWindow, one mWindow has one mDecor.

When the mWindowManager.addView(mDecor, l) was called, it went to the WindowManagerGlobal#addView().

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        // ...
        synchronized (mLock) {
            // ...
            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    mRoots.get(index).doDie();
                } else {
                    // EXCEPTION HERE!!!
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
            }
            // ...
        }
    }

The WindowManagerGlobal was singleton, so that means if you add the same view to WindowManagerGlobal twice, it will crash.

We can reprocedure this exception:

val dlg = AlertDialog.Builder(context).create()
dlg.setView(View.inflate(context, R.layout.layout_dialog_title_sample, null))
dlg.show()
val f = Dialog::class.java.getDeclaredField("mShowing")
f.isAccessible = true
f.setBoolean(dlg, false)
dlg.show()

or,

        dlg = AlertDialog.Builder(context).create()
        dlg?.setView(View.inflate(context, R.layout.layout_dialog_title_sample, null))
        dlg?.show()
        dlg?.dismiss()
        for (i in 1..2) {
            Thread(Runnable {
                Looper.prepare()
                dlg?.show()
                Looper.loop()
            }).start()
        }

Above, we change the the field mShowing after the Dialog#show() was called to show the dialog 'twice'. And finally it throws the exception:

    ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    │ main, me.shouheng.suix.SampleApp$customCrash$1.onCrash(SampleApp.kt:64)
    ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
    │ ************* uncaught exception *************
    │ Time Of Crash      : 2020-01-10 14-46-43
    │ Device Manufacturer: OnePlus
    │ Device Model       : ONEPLUS A6000
    │ Android Version    : 9
    │ Android SDK        : 28
    │ App VersionName    : 1.0
    │ App VersionCode    : 1
    │ 
    │ java.lang.IllegalStateException: View DecorView@3a84c11[MainActivity] has already been added to the window manager.
    │   at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:328)
    │   at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:94)
    │   at android.app.Dialog.show(Dialog.java:329)
    │   at me.shouheng.suix.MainActivity$doCreateView$7.onClick(MainActivity.kt:72)
    │   at android.view.View.performClick(View.java:6669)
    │   at android.view.View.performClickInternal(View.java:6638)
    │   at android.view.View.access$3100(View.java:789)
    │   at android.view.View$PerformClick.run(View.java:26145)
    │   at android.os.Handler.handleCallback(Handler.java:873)
    │   at android.os.Handler.dispatchMessage(Handler.java:99)
    │   at android.os.Looper.loop(Looper.java:193)
    │   at android.app.ActivityThread.main(ActivityThread.java:6898)
    │   at java.lang.reflect.Method.invoke(Native Method)
    │   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:537)
    │   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
    └────────────────────────────────────────────────────────────────────────────────────────────────────────────────

So the final resolution of solving this problem was to check if you showed dialog twice exceptially in different thread.

Upvotes: 0

Emil Re&#241;a Enriquez
Emil Re&#241;a Enriquez

Reputation: 2971

You can use setProgressBaIndeterminateVisibility(true)

@Override
    protected void onPreExecute() {
        setProgressBarIndeterminateVisibility(true);
    }

Upvotes: 0

Zar E Ahmer
Zar E Ahmer

Reputation: 34360

try to use this code

import java.util.ArrayList;
import java.util.HashMap;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONObject;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;

import com.example.tabs.R;
import com.s3.daycare.adapters.CalendarAdapter;
import com.s3.daycare.description.CalendarDescription;

public class Calendar extends Activity {

    String url = "http://mobile.s3technology.net/DayCare/webservices/Get_calender.php?";

    GetData data;

    ProgressDialog progressDialog;

    ListView list_of_calendar;

    ArrayList<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();

    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.calendar);

        list_of_calendar = (ListView) findViewById(R.id.list_of_calendar);

        new GetData().execute();

        //ListView listView = getListView();
        list_of_calendar.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) 
            {
                HashMap<String, String> map = list.get(position);               

                Intent intent = new Intent(Calendar.this, CalendarDescription.class);

                intent.putExtra("name", map.get("name"));

                intent.putExtra("date", map.get("date"));

                intent.putExtra("description", map.get("description"));

                startActivity(intent);


            }

        });
    }

    private class GetData extends AsyncTask<String, Void, JSONObject> {

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            progressDialog = ProgressDialog.show(Calendar.this,
                    "", "");

        }

        @Override
        protected JSONObject doInBackground(String... params) {

            String response;

            try {

                HttpClient httpclient = new DefaultHttpClient();

                HttpPost httppost = new HttpPost(url);

                HttpResponse responce = httpclient.execute(httppost);

                HttpEntity httpEntity = responce.getEntity();

                response = EntityUtils.toString(httpEntity);

                Log.d("response is", response);

                return new JSONObject(response);

            } catch (Exception ex) {

                ex.printStackTrace();

            }

            return null;
        }

        @Override
        protected void onPostExecute(JSONObject result) 
        {
            super.onPostExecute(result);

            progressDialog.dismiss();

            if(result != null)
            {
                try
                {
                    JSONObject jobj = result.getJSONObject("result");

                    String status = jobj.getString("status");

                    if(status.equals("true"))
                    {
                        JSONArray array = jobj.getJSONArray("data");

                        for(int x = 0; x < array.length(); x++)
                        {
                            HashMap<String, String> map = new HashMap<String, String>();

                            map.put("name", array.getJSONObject(x).getString("name"));

                            map.put("date", array.getJSONObject(x).getString("date"));

                            map.put("description", array.getJSONObject(x).getString("description"));

                            list.add(map);
                        }

                        CalendarAdapter adapter = new CalendarAdapter(Calendar.this, list);

                        list_of_calendar.setAdapter(adapter);
                    }
                }
                catch (Exception e) 
                {
                    e.printStackTrace();
                }
            }
            else
            {
                Toast.makeText(Calendar.this, "Network Problem", Toast.LENGTH_LONG).show();
            }
        }

    }
}

Upvotes: 0

Vladimir Ivanov
Vladimir Ivanov

Reputation: 43098

if ((numResults <= 0)) {
    Toast.makeText(TopNewsActivity.this, "No Result Found.",Toast.LENGTH_LONG).show();
    finish();
}

I believe this is not a good thing to do. Don't finish your activity from the non ui thread. Just return null.

Upvotes: 2

ReNa
ReNa

Reputation: 1124

Thank you everybody but i've figured out what the problem was, I'm using ActivityGroup so I needed to put progressDialog = new ProgressDialog(TopNewsGroup.group); this solved my problem

:)

Upvotes: 1

CaseyB
CaseyB

Reputation: 25058

Try removing the super.onPreExecute();

Upvotes: 1

NotACleverMan
NotACleverMan

Reputation: 12237

There is a usual problem with progressdialogs and contexts, it happens to me all the time and there's a section on the android doc for this exact problem. You have probably declared it with a context of "this" when the context should actually be the name of your Java class followed by ".this".

dialog = ProgressDialog.show(Example.this, "",
                "Doing stuff. Please wait...", true);

This is because you want the progressDialog to show in the main class, not in the Async class.

If this doesn't solve it, you'll need to post the code.

Upvotes: 4

Related Questions