catalogue

  • 01. What is the interface status
  • 02. Use include
  • 03. Handle logic in the Base class
  • 04. How to reduce compatibility and invasiveness
  • 05. Encapsulate a low intrusion state library
    • 5.1 Custom Frame Layout
    • 5.2 Customizing status Managers
    • 5.3 How do I Manage Multiple States
  • 06. Description of the ultimate optimization points of packaging library
    • 6.1 Using the ViewStub to Display the Layout
    • 6.2 Handling the reload logic
  • 07. How to use the wrapper library

Good news

  • Summary of blog notes [March 2016 to present], including Java basic and in-depth knowledge points, Android technology blog, Python learning notes, etc., including the summary of bugs encountered in daily development, of course, I also collected a lot of interview questions in my spare time, updated, maintained and corrected for a long time, and continued to improve… Open source files are in Markdown format! At the same time, ALSO open source life blog, from 12 years, accumulated a total of N [nearly 1 million words, gradually moved to the Internet], reprint please indicate the source, thank you!
  • Link address:Github.com/yangchong21…
  • If you feel good, you can star, thank you! Of course, also welcome to put forward suggestions, everything starts from small, quantitative change causes qualitative change!

01. What is the interface status

  • In Android, whether an activity or fragment is loading a View, there may be a variety of state page views. For example, there are some common ones:
    • Content interface, that is, normal data pages
    • Loading data, loading loading
    • Error loading data, request data exception
    • No data after loading, request data is empty
    • No network is available. The network is abnormal
  • In the meantime, think about a few questions.
    • How to switch interface status? Some interface want to customize custom state? How does status add click events? The following is to solve these problems!
  • Why?
    • Generally, when Loading network data, users need to wait. Displaying a Loading Loading animation can let users know that App is Loading data instead of the program being stuck, thus providing users with a better use experience.
    • Displaying an empty view when the loaded data is empty, displaying the UI for a failed load when the data fails, and supporting retry is a better user experience than a blank screen.
    • Generally speaking, the page styles of different states, such as loading, loading failure and empty data, need to be consistent in all pages within the App, that is, the need to achieve global unification.

02. Use include

  • Include these screens directly into the main screen, and then dynamically switch them, as shown below.
    • In a layout, multiple states of the layout are stored. Then in the page according to the logic of the corresponding layout to show or hide, but there are many problems.
    <? xml version="1.0" encoding="utf-8"? > <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/activity_main"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"> <! --> <include layout="@layout/activity_content"/ > <! Loading layout --> <include layout="@layout/activity_loading"/ > <! --> <include layout="@layout/activity_error"/ > <! --> <include Layout ="@layout/activity_emptydata"/>
    
    </LinearLayout>
    Copy the code
  • Analysis of existing problems
    • Later, it was found that this process is not easy to reuse in other projects, the code is very low reusability
    • Handling the display and hiding of these states in an activity is messy
    • When the setContentView method is called, all the layout is loaded and drawn. It’s not really necessary
    • If you write logic in BaseActivity, use the subclass to inherit the parent class feature, write switch state in the parent class, but some interfaces do not inherit the parent class, and how to deal with

03. Handle logic in the Base class

  • Start by defining a custom control, such as LoadingView, and include a layout that contains views in different states. The code idea is as follows:
    public class LoadingView extends LinearLayout implements View.OnClickListener {
    
        public static final int LOADING = 0;
        public static final int STOP_LOADING = 1;
        public static final int NO_DATA = 2;
        public static final int NO_NETWORK = 3;
        public static final int GONE = 4;
        public static final int LOADING_DIALOG = 5;
    
        private TextView mNoDataTextView;
        private ProgressBar mLoadingProgressBar;
        private RelativeLayout mRlError;
        private LinearLayout mLlLoading;
        private View mView;
    
        private OnRefreshListener mListener;
    
        public void setRefrechListener(OnRefreshListener mListener) {
            this.mListener = mListener;
        }
    
        public interface OnRefreshListener {
            void refresh();
        }
    
        public LoadingView(Context context) {
            super(context);
            init(context);
        }
    
        public LoadingView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
    
        public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init(context);
        }
    
        private void init(Context context) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            mView = inflater.inflate(R.layout.common_loading_get, this);
            mLoadingProgressBar = (ProgressBar) mView.findViewById(R.id.mLoadingProgressBar);
            mNoDataTextView  = (TextView) mView.findViewById(R.id.mNoDataTextView);
            mLlLoading = (LinearLayout) mView.findViewById(R.id.ll_loading);
            mRlError = (RelativeLayout) mView.findViewById(R.id.rl_error);
            mRlError.setOnClickListener(this);
            setStatue(GONE);
        }
    
        public void setStatue(int status) {
            setVisibility(View.VISIBLE);
            try {
                if(status == LOADING) {// Update mrlerror.setvisibility (view.gone); mLlLoading.setVisibility(View.VISIBLE); }else if (status == STOP_LOADING) {
                    setVisibility(View.GONE);
                } else if(status == NO_DATA) {// Mrlerror.setvisibility (view.visible); mLlLoading.setVisibility(View.GONE); mNoDataTextView.setText("No data at present");
                } else if(status == NO_NETWORK) {// Mrlerror.setvisibility (view.visible); mLlLoading.setVisibility(View.GONE); mNoDataTextView.setText("Network load failed, click reload");
                } else {
                    setVisibility(View.GONE);
                }
            } catch (OutOfMemoryError e) {
            }
        }
    
        @Override
        public void onClick(View v) {
            mListener.refresh();
            setStatue(LOADING); }}Copy the code
  • Then encapsulated in BaseActivity/BaseFragment LoadingView initialization logic, and encapsulates loading state when switching the UI display logic, exposed to subclass the following methods:
    void showLoading(); // Call this method to display loading animation void showLoadFailed(); Void showEmpty(); Void onClickRetry(); // Call this method to display empty pages; // A callback method implemented in subclassesCopy the code
    • In BaseActivity/BaseFragment subclasses can pass on the step of packaging is more convenient to use load status display function. This way of use is too high coupling, each page layout file need to add LoadingView, it is not convenient to use and high maintenance cost, for example, sometimes the abnormal state of the layout of each page is different, so it is difficult to customize processing, high cost to modify.
    • Also, if you want to use this state management tool, you need to add the LoadingView view to the desired page layout. This can also fulfill the requirements, but it feels a bit cumbersome.
  • How do you use it for state management? You can see that you need to write LoadingView in the corresponding layout
    <? xml version="1.0" encoding="utf-8"? > <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.cheoo.app.view.recyclerview.TypeRecyclerView
            android:id="@+id/mRecyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:overScrollMode="never"
            android:scrollbars="none">
    
        </com.cheoo.app.view.recyclerview.TypeRecyclerView>
    
        <com.cheoo.app.view.LoadingView
            android:id="@+id/mLoadingView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </RelativeLayout>
    Copy the code
  • So how do you use the state manager if a subclass doesn’t want to inherit from the BaseActivity class? This can be used in code.
    mLoadingView  = (LoadingView)findViewById(R.id.mLoadingView);
    mLoadingView.setStatue(LoadingView.LOADING);
    mLoadingView.setStatue(LoadingView.STOP_LOADING);
    mLoadingView.setStatue(LoadingView.NO_NETWORK);
    mLoadingView.setStatue(LoadingView.NO_DATA);
    Copy the code

04. How to reduce compatibility and invasiveness

  • To completely separate the View state switch from the Activity, you must wrap these state views into a management class and expose several methods for switching between views. Different projects can require different views, so consider designing the management class as Builder mode to add the required state views.
  • So how do you reduce coupling and make your code less intrusive? Easy to maintain and modify, and portability? Something like this…
    • Can be used in activities or fragments
    • There is no need to add LoadingView in the layout, but unified management of different state views, and exposed external Settings of the custom state view method, convenient UI specific page customization
    • Support for customizing different state views, even if the BaseActivity handles state view management uniformly, it also supports individual page customization
    • Can you use a ViewStub instead of an exception or empty page when loading a view to reduce the rendering and only inflate the view out when an exception or empty page occurs
    • When the page appears network abnormal page, empty page, etc., the page will have interactive events, at this time you can set click to set the network or click reload, etc

05. Encapsulate a low intrusion state library

5.1 Custom Frame Layout

  • First you need to customize a StateFrameLayout layout that inherits FrameLayout. In this class, the view layout is currently set in five different states, and the main functional action is to show or hide the layout. In order to maintain the code later, according to the idea of object-oriented, the class should keep a single responsibility as far as possible, so regarding the state switch and setting up the custom state layout, this function is separated and handled in a StateLayoutManager.
    • As you can see from the code, the purpose of this class is to hide or show views.
    /** * <pre> * @author yangchong * blog : https://github.com/yangchong211/YCStateLayout * time : 2017/7/6 * desc : * revise: * </pre> */ public class StateFrameLayout extends FrameLayout {/** * Loading loading ID */ public static final int LAYOUT_LOADING_ID = 1; Public static final int LAYOUT_CONTENT_ID = 2; Public static final int LAYOUT_ERROR_ID = 3; /** * network error id */ public static final int LAYOUT_NETWORK_ERROR_ID = 4; Public static final int LAYOUT_EMPTY_DATA_ID = 5; Private SparseArray<View> layoutSparseArray = new SparseArray<>(); //private HashMap<Integer,View> map = new HashMap<>(); /** * layout manager */ private StateLayoutManager mStatusLayoutManager; public StateFrameLayout(Context context) { super(context); } public StateFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); } public StateFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public voidsetStatusLayoutManager(StateLayoutManager statusLayoutManager) { mStatusLayoutManager = statusLayoutManager; // Add all layouts to frame layout addAllLayoutToRootLayout(); } private voidaddAllLayoutToRootLayout() {
            if(mStatusLayoutManager.contentLayoutResId ! = 0) { addLayoutResId(mStatusLayoutManager.contentLayoutResId, StateFrameLayout.LAYOUT_CONTENT_ID); }if(mStatusLayoutManager.loadingLayoutResId ! = 0) { addLayoutResId(mStatusLayoutManager.loadingLayoutResId, StateFrameLayout.LAYOUT_LOADING_ID); }if(mStatusLayoutManager.emptyDataVs ! = null) { addView(mStatusLayoutManager.emptyDataVs); }if(mStatusLayoutManager.errorVs ! = null) { addView(mStatusLayoutManager.errorVs); }if(mStatusLayoutManager.netWorkErrorVs ! = null) { addView(mStatusLayoutManager.netWorkErrorVs); } } private void addLayoutResId(@LayoutRes int layoutResId, int id) { View resView = LayoutInflater.from(mStatusLayoutManager.context).inflate(layoutResId, null); layoutSparseArray.put(id, resView); addView(resView); } /** * displays loading */ public voidshowLoading() {
            if(layoutSparseArray.get(LAYOUT_LOADING_ID) ! = null) { showHideViewById(LAYOUT_LOADING_ID); }} /** * display content */ public voidshowContent() {
            if(layoutSparseArray.get(LAYOUT_CONTENT_ID) ! = null) { showHideViewById(LAYOUT_CONTENT_ID); Public void showEmptyData(int iconImage, String textTip) {public void showEmptyData(int iconImage, String textTip) {if(inflateLayout(LAYOUT_EMPTY_DATA_ID)) { showHideViewById(LAYOUT_EMPTY_DATA_ID); emptyDataViewAddData(iconImage, textTip); Private void showHideViewById(int ID) {private void showHideViewById(int ID) {for(int i = 0; i < layoutSparseArray.size(); i++) { int key = layoutSparseArray.keyAt(i); View valueView = layoutSparseArray.valueAt(i); // Display the viewif(key == id) {
                    valueView.setVisibility(View.VISIBLE);
                    if(mStatusLayoutManager.onShowHideViewListener != null) {
                        mStatusLayoutManager.onShowHideViewListener.onShowView(valueView, key);
                    }
                } else {
                    if(valueView.getVisibility() ! = View.GONE) { valueView.setVisibility(View.GONE);if(mStatusLayoutManager.onShowHideViewListener ! = null) { mStatusLayoutManager.onShowHideViewListener.onHideView(valueView, key); }}}}} /** * This is the logic that handles ViewStub, mainly network exception layout, load exception layout, empty data layout * @param id layout ID * @returnBoolean */ private Boolean inflateLayout(int ID) {Boolean isShow =true; // If null, return directlyfalse
            if (layoutSparseArray.get(id) == null) {
                return false;
            }
            switch (id) {
                case LAYOUT_NETWORK_ERROR_ID:
                    if(mStatusLayoutManager.netWorkErrorVs ! = null) { View view = mStatusLayoutManager.netWorkErrorVs.inflate(); retryLoad(view, mStatusLayoutManager.netWorkErrorRetryViewId); layoutSparseArray.put(id, view); isShow =true;
                    } else {
                        isShow = false;
                    }
                    break;
                case LAYOUT_ERROR_ID:
                    if(mStatusLayoutManager.errorVs ! = null) { View view = mStatusLayoutManager.errorVs.inflate();if(mStatusLayoutManager.errorLayout ! = null) { mStatusLayoutManager.errorLayout.setView(view); } retryLoad(view, mStatusLayoutManager.errorRetryViewId); layoutSparseArray.put(id, view); isShow =true;
                    } else {
                        isShow = false;
                    }
                    break;
                case LAYOUT_EMPTY_DATA_ID:
                    if(mStatusLayoutManager.emptyDataVs ! = null) { View view = mStatusLayoutManager.emptyDataVs.inflate();if(mStatusLayoutManager.emptyDataLayout ! = null) { mStatusLayoutManager.emptyDataLayout.setView(view); } retryLoad(view, mStatusLayoutManager.emptyDataRetryViewId); layoutSparseArray.put(id, view); isShow =true;
                    } else {
                        isShow = false;
                    }
                    break;
                default:
                    break;
            }
            returnisShow; }}Copy the code

5.2 Customizing status Managers

  • The custom layout for the above states is created, and both hide and show are done. So how to control setting custom view layout, and how to control switching between different layouts, then need to use this class!Github.com/yangchong21…
    • LoadingLayoutResId and contentLayoutResId represent XML files waiting to be loaded and displayed
    • ViewStub should be used for several abnormal states, because loading and content View are always loaded and displayed during interface state transition. However, the other three states can only be loaded and displayed when there is no data or network abnormality. Therefore, loading them with ViewStub can improve performance.
    • Using Builder mode, very simple, code as shown below. Create the StateFrameLayout object and then set setStatusLayoutManager. This step is to pass a Manager object to the StateFrameLayout to establish a connection.
    public final class StateLayoutManager {
    
        final Context context;
    
        final int netWorkErrorRetryViewId;
        final int emptyDataRetryViewId;
        final int errorRetryViewId;
        final int loadingLayoutResId;
        final int contentLayoutResId;
        final int retryViewId;
        final int emptyDataIconImageId;
        final int emptyDataTextTipId;
        final int errorIconImageId;
        final int errorTextTipId;
    
        final ViewStub emptyDataVs;
        final ViewStub netWorkErrorVs;
        final ViewStub errorVs;
        final AbsViewStubLayout errorLayout;
        final AbsViewStubLayout emptyDataLayout;
    
        private final StateFrameLayout rootFrameLayout;
        final OnShowHideViewListener onShowHideViewListener;
        final OnRetryListener onRetryListener;
    
        public static Builder newBuilder(Context context) {
            returnnew Builder(context); } private StateLayoutManager(Builder builder) { this.context = builder.context; this.loadingLayoutResId = builder.loadingLayoutResId; this.netWorkErrorVs = builder.netWorkErrorVs; this.netWorkErrorRetryViewId = builder.netWorkErrorRetryViewId; this.emptyDataVs = builder.emptyDataVs; this.emptyDataRetryViewId = builder.emptyDataRetryViewId; this.errorVs = builder.errorVs; this.errorRetryViewId = builder.errorRetryViewId; this.contentLayoutResId = builder.contentLayoutResId; this.onShowHideViewListener = builder.onShowHideViewListener; this.retryViewId = builder.retryViewId; this.onRetryListener = builder.onRetryListener; this.emptyDataIconImageId = builder.emptyDataIconImageId; this.emptyDataTextTipId = builder.emptyDataTextTipId; this.errorIconImageId = builder.errorIconImageId; this.errorTextTipId = builder.errorTextTipId; this.errorLayout = builder.errorLayout; this.emptyDataLayout = builder.emptyDataLayout; RootFrameLayout = new StateFrameLayout(this.context); ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); rootFrameLayout.setLayoutParams(layoutParams); / / set the state manager rootFrameLayout. SetStatusLayoutManager (this); } /** * displays loading */ public voidshowLoading() { rootFrameLayout.showLoading(); } /** * display content */ public voidshowContent() { rootFrameLayout.showContent(); } / display empty data * * * * / public void showEmptyData (int iconImage, String textTip) {rootFrameLayout. ShowEmptyData (iconImage, textTip); } /** * displays empty data */ public voidshowEmptyData() {
            showEmptyData(0, ""); } /** * public void showLayoutEmptyData(Object... objects) { rootFrameLayout.showLayoutEmptyData(objects); } /** * Display network exception */ public voidshowNetWorkError() { rootFrameLayout.showNetWorkError(); } / display abnormal * * * * / public void showError (int iconImage, String textTip) {rootFrameLayout. ShowError (iconImage textTip); } /** * display exception */ public voidshowError() {
            showError(0, ""); } public void showLayoutError(Object... objects) { rootFrameLayout.showLayoutError(objects); } /** * get root layout */ public ViewgetRootLayout() {
            returnrootFrameLayout; } public static final class Builder { private Context context; private int loadingLayoutResId; private int contentLayoutResId; private ViewStub netWorkErrorVs; private int netWorkErrorRetryViewId; private ViewStub emptyDataVs; private int emptyDataRetryViewId; private ViewStub errorVs; private int errorRetryViewId; private int retryViewId; private int emptyDataIconImageId; private int emptyDataTextTipId; private int errorIconImageId; private int errorTextTipId; private AbsViewStubLayout errorLayout; private AbsViewStubLayout emptyDataLayout; private OnShowHideViewListener onShowHideViewListener; private OnRetryListener onRetryListener; Builder(Context context) { this.context = context; } /** * Public Builder loadingView(@layoutres int loadingLayoutResId) {this.loadingLayoutResId = loadingLayoutResId;returnthis; } public Builder netWorkErrorView(@layoutres int newWorkErrorId) {netWorkErrorVs = new ViewStub(context); netWorkErrorVs.setLayoutResource(newWorkErrorId);returnthis; } /** * Public Builder emptyDataView(@layoutres int noDataViewId) {emptyDataVs = new ViewStub(context); emptyDataVs.setLayoutResource(noDataViewId);returnthis; } public Builder errorView(@layoutres int errorViewId) {errorVs = new ViewStub(context);} public Builder errorView(@layoutRes int errorViewId) {errorVs = new ViewStub(context); errorVs.setLayoutResource(errorViewId);returnthis; } /** * Public Builder contentView(@layoutres int contentLayoutResId) {this.contentLayOutresid = contentLayoutResId;return this;
            }
    
            public Builder errorLayout(AbsViewStubLayout errorLayout) {
                this.errorLayout = errorLayout;
                this.errorVs = errorLayout.getLayoutVs();
                return this;
            }
    
            public Builder emptyDataLayout(AbsViewStubLayout emptyDataLayout) {
                this.emptyDataLayout = emptyDataLayout;
                this.emptyDataVs = emptyDataLayout.getLayoutVs();
                return this;
            }
    
            public Builder netWorkErrorRetryViewId(@LayoutRes int netWorkErrorRetryViewId) {
                this.netWorkErrorRetryViewId = netWorkErrorRetryViewId;
                return this;
            }
    
            public Builder emptyDataRetryViewId(@LayoutRes int emptyDataRetryViewId) {
                this.emptyDataRetryViewId = emptyDataRetryViewId;
                return this;
            }
    
            public Builder errorRetryViewId(@LayoutRes int errorRetryViewId) {
                this.errorRetryViewId = errorRetryViewId;
                return this;
            }
    
            public Builder retryViewId(@LayoutRes int retryViewId) {
                this.retryViewId = retryViewId;
                return this;
            }
    
            public Builder emptyDataIconImageId(@LayoutRes int emptyDataIconImageId) {
                this.emptyDataIconImageId = emptyDataIconImageId;
                return this;
            }
    
            public Builder emptyDataTextTipId(@LayoutRes int emptyDataTextTipId) {
                this.emptyDataTextTipId = emptyDataTextTipId;
                return this;
            }
    
            public Builder errorIconImageId(@LayoutRes int errorIconImageId) {
                this.errorIconImageId = errorIconImageId;
                return this;
            }
    
            public Builder errorTextTipId(@LayoutRes int errorTextTipId) {
                this.errorTextTipId = errorTextTipId;
                returnthis; } /** * Shows hidden listening events for the state View * @param listener Listener * @return
             */
            public Builder onShowHideViewListener(OnShowHideViewListener listener) {
                this.onShowHideViewListener = listener;
                returnthis; } /** * listener event for retry load button * @param onRetryListener listener * @return
             */
            public Builder onRetryListener(OnRetryListener onRetryListener) {
                this.onRetryListener = onRetryListener;
                returnthis; } /** * create object * @return
             */
            public StateLayoutManager build() {
                returnnew StateLayoutManager(this); }}}Copy the code

5.3 How do I Manage Multiple States

  • About 5 states. How do you manage them? SparseArray is more efficient than HashMap, and performs better in some cases, mainly because it avoids automatic boxing of keys (int to Integer type), and internally stores data in two arrays, one for keys, The other stores value. In order to optimize performance, the data in the other store is compressed to represent sparse array data, so as to save memory space
    Private SparseArray<View> layoutSparseArray = new SparseArray(); Private void addLayoutResId(@layOutres int layoutResId, int id) { View resView = LayoutInflater.from(mStatusLayoutManager.context).inflate(layoutResId, null); layoutSparseArray.put(id, resView); addView(resView); } // Where to get data from the collection public voidshowContent() {
        if (layoutSparseArray.get(LAYOUT_CONTENT_ID) != null) {
            showHideViewById(LAYOUT_CONTENT_ID);
        }
    }
    Copy the code

06. Description of the ultimate optimization points of packaging library

6.1 Using the ViewStub to Display the Layout

  • The showHideViewById method is used to display the hidden View by calling the showHideViewById method. If the View stub is empty, it will return false. If the View stub is empty, it will load and add the View to the collection. The retryLoad method adds an event to the retry button
    • Note that even when you set up multiple state views, calling setContentView does not affect performance when drawing because the exception page uses the ViewStub.
    /** * Displays loading */ public voidshowLoading() {
        if(layoutSparseArray.get(LAYOUT_LOADING_ID) ! = null) showHideViewById(LAYOUT_LOADING_ID); } /** * display content */ public voidshowContent() {
        if(layoutSparseArray.get(LAYOUT_CONTENT_ID) ! = null) showHideViewById(LAYOUT_CONTENT_ID); } // call the inflateLayout method, which returnstrueThen call the showHideViewById method private Boolean inflateLayout(int ID) {Boolean isShow =true;
        if(layoutSparseArray.get(id) ! = null)return isShow;
        switch (id) {
            case LAYOUT_NETWORK_ERROR_ID:
                if(mStatusLayoutManager.netWorkErrorVs ! = null) { View view = mStatusLayoutManager.netWorkErrorVs.inflate(); retryLoad(view, mStatusLayoutManager.netWorkErrorRetryViewId); layoutSparseArray.put(id, view); isShow =true;
                } else {
                    isShow = false;
                }
                break;
            case LAYOUT_ERROR_ID:
                if(mStatusLayoutManager.errorVs ! = null) { View view = mStatusLayoutManager.errorVs.inflate();if(mStatusLayoutManager.errorLayout ! = null) mStatusLayoutManager.errorLayout.setView(view); retryLoad(view, mStatusLayoutManager.errorRetryViewId); layoutSparseArray.put(id, view); isShow =true;
                } else {
                    isShow = false;
                }
                break;
            case LAYOUT_EMPTYDATA_ID:
                if(mStatusLayoutManager.emptyDataVs ! = null) { View view = mStatusLayoutManager.emptyDataVs.inflate();if(mStatusLayoutManager.emptyDataLayout ! = null) mStatusLayoutManager.emptyDataLayout.setView(view); retryLoad(view, mStatusLayoutManager.emptyDataRetryViewId); layoutSparseArray.put(id, view); isShow =true;
                } else {
                    isShow = false;
                }
                break;
        }
        return isShow;
    }
    Copy the code

6.2 Handling the reload logic

  • Finally, look at the reload method
    / / private void retryLoad(View View, View View) int id) { View retryView = view.findViewById(mStatusLayoutManager.retryViewId ! = 0? mStatusLayoutManager.retryViewId : id);if (retryView == null || mStatusLayoutManager.onRetryListener == null) return;
        retryView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mStatusLayoutManager.onRetryListener.onRetry(); }}); }Copy the code

07. How to use the wrapper library

  • You can freely switch content, empty data, abnormal error, load, network error and other 5 states. The parent BaseActivity class directly exposes 5 states, which is convenient for subclasses to manage state switching in a unified manner. Here, the encapsulation of fragment is similar to that of activity.
    / * * * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * : Yang Chong * this: 1.0 * created date: 2017/7/6 * description: extract class * revision history:  * ================================================ */ public abstract class BaseActivity extends AppCompatActivity { protected StatusLayoutManager statusLayoutManager; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState);setContentView(R.layout.activity_base_view); initStatusLayout(); initBaseView(); initToolBar(); initView(); } // Subclasses must override this method. protected abstract void initView(); /** * get the layout */ private voidinitBaseView() { LinearLayout ll_main = (LinearLayout) findViewById(R.id.ll_main); ll_main.addView(statusLayoutManager.getRootLayout()); } // Display the data state normallyshowContent() { statusLayoutManager.showContent(); } // Load data is null state protected voidshowEmptyData() { statusLayoutManager.showEmptyData(); } // Data loading error state protected voidshowError() { statusLayoutManager.showError(); } // Network error state protected voidshowNetWorkError() { statusLayoutManager.showNetWorkError(); } // The loading state is protected voidshowLoading() { statusLayoutManager.showLoading(); }}Copy the code
  • What happens when a subclass inherits BaseActivity? The details are as follows
    @Override
    protected void initStatusLayout() { statusLayoutManager = StateLayoutManager.newBuilder(this) .contentView(R.layout.activity_main) .emptyDataView(R.layout.activity_emptydata) .errorView(R.layout.activity_error) .loadingView(R.layout.activity_loading) .netWorkErrorView(R.layout.activity_networkerror) .build(); } // Add the listener event @override protected voidinitStatusLayout() {
        statusLayoutManager = StateLayoutManager.newBuilder(this)
                .contentView(R.layout.activity_content_data)
                .emptyDataView(R.layout.activity_empty_data)
                .errorView(R.layout.activity_error_data)
                .loadingView(R.layout.activity_loading_data)
                .netWorkErrorView(R.layout.activity_networkerror)
                .onRetryListener(new OnRetryListener() {
                    @Override
                    public void onRetry() {// Load button listener event for retry}}). OnShowHideViewListener (newOnShowHideViewListener() { @Override public void onShowView(View view, Public void onHideView(View View, int id) {public void onHideView(View View, int id) {build(); } // How to switch states? showContent(); showEmptyData(); showError(); showLoading(); showNetWorkError(); / / or operations can also be statusLayoutManager. ShowLoading (); statusLayoutManager.showContent();Copy the code
  • So how do you set up the interactive events for the status page? When loading data fails, click to refresh data. When the state is no network, click to set the network. The code looks like this:
    /** * Click refresh */ private voidinitErrorDataView() {
        statusLayoutManager.showError();
        LinearLayout ll_error_data = (LinearLayout) findViewById(R.id.ll_error_data);
        ll_error_data.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { initData(); adapter.notifyDataSetChanged(); showContent(); }}); } /** * click Set network */ private voidinitSettingNetwork() {
        statusLayoutManager.showNetWorkError();
        LinearLayout ll_set_network = (LinearLayout) findViewById(R.id.ll_set_network);
        ll_set_network.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("android.settings.WIRELESS_SETTINGS"); startActivity(intent); }}); }Copy the code
  • What about pages that want to customize their status UI? If some pages want to customize the state layout, they are free to do so, very simple:
    /** * Custom state layout when load data is null */ private voidinitEmptyDataView() { statusLayoutManager.showEmptyData(); / / here is self-defining state layout statusLayoutManager showLayoutEmptyData (R.l ayout. Activity_emptydata); LinearLayout ll_empty_data = (LinearLayout) findViewById(R.id.ll_empty_data); ll_empty_data.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { initData(); adapter.notifyDataSetChanged(); showContent(); }}); }Copy the code

The other is introduced

01. About blog summary links

  • 1. Tech blog round-up
  • 2. Open source project summary
  • 3. Life Blog Summary
  • 4. Himalayan audio summary
  • 5. Other summaries

02. About my blog

  • Github:github.com/yangchong21…
  • Zhihu: www.zhihu.com/people/yczb…
  • Jane: www.jianshu.com/u/b7b2c6ed9…
  • csdn:my.csdn.net/m0_37700275
  • The Himalayan listening: www.ximalaya.com/zhubo/71989…
  • Source: China my.oschina.net/zbj1618/blo…
  • Soak in the days of online: www.jcodecraeer.com/member/cont.
  • Email address: [email protected]
  • Blog: ali cloud yq.aliyun.com/users/artic… 239.headeruserinfo.3.dT4bcV
  • Segmentfault headline: segmentfault.com/u/xiangjian…
  • The Denver nuggets: juejin. Cn/user / 197877…

Project Open Source address:Github.com/yangchong21…