1 package de.example.exampletdd.fragment.map;
3 import java.io.IOException;
5 import java.util.Locale;
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;
22 * {@link http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html}
25 public class MapProgressFragment extends Fragment {
29 * Callback interface through which the fragment will report the
30 * task's progress and results back to the Activity.
32 public static interface TaskCallbacks {
33 void onPostExecute(final WeatherLocation weatherLocation);
36 private TaskCallbacks mCallbacks;
39 public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
40 final Bundle savedInstanceState) {
42 // Inflate the layout for this fragment
43 return inflater.inflate(R.layout.weather_map_progress, container, false);
47 * This method will only be called once when the retained
48 * Fragment is first created.
51 public void onCreate(Bundle savedInstanceState) {
52 super.onCreate(savedInstanceState);
54 // Retain this fragment across configuration changes.
55 this.setRetainInstance(true);
57 final Bundle bundle = this.getArguments();
58 double latitude = bundle.getDouble("latitude");
59 double longitude = bundle.getDouble("longitude");
61 // Create and execute the background task.
62 new GetAddressTask(this.getActivity().getApplicationContext()).execute(latitude, longitude);
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.
72 public void onAttach(final Activity activity) {
73 super.onAttach(activity);
74 mCallbacks = (TaskCallbacks) activity;
78 * Set the callback to null so we don't accidentally leak the
82 // public void onDetach() {
88 * I am not using onDetach because there are problems when my activity goes to background.
90 * {@link http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html}
93 public void onPause() {
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;
103 private GetAddressTask(final Context context) {
104 this.localContext = context;
108 protected WeatherLocation doInBackground(final Object... params) {
109 final double latitude = (Double) params[0];
110 final double longitude = (Double) params[1];
112 WeatherLocation weatherLocation = this.doDefaultLocation(latitude, longitude);
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);
119 return weatherLocation;
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 :(
127 // Call updateUI on the UI thread.
128 if (mCallbacks != null) {
129 mCallbacks.onPostExecute(weatherLocation);
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);
139 WeatherLocation weatherLocation = this.doDefaultLocation(latitude, longitude);
141 if (addresses != null && addresses.size() > 0) {
142 if (addresses.get(0).getLocality() != null) {
143 weatherLocation.setCity(addresses.get(0).getLocality());
145 if(addresses.get(0).getCountryName() != null) {
146 weatherLocation.setCountry(addresses.get(0).getCountryName());
150 return weatherLocation;
153 private WeatherLocation doDefaultLocation(final double latitude, final double longitude) {
155 String city = this.localContext.getString(R.string.city_not_found);
156 String country = this.localContext.getString(R.string.country_not_found);
158 return new WeatherLocation()
159 .setLatitude(latitude)
160 .setLongitude(longitude)
162 .setCountry(country);