Android 片段中的 Toast 显示空指针 expn

Toast in Android fragments showing null pointer expn

我尝试在片段中显示吐司时,在少数设备上遇到错误。这个吐司通常是在改造响应失败时。 toast代码很简单。求指点,搜来搜去也找不到原因

Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();

下面是我的ST日志。

Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
   at android.widget.Toast.(Toast.java:103)
   at android.widget.Toast.makeText(Toast.java:256)

你的activitycontext在这行是空的:

Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();// getActivity() is null

为避免崩溃,请使用:

if(getActivity() != null)
   Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();

有时,当片段未与 Activity 相关联时,getActivity() 或 getContext() 可能会产生空指针异常。所以使用onAttach方法

public class yourFragment extends Fragment {
   Context context

   @Override
   public void onAttach(Context context) {
        this.context = context;
        super.onAttach(context);
   }
}

将您的 getActivity() 更改为 getContext()。试试下面给定的代码:

Toast.makeText(getContext(), "Connection Failure", Toast.LENGTH_LONG).show();

可能 getActivity() 在片段分离时调用。试试吧。

if (isAdded()) {
    Toast.makeText(getActivity(), "something", Toast.LENGTH_SHORT).show();
}

根据 Fragment.getActivity() 的代码和 javadoc,您可以得到 null returned:

/**
 * Return the {@link FragmentActivity} this fragment is currently associated with.
 * May return {@code null} if the fragment is associated with a {@link Context}
 * instead.
 *
 * @see #requireActivity()
 */
@Nullable
final public FragmentActivity getActivity() {
    return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}

尤其是当您的 Fragment 未附加到 activity 时(如 and 所指出的),这可能会发生。

同理,getContext()也可以returnnull。

在这个可能相关的 post:

上,关于何时这些可以为 null 的讨论很好

- 在显示 Toast.

之前进行空检查

但潜在的问题是架构之一 - 您的代码将 API activity 耦合到您的 UI,并假设您的 UI 状态的某些事情,即您假设当 API 调用 return 时,您的屏幕仍然对用户可见。


更好的解决方案是将 Retrofit 调用与 UI - put the API calls in a separate class that does not depend on the UI state.

分离

使用事件或发布-订阅框架从这个 API 包装器 class 返回到任何 UI 需要知道何时 API 调用 return秒。

EventBusRxJava 将是 2 种常见的解决方案(LocalBroadcastManager 将是一种不太常见的方法)。

这将允许任何代码调用您的 API,并订阅在 API return 时收到通知。

它还允许您将 API 响应保存在(例如)本地数据库中,在这种情况下,您可以仅依靠 LiveData 模式来更新任何 UI那是必须的。

Here's a Medium article giving a brief description of how to use the Android Architecture Components in this manner using the Repository pattern.


鉴于某些项目无法立即重新设计,可能需要变通办法。

上面提到的 null 检查解决方法很有用,因为应用程序将不再崩溃。不幸的是,这确实意味着用户不会收到有关失败的 API 呼叫的警报。

一种替代方法是创建您自己的 Application subclass(许多项目已经这样做以初始化公共库)并提供静态访问此应用程序的方法 Context

然后您可以选择使用应用程序 Context 而不是片段中的应用程序来显示 Toast。您可能会丢失从更具体的上下文中获得的任何特定样式,但优点是您的用户仍然可以看到 Toast 消息。

将您的 Application 暴露为单身人士已在 post:

上进行了很好的描述
if (isAdded()) {
    Toast.makeText(getActivity(), "something", Toast.LENGTH_SHORT).show();
}

或者试试这个

if(getActivity() != null)
   Toast.makeText(getActivity(), "Connection Failure", Toast.LENGTH_LONG).show();

两者在我的情况下都可以正常工作,因为在某些情况下 getActivity() 在片段分离时调用。

所以我们也必须解决这个问题。