From 9826b5e9e7a2b7736a8b625e437a585fcfb61f59 Mon Sep 17 00:00:00 2001 From: "gu.martinm@gmail.com" Date: Mon, 15 Sep 2014 19:52:14 +0200 Subject: [PATCH] WeatherInformation: usind broadcastrecevier Because there are many problems when screen rotates I am going to use local broadcast receiver. Android sucks a lot!!!! --- .../src/de/example/exampletdd/MapActivity.java | 100 ++++++++++++++------- .../fragment/current/CurrentFragment.java | 72 +++++++++++---- .../fragment/overview/OverviewFragment.java | 92 +++++++++++++------ 3 files changed, 193 insertions(+), 71 deletions(-) diff --git a/Android/WeatherInformation/src/de/example/exampletdd/MapActivity.java b/Android/WeatherInformation/src/de/example/exampletdd/MapActivity.java index 92fea33..7df3ba0 100644 --- a/Android/WeatherInformation/src/de/example/exampletdd/MapActivity.java +++ b/Android/WeatherInformation/src/de/example/exampletdd/MapActivity.java @@ -7,8 +7,10 @@ import java.util.Locale; import android.app.ActionBar; import android.app.Activity; import android.app.Dialog; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.IntentSender.SendIntentException; import android.location.Address; import android.location.Geocoder; @@ -18,10 +20,10 @@ import android.os.Build; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; +import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.view.View; import android.widget.Button; -import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; @@ -53,14 +55,16 @@ public class MapActivity extends FragmentActivity implements // Request code to use when launching the resolution activity private static final int REQUEST_RESOLVE_ERROR = 1001; private WeatherLocation mRestoreUI; + private BroadcastReceiver mReceiver; // Google Play Services Map private GoogleMap mMap; // TODO: read and store from different threads? Hopefully always from UI thread. private Marker mMarker; - private ProgressBar mActivityIndicator; - // true progress bar visible/false progress bar gone - private boolean mIsProgressBarVisible; + // IT IS IMPOSSIBLE IF SCREEN MAY ROTATE!!!! ANDROID SUCKS!!!! +// private ProgressBar mActivityIndicator; +// // true progress bar visible/false progress bar gone +// private boolean mIsProgressBarVisible; // Google Play Services Location private GoogleApiClient mGoogleApiClient; @@ -99,15 +103,15 @@ public class MapActivity extends FragmentActivity implements this.mMap.setOnMapLongClickListener(new MapActivityOnMapLongClickListener(this)); // Progress bar. View and status (we keep status even after screen rotations. - this.mActivityIndicator = (ProgressBar) this.findViewById(R.id.weather_map_progress); - if (savedInstanceState != null) { - this.mIsProgressBarVisible = savedInstanceState.getBoolean("mIsProgressBarVisible", false); - } - if (this.mIsProgressBarVisible) { - this.mActivityIndicator.setVisibility(View.VISIBLE); - } else { - this.mActivityIndicator.setVisibility(View.GONE); - } +// this.mActivityIndicator = (ProgressBar) this.findViewById(R.id.weather_map_progress); +// if (savedInstanceState != null) { +// this.mIsProgressBarVisible = savedInstanceState.getBoolean("mIsProgressBarVisible", false); +// } +// if (this.mIsProgressBarVisible) { +// this.mActivityIndicator.setVisibility(View.VISIBLE); +// } else { +// this.mActivityIndicator.setVisibility(View.GONE); +// } } @Override @@ -138,7 +142,7 @@ public class MapActivity extends FragmentActivity implements // just once this.mRestoreUI = null; } else { - final DatabaseQueries query = new DatabaseQueries(this); + final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext()); weatherLocation = query.queryDataBase(); } @@ -169,7 +173,7 @@ public class MapActivity extends FragmentActivity implements savedInstanceState.putSerializable("WeatherLocation", location); } // Save progress bar status. - savedInstanceState.putBoolean("mIsProgressBarVisible", this.mIsProgressBarVisible); +// savedInstanceState.putBoolean("mIsProgressBarVisible", this.mIsProgressBarVisible); // Google Play Services // To keep track of the boolean across activity restarts (such as when @@ -190,7 +194,7 @@ public class MapActivity extends FragmentActivity implements final String cityString = city.getText().toString(); final String countryString = country.getText().toString(); - final DatabaseQueries query = new DatabaseQueries(this); + final DatabaseQueries query = new DatabaseQueries(this.getApplicationContext()); final WeatherLocation weatherLocation = query.queryDataBase(); if (weatherLocation != null) { weatherLocation @@ -265,9 +269,9 @@ public class MapActivity extends FragmentActivity implements protected void onPreExecute() { // TODO: The same with Overview and Current? I guess so... // Show the activity indicator - final MapActivity activity = (MapActivity) this.localContext; - activity.mActivityIndicator.setVisibility(View.VISIBLE); - activity.mIsProgressBarVisible = true; +// final MapActivity activity = (MapActivity) this.localContext; +// activity.mActivityIndicator.setVisibility(View.VISIBLE); +// activity.mIsProgressBarVisible = true; } @Override @@ -287,20 +291,18 @@ public class MapActivity extends FragmentActivity implements @Override protected void onPostExecute(final WeatherLocation weatherLocation) { - final MapActivity activity = (MapActivity) this.localContext; - activity.mActivityIndicator.setVisibility(View.GONE); - activity.mIsProgressBarVisible = false; - // TODO: Is AsyncTask calling this method even when RunTimeException in doInBackground method? - // I hope so, otherwise I must catch(Throwable) in doInBackground method :( - if (weatherLocation == null) { - // TODO: if user changed activity, where is this going to appear? - final DialogFragment newFragment = ErrorDialogFragment.newInstance(R.string.error_dialog_location_error); - newFragment.show(activity.getSupportFragmentManager(), "errorDialog"); - return; - } + // I hope so, otherwise I must catch(Throwable) in doInBackground method :( + if (weatherLocation == null) { + // Nothing to do + // TODO: Should I show some error message? I am not doing it on WP8 Should I do it on WP8? + return; + } - activity.updateUI(weatherLocation); + // Call updateUI on the UI thread. + final Intent weatherLocationData = new Intent("de.example.exampletdd.UPDATEWEATHERLOCATION"); + weatherLocationData.putExtra("weatherLocation", weatherLocation); + LocalBroadcastManager.getInstance(this.localContext).sendBroadcastSync(weatherLocationData); } private WeatherLocation getLocation(final double latitude, final double longitude) throws IOException { @@ -434,6 +436,36 @@ public class MapActivity extends FragmentActivity implements if (!mResolvingError) { mGoogleApiClient.connect(); } + + this.mReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + if (action.equals("de.example.exampletdd.UPDATEWEATHERLOCATION")) { + final WeatherLocation weatherLocation = (WeatherLocation) intent.getSerializableExtra("weatherLocation"); + +// MapActivity.this.mActivityIndicator.setVisibility(View.GONE); +// MapActivity.this.mIsProgressBarVisible = false; + + // TODO: Is AsyncTask calling this method even when RunTimeException in doInBackground method? + // I hope so, otherwise I must catch(Throwable) in doInBackground method :( + if (weatherLocation == null) { + final DialogFragment newFragment = ErrorDialogFragment.newInstance(R.string.error_dialog_location_error); + newFragment.setRetainInstance(true); + newFragment.show(MapActivity.this.getSupportFragmentManager(), "errorDialog"); + return; + } + + MapActivity.this.updateUI(weatherLocation); + } + } + }; + + // Register receiver + final IntentFilter filter = new IntentFilter(); + filter.addAction("de.example.exampletdd.UPDATEWEATHERLOCATION"); + LocalBroadcastManager.getInstance(this.getApplicationContext()).registerReceiver(this.mReceiver, filter); } /** @@ -449,6 +481,8 @@ public class MapActivity extends FragmentActivity implements mGoogleApiClient.unregisterConnectionFailedListener(this); mGoogleApiClient.disconnect(); + LocalBroadcastManager.getInstance(this.getApplicationContext()).unregisterReceiver(this.mReceiver); + super.onStop(); } @@ -492,6 +526,8 @@ public class MapActivity extends FragmentActivity implements /** * Called by Location Services if the attempt to * Location Services fails. + * + * IT NEVER DOES ANYTHING. ANDROID SUCKS!!! */ @Override public void onConnectionFailed(final ConnectionResult result) { @@ -535,6 +571,8 @@ public class MapActivity extends FragmentActivity implements * LocationUpdateRemover and LocationUpdateRequester may call startResolutionForResult() to * start an Activity that handles Google Play services problems. The result of this * call returns here, to onActivityResult. + * + * IT NEVER DOES ANYTHING. ANDROID SUCKS!!! */ @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent intent) { diff --git a/Android/WeatherInformation/src/de/example/exampletdd/fragment/current/CurrentFragment.java b/Android/WeatherInformation/src/de/example/exampletdd/fragment/current/CurrentFragment.java index b605248..ca61875 100644 --- a/Android/WeatherInformation/src/de/example/exampletdd/fragment/current/CurrentFragment.java +++ b/Android/WeatherInformation/src/de/example/exampletdd/fragment/current/CurrentFragment.java @@ -13,6 +13,10 @@ import java.util.Locale; import org.apache.http.client.ClientProtocolException; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -21,6 +25,7 @@ import android.os.AsyncTask; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; +import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -42,6 +47,7 @@ import de.example.exampletdd.service.ServiceParser; public class CurrentFragment extends Fragment { private static final String TAG = "CurrentFragment"; + private BroadcastReceiver mReceiver; @Override public void onCreate(final Bundle savedInstanceState) { @@ -75,10 +81,45 @@ public class CurrentFragment extends Fragment { } @Override + public void onStart() { + super.onStart(); + + this.mReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + if (action.equals("de.example.exampletdd.UPDATECURRENT")) { + final Current current = (Current) intent.getSerializableExtra("current"); + + if (current != null) { + CurrentFragment.this.updateUI(current); + + final WeatherInformationApplication application = + (WeatherInformationApplication) getActivity().getApplication(); + application.setCurrent(current); + + final DatabaseQueries query = new DatabaseQueries(CurrentFragment.this.getActivity().getApplicationContext()); + final WeatherLocation weatherLocation = query.queryDataBase(); + weatherLocation.setLastCurrentUIUpdate(new Date()); + query.updateDataBase(weatherLocation); + } + } + } + }; + + // Register receiver + final IntentFilter filter = new IntentFilter(); + filter.addAction("de.example.exampletdd.UPDATECURRENT"); + LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext()) + .registerReceiver(this.mReceiver, filter); + } + + @Override public void onResume() { super.onResume(); - final DatabaseQueries query = new DatabaseQueries(this.getActivity()); + final DatabaseQueries query = new DatabaseQueries(this.getActivity().getApplicationContext()); final WeatherLocation weatherLocation = query.queryDataBase(); if (weatherLocation == null) { // Nothing to do. @@ -95,7 +136,7 @@ public class CurrentFragment extends Fragment { // Load remote data (aynchronous) // Gets the data from the web. final CurrentTask task = new CurrentTask( - this, + this.getActivity().getApplicationContext(), new CustomHTTPClient(AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent")), new ServiceParser(new JPOSWeatherParser())); @@ -121,6 +162,13 @@ public class CurrentFragment extends Fragment { super.onSaveInstanceState(savedInstanceState); } + @Override + public void onStop() { + LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext()).unregisterReceiver(this.mReceiver); + + super.onStop(); + } + private void updateUI(final Current current) { final SharedPreferences sharedPreferences = PreferenceManager @@ -287,13 +335,14 @@ public class CurrentFragment extends Fragment { // I mean, if OverviewTask shows one progress dialog and CurrentTask does the same I will have // have two progress dialogs... How may I solve this problem? I HATE ANDROID. private class CurrentTask extends AsyncTask { - private final Fragment localFragment; + // Store the context passed to the AsyncTask when the system instantiates it. + private final Context localContext; final CustomHTTPClient weatherHTTPClient; final ServiceParser weatherService; - public CurrentTask(final Fragment fragment, final CustomHTTPClient weatherHTTPClient, + public CurrentTask(final Context context, final CustomHTTPClient weatherHTTPClient, final ServiceParser weatherService) { - this.localFragment = fragment; + this.localContext = context; this.weatherHTTPClient = weatherHTTPClient; this.weatherService = weatherService; } @@ -353,16 +402,9 @@ public class CurrentFragment extends Fragment { } // Call updateUI on the UI thread. - updateUI(current); - - final WeatherInformationApplication application = - (WeatherInformationApplication) getActivity().getApplication(); - application.setCurrent(current); - - final DatabaseQueries query = new DatabaseQueries(this.localFragment.getActivity()); - final WeatherLocation weatherLocation = query.queryDataBase(); - weatherLocation.setLastCurrentUIUpdate(new Date()); - query.updateDataBase(weatherLocation); + final Intent currentData = new Intent("de.example.exampletdd.UPDATECURRENT"); + currentData.putExtra("current", current); + LocalBroadcastManager.getInstance(this.localContext).sendBroadcastSync(currentData); } } } diff --git a/Android/WeatherInformation/src/de/example/exampletdd/fragment/overview/OverviewFragment.java b/Android/WeatherInformation/src/de/example/exampletdd/fragment/overview/OverviewFragment.java index ef3f73f..bb9b881 100644 --- a/Android/WeatherInformation/src/de/example/exampletdd/fragment/overview/OverviewFragment.java +++ b/Android/WeatherInformation/src/de/example/exampletdd/fragment/overview/OverviewFragment.java @@ -15,8 +15,11 @@ import java.util.Locale; import org.apache.http.client.ClientProtocolException; +import android.content.BroadcastReceiver; import android.content.ComponentName; +import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -24,8 +27,8 @@ import android.net.http.AndroidHttpClient; import android.os.AsyncTask; import android.os.Bundle; import android.preference.PreferenceManager; -import android.support.v4.app.Fragment; import android.support.v4.app.ListFragment; +import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.view.View; import android.widget.ListView; @@ -45,6 +48,7 @@ import de.example.exampletdd.service.ServiceParser; public class OverviewFragment extends ListFragment { private static final String TAG = "OverviewFragment"; + private BroadcastReceiver mReceiver; @Override public void onCreate(final Bundle savedInstanceState) { @@ -79,10 +83,45 @@ public class OverviewFragment extends ListFragment { } @Override + public void onStart() { + super.onStart(); + + this.mReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + if (action.equals("de.example.exampletdd.UPDATEFORECAST")) { + final Forecast forecast = (Forecast) intent.getSerializableExtra("forecast"); + + if (forecast != null) { + OverviewFragment.this.updateUI(forecast); + + final WeatherInformationApplication application = + (WeatherInformationApplication) getActivity().getApplication(); + application.setForecast(forecast); + + final DatabaseQueries query = new DatabaseQueries(OverviewFragment.this.getActivity().getApplicationContext()); + final WeatherLocation weatherLocation = query.queryDataBase(); + weatherLocation.setLastForecastUIUpdate(new Date()); + query.updateDataBase(weatherLocation); + } + } + } + }; + + // Register receiver + final IntentFilter filter = new IntentFilter(); + filter.addAction("de.example.exampletdd.UPDATEFORECAST"); + LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext()) + .registerReceiver(this.mReceiver, filter); + } + + @Override public void onResume() { super.onResume(); - final DatabaseQueries query = new DatabaseQueries(this.getActivity()); + final DatabaseQueries query = new DatabaseQueries(this.getActivity().getApplicationContext()); final WeatherLocation weatherLocation = query.queryDataBase(); if (weatherLocation == null) { // Nothing to do. @@ -99,7 +138,7 @@ public class OverviewFragment extends ListFragment { // Load remote data (aynchronous) // Gets the data from the web. final OverviewTask task = new OverviewTask( - this, + this.getActivity().getApplicationContext(), new CustomHTTPClient(AndroidHttpClient.newInstance("Android 4.3 WeatherInformation Agent")), new ServiceParser(new JPOSWeatherParser())); @@ -126,6 +165,13 @@ public class OverviewFragment extends ListFragment { } @Override + public void onStop() { + LocalBroadcastManager.getInstance(this.getActivity().getApplicationContext()).unregisterReceiver(this.mReceiver); + + super.onStop(); + } + + @Override public void onListItemClick(final ListView l, final View v, final int position, final long id) { final SpecificFragment fragment = (SpecificFragment) this .getFragmentManager().findFragmentById(R.id.weather_specific_fragment); @@ -255,24 +301,26 @@ public class OverviewFragment extends ListFragment { // I mean, if OverviewTask shows one progress dialog and CurrentTask does the same I will have // have two progress dialogs... How may I solve this problem? I HATE ANDROID. private class OverviewTask extends AsyncTask { - private final Fragment localFragment; + // Store the context passed to the AsyncTask when the system instantiates it. + private final Context localContext; private final CustomHTTPClient weatherHTTPClient; private final ServiceParser weatherService; - public OverviewTask(final Fragment fragment, final CustomHTTPClient weatherHTTPClient, + public OverviewTask(final Context context, final CustomHTTPClient weatherHTTPClient, final ServiceParser weatherService) { - this.localFragment = fragment; + this.localContext = context; this.weatherHTTPClient = weatherHTTPClient; this.weatherService = weatherService; } @Override protected void onPreExecute() { - final OverviewFragment overview = (OverviewFragment) this.localFragment; - overview.setListAdapter(null); - // TODO: string static resource - overview.setEmptyText("No data available"); - overview.setListShownNoAnimation(false); + // IMPOSSIBLE IF I USE JUST Context (I like Context because it doesn't die like Activity does when screen rotates) +// final OverviewFragment overview = (OverviewFragment) this.localFragment; +// overview.setListAdapter(null); +// // TODO: string static resource +// overview.setEmptyText("No data available"); +// overview.setListShownNoAnimation(false); } @Override @@ -320,10 +368,11 @@ public class OverviewFragment extends ListFragment { protected void onPostExecute(final Forecast forecast) { // TODO: Is AsyncTask calling this method even when RunTimeException in doInBackground method? // I hope so, otherwise I must catch(Throwable) in doInBackground method :( - final OverviewFragment overview = (OverviewFragment) this.localFragment; - // TODO: string static resource - overview.setEmptyText("Error trying to download remote data"); - overview.setListShownNoAnimation(true); + // IMPOSSIBLE IF I USE JUST Context (I like Context because it doesn't die like Activity does when screen rotates) +// final OverviewFragment overview = (OverviewFragment) this.localFragment; +// // TODO: string static resource +// overview.setEmptyText("Error trying to download remote data"); +// overview.setListShownNoAnimation(true); if (forecast == null) { // Nothing to do @@ -332,16 +381,9 @@ public class OverviewFragment extends ListFragment { } // Call updateUI on the UI thread. - updateUI(forecast); - - final WeatherInformationApplication application = - (WeatherInformationApplication) getActivity().getApplication(); - application.setForecast(forecast); - - final DatabaseQueries query = new DatabaseQueries(this.localFragment.getActivity()); - final WeatherLocation weatherLocation = query.queryDataBase(); - weatherLocation.setLastForecastUIUpdate(new Date()); - query.updateDataBase(weatherLocation); + final Intent forecastData = new Intent("de.example.exampletdd.UPDATEFORECAST"); + forecastData.putExtra("forecast", forecast); + LocalBroadcastManager.getInstance(this.localContext).sendBroadcastSync(forecastData); } } } -- 2.1.4