“Activity has leaked window that was originally added here”

I have the following code where I want to synchronize Mysql to SQLITE. The problem is that when I hit the synchronization button an error appears. The data is being transmited from the Mysql server to my SQLITE but it won't appear in the activity of my app where I put the data in a list.

public class MainActivity extends ActionBarActivity {
    // DB Class to perform DB related operations
    DBController controller = new DBController(this);
    // Progress Dialog Object
    ProgressDialog prgDialog;
    HashMap<String, String> queryValues;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Get User records from SQLite DB
        ArrayList<HashMap<String, String>> userList = controller.getAllUsers();
        // If users exists in SQLite DB
        if (userList.size() != 0) {
            // Set the User Array list in ListView
            ListAdapter adapter = new SimpleAdapter(MainActivity.this, userList, R.layout.view_user_entry, new String[] {
                            "userId", "userName" }, new int[] { R.id.userId, R.id.userName });
            ListView myList = (ListView) findViewById(android.R.id.list);
            myList.setAdapter(adapter);
        }
        // Initialize Progress Dialog properties
        prgDialog = new ProgressDialog(this);
        prgDialog.setMessage("Transferring Data from Remote MySQL DB and Syncing SQLite. Please wait...");
        prgDialog.setCancelable(false);
        // BroadCase Receiver Intent Object
        Intent alarmIntent = new Intent(getApplicationContext(), SampleBC.class);
        // Pending Intent Object
        PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        // Alarm Manager Object
        AlarmManager alarmManager = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        // Alarm Manager calls BroadCast for every Ten seconds (10 * 1000), BroadCase further calls service to check if new records are inserted in 
        // Remote MySQL DB
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + 5000, 10 * 1000, pendingIntent);
    }

    // Options Menu (ActionBar Menu)
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    // When Options Menu is selected
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. 
        int id = item.getItemId();
        // When Sync action button is clicked
        if (id == R.id.refresh) {
            // Transfer data from remote MySQL DB to SQLite on Android and perform Sync
            syncSQLiteMySQLDB();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    // Method to Sync MySQL to SQLite DB
    public void syncSQLiteMySQLDB() {
        // Create AsycHttpClient object
        AsyncHttpClient client = new AsyncHttpClient();
        // Http Request Params Object
        RequestParams params = new RequestParams();
        // Show ProgressBar
        prgDialog.show();

        // Make Http call to getusers.php
        client.post("http://download.grupsapte.ro/sinc/getusers.php", params, new AsyncHttpResponseHandler() {
                @Override
                public void onSuccess(String response) {
                    // Hide ProgressBar
                    prgDialog.hide();
                    // Update SQLite DB with response sent by getusers.php
                    updateSQLite(response);
                }
                // When error occured
                @Override
                public void onFailure(int statusCode, Throwable error, String content) {
                    // TODO Auto-generated method stub
                    // Hide ProgressBar
                    prgDialog.hide();
                    if (statusCode == 404) {
                        Toast.makeText(getApplicationContext(), "Requested resource not found", Toast.LENGTH_LONG).show();
                    } else if (statusCode == 500) {
                        Toast.makeText(getApplicationContext(), "Something went wrong at server end", Toast.LENGTH_LONG).show();
                    } else {
                        Toast.makeText(getApplicationContext(), "Unexpected Error occcured! [Most common Error: Device might not be connected to Internet]",
                                Toast.LENGTH_LONG).show();
                    }
                }
        });
    }

    public void updateSQLite(String response){
        ArrayList<HashMap<String, String>> usersynclist;
        usersynclist = new ArrayList<HashMap<String, String>>();
        // Create GSON object
        Gson gson = new GsonBuilder().create();
        try {
            // Extract JSON array from the response
            JSONArray arr = new JSONArray(response);
            System.out.println(arr.length());
            // If no of array elements is not zero
            if(arr.length() != 0){
                // Loop through each array element, get JSON object which has userid and username
                for (int i = 0; i < arr.length(); i++) {
                    // Get JSON object
                    JSONObject obj = (JSONObject) arr.get(i);
                    System.out.println(obj.get("userId"));
                    System.out.println(obj.get("userName"));
                    // DB QueryValues Object to insert into SQLite
                    queryValues = new HashMap<String, String>();
                    // Add userID extracted from Object
                    queryValues.put("userId", obj.get("userId").toString());
                    // Add userName extracted from Object
                    queryValues.put("userName", obj.get("userName").toString());
                    // Insert User into SQLite DB
                    controller.insertUser(queryValues);
                    HashMap<String, String> map = new HashMap<String, String>();
                    // Add status for each User in Hashmap
                    map.put("Id", obj.get("userId").toString());
                    map.put("status", "1");
                    usersynclist.add(map);
                }
                // Inform Remote MySQL DB about the completion of Sync activity by passing Sync status of Users
                updateMySQLSyncSts(gson.toJson(usersynclist));
                // Reload the Main Activity
                reloadActivity();
            }
        } catch (JSONException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    // Method to inform remote MySQL DB about completion of Sync activity
    public void updateMySQLSyncSts(String json) {
        System.out.println(json);
        AsyncHttpClient client = new AsyncHttpClient();
        RequestParams params = new RequestParams();
        params.put("syncsts", json);
        // Make Http call to updatesyncsts.php with JSON parameter which has Sync statuses of Users
        client.post("http://download.grupsapte.ro/sinc/updatesyncsts.php", params, new AsyncHttpResponseHandler() {
            @Override
            public void onSuccess(String response) {
                Toast.makeText(getApplicationContext(), "MySQL DB has been informed about Sync activity", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onFailure(int statusCode, Throwable error, String content) {
                    Toast.makeText(getApplicationContext(), "Error Occured", Toast.LENGTH_LONG).show();
            }
        });
    }

    // Reload MainActivity
    public void reloadActivity() {
        Intent objIntent = new Intent(getApplicationContext(), MainActivity.class);
        startActivity(objIntent);
    }
}

And the error is the following:

01-18 12:54:59.821: E/WindowManager(2022): android.view.WindowLeaked: Activity com.prgguru.example.MainActivity has leaked window com.android.internal.policy.PhoneWindow$DecorView{a19b187 G.E...... R.....ID 0,0-1336,384} that was originally added here
01-18 12:54:59.821: E/WindowManager(2022):  at android.view.ViewRootImpl.<init>(ViewRootImpl.java:565)
01-18 12:54:59.821: E/WindowManager(2022):  at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:326)
01-18 12:54:59.821: E/WindowManager(2022):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
01-18 12:54:59.821: E/WindowManager(2022):  at android.app.Dialog.show(Dialog.java:350)
01-18 12:54:59.821: E/WindowManager(2022):  at com.prgguru.example.MainActivity.syncSQLiteMySQLDB(MainActivity.java:96)
01-18 12:54:59.821: E/WindowManager(2022):  at com.prgguru.example.MainActivity.onOptionsItemSelected(MainActivity.java:83)
01-18 12:54:59.821: E/WindowManager(2022):  at android.app.Activity.onMenuItemSelected(Activity.java:3204)
01-18 12:54:59.821: E/WindowManager(2022):  at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:353)
01-18 12:54:59.821: E/WindowManager(2022):  at android.support.v7.app.ActionBarActivity.superOnMenuItemSelected(ActionBarActivity.java:244)
01-18 12:54:59.821: E/WindowManager(2022):  at android.support.v7.app.ActionBarActivityDelegateICS.onMenuItemSelected(ActionBarActivityDelegateICS.java:165)
01-18 12:54:59.821: E/WindowManager(2022):  at android.support.v7.app.ActionBarActivity.onMenuItemSelected(ActionBarActivity.java:130)
01-18 12:54:59.821: E/WindowManager(2022):  at android.support.v7.app.ActionBarActivityDelegateICS$WindowCallbackWrapper.onMenuItemSelected(ActionBarActivityDelegateICS.java:300)
01-18 12:54:59.821: E/WindowManager(2022):  at com.android.internal.policy.PhoneWindow.onMenuItemSelected(PhoneWindow.java:1259)
01-18 12:54:59.821: E/WindowManager(2022):  at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:801)
01-18 12:54:59.821: E/WindowManager(2022):  at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:155)
01-18 12:54:59.821: E/WindowManager(2022):  at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:954)
01-18 12:54:59.821: E/WindowManager(2022):  at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:944)
01-18 12:54:59.821: E/WindowManager(2022):  at android.widget.ActionMenuView.invokeItem(ActionMenuView.java:655)
01-18 12:54:59.821: E/WindowManager(2022):  at com.android.internal.view.menu.ActionMenuItemView.onClick(ActionMenuItemView.java:251)
01-18 12:54:59.821: E/WindowManager(2022):  at android.view.View.performClick(View.java:5697)
01-18 12:54:59.821: E/WindowManager(2022):  at android.widget.TextView.performClick(TextView.java:10826)
01-18 12:54:59.821: E/WindowManager(2022):  at android.view.View$PerformClick.run(View.java:22526)
01-18 12:54:59.821: E/WindowManager(2022):  at android.os.Handler.handleCallback(Handler.java:739)
01-18 12:54:59.821: E/WindowManager(2022):  at android.os.Handler.dispatchMessage(Handler.java:95)
01-18 12:54:59.821: E/WindowManager(2022):  at android.os.Looper.loop(Looper.java:158)
01-18 12:54:59.821: E/WindowManager(2022):  at android.app.ActivityThread.main(ActivityThread.java:7225)
01-18 12:54:59.821: E/WindowManager(2022):  at java.lang.reflect.Method.invoke(Native Method)
01-18 12:54:59.821: E/WindowManager(2022):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
01-18 12:54:59.821: E/WindowManager(2022):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

I know I should put a this.finish() somewhere but I don't know exactly where. Hope someone to help me.

public void syncSQLiteMySQLDB() {
   // Create AsycHttpClient object
   AsyncHttpClient client = new AsyncHttpClient();
   // Http Request Params Object
   RequestParams params = new RequestParams();
   // Show ProgressBar
   prgDialog = new ProgressDialog(MainActivity.this);
   prgDialog.setMessage("Transferring Data from Remote MySQL DB and Syncing SQLite. Please wait...");
   prgDialog.setCancelable(false);
   prgDialog.show();

   // Make Http call to getusers.php
   client.post("http://download.grupsapte.ro/sinc/getusers.php", params, new AsyncHttpResponseHandler() {
           @Override
           public void onSuccess(String response) {

               // Update SQLite DB with response sent by getusers.php
               updateSQLite(response);
           }
           // When error occured
           @Override
           public void onFailure(int statusCode, Throwable error, String content) {
               // TODO Auto-generated method stub

               if (statusCode == 404) {
                   Toast.makeText(getApplicationContext(), "Requested resource not found", Toast.LENGTH_LONG).show();
               } else if (statusCode == 500) {
                   Toast.makeText(getApplicationContext(), "Something went wrong at server end", Toast.LENGTH_LONG).show();
               } else {
                   Toast.makeText(getApplicationContext(), "Unexpected Error occcured! [Most common Error: Device might not be connected to Internet]",
                           Toast.LENGTH_LONG).show();
               }
           }

            @Override
            public void onFinish(){
                // Hide ProgressBar
                if(prgDialog.isShowing())
               prgDialog.hide();
            }
   });

}

First of all you should declare local progress bar object and initialize with MainActivity.this also AsyncHttpClient have a method onFinish() which will call after success or failure called so you only need to hide your progress bar in onfinsh method and you always should check is progress bar is showing or not so it will not lead to generate excepetion

Try, Before showing the progress dialog. Check if its already showing if yes, dismiss it and show the dialog.

In syncSQLiteMySQLDB you are showing the progress dialog. First check you already have an instance of prgDialog and its showing. Then dismiss the existing prgDialog and show. and check whether the activity is not finishing before showing it.

public void syncSQLiteMySQLDB() {
....
if( !isFinishing()) {
    if(prgDialog !=null) {
        if(prgDialog.isShowing()) {
              prgDialog.dismiss()
        }
        prgDialog.show();
    }

  }
}

you need to dismiss() the progressDialog

@Override
            public void onSuccess(String response) {
                // dismiss ProgressBar
                if (prgDialog != null) {
                prgDialog.dismiss(); //not hide try dismiss the dialog
                // Update SQLite DB with response sent by getusers.php
                updateSQLite(response);
            }
        }

also in your onFailure method dismiss() the dialog

you are reloading activity without closing your dialog, so you should dismiss first.

public void reloadActivity() {
           // dissmiss dialog first then reload activity.
            if(prgDialog.isShowing()) {
              prgDialog.dismiss();
              Intent objIntent = new Intent(getApplicationContext(), MainActivity.class);
              startActivity(objIntent);
             }

    }

took a couple of minutes to find this memory leak, no need for the .show inside a prepare dialogbuilder

  @Override
  protected void onPrepareDialogBuilder(final AlertDialog.Builder builder) {

        builder
           .setIcon(getIconImage(context))
           .setTitle("title)
           .setMessage("message")
           .setPositiveButton("ok",
                  new DialogInterface.OnClickListener() {
                      public void onClick(DialogInterface dialog, int which) {
                         dialog.cancel();
                          start intent
                      }
                  })
           .setNegativeButton("cancel",
                  new DialogInterface.OnClickListener() {
                      public void onClick(DialogInterface dialog, int which) {
                         dialog.cancel();

                     }
                  })
            .show();

  }
  else{
         do something else
   }
}

Comments
  • see this... stackoverflow.com/questions/21817888/…
  • Possible duplicate of Activity has leaked window that was originally added
  • Possible duplicate of Activity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@44f72ff0 that was originally added here
  • You've created a progress dialog, but you never dismiss it. When your Activity finishes, the dialog is still active, so you get this "Activity has leaked Window" error. The linked questions have some useful information.
  • You should explain what you have done and why. Code only answers are usually not helpful.
  • @AxelH Thanks for your suggestion :)
  • ok..so the error disappeared but I don't know why the list from where I get the data isn't being populated.
  • Why ? When ? Where ? Please explain your solution by editing your answer
  • @AxelH I appreciate your suggestion buddy:)