Best approach to show network error in android in Android with Tap to Retry option
Asked Answered
M

4

2

I have Navigation Drawer in my application with several Fragments and few new Activity also apart from main application flow.

  • Current Functionality
    For navigating to each Fragment, Network is required and in case of any network error, I used to show Dialog. User needs to click on "OK" button and again go back to navigation drawer to retry.
  • New Approach I am trying
    User should be shown and error screen similar to LinkedIn android app with option to retry. enter image description here

As inner Fragments and handling call back can be cumbersome, how to handle this situation efficiently?
For individual Activities this can be achieved easily, but worried about the Navigation Drawer and inner Fragments.
Any suggestions?

Minute answered 17/3, 2016 at 7:36 Comment(0)
E
2

Make this error layout hidden in this fragment. When there is any network error then change its visibility to VISIBLE. and in this hidden layout add a button to recall same method to check network connection etc.

Let say you have fragment xml like - fragment -
Relative Layout consisting - 1. -All layouts (VISIBLE) & 2. -Hidden network error layout with a button (GONE)

When there is network error then change 1. 's visibility to - GONE and 2.'s visibility to VISIBLE

and on retry button call -

checkNetworkConnectionCall(); 

I hope this will solve you problem.

Elburr answered 17/3, 2016 at 7:49 Comment(2)
you mean in all the layout's to include this layout for error as hidden? I doubt whether it will be an overburden !Minute
Actually when we set visibility to GONE then this view remains invisible, and it doesn't take any space for layout purposes. So I hope it will not create any overburden.Elburr
D
0

You can place some ContentFragment in a FrameLayout, then replace with a NetworkDisconnectedFragment when the network disconnects. This would require the button to a call the callback, then when reconnected, replace the NetworkDisconnectedFragment with the old ContentFragment in the callback implementation.

Dudeen answered 17/3, 2016 at 7:41 Comment(1)
Just wondering whether any sample implementations for this approach is available or not ?Minute
F
0

You can include this UI in each fragment and create a BaseFragment which will be extended by every fragment in nav drawer.

Write a method in that base fragment that will do the need full logic of changing the UI.

And whenever you detect a network failure just blindly call that method from base fragment there.

Fruin answered 17/3, 2016 at 7:56 Comment(2)
You mean to say , BaseFragment will be having xml for error which is hidden by default, and according to network status hide/show this basefragment views and hide/show child fragment views ?Minute
you can have a separate xml for network issue and use include tag to add it in every fragment of nav activity and can hide and show that included layout in base fragmentFruin
D
0

It's been almost 3 years, but I think it may be helpful for somebody. This example uses MVP pattern. BaseNetContentActivity, BaseNetContentFragment and NetworkErrorFragment are encapsulate change UI logic (by fragments' swapping), in case of network error. They should be extended by other classes.

1) BaseNetContentView.java - base interface for all Views, that should show "network error" UI.

public interface BaseNetContentView {
    public void showNetworkContentError();
}

2) BaseNetContentFragment.java - base for all Fragments, that should show "network error" UI. It contains listener and corresponding interface.

public abstract class BaseNetContentFragment extends Fragment implements BaseNetContentView {
    @Nullable
    private OnNetworkErrorListener mOnNetworkErrorListener;

    protected final void tryToShowNetworkError() {
        if (mOnNetworkErrorListener != null) {
            mOnNetworkErrorListener.onNetworkError();
        }
    }

    protected final boolean hasOnNetworkErrorListener() {
        return mOnNetworkErrorListener != null;
    }

    public final void setOnNetworkErrorListener(
            @Nullable OnNetworkErrorListener onNetworkErrorListener) {
        mOnNetworkErrorListener = onNetworkErrorListener;
    }

    public interface OnNetworkErrorListener {
        public void onNetworkError();
    }
}

3) BaseNetContentActivity - base Activity, that handling network error by changing UI fragments

public abstract class BaseNetContentActivity<T extends BaseNetContentFragment>
        extends AppCompatActivity implements BaseNetContentFragment.OnNetworkErrorListener {
    private static final String TAG = "BaseNetContentActivity";

    @Override
    public void onNetworkError() {
        FragmentManager fragmentManager = getSupportFragmentManager();
        Fragment fragment = getCurrentContentFragment(fragmentManager);

        // Skip if already NetworkErrorFragment
        if (!(fragment instanceof NetworkErrorFragment)) {
            setFragmentToActivity(fragmentManager, new NetworkErrorFragment());
        }
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutResId());
        Fragment fragment = getCurrentContentFragment(getSupportFragmentManager());

        // NetworkErrorFragment is self-sufficient
        if (fragment instanceof NetworkErrorFragment) {
            return;
        }

        setNetworkContentFragmentToActivity(savedInstanceState);

    }

    @Override
    public void onAttachFragment(Fragment fragment) {
        // Set appropriate listener to fragment
        if (fragment instanceof NetworkErrorFragment) {
            ((NetworkErrorFragment) fragment)
                    .setOnReloadContentListener(new NetworkErrorFragment.OnReloadContentListener() {
                        @Override
                        public void onReloadContent() {
                                setNetworkContentFragmentToActivity(null);
                        }
                    });
        } else if (fragment instanceof BaseNetContentFragment) {
            ((BaseNetContentFragment) fragment).setOnNetworkErrorListener(this);
        }
        // Don't do anything with other fragment's type
    }

    @NonNull
    protected abstract T createNetworkContentFragment();

    protected abstract void setPresenter(@NonNull T fragment, @Nullable Bundle savedInstanceState);

    @LayoutRes
    protected int getLayoutResId() {
        return R.layout.basenetworkcontent_act;
    }

    @IdRes
    protected int getContentFrameId() {
        return R.id.network_content_frame;
    }

    private void setNetworkContentFragmentToActivity(@Nullable Bundle savedInstanceState) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        Fragment fragment = getCurrentContentFragment(fragmentManager);

        if (fragment == null || fragment instanceof NetworkErrorFragment) {
            fragment = createNetworkContentFragment();
        }

        try {
            setPresenter((T) fragment, savedInstanceState);
        } catch (ClassCastException e) {
            // Unexpected fragment type
            Log.d(TAG,"Can't set Presenter because of wrong View type (wrong fragment)" + e);

            // Casting to T type is safe, because createNetworkFragment() returns T type
            fragment = createNetworkContentFragment(); // returns type T
            setPresenter((T) fragment, savedInstanceState);
        }

        setFragmentToActivity(fragmentManager, fragment);

    }

    private Fragment getCurrentContentFragment(@NonNull FragmentManager fragmentManager) {
        return fragmentManager.findFragmentById(getContentFrameId());
    }

    private void setFragmentToActivity(@NonNull FragmentManager fragmentManager,
                                       @NonNull Fragment fragment) {
        fragmentManager.beginTransaction()
                       .replace(getContentFrameId(), fragment)
                       .commit();
    }
}

4) NetworkErrorFragment

public static class NetworkErrorFragment extends Fragment implements View.OnClickListener {
    @Nullable
    private OnReloadContentListener mOnReloadContentListener;
    private Button mReloadButton;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater,
                             @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        View root = inflater.inflate(R.layout.networkerror_frag, container, false);
        mReloadButton = (Button) root.findViewById(R.id.reload_content_button);
        if (mOnReloadContentListener != null) {
            mReloadButton.setOnClickListener(this);
        } else {
            mReloadButton.setVisibility(View.INVISIBLE);
        }
        return root;
    }

    @Override
    public void onClick(View v) {
        if (mOnReloadContentListener != null) {
            mOnReloadContentListener.onReloadContent();
        }
    }

    public void setOnReloadContentListener(@Nullable OnReloadContentListener onReloadContentListener) {
        mOnReloadContentListener = onReloadContentListener;
    }

    public interface OnReloadContentListener {
        public void onReloadContent();
    }

}

Full example at https://github.com/relativizt/android-network-error-ui

Derisible answered 7/1, 2019 at 12:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.