aa4b6e4286e4c0ff18c7a1d57539adfb6264d4de
[JavaForFun] /
1 package de.example.exampletdd.fragment.map;
2
3 import java.io.IOException;
4 import java.util.List;
5 import java.util.Locale;
6
7 import android.app.Activity;
8 import android.content.Context;
9 import android.location.Address;
10 import android.location.Geocoder;
11 import android.os.AsyncTask;
12 import android.os.Bundle;
13 import android.support.v4.app.Fragment;
14 import android.util.Log;
15 import android.view.LayoutInflater;
16 import android.view.View;
17 import android.view.ViewGroup;
18 import de.example.exampletdd.R;
19 import de.example.exampletdd.model.WeatherLocation;
20
21 /**
22  * {@link http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html}
23  *
24  */
25 public class MapProgressFragment extends Fragment {
26
27         /**
28          * 
29          * Callback interface through which the fragment will report the
30          * task's progress and results back to the Activity.
31          */
32         public static interface TaskCallbacks {
33                 void onPostExecute(final WeatherLocation weatherLocation);
34         }
35         
36         private TaskCallbacks mCallbacks;
37         
38     @Override
39     public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
40                              final Bundle savedInstanceState) {
41     
42         // Inflate the layout for this fragment
43         return inflater.inflate(R.layout.weather_map_progress, container, false);
44     }
45     
46     /**
47      * This method will only be called once when the retained
48      * Fragment is first created.
49      */
50     @Override
51     public void onCreate(Bundle savedInstanceState) {
52         super.onCreate(savedInstanceState);
53         
54         // Retain this fragment across configuration changes.
55         this.setRetainInstance(true);
56         
57         final Bundle bundle = this.getArguments();
58         double latitude = bundle.getDouble("latitude");
59         double longitude = bundle.getDouble("longitude");
60         
61         // Create and execute the background task.
62         new GetAddressTask(this.getActivity().getApplicationContext()).execute(latitude, longitude);
63     }
64     
65         /**
66          * Hold a reference to the parent Activity so we can report the
67          * task's current progress and results. The Android framework 
68          * will pass us a reference to the newly created Activity after 
69          * each configuration change.
70          */
71         @Override
72         public void onAttach(final Activity activity) {
73                 super.onAttach(activity);
74                 mCallbacks = (TaskCallbacks) activity;
75         }
76         
77         /**
78          * Set the callback to null so we don't accidentally leak the 
79          * Activity instance.
80          */
81 //      @Override
82 //      public void onDetach() {
83 //              super.onDetach();
84 //              mCallbacks = null;
85 //      }
86         
87         /**
88          * I am not using onDetach because there are problems when my activity goes to background.
89          * 
90          * {@link http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html}
91          */
92         @Override
93         public void onPause() {
94                 super.onPause();
95                 mCallbacks = null;
96         }
97     
98     private class GetAddressTask extends AsyncTask<Object, Void, WeatherLocation> {
99         private static final String TAG = "GetAddressTask";
100         // Store the context passed to the AsyncTask when the system instantiates it.
101         private final Context localContext;
102
103         private GetAddressTask(final Context context) {
104                 this.localContext = context;    
105         }
106         
107         @Override
108         protected WeatherLocation doInBackground(final Object... params) {
109             final double latitude = (Double) params[0];
110             final double longitude = (Double) params[1];
111
112             WeatherLocation weatherLocation = this.doDefaultLocation(latitude, longitude);
113             try {
114                 weatherLocation = this.getLocation(latitude, longitude);
115             } catch (final Throwable e) { // Hopefully nothing goes wrong because of catching Throwable.
116                 Log.e(TAG, "GetAddressTask doInBackground exception: ", e);
117             }
118
119             return weatherLocation;
120         }
121
122         @Override
123         protected void onPostExecute(final WeatherLocation weatherLocation) {
124                 // TODO: Is AsyncTask calling this method even when RunTimeException in doInBackground method?
125                 // I hope so, otherwise I must catch(Throwable) in doInBackground method :(
126  
127             // Call updateUI on the UI thread.
128                 if (mCallbacks != null) {
129                         mCallbacks.onPostExecute(weatherLocation);
130                 }
131         }
132         
133         private WeatherLocation getLocation(final double latitude, final double longitude) throws IOException {
134                 // TODO: i18n Locale.getDefault()
135             final Geocoder geocoder = new Geocoder(this.localContext, Locale.US);
136             final List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
137
138             // Default values
139             WeatherLocation weatherLocation = this.doDefaultLocation(latitude, longitude);
140             
141             if (addresses != null && addresses.size() > 0) {
142                 if (addresses.get(0).getLocality() != null) {
143                         weatherLocation.setCity(addresses.get(0).getLocality());
144                 }
145                 if(addresses.get(0).getCountryName() != null) {
146                         weatherLocation.setCountry(addresses.get(0).getCountryName());
147                 }       
148             }
149
150             return weatherLocation;
151         }
152
153         private WeatherLocation doDefaultLocation(final double latitude, final double longitude) {
154                 // Default values
155             String city = this.localContext.getString(R.string.city_not_found);
156             String country = this.localContext.getString(R.string.country_not_found);
157
158             return new WeatherLocation()
159                         .setLatitude(latitude)
160                         .setLongitude(longitude)
161                         .setCity(city)
162                         .setCountry(country);
163         }
164     }
165 }