I need to include this in my app
When should it get triggered?
- Any action triggered by user from UI requires internet and there's no internet
- Any background activities (like asynchronous loading of images) requiring internet has no internet
- NOT when the app is idle or background/user actions not requiring internet are being processed
What I tried?
- I use Volley. Triggered
AlertDialog
insideResponse.ErrorListener
of Volley, everytime I wrote aJsonObjectRequest
Problem: too repetitive, had too many lines of AlertDialog code
Added a common class called
Alerts
and called theAlertDialog
from it likeDialogInterface.OnClickListener onClickTryAgain = new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Swift.getInstance(ProfileActivity.this).addToRequestQueue(jsonObjectRequest); } }; if(error instanceof TimeoutError) Alerts.timeoutErrorAlert(ProfileActivity.this, onClickTryAgain); else if(error instanceof NoConnectionError) Alerts.internetConnectionErrorAlert(ProfileActivity.this, onClickTryAgain); else Alerts.unknownErrorAlert(ProfileActivity.this);
My Alerts.class
public class Alerts {
public static void internetConnectionErrorAlert(final Context context, DialogInterface.OnClickListener onClickTryAgainButton) {
String message = "Sometimes the internet gets a bit sleepy and takes a nap. Make sure its up and running then we'll give it another go";
new AlertDialog.Builder(context)
.setIconAttribute(android.R.attr.alertDialogIcon)
.setTitle("Network Error")
.setMessage(message)
.setPositiveButton("Try Again", onClickTryAgainButton)
.setNegativeButton("Turn Internet On", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent i = new Intent(Settings.ACTION_SETTINGS);
((Activity) context).startActivityForResult(i, 0);
}
})
.show();
}
public static void timeoutErrorAlert(Context context, DialogInterface.OnClickListener onClickTryAgainButton) {
String message = "Are you connected to internet? We guess you aren't. Turn it on and we'll rock and roll!";
new AlertDialog.Builder(context)
.setIconAttribute(android.R.attr.alertDialogIcon)
.setTitle("Network Error")
.setMessage(message)
.setPositiveButton("Try Again", onClickTryAgainButton)
.show();
}
public static void unknownErrorAlert(Context context) {
new AlertDialog.Builder(context)
.setIconAttribute(android.R.attr.alertDialogIcon)
.setTitle("Server Error")
.setMessage("We all have bad days! We'll fix this soon...")
.setPositiveButton("Hmm, I understand", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.show();
}
}
Problem: Try again
button doesn't do what I wanted. Well, assuming someone gives a fix for that, I can say, it just replaced some 30 lines of code with 5 lines, well, but what about the transitions? I need to say connecting
, till response arrives
This time, I added a layout called
ConnectingLayout
covering the whole of the screen.<LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical|center_horizontal" android:id="@+id/loading_layout" android:visibility="gone"> <ProgressBar style="?android:attr/progressBarStyleLarge" android:layout_width="wrap_content" android:layout_height="wrap_content" android:indeterminate="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/loading" android:gravity="center_horizontal" android:textSize="25sp" android:fontFamily="sans-serif-light" android:layout_margin="5dp" android:singleLine="true" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/loading_description" android:gravity="center_horizontal" android:fontFamily="sans-serif-light" android:layout_margin="5dp" android:singleLine="true" /> </LinearLayout>
and used it as in
jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, getString(R.string.api_root_path) + "/profile", getJson(), new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
if(response.getBoolean("success")) {
Animations.fadeOut(loadingLayout,500);
Animations.fadeIn(mainLayout,500);
JSONObject dataJson = response.getJSONObject("data");
JSONObject userJson = dataJson.getJSONObject("user");
name.setText(userJson.getString("name"));
dob.setText(userJson.getString("dob").equals("null")?null:userJson.getString("dob"));
email.setText(userJson.getString("email"));
phone.setText(userJson.getString("mobile_no"));
promotionOffers.setChecked(userJson.getBoolean("offers"));
} else {
Alerts.requestUnauthorisedAlert(ProfileActivity.this);
System.out.println(response.getString("error"));
}
} catch (JSONException e) { e.printStackTrace(); }
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
DialogInterface.OnClickListener onClickTryAgain = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
VolleyBaseClass.getInstance(ProfileActivity.this).addToRequestQueue(jsonObjectRequest);
}
};
if(error instanceof TimeoutError) Alerts.timeoutErrorAlert(ProfileActivity.this, onClickTryAgain);
else if(error instanceof NoConnectionError) Alerts.internetConnectionErrorAlert(ProfileActivity.this, onClickTryAgain);
else Alerts.unknownErrorAlert(ProfileActivity.this);
System.out.println("Response Error: " + error);
}
});
Animations.fadeIn(loadingLayout, 500);
Animations.fadeOut(mainLayout, 500);
VolleyBaseClass.getInstance(this).addToRequestQueue(jsonObjectRequest);
Assume that Animations.fadeIn(View view, int ms);
and Animations.fadeOut(View view, int ms);
are properly defined and does the job.
Problem: Pain of repeating layouts in all acivities and writing code to fade
- Learnt about
ViewStub
s. Generated code programmatically to get the sameConnectingLayout
. Now I can change text like saving, loading, etc.
Problem: Not a big leap, but... .., it's one more stepping stone I just landed on
- I don't need to say its connecting or loading, I just need to say 'Hey, your phone is processing someething'. So I just thought why not use the loading circle in SwipeRefreshLayouts ?
Problem: Great, it shows little loading circular notch on top, and if loading fails, i can call the alert, but where is turn wifi on, turn 3G on and other things, too big for an AlertDialog
to accommodate all that, is there any other way to show try again
?
- Looked about using
same fragment in all activities
andredirecting to a callActivityForResult
(sorry that I can't add more than two links)
Problem: Hmm...! Taking the user to a new activity is what I find eating resources and bringing down performance considerably. And fragments?
I am not giving up! I know I'm learning it the hard way, but with great hopes that the developer community will help me.
I have encountered the same needs and issues. I am working on a Volley based library jus where most the issues you have had i handle with rxJava global observables and of course Alerts class with static alerts/views generators. the connectivity handling I try to make it smooth using ConnectivityManager and NoConnectionPolicy concepts.
A request needs to constructed everytime it should be sent or resent.
These steps will help achieve it
Retry
and other necessary buttons likeWifi Settings
,Mobile Network Settings
FrameLayout
insideRelativeLayout
on necessary views to accommodate the fragment created and hide it initiallyFrameLayout
visible and the retry button should call the function that constructs and calls the request