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!!!!!
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.
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.
Try removing the super.onPreExecute();
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
:)
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();
}
}
}
}
You can use setProgressBaIndeterminateVisibility(true)
@Override
protected void onPreExecute() {
setProgressBarIndeterminateVisibility(true);
}
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.
精彩评论