1 package com.weather.information.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;
19 import com.weather.information.R;
20 import com.weather.information.model.WeatherLocation;
23 * {@link http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html}
26 public class MapProgressFragment extends Fragment {
30 * Callback interface through which the fragment will report the
31 * task's progress and results back to the Activity.
33 public static interface TaskCallbacks {
34 void onPostExecute(final WeatherLocation weatherLocation);
37 private TaskCallbacks mCallbacks;
40 public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
41 final Bundle savedInstanceState) {
43 // Inflate the layout for this fragment
44 return inflater.inflate(R.layout.weather_map_progress, container, false);
48 * This method will only be called once when the retained
49 * Fragment is first created.
52 public void onCreate(Bundle savedInstanceState) {
53 super.onCreate(savedInstanceState);
55 // Retain this fragment across configuration changes.
56 this.setRetainInstance(true);
58 final Bundle bundle = this.getArguments();
59 double latitude = bundle.getDouble("latitude");
60 double longitude = bundle.getDouble("longitude");
62 // Create and execute the background task.
63 new GetAddressTask(this.getActivity().getApplicationContext()).execute(latitude, longitude);
67 * Hold a reference to the parent Activity so we can report the
68 * task's current progress and results. The Android framework
69 * will pass us a reference to the newly created Activity after
70 * each configuration change.
73 public void onAttach(final Activity activity) {
74 super.onAttach(activity);
75 mCallbacks = (TaskCallbacks) activity;
79 * Set the callback to null so we don't accidentally leak the
83 // public void onDetach() {
89 * I am not using onDetach because there are problems when my activity goes to background.
91 * {@link http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html}
94 public void onPause() {
99 private class GetAddressTask extends AsyncTask<Object, Void, WeatherLocation> {
100 private static final String TAG = "GetAddressTask";
101 // Store the context passed to the AsyncTask when the system instantiates it.
102 private final Context localContext;
104 private GetAddressTask(final Context context) {
105 this.localContext = context;
109 protected WeatherLocation doInBackground(final Object... params) {
110 final double latitude = (Double) params[0];
111 final double longitude = (Double) params[1];
113 WeatherLocation weatherLocation = this.doDefaultLocation(latitude, longitude);
115 weatherLocation = this.getLocation(latitude, longitude);
116 } catch (final Throwable e) { // Hopefully nothing goes wrong because of catching Throwable.
117 Log.e(TAG, "GetAddressTask doInBackground exception: ", e);
120 return weatherLocation;
124 protected void onPostExecute(final WeatherLocation weatherLocation) {
126 // Call updateUI on the UI thread.
127 if (mCallbacks != null) {
128 mCallbacks.onPostExecute(weatherLocation);
132 private WeatherLocation getLocation(final double latitude, final double longitude) throws IOException {
133 // TODO: i18n Locale.getDefault()
134 final Geocoder geocoder = new Geocoder(this.localContext, Locale.US);
135 final List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
138 WeatherLocation weatherLocation = this.doDefaultLocation(latitude, longitude);
140 if (addresses != null && addresses.size() > 0) {
141 if (addresses.get(0).getLocality() != null) {
142 weatherLocation.setCity(addresses.get(0).getLocality());
144 if(addresses.get(0).getCountryName() != null) {
145 weatherLocation.setCountry(addresses.get(0).getCountryName());
149 return weatherLocation;
152 private WeatherLocation doDefaultLocation(final double latitude, final double longitude) {
154 String city = this.localContext.getString(R.string.city_not_found);
155 String country = this.localContext.getString(R.string.country_not_found);
157 return new WeatherLocation()
158 .setLatitude(latitude)
159 .setLongitude(longitude)
161 .setCountry(country);