In our development, network requests often encounter the judgment of various error codes. For example:
Not to mention the normal error codes, it is impossible for us to judge these codes in the project every time, which is too troublesome. Just during the internship, there were many needs in the project, so I wrote a simple gadget.
The code is very simple without too much optimization. We can customize freely according to our own ideas. No matter how many design patterns are just for better use, so don't care too much. If optimization is considered, better packaging and transformation can be carried out. Here I just give a simple solution.
The process is roughly as follows:
- First, create your own data bean class, which is generated by GsonGormat with one click, and then inherit it from BaseDataBean to realize our requirements freely by using generics. Successfully return the bean object we need, otherwise the failed dialog will pop up.
- When used
String json=""; //Whether the request is successful or not: boolean mode = ErrorDialogFragmentUtils .Builder() .setContext(getContext()) .setMessage("Successful response") //The error code will be directly assigned when an error is reported .setManager(getFragmentManager()) .setIlistener(new IDialogListener() { @Override public void onPositiveClick() { //OK button } @Override public void onNegativeClick() { //Cancel button } }) .setDialogDimss(() -> { //dialog turn off listening }) .setiDataCode((code, res) -> { //Receiving network code }) .build() .setJson(json, GLoginBean.class, gLoginBean -> { //If successful, get your bean object here });
3. Freely change the codes in ErrorDialogFragmentUtils, such as the processing logic of error codes and some specific error codes. Here, because our back-end does not have processing logic for some specific codes, I'm waiting for time and space for the moment, but for standby, an exit for the error code is left. You can call setIDataCode() to implement the corresponding interface to get the failure code. More specific business methods can be added or changed freely according to my writing.
Here are my views on some processing logic:
- The error code is stored in spasearray (better performance), rather than HashMap (internal enumeration key), and placed in static code blocks to prevent multiple additions. According to individual business needs. (if you need to customize the error code prompt, the storage will work at this time. Add switch in the setJson method to decide)
- Why use static internal classes, data holding, and avoid accessing external variables or methods, imitating the use of builders. (you can annotate the Builder method, and then use new ErrorDialogFragmentUtils.Client, and then pause a little bit, but in order to get used to it, the Builder method is added)
- There's no need to define DialogFragment. Here I'll give you a simple prompt window, which you can play at will
Let's take a look at the code. It's very simple. Let's start with the code:
Tool class, freely defined
/** * Created by Petterp * on 2019-09-24 * Function: Judge the status code to make different processing. */ public class ErrorDialogFragmentUtils { // private static SparseArray<String> codes; /*static { // Customize the corresponding error code, or ignore it if it is provided by the back end codes = new SparseArray<>(); codes.put(-1, "The system is busy, please try again later) "; codes.put(0, "Operation succeeded "); codes.put(100, "Signature verification error, operation failed "); codes.put(200, "Parameter error, operation failed "); codes.put(210, "The user name and password do not match, please try again "); codes.put(211, "Login verification code error, please try again "); codes.put(900, "token Failure, refresh in time "); codes.put(901, "token Invalid, login again "); codes.put(500, "Logical exception ""); }*/ private static class ClientParams { private FragmentManager manager; private Context context; //Display custom Message private boolean isDiaMode = false; //Custom Message private String message = ""; //Dialog button listening private IDialogListener ilistener; //Is it necessary to control the operation when dialog is closed private IDataDialogDimss dialogDimss; //Return network code private IDataCode iDataCode; } private ErrorDialogFragmentUtils() { } private ClientParams params; private ErrorDialogFragmentUtils setParams(ClientParams params) { this.params = params; return this; } public static Client Builder() { return new Client(); } public static class Client { private ClientParams params; private Client() { params = new ClientParams(); } public Client setManager(FragmentManager manager) { params.manager = manager; return this; } public Client setContext(Context context) { params.context = context; return this; } public Client setMessage(String message) { params.message = message; params.isDiaMode = true; return this; } public Client setDialogDimss(IDataDialogDimss dialogDimss) { params.dialogDimss = dialogDimss; return this; } public Client setIlistener(IDialogListener ilistener) { params.ilistener = ilistener; return this; } public Client setiDataCode(IDataCode iDataCode) { params.iDataCode = iDataCode; return this; } public ErrorDialogFragmentUtils build() { return getUtils().setParams(params); } protected ErrorDialogFragmentUtils getUtils() { return new ErrorDialogFragmentUtils(); } } /** * Set the data source and conduct preliminary analysis * * @param json * @param g * @param dataInfo * @param <T> * @return */ public <T extends BaseDataBean> boolean setJson(String json, Class<T> g, IDataSuccess<T> dataInfo) { JSONObject jsonObject = JSONObject.parseObject(json); JSONObject jsonObject1 = JSONObject.parseObject(jsonObject.getString("result")); int code = jsonObject1.getInteger("c"); String res = jsonObject1.getString("m"); LatteLogger.e("demo", "The data parser starts to validate the data, code:" + code + "\tres:" + res + "\n Data source:" + json); //Return network code if (params.iDataCode != null) { params.iDataCode.code(code, res); } //Callback successful bean if (code == 0) { Gson gson = new Gson(); T bean = gson.fromJson(json, g); dataInfo.getData(bean); //If the user needs to display the success Dialog, customize the display if (params.isDiaMode) { ToastUtils.showText("success"); showDialog(false); } else { params = null; } return true; } //The following is user-defined business processing //Priority error reporting business processing params.message = res; if (code == 901) { //token failure showDialog(true); } else { //Perform default actions showDialog(false); } return false; } private void showDialog(boolean mode) { LatteLoader.stopLoading(); new CommonDialog .Builder() .setDialogDimss(() -> { //The following logic is determined according to business requirements if (mode) { //Default handling error logic restLogin(); } if (params.dialogDimss != null) { params.dialogDimss.onDialogDimss(); } //Clear configuration information params = null; }) .setContentMessage(params.message) .setDialogButtonClickListener(new CommonDialog.OnDialogButtonClickListener() { @Override public void onPositiveClick(View v, Bundle bundle) { if (params.ilistener != null) { params.ilistener.onPositiveClick(); } } @Override public void onNegativeClick(View v, Bundle bundle) { if (params.ilistener != null) { params.ilistener.onNegativeClick(); } } }) .build() .show(params.manager, getClass().getName()); } /** * Customize business needs */ private void restLogin() { . . . } }
Gson data class
/** * Created by Petterp * on 2019-10-04 * Function: Unified Gson data */ public class BaseDataBean { }
public class GLoginBean extends BaseDataBean{ private ResultBean result; private DataBean data; private long refreshTime; public ResultBean getResult() { return result; } public void setResult(ResultBean result) { this.result = result; } public DataBean getData() { return data; } public void setData(DataBean data) { this.data = data; } public long getRefreshTime() { return refreshTime; } public void setRefreshTime(long refreshTime) { this.refreshTime = refreshTime; } public static class ResultBean { /** * c : 0 * m : Operation successful */ private int c; private String m; public int getC() { return c; } public void setC(int c) { this.c = c; } public String getM() { return m; } public void setM(String m) { this.m = m; } } public static class DataBean { ... } }
A general dialog fragment dialog
/** * Common dialog box */ public class CommonDialog extends DialogFragment { private static class ControllerParams { public boolean isCancelable; public CharSequence contentMessage; public Bundle expandParams; public OnDialogButtonClickListener listener; public int positiveText; public int negativeText; public OnDialogDimss dialogDimss; private boolean isOnlyConfirm; } private static final String COMMON_DIALOG_PARAMS = "common_dialog_params"; private ControllerParams params; @Override public void onStart() { super.onStart(); //Transparent background Window window = getDialog().getWindow(); //Background color window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = getDialogView(); if (view == null) { view = View.inflate(getContext(), R.layout.commom_dialog_base, null); } Button negative = view.findViewById(R.id.dialog_btn_negative); Button positive = view.findViewById(R.id.dialog_btn_positive); View btnSeparate = view.findViewById(R.id.dialog_v_btn_separate); RelativeLayout contentContainer = view.findViewById(R.id.dialog_content_container); TextView content = view.findViewById(R.id.dialog_tv_content); negative.setOnClickListener(v -> { dismiss(); if (onNegativeClick()) { return; } if (params.listener != null) { params.listener.onNegativeClick(v, getNegativeDatas()); } }); positive.setOnClickListener(v -> { dismiss(); if (onPositiveClick()) { return; } if (params.listener != null) { params.listener.onPositiveClick(v, getPositiveDatas()); } }); if (params != null) { View contentView = onCreateContentView(); if (contentView != null) { contentContainer.removeAllViews(); contentContainer.addView(contentView); } else if (!TextUtils.isEmpty(params.contentMessage)) { content.setText(Html.fromHtml(params.contentMessage.toString())); } if (params.positiveText > 0) { positive.setText(params.positiveText); } if (params.negativeText > 0) { negative.setText(params.negativeText); } if (params.isOnlyConfirm) { negative.setVisibility(View.GONE); btnSeparate.setVisibility(View.GONE); positive.setBackgroundResource(R.drawable.common_dialog_single_positive_seletor); } setCancelable(params.isCancelable); } Dialog dialog = getDialog(); if (dialog != null) { dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); } return view; } /** * This method is only available for user-defined dialog whose layout changes but the control id does not change * * @return */ protected View getDialogView() { return null; } /** * By copying this method, you can recreate settings in subclasses * New content layout * * @return */ protected View onCreateContentView() { return null; } /** * Copy this method, and you can set it in this method to call back the data required by the listening OK button * * @return */ protected Bundle getPositiveDatas() { return null; } /** * Copy this method, and you can set it in this method to call back the data required by the listening cancel button * * @return */ protected Bundle getNegativeDatas() { return null; } /** * If the integrated subclass wants to handle Positive click monitoring internally, this method can be duplicated. If it returns true, it can be intercepted without external click monitoring * * @return true Intercept and listen, false do not intercept */ protected boolean onPositiveClick() { return false; } /** * If the integrated subclass wants to handle Negative click monitoring internally, this method can be duplicated. If it returns true, it can be intercepted without external click monitoring * * @return */ protected boolean onNegativeClick() { return false; } private void setParams(ControllerParams params) { this.params = params; } public Bundle getExpandParams() { if (params == null) { return null; } return params.expandParams; } public interface OnDialogButtonClickListener { void onPositiveClick(View v, Bundle bundle); void onNegativeClick(View v, Bundle bundle); } public interface OnDialogDimss { void onCancel(); } /** * Integrate subclasses of CommonDialog. You need to inherit this class and replicate it * getCurrentDialog Method to return the dialog object of the subclass */ public static class Builder { private ControllerParams params; public Builder() { params = new ControllerParams(); } public Builder setContentMessage(CharSequence content) { params.contentMessage = content; return this; } public Builder isCancelable(boolean cancelable) { params.isCancelable = cancelable; return this; } public Builder setButtonText(int positiveText, int negativeText) { params.positiveText = positiveText; params.negativeText = negativeText; return this; } public Builder setDialogButtonClickListener(OnDialogButtonClickListener listener) { params.listener = listener; return this; } public Builder setExpandParams(Bundle expandParams) { params.expandParams = expandParams; return this; } /** * Hide button * * @param isOnlyConfirm * @return */ public Builder setIsOnlyConfirm(boolean isOnlyConfirm) { params.isOnlyConfirm = isOnlyConfirm; return this; } public Builder setDialogDimss(OnDialogDimss dialogDimss) { params.dialogDimss = dialogDimss; return this; } public CommonDialog build() { CommonDialog dialog = getCurrentDialog(); dialog.setParams(params); return dialog; } protected CommonDialog getCurrentDialog() { return new CommonDialog(); } } @Override public void onDismiss(@NonNull DialogInterface dialog) { super.onDismiss(dialog); if (params.dialogDimss!=null){ params.dialogDimss.onCancel(); } } }
dialog xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="@dimen/common_dialog_width" android:layout_height="wrap_content" android:background="@drawable/common_dialog_bg" android:paddingBottom="5dp" android:orientation="vertical"> <RelativeLayout android:id="@+id/dialog_content_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:minHeight="@dimen/common_dialog_common_min_height" android:orientation="vertical"> <TextView android:id="@+id/dialog_tv_content" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:paddingLeft="@dimen/common_dialog_text_margin_left" android:paddingTop="@dimen/common_dialog_text_margin_top" android:paddingRight="@dimen/common_dialog_text_margin_right" android:paddingBottom="@dimen/common_dialog_text_margin_bottom" android:textColor="@color/common_dialog_base_text" android:textSize="@dimen/common_dialog_text_size" /> </RelativeLayout> <View android:layout_width="match_parent" android:layout_height="@dimen/common_dialog_line_width" android:background="@color/common_dialog_base_line" /> <LinearLayout android:layout_width="match_parent" android:layout_height="@dimen/common_dialog_button_height" android:orientation="horizontal"> <Button android:id="@+id/dialog_btn_negative" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/common_dialog_negative_seletor" android:text="@string/common_cancel" android:textColor="@color/common_dialog_base_text" android:textSize="@dimen/common_dialog_text_size" /> <View android:id="@+id/dialog_v_btn_separate" android:layout_width="@dimen/common_dialog_line_width" android:layout_height="match_parent" android:background="@color/common_dialog_base_line" /> <Button android:id="@+id/dialog_btn_positive" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/common_dialog_positive_seletor" android:text="@string/common_confirm" android:textColor="@color/default_clickable_text" android:textSize="@dimen/common_dialog_text_size" /> </LinearLayout> </LinearLayout>
Well, it's very simple. I hope it will help you.