Question

I have a AsyncTask in my app which downloads data from a webserver. But when i rotate my screen, my app crashes. It's because the onPostExecute(where i storage the downloaded data) isn't executed the second time. But after a screen rotation the onCreate() method runs and so should the AsynchTask(it does) but it doesn't call the onPostExecute the second time. I hope you have a solution.

    class ProductManager{

    public ArrayList<ProductClass> productArray;

    ProductManager(){
        Log.d("LOGTAG","TAG2"); 
            new DownloadProductTask().execute();
    }

    class DownloadProductTask extends AsyncTask<String,Integer,Void>
    {
        private ProgressDialog progressDialog = new ProgressDialog(ProductList.this);
        InputStream is = null ;
        String result = "";
        @Override
        protected void onPreExecute() {         
            progressDialog.setMessage("Download data...");
            progressDialog.show();                  
            progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
                @Override
                public void onCancel(DialogInterface arg0) {
                    DownloadProductTask.this.cancel(true);
                   }
                });                            
        }
           @Override
        protected Void doInBackground(String... params) {   
               Log.d("LOGTAG","TAG2.1");
               String url_select = "http://jaspevj20.twenty.axc.nl/vhapp/displayproducts.php"; //Use http:// except for localhost & 127.0.0.1// jaspevj20.twenty.axc.nl for emulator local connection

          HttpClient httpClient = new DefaultHttpClient();
          HttpPost httpPost = new HttpPost(url_select);

          ArrayList param = new ArrayList();

            try {
            httpPost.setEntity(new UrlEncodedFormEntity(param));
            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();

            //read content
            is =  httpEntity.getContent();                  

            } catch (Exception e) {

            Log.e("log_tag", "Error in http connection "+e.toString());
            }
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line = "";
            while((line=br.readLine())!=null)
            {
               sb.append(line+"\n");
            }
                is.close();
                result=sb.toString();               

                    } catch (Exception e) {
                        // TODO: handle exception
                        Log.e("log_tag", "Error converting result "
                                            +e.toString());
                    }

                return null;

            }        
        @Override
        protected void onPostExecute(Void v) {                  
            // ambil data dari Json database
            try {   
                Log.d("LOGTAG","TAG3"); 
                JSONArray Jarray = new JSONArray(result);                                                                                               
                productArray = new ArrayList<ProductClass>();

                int productid;
                String productname;
                double productprice;
                int cookingtime;
                String productoptionsstring;
                List<String> productoptionslist;
                String productflavoursstring;
                List<String> productflavourslist;
                String productdescription;
                String category;
                List<String> categorylist;


                for(int i=0;i<Jarray.length();i++)
                            {                                                                                                                           
                                 JSONObject Jasonobject = null;                                                              
                                 Jasonobject = Jarray.getJSONObject(i);
                                 productid = Integer.parseInt(Jasonobject.getString("ProductId"));
                                 productname = Jasonobject.getString("ProductName");
                                 productprice = Double.parseDouble(Jasonobject.getString("ProductPrice"));                                       
                                 cookingtime = Integer.parseInt(Jasonobject.getString("CookingTime"));
                                 productoptionsstring = Jasonobject.getString("ProductOptions");    
                                 productoptionslist = Arrays.asList(productoptionsstring.split("\\s*,\\s*"));
                                 productflavoursstring = Jasonobject.getString("ProductFlavours");
                                 productflavourslist = Arrays.asList(productflavoursstring.split("\\s*,\\s*"));
                                 productdescription = Jasonobject.getString("ProductDescription");
                                 category = Jasonobject.getString("Category");
                                 categorylist = Arrays.asList(category.split("\\s*,\\s*"));
                                 Log.d("LOGTAG","TAG4"); 
                                 productArray.add(new ProductClass(productid,productname,productprice,cookingtime));     
                                 ProductClass product = productArray.get(productArray.size()-1);                                     
                                 product.setProductOptions(productoptionslist);
                                 product.setFlavours(productflavourslist);
                                 product.setDescription(productdescription);
                                 product.setCategories(categorylist);                                    
                            }

                mTitle = mDrawerTitle = getTitle();
                mCategoryTitles = mProductManager.getAllCategories();                                       
                // set a custom shadow that overlays the main content when the drawer opens
                mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
                mDrawerList.setAdapter(new ArrayAdapter<String>(ProductList.this,
                        R.layout.drawer_list_item, mCategoryTitles));
                mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
                // Select the first category displaying as default
                selectItem(0);              
                this.progressDialog.dismiss();                                                                                  
                     } 
            catch (Exception e) 
            {
                Log.e("log_tag", "Error parsing data "+e.toString());
            }   
        }
    }
Était-ce utile?

La solution

Actually whats more probable is that your AsyncTask actually does execute and in onPostExecute is using references to widgets (from previous Activity instance) that were destroyed by Android. Since your DownloadProductTask is internal to your Activity it hold implicit reference to your Activity and it disallows freeing your activity.

If you dont want to use android:configChanges hack - then make your AsyncTask static, then retain your AsyncTask instance using onRetainNonConfigurationInstance / getLastNonConfigurationInstance, and in onCreate update your AsyncTask with new widgets to update. Thats actually short story, its quite complicated. Other options - IMO a lot easier is to put your AsyncTask into retained fragment. Here are some info on this:

Android Fragments. Retaining an AsyncTask during screen rotation or configuration change

The problam with android:configChanges is that it does not protect you when your Activity is destroyed during normal LifeCycle changes, ie. you call you AsyncTask and then you hide your activity, and go to some other Activity - Android is now free to destroy your Activity - causing the same problems.

Autres conseils

Use a Bundle to save your Data. Or edit the Manifest for the required Activity with

Incase of Async Task, I would suggest you use the first method

android:configChanges="orientation|keyboardHidden"

Introduction to Bundle:

 @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
      super.onSaveInstanceState(savedInstanceState);
      // Save UI state changes to the savedInstanceState.
      // This bundle will be passed to onCreate if the process is
      // killed and restarted.
      savedInstanceState.putBoolean("MyBoolean", true);
      savedInstanceState.putDouble("myDouble", 1.9);
      savedInstanceState.putInt("MyInt", 1);
      savedInstanceState.putString("MyString", "Welcome back to Android");
      // etc.
    }

The Bundle is essentially a way of storing a NVP ("Name-Value Pair") map, and it will get passed in to onCreate and also onRestoreInstanceState where you'd extract the values like this:

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
  super.onRestoreInstanceState(savedInstanceState);
  // Restore UI state from the savedInstanceState.
  // This bundle has also been passed to onCreate.
  boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
  double myDouble = savedInstanceState.getDouble("myDouble");
  int myInt = savedInstanceState.getInt("MyInt");
  String myString = savedInstanceState.getString("MyString");
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top