【问题标题】:Null object reference for an interface/bundle接口/包的空对象引用
【发布时间】:2019-06-27 09:24:31
【问题描述】:

我有一个正在收集付款信息的屏幕。在这里,用户可以按“返回”按钮更改 ShopFragment 中的采购订单,也可以按“提交”按钮转到 ConfirmationFragment。 Back 按钮可以正常工作,但 Submit 按钮会导致此错误:

06-27 01:07:38.321 14771-14771/com.shop.away E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.shop.away, PID: 14771
    java.lang.NullPointerException: Attempt to invoke interface method 'void com.shop.away.ui.PaymentFragment$OnPaymentSubmitListener.onPaymentSubmit(android.os.Bundle)' on a null object reference
        at com.shop.away.ui.PaymentFragment$7.onSuccess(PaymentFragment.java:294)
        at com.shop.away.ui.PaymentFragment$7.onSuccess(PaymentFragment.java:289)
        at com.google.android.gms.tasks.zzn.run(Unknown Source)
        at android.os.Handler.handleCallback(Handler.java:739)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:158)
        at android.app.ActivityThread.main(ActivityThread.java:7224)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)

这是PaymentFragment的代码:

private OnPaymentSubmitListener paymentSubmitListener;

@Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment

        paymentView = inflater.inflate(R.layout.fragment_payment, container, false);

btnBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                bundle.putBoolean("direction", false);
                paymentSubmitListener.onPaymentSubmit(bundle);
            }
        });

        btnPlaceOrder.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                getToken();
            }
        });
        return paymentView;
    }

private void getToken() {
// If token obtained successfully place order
}

private void placeOrder() {
if (orderPlaced.isSuccessful) {
bundle.putBoolean("direction", true);
                paymentSubmitListener.onPaymentSubmit(bundle);
}

public void onButtonPressed(Bundle bundle) {
        if (paymentSubmitListener != null) {
            paymentSubmitListener.onPaymentSubmit(bundle);
        }
    }

    @Override
    public void onAttach(Context context) {
        paymentContext = context;
        super.onAttach(paymentContext);
        if (context instanceof OnPaymentSubmitListener) {
            paymentSubmitListener = (OnPaymentSubmitListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        paymentSubmitListener = null;
    }

    public interface OnPaymentSubmitListener {
        void onPaymentSubmit(Bundle bundle);
    }
}

在我的 MainActivity 中,这就是我处理界面的方式:

public void onPaymentSubmit(Bundle bundle) {
        if (bundle != null && bundle.containsKey("direction")) {
            Boolean direction = bundle.getBoolean("direction");
            if (!direction) {
                ShopFragment fragment = new ShopFragment();
                openFragment(bundle, fragment, direction);
            } else {
                ConfirmationFragment fragment = new ConfirmationFragment();
                openFragment(bundle, fragment, direction);
            }
        }
    }

private void openFragment(Bundle bundle, Fragment fragment, Boolean direction) {
// Open corresponding fragment using animation
}

PaymentFragment.java:294 在这里特指这一行:paymentSubmitListener.onPaymentSubmit(bundle)

【问题讨论】:

  • 你在哪里初始化'paymentSubmitListener'
  • 在 onAttach 中。这就是你现在初始化它的方式吗?
  • 你在哪里初始化了 paymentSubmitListener 。做 paymentSubmitListener=new PaymentSubmitLisetner(params);
  • 在getToken()方法中,有没有机会调用onDetach()?
  • 不,没有机会调用 onDetach()。我会尝试 Shivam 的建议,但奇怪的是后退按钮总是在没有实例化的情况下工作。

标签: android interface


【解决方案1】:

onCreateView() 中初始化你的监听器并添加检查

if(paymentSubmitListener != null)

使用前。

你得到空指针是因为当返回到前一个片段监听器时没有初始化因为 onAttach(Context context) 仅在片段被附加并且当你恢复它时仍然被附加时调用,但是监听器字段初始化消失了。

尝试移动这部分

  if (context instanceof OnPaymentSubmitListener) {
            paymentSubmitListener = (OnPaymentSubmitListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
}

转至public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)

顺便说一句,我建议重新考虑您的架构,因为我认为将上下文用作侦听器的实例并不是一个好习惯。更好的想法是让 Fragment 实现监听器并将其用作this

另一个想法是片段中的Context 可能是null

【讨论】:

  • 但是如果它为空怎么办。如何实例化它?
  • 同意上下文部分。我刚刚创建了一个单独的上下文实例,并且几乎 24 小时没有崩溃并进行了多次测试。这样,我不必移动你说我应该考虑移动的部分。我还使用了默认构造函数 onButtonPressed。谢谢。
  • 单独的上下文实例也是非常糟糕的主意。不要使用上下文作为侦听器:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多