使用“点击重试”选项在 Android 中显示 android 中的网络错误的最佳方法
Best approach to show network error in android in Android with Tap to Retry option
我的申请中有 Navigation Drawer
,除了主要申请流程外,还有几个 Fragments
和几个新的 Activity
。
- 当前功能
为了导航到每个 Fragment
,需要网络,如果出现任何网络错误,我曾经显示 Dialog
.用户需要单击 "OK" 按钮并再次返回导航抽屉重试。
- 我正在尝试的新方法
应该显示用户和类似于 LinkedIn android 应用程序的错误屏幕,并提供重试选项。
由于内部Fragments
和处理回调可能很麻烦,如何有效地处理这种情况?
对于单个 Activity,这可以轻松实现,但担心导航抽屉和内部 Fragments。
有什么建议吗?
您可以在FrameLayout
中放置一些ContentFragment
,然后在网络断开时替换为NetworkDisconnectedFragment
。这将需要按钮调用回调,然后在重新连接时,在回调实现中将 NetworkDisconnectedFragment
替换为旧的 ContentFragment
。
将此错误布局隐藏在此片段中。当出现任何网络错误时,将其可见性更改为 VISIBLE。并在此隐藏布局中添加一个按钮以调用相同的方法来检查网络连接等。
假设你有片段 xml 比如 -
片段-
相对布局包括 -
1.-所有布局(可见)&
2. - 带有按钮的隐藏网络错误布局(消失)
当出现网络错误时,将 1. 的可见性更改为 - GONE
和 2. 对 VISIBLE
的可见性
和重试按钮调用 -
checkNetworkConnectionCall();
希望这能解决您的问题。
您可以在每个片段中包含此 UI 并创建一个 BaseFragment,它将被导航抽屉中的每个片段扩展。
在该基本片段中编写一个方法来完成更改 UI 所需的完整逻辑。
每当您检测到网络故障时,只需从那里的基本片段中盲目调用该方法即可。
已经将近 3 年了,但我认为它可能对某些人有所帮助。此示例使用 MVP 模式。 BaseNetContentActivity、BaseNetContentFragment 和NetworkErrorFragment 封装了变化UI 逻辑(通过分片交换),以防网络错误。它们应该由其他 类.
扩展
1) BaseNetContentView.java - 所有视图的基本界面,应显示 "network error" UI。
public interface BaseNetContentView {
public void showNetworkContentError();
}
2) BaseNetContentFragment.java - 所有片段的基础,应该显示 "network error" UI。它包含监听器和相应的接口。
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,通过改变 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();
}
}
完整示例位于 https://github.com/relativizt/android-network-error-ui
我的申请中有 Navigation Drawer
,除了主要申请流程外,还有几个 Fragments
和几个新的 Activity
。
- 当前功能
为了导航到每个Fragment
,需要网络,如果出现任何网络错误,我曾经显示Dialog
.用户需要单击 "OK" 按钮并再次返回导航抽屉重试。 - 我正在尝试的新方法
应该显示用户和类似于 LinkedIn android 应用程序的错误屏幕,并提供重试选项。
由于内部Fragments
和处理回调可能很麻烦,如何有效地处理这种情况?
对于单个 Activity,这可以轻松实现,但担心导航抽屉和内部 Fragments。
有什么建议吗?
您可以在FrameLayout
中放置一些ContentFragment
,然后在网络断开时替换为NetworkDisconnectedFragment
。这将需要按钮调用回调,然后在重新连接时,在回调实现中将 NetworkDisconnectedFragment
替换为旧的 ContentFragment
。
将此错误布局隐藏在此片段中。当出现任何网络错误时,将其可见性更改为 VISIBLE。并在此隐藏布局中添加一个按钮以调用相同的方法来检查网络连接等。
假设你有片段 xml 比如 -
片段-
相对布局包括 -
1.-所有布局(可见)&
2. - 带有按钮的隐藏网络错误布局(消失)
当出现网络错误时,将 1. 的可见性更改为 - GONE 和 2. 对 VISIBLE
的可见性和重试按钮调用 -
checkNetworkConnectionCall();
希望这能解决您的问题。
您可以在每个片段中包含此 UI 并创建一个 BaseFragment,它将被导航抽屉中的每个片段扩展。
在该基本片段中编写一个方法来完成更改 UI 所需的完整逻辑。
每当您检测到网络故障时,只需从那里的基本片段中盲目调用该方法即可。
已经将近 3 年了,但我认为它可能对某些人有所帮助。此示例使用 MVP 模式。 BaseNetContentActivity、BaseNetContentFragment 和NetworkErrorFragment 封装了变化UI 逻辑(通过分片交换),以防网络错误。它们应该由其他 类.
扩展1) BaseNetContentView.java - 所有视图的基本界面,应显示 "network error" UI。
public interface BaseNetContentView {
public void showNetworkContentError();
}
2) BaseNetContentFragment.java - 所有片段的基础,应该显示 "network error" UI。它包含监听器和相应的接口。
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,通过改变 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();
}
}
完整示例位于 https://github.com/relativizt/android-network-error-ui