Note that there are some explanatory texts on larger screens.

plurals
  1. POAsyncTask and changes of orientation
    text
    copied!<p>I've problem with the re-creation of the activity, the progress dialog and the Async Task when change the orientation of the screen. I saw some solutions here and i decided to use the onRetainCustomNonConfigurationInstance() to save the instance of AsyncTask. Well, in onCreate i check if there is an instance of AsyncTask and, if exist, i show a new Progress Dialog. But this dialog blocks the UI in an infinite loop (in the onPostExecute there is dialog.dismiss() ) and the activity doesn't show the results of course. </p> <p><strong>onCreate</strong></p> <pre class="lang-java prettyprint-override"><code>getDirection = (GetDirection) getLastCustomNonConfigurationInstance(); if(getDirection != null) { dialog = new ProgressDialog(RouteActivity.this); dialog.setMessage(getResources().getString(R.string.loading_data)); dialog.setIndeterminate(false); dialog.setCancelable(false); dialog.show(); } else { getDirection = new GetDirection(); getDirection.execute(); } </code></pre> <p><strong>onRetainCustomNonConfigurationInstance</strong></p> <pre class="lang-java prettyprint-override"><code>@Override public Object onRetainCustomNonConfigurationInstance() { return getDirection; } @Override protected void onDestroy() { super.onDestroy(); if (dialog.isShowing()) { dialog.dismiss(); } } </code></pre> <p><strong>EDIT #1</strong>: I adopted the solution of Kingfisher with Fragment and Retained Fragment but there is a NPE on Expandable Listview when i change the orientation during the doInBackground of AsyncTask. </p> <pre class="lang-java prettyprint-override"><code>08-14 12:50:40.866: E/AndroidRuntime(22739): FATAL EXCEPTION: main 08-14 12:50:40.866: E/AndroidRuntime(22739): java.lang.NullPointerException 08-14 12:50:40.866: E/AndroidRuntime(22739): at com.pasquini.adapter.ListRouteExpandableAdapter.getGroupCount(ListRouteExpandableAdapter.java:78) 08-14 12:50:40.866: E/AndroidRuntime(22739): at android.widget.ExpandableListConnector.getCount(ExpandableListConnector.java:399) 08-14 12:50:40.866: E/AndroidRuntime(22739): at android.widget.ListView.setAdapter(ListView.java:460) 08-14 12:50:40.866: E/AndroidRuntime(22739): at android.widget.ExpandableListView.setAdapter(ExpandableListView.java:470) 08-14 12:50:40.866: E/AndroidRuntime(22739): at com.pasquini.activity.RouteActivity.onPostExecute(RouteActivity.java:792) 08-14 12:50:40.866: E/AndroidRuntime(22739): at com.pasquini.fragment.GetDirectionFragment$GetDirectionTask.onPostExecute(GetDirectionFragment.java:244) 08-14 12:50:40.866: E/AndroidRuntime(22739): at com.pasquini.fragment.GetDirectionFragment$GetDirectionTask.onPostExecute(GetDirectionFragment.java:1) 08-14 12:50:40.866: E/AndroidRuntime(22739): at android.os.AsyncTask.finish(AsyncTask.java:631) 08-14 12:50:40.866: E/AndroidRuntime(22739): at android.os.AsyncTask.access$600(AsyncTask.java:177) 08-14 12:50:40.866: E/AndroidRuntime(22739): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644) 08-14 12:50:40.866: E/AndroidRuntime(22739): at android.os.Handler.dispatchMessage(Handler.java:99) 08-14 12:50:40.866: E/AndroidRuntime(22739): at android.os.Looper.loop(Looper.java:137) 08-14 12:50:40.866: E/AndroidRuntime(22739): at android.app.ActivityThread.main(ActivityThread.java:4895) 08-14 12:50:40.866: E/AndroidRuntime(22739): at java.lang.reflect.Method.invokeNative(Native Method) 08-14 12:50:40.866: E/AndroidRuntime(22739): at java.lang.reflect.Method.invoke(Method.java:511) 08-14 12:50:40.866: E/AndroidRuntime(22739): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994) 08-14 12:50:40.866: E/AndroidRuntime(22739): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761) 08-14 12:50:40.866: E/AndroidRuntime(22739): at dalvik.system.NativeStart.main(Native Method). </code></pre> <p><strong>Here the code in Fragment:</strong></p> <pre class="lang-java prettyprint-override"><code>public class GetDirectionFragment extends Fragment { private Map&lt;Leg, List&lt;Step&gt;&gt; legsCollection; private ArrayList&lt;Object&gt; legsAndSteps; private List&lt;Leg&gt; legs; private List&lt;Poi&gt; pois; private List&lt;LatLng&gt; polyz; /** * Callback interface through which the fragment will report the * task's progress and results back to the Activity. */ public static interface TaskCallbacks { void onPreExecute(); void onPostExecute(); List&lt;Poi&gt; getListPoiByRoute(); void setLegs(List&lt;Leg&gt; legs, Map&lt;Leg, List&lt;Step&gt;&gt; legsCollection); void setPolyline(List&lt;LatLng&gt; polyz); } private TaskCallbacks callbacks; private GetDirectionTask getDirectionTask; /** * Hold a reference to the parent Activity so we can report the * task's current progress and results. The Android framework * will pass us a reference to the newly created Activity after * each configuration change. */ @Override public void onAttach(Activity activity) { super.onAttach(activity); try { callbacks = (TaskCallbacks) activity; } catch(ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement TaskCallbacks"); } pois = callbacks.getListPoiByRoute(); } /** * This method will only be called once when the retained * Fragment is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Retain this fragment across configuration changes. setRetainInstance(true); // Create and execute the background task. getDirectionTask = new GetDirectionTask(); getDirectionTask.execute(); } /** * Set the callback to null so we don't accidentally leak the * Activity instance. */ @Override public void onDetach() { super.onDetach(); callbacks = null; } private class GetDirectionTask extends AsyncTask&lt;Void, Integer, Void&gt; { @Override protected void onPreExecute() { if (callbacks != null) { callbacks.onPreExecute(); } } /** * Note that we do NOT call the callback object's methods * directly from the background thread, as this could result * in a race condition. */ @Override protected Void doInBackground(Void... ignore) { List&lt;String&gt; lats = new ArrayList&lt;String&gt;(); List&lt;String&gt; longs = new ArrayList&lt;String&gt;(); for(Poi poi: pois) { lats.add(poi.getCoordinates().getLatitude()); longs.add(poi.getCoordinates().getLongitude()); } String stringUrl = "http://maps.googleapis.com/maps/api/directions/" + "json?"; //if(actualLanguage.equals("en")) { // stringUrl += "language=en_EN"; //} else { stringUrl += "language=it"; //} stringUrl+="&amp;mode=walking&amp;units=metric&amp;origin=" + lats.get(0) + "," + longs.get(0); stringUrl += "&amp;destination=" + lats.get(pois.size()-1) + "," + longs.get(pois.size()-1) + "&amp;" + "waypoints="; for(int i = 1; i&lt;=lats.size()-2 &amp;&amp; i&lt;=longs.size()-2; i++) { stringUrl += lats.get(i)+","+longs.get(i); if(i==(lats.size()-2) &amp;&amp; i==(longs.size()-2)) { stringUrl += "&amp;sensor=false"; } else { stringUrl +="|"; } } Log.i("urlgoogle", stringUrl); StringBuilder response = new StringBuilder(); try { URL url = new URL(stringUrl); HttpURLConnection httpconn = (HttpURLConnection) url .openConnection(); if (httpconn.getResponseCode() == HttpURLConnection.HTTP_OK) { BufferedReader input = new BufferedReader( new InputStreamReader(httpconn.getInputStream()), 8192); String strLine = null; while ((strLine = input.readLine()) != null) { response.append(strLine); } input.close(); } String jsonOutput = response.toString(); JSONObject jsonObject = new JSONObject(jsonOutput); // routesArray contains ALL routes JSONArray routesArray = jsonObject.getJSONArray("routes"); // Grab the first route JSONObject route = routesArray.getJSONObject(0); JSONArray legsArray = route.getJSONArray("legs"); legs = new ArrayList&lt;Leg&gt;(); legsAndSteps = new ArrayList&lt;Object&gt;(); String htmlInstructions; legsCollection = new LinkedHashMap&lt;Leg, List&lt;Step&gt;&gt;(); for(int i=0; i&lt;legsArray.length(); i++) { List&lt;Step&gt; steps = new ArrayList&lt;Step&gt;(); Leg leg = new Leg(); //int idLeg = 0; JSONObject legJson = legsArray.getJSONObject(i); leg.setDistance(legJson.getJSONObject("distance").getString("text")); leg.setDuration(legJson.getJSONObject("duration").getString("text")); leg.setEndAddress(legJson.getString("end_address")); leg.setStartAddress(legJson.getString("start_address")); leg.setIdLeg(pois.get(i).getId()); leg.setStartPoiName(pois.get(i).getName()); leg.setEndPoiName(pois.get(i+1).getName()); legsAndSteps.add(leg); JSONArray stepsArray = legJson.getJSONArray("steps"); for(int j=0; j&lt;stepsArray.length(); j++) { Step step = new Step(); JSONObject stepJson = stepsArray.getJSONObject(j); step.setDistance(stepJson.getJSONObject("distance").getString("text")); step.setDuration(stepJson.getJSONObject("duration").getString("text")); htmlInstructions = android.text.Html.fromHtml(stepJson.getString("html_instructions")).toString(); step.setInstructions(htmlInstructions); //step.setIdLeg(idLeg); //Aggiunto per Exp steps.add(step); legsAndSteps.add(step); } legsCollection.put(leg, steps); legs.add(leg); } JSONObject poly = route.getJSONObject("overview_polyline"); String polyline = poly.getString("points"); polyz = decodePoly(polyline); callbacks.setLegs(legs, legsCollection); callbacks.setPolyline(polyz); } catch (Exception e) { } return null; } @Override protected void onPostExecute(Void ignore) { if (callbacks != null) { callbacks.onPostExecute(); } } } /* Method to decode polyline points */ private List&lt;LatLng&gt; decodePoly(String encoded) { [code...] } </code></pre> <p>}</p> <p><strong>Here the code in Activity</strong>:</p> <pre class="lang-java prettyprint-override"><code> @Override public void onPostExecute() { expListView = (ExpandableListView) findViewById(R.id.lv_routepoi); ListRouteExpandableAdapter expListAdapter = new ListRouteExpandableAdapter( getApplicationContext(), legs, legsCollection); expListView.setAdapter(expListAdapter); setGroupIndicatorToRight(); expListView.setChildDivider(getResources().getDrawable(R.drawable.divider_route)); [code...] dialog.dismiss(); } @Override public void setLegs(List&lt;Leg&gt; legs, Map&lt;Leg, List&lt;Step&gt;&gt; legsCollection) { this.legs = legs; this.legsCollection = legsCollection; } @Override public void setPolyline(List&lt;LatLng&gt; polyz) { this.polyz = polyz; } </code></pre> <p><strong>EDIT #2</strong>: I tried the new solution of Kingfisher but there is always an NPE in doInBackground method. If i don't change the orientation of screen during the loading, app doesn't crash and show data on listview.</p> <pre class="lang-java prettyprint-override"><code>08-14 17:27:44.897: I/AsyncTask(30604): java.lang.NullPointerException 08-14 17:27:44.897: E/AndroidRuntime(30604): FATAL EXCEPTION: main 08-14 17:27:44.897: E/AndroidRuntime(30604): java.lang.NullPointerException 08-14 17:27:44.897: E/AndroidRuntime(30604): at com.pasquini.activity.RouteActivity.onPostExecute(RouteActivity.java:847) 08-14 17:27:44.897: E/AndroidRuntime(30604): at com.pasquini.fragment.GetDirectionFragment$GetDirectionTask.onPostExecute(GetDirectionFragment.java:253) 08-14 17:27:44.897: E/AndroidRuntime(30604): at com.pasquini.fragment.GetDirectionFragment$GetDirectionTask.onPostExecute(GetDirectionFragment.java:1) 08-14 17:27:44.897: E/AndroidRuntime(30604): at android.os.AsyncTask.finish(AsyncTask.java:631) 08-14 17:27:44.897: E/AndroidRuntime(30604): at android.os.AsyncTask.access$600(AsyncTask.java:177) 08-14 17:27:44.897: E/AndroidRuntime(30604): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644) 08-14 17:27:44.897: E/AndroidRuntime(30604): at android.os.Handler.dispatchMessage(Handler.java:99) 08-14 17:27:44.897: E/AndroidRuntime(30604): at android.os.Looper.loop(Looper.java:137) 08-14 17:27:44.897: E/AndroidRuntime(30604): at android.app.ActivityThread.main(ActivityThread.java:4895) 08-14 17:27:44.897: E/AndroidRuntime(30604): at java.lang.reflect.Method.invokeNative(Native Method) 08-14 17:27:44.897: E/AndroidRuntime(30604): at java.lang.reflect.Method.invoke(Method.java:511) 08-14 17:27:44.897: E/AndroidRuntime(30604): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994) 08-14 17:27:44.897: E/AndroidRuntime(30604): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761) 08-14 17:27:44.897: E/AndroidRuntime(30604): at dalvik.system.NativeStart.main(Native Method) </code></pre> <p><strong>Here the code in Fragment:</strong></p> <pre class="lang-java prettyprint-override"><code>public class GetDirectionFragment extends Fragment { private Map&lt;Leg, List&lt;Step&gt;&gt; legsCollection; private ArrayList&lt;Object&gt; legsAndSteps; private List&lt;Leg&gt; legs; private List&lt;Poi&gt; pois; private List&lt;LatLng&gt; polyz; /** * Callback interface through which the fragment will report the * task's progress and results back to the Activity. */ public static interface TaskCallbacks { void onPreExecute(); void onPostExecute(); List&lt;Poi&gt; getListPoiByRoute(); void setLegs(List&lt;Leg&gt; legs, Map&lt;Leg, List&lt;Step&gt;&gt; legsCollection); void setPolyline(List&lt;LatLng&gt; polyz); } private TaskCallbacks callbacks; private GetDirectionTask getDirectionTask; /** * Hold a reference to the parent Activity so we can report the * task's current progress and results. The Android framework * will pass us a reference to the newly created Activity after * each configuration change. */ @Override public void onAttach(Activity activity) { super.onAttach(activity); try { callbacks = (TaskCallbacks) activity; } catch(ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement TaskCallbacks"); } pois = callbacks.getListPoiByRoute(); } /** * This method will only be called once when the retained * Fragment is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Retain this fragment across configuration changes. setRetainInstance(true); // Create and execute the background task. getDirectionTask = new GetDirectionTask(); getDirectionTask.execute(); } /** * Set the callback to null so we don't accidentally leak the * Activity instance. */ @Override public void onDetach() { super.onDetach(); callbacks = null; } private class GetDirectionTask extends AsyncTask&lt;Void, Integer, Void&gt; { @Override protected void onPreExecute() { if (callbacks != null) { callbacks.onPreExecute(); } } /** * Note that we do NOT call the callback object's methods * directly from the background thread, as this could result * in a race condition. */ @Override protected Void doInBackground(Void... ignore) { List&lt;String&gt; lats = new ArrayList&lt;String&gt;(); List&lt;String&gt; longs = new ArrayList&lt;String&gt;(); for(Poi poi: pois) { lats.add(poi.getCoordinates().getLatitude()); longs.add(poi.getCoordinates().getLongitude()); } String stringUrl = "http://maps.googleapis.com/maps/api/directions/" + "json?"; //if(actualLanguage.equals("en")) { // stringUrl += "language=en_EN"; //} else { stringUrl += "language=it"; //} stringUrl+="&amp;mode=walking&amp;units=metric&amp;origin=" + lats.get(0) + "," + longs.get(0); stringUrl += "&amp;destination=" + lats.get(pois.size()-1) + "," + longs.get(pois.size()-1) + "&amp;" + "waypoints="; for(int i = 1; i&lt;=lats.size()-2 &amp;&amp; i&lt;=longs.size()-2; i++) { stringUrl += lats.get(i)+","+longs.get(i); if(i==(lats.size()-2) &amp;&amp; i==(longs.size()-2)) { stringUrl += "&amp;sensor=false"; } else { stringUrl +="|"; } } Log.i("urlgoogle", stringUrl); StringBuilder response = new StringBuilder(); try { URL url = new URL(stringUrl); HttpURLConnection httpconn = (HttpURLConnection) url .openConnection(); if (httpconn.getResponseCode() == HttpURLConnection.HTTP_OK) { BufferedReader input = new BufferedReader( new InputStreamReader(httpconn.getInputStream()), 8192); String strLine = null; while ((strLine = input.readLine()) != null) { response.append(strLine); } input.close(); } String jsonOutput = response.toString(); JSONObject jsonObject = new JSONObject(jsonOutput); // routesArray contains ALL routes JSONArray routesArray = jsonObject.getJSONArray("routes"); // Grab the first route JSONObject route = routesArray.getJSONObject(0); JSONArray legsArray = route.getJSONArray("legs"); legs = new ArrayList&lt;Leg&gt;(); legsAndSteps = new ArrayList&lt;Object&gt;(); String htmlInstructions; legsCollection = new LinkedHashMap&lt;Leg, List&lt;Step&gt;&gt;(); for(int i=0; i&lt;legsArray.length(); i++) { List&lt;Step&gt; steps = new ArrayList&lt;Step&gt;(); Leg leg = new Leg(); //int idLeg = 0; JSONObject legJson = legsArray.getJSONObject(i); leg.setDistance(legJson.getJSONObject("distance").getString("text")); leg.setDuration(legJson.getJSONObject("duration").getString("text")); leg.setEndAddress(legJson.getString("end_address")); leg.setStartAddress(legJson.getString("start_address")); leg.setIdLeg(pois.get(i).getId()); leg.setStartPoiName(pois.get(i).getName()); leg.setEndPoiName(pois.get(i+1).getName()); legsAndSteps.add(leg); JSONArray stepsArray = legJson.getJSONArray("steps"); for(int j=0; j&lt;stepsArray.length(); j++) { Step step = new Step(); JSONObject stepJson = stepsArray.getJSONObject(j); step.setDistance(stepJson.getJSONObject("distance").getString("text")); step.setDuration(stepJson.getJSONObject("duration").getString("text")); htmlInstructions = android.text.Html.fromHtml(stepJson.getString("html_instructions")).toString(); step.setInstructions(htmlInstructions); //step.setIdLeg(idLeg); steps.add(step); legsAndSteps.add(step); } legsCollection.put(leg, steps); legs.add(leg); } JSONObject poly = route.getJSONObject("overview_polyline"); String polyline = poly.getString("points"); polyz = decodePoly(polyline); setLegs(legs, legsCollection); setPolyline(polyz); } catch (Exception e) { Log.i(TAG, e.toString()); } return null; } @Override protected void onPostExecute(Void ignore) { if (callbacks != null) { callbacks.onPostExecute(); } } } /* Method to decode polyline points */ private List&lt;LatLng&gt; decodePoly(String encoded) { [code...] } public void setLegs(List&lt;Leg&gt; legs, Map&lt;Leg, List&lt;Step&gt;&gt; legsCollection) { this.legs = legs; this.legsCollection = legsCollection; } public void setPolyline(List&lt;LatLng&gt; polyz) { this.polyz = polyz; } public List&lt;Leg&gt; getLegs() { return this.legs; } public Map&lt;Leg, List&lt;Step&gt;&gt; getMap() { return this.legsCollection; } public List&lt;LatLng&gt; getPolyline() { return this.polyz; } </code></pre> <p>}</p> <p><strong>Here the code in Activity</strong>:</p> <pre class="lang-java prettyprint-override"><code>@Override protected void onCreate(Bundle savedInstanceState) { [code...] FragmentManager fm = getSupportFragmentManager(); getDirectionFragment = (GetDirectionFragment) fm.findFragmentByTag(TASK_FRAGMENT_TAG); // If the Fragment is non-null, then it is currently being // retained across a configuration change. if (getDirectionFragment == null) { getDirectionFragment = new GetDirectionFragment(); fm.beginTransaction().add(getDirectionFragment, TASK_FRAGMENT_TAG).commit(); [code...] } @Override public void onPostExecute() { legs = getDirectionFragment.getLegs(); legsCollection = getDirectionFragment.getMap(); polyz = getDirectionFragment.getPolyline(); expListView = (ExpandableListView) findViewById(R.id.lv_routepoi); ListRouteExpandableAdapter expListAdapter = new ListRouteExpandableAdapter( getApplicationContext(), legs, legsCollection); expListView.setAdapter(expListAdapter); setGroupIndicatorToRight(); expListView.setChildDivider(getResources().getDrawable(R.drawable.divider_route)); [code...] } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload