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
AlertDialoginsideResponse.ErrorListenerof Volley, everytime I wrote aJsonObjectRequest
Problem: too repetitive, had too many lines of AlertDialog code
Added a common class called
Alertsand called theAlertDialogfrom 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
ConnectingLayoutcovering 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
ViewStubs. 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 activitiesandredirecting 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.
Volley DETROYS all listeners as soon as it receives something from the server, regardless of whether the response is a proper response or an error response.
A request needs to constructed everytime it should be sent or resent.
These steps will help achieve it
- Create a fragment with
Retryand other necessary buttons likeWifi Settings,Mobile Network Settings - Create a full sized
FrameLayoutinsideRelativeLayouton necessary views to accommodate the fragment created and hide it initially - When request fails, make the
FrameLayoutvisible and the retry button should call the function that constructs and calls the request
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.
来源:https://stackoverflow.com/questions/34840168/efiicient-way-to-show-cant-access-network-view-with-retry-and-additional-opt
