Android leaked window


A common error that occurs when you use AsyncTask to perform a background task (e.g. download a file or fetch data from a remote server) with a progress dialog to display the task progress is leaked window. This problem happens when there is a configuration change (e.g. screen rotation) that leads to destruction and re-creation of the activity. After the activity is destroyed, the progress dialog is not closed so you get the leaked window exception and your application crashes. To solve the leaked window problem, there are a lot of approaches. In this Android, I am going to show one approach to solve the problem.
In this approach, the download task is placed in a fragment. An instance of the fragment is retained across the configuration changes (not being re-created) using setRetainInstance() method. However, this is not enough. You need to close the dialog when the fragment instance is detached from its parent activity. When the fragment instance is reattached to its parent activity again after the configuration changes, you check whether the task is still running. If it is running, you display the progress dialog again. You note that the setRetainInstance() method works if the fragment is not added to back stack.



Now to have an example application to implement the solution to the leak window error, you create a new Android project. In the scr folder, you create a class called DownloadTask that extends the Fragment class. In this class, code are written to perform the download task in background, display a progress dialog, close the progress dialog when the fragment is detached from its parent activity, and redisplay it when the fragment is reattached to the activity after the configuration changes.


package com.example.androidproj;


import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
public class DownloadFragment extends Fragment{
ProgressDialog pd;
DownloadTask task;
boolean isRunning=false;
Activity context;
public void onAttach(Activity activity) {
   super.onAttach(activity);
   context=activity;
   // Display ProgressDialog if AsyncTask is running
   initProgress(activity);
   if(isRunning){
   pd.show();
   Log.e("Fragment","Download task is still running after configuration changed.");
   }   
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Control whether a fragment instance is retained across Activity re-creation
   setRetainInstance(true);
Log.e("Fragment","Fragment is created.");     
   }

public void initProgress(Activity context){
if(pd==null){
pd = new ProgressDialog(context);
pd.setTitle("Downloading the file");
pd.setMessage("Please wait.");
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMax(100);
pd.setCancelable(true);
pd.setIndeterminate(false);
}
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view=inflater.inflate(R.layout.fdownloadlayout, container, false);
Button bt=(Button)view.findViewById(R.id.btdownload);
bt.setOnClickListener(new OnClickListener(){
public void onClick(View view){
loadDownloadTask("http://upload.wikimedia.org/wikipedia/commons/3/37/Rose_Amber_Flush_20070601.jpg");
}
});
return view;
}
@Override
public void onDetach() {
// Close the ProgressDialog to avoid
// the: Activity has leaked window com.android.internal.policy... exception
if (pd != null) {
pd.dismiss(); pd=null; }
super.onDetach();
}
public void loadDownloadTask(String url){
DownloadTask task=new DownloadTask();
task.execute(url);
}
// Download task in background
  private class DownloadTask extends AsyncTask<String,Integer,Void>{
  protected void onPreExecute(){
   super.onPreExecute();
   // Display progress dialog
   pd.show();   
     }   
     protected Void doInBackground(String...params){
     URL url;
     int count;
     String outpath=Environment.getExternalStorageDirectory()+"/";  
     HttpURLConnection con=null;
     InputStream is=null;
     FileOutputStream fos=null;
     isRunning=true;
      try {
    
     url = new URL(params[0]);
     con=(HttpURLConnection)url.openConnection();
     is=con.getInputStream();
     String fullpath=url.getPath();
     String filename=fullpath.substring(fullpath.lastIndexOf('/')+1);
     outpath+=filename;
     fos=new FileOutputStream(outpath);
     int lenghtOfFile = con.getContentLength();
     byte data[] = new byte[1024];   
     long total = 0;   
     while ((count = is.read(data)) != -1) {
     total += count;
     // publishing the progress
     publishProgress((int)((total*100)/lenghtOfFile));         
     // writing data to output file
     fos.write(data, 0, count);
     }
     fos.flush();   
      } catch (IOException e) {
     e.printStackTrace();
     isRunning=false;
      }       
      finally{     
     try {
     if(is!=null)
     is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
     try {
     if(fos!=null)
     fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}       }
      return null;     
}       
     protected void onProgressUpdate(Integer... progress) {
       // Setting progress percentage
       if(pd!=null) pd.setProgress(progress[0]);
     }
   
     protected void onPostExecute(Void result){
     if(pd!=null) // Close the ProgressDialog
     pd.dismiss();    
     isRunning=false;    
     }     
    }
}

Here is the layout file (fdownload.xml) of the fragment to display the download button to the user. It will be inflated in the onCreateView method of the fragment.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical" >   
<Button  
      android:id="@+id/btdownload"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:text="Download"
      />     
</LinearLayout>


In the MainActivity that is the parent of the fragment, you write code to add the fragment to its container. Its container is a RelativeLayout in the layout file of the MainActivity ( activity_main.xml file). You need to add android:id="@+id/parentlayout" to the container so that you can refer to it later in code.

package com.example.androidproj;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends FragmentActivity {
   @Override
   protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     FragmentManager fm =(FragmentManager) getSupportFragmentManager();
     DownloadFragment fragment = (DownloadFragment) fm.findFragmentByTag("DownloadFragment");
if (fragment == null) {
fragment = new DownloadFragment();
fm.beginTransaction().add(R.id.parentlayout,fragment,"DownloadFragment").commit();
}
  }

   public void onDestroy(){
   super.onDestroy();
   Log.e("Main","The activity is destroyed.");
   }
}

Before you run the example application, don't forget to add INTERNET and WRITE_EXTERNAL_STORAGE permissions to the AndroidManifest.xml file. Otherwise, the download task doesn't work.
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Android-leaked-window

Posted by: Dara | post date: 12-05-2014 | Subject: Android Apps Development

write programming tip




This website intents to provide free and high quality tutorials, examples, exercises and solutions, questions and answers of programming and scripting languages:
C, C++, C#, Java, VB.NET, Python, VBA,PHP & Mysql, SQL, JSP, ASP.NET,HTML, CSS, JQuery, JavaScript and other applications such as MS Excel, MS Access, and MS Word. However, we don't guarantee all things of the web are accurate. If you find any error, please report it then we will take actions to correct it as soon as possible.