问题
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 eachFragment
, Network is required and in case of any network error, I used to showDialog
. 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.
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?
回答1:
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.
回答2:
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.
回答3:
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.
回答4:
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
来源:https://stackoverflow.com/questions/36054212/best-approach-to-show-network-error-in-android-in-android-with-tap-to-retry-opti