【问题标题】:new Intent(Context, Class) throws NullPointerException新意图(上下文,类)抛出 NullPointerException
【发布时间】:2024-04-24 16:10:02
【问题描述】:

我有以下功能:

@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
    if (s.equals("service_enabled")) {
        boolean shouldStart = sharedPreferences.getBoolean(s, false);
        Intent intent = new Intent(getActivity(), HUD.class);
        if (shouldStart) {  // Turn on
            getActivity().startService(intent);
        } else {            // Turn off
            getActivity().stopService(intent);
        }

    }
}

当我的PreferenceFragment 发生更改时调用该函数。如果shouldStart == false,服务Hud(可能)正在运行,然后我想停止它。如果您只需单击该选项两次,这将按预期工作;服务启动和停止。但是,如果你启动它,回到之前的activity,再次输入这个fragment,并尝试禁用它,会发生以下情况:

01-25 22:22:44.848  32548-32548/net.hath.drawcut E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NullPointerException
        at android.content.ComponentName.<init>(ComponentName.java:75)
        at android.content.Intent.<init>(Intent.java:3558)
        at net.hath.drawcut.ui.fragment.PrefsFragment.onSharedPreferenceChanged(PrefsFragment.java:35)
        at android.app.SharedPreferencesImpl$EditorImpl.notifyListeners(SharedPreferencesImpl.java:475)
        at android.app.SharedPreferencesImpl$EditorImpl.apply(SharedPreferencesImpl.java:385)
        at android.preference.Preference.tryCommit(Preference.java:1349)
        at android.preference.Preference.persistBoolean(Preference.java:1615)
        at android.preference.TwoStatePreference.setChecked(TwoStatePreference.java:83)
        at android.preference.TwoStatePreference.onClick(TwoStatePreference.java:69)
        at android.preference.Preference.performClick(Preference.java:949)
        at android.preference.PreferenceScreen.onItemClick(PreferenceScreen.java:215)
        at android.widget.AdapterView.performItemClick(AdapterView.java:298)
        at android.widget.AbsListView.performItemClick(AbsListView.java:1100)
        at android.widget.AbsListView$PerformClick.run(AbsListView.java:2749)
        at android.widget.AbsListView$1.run(AbsListView.java:3423)
        at android.os.Handler.handleCallback(Handler.java:725)
        at android.os.Handler.dispatchMessage(Handler.java:92)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:5227)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:795)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:562)
        at dalvik.system.NativeStart.main(Native Method)

第 35 行是Intent intent = new Intent(getActivity(), HUD.class);

这里发生了什么?

【问题讨论】:

  • 请上传完整的堆栈跟踪
  • 您提到HUD是一项服务,第35行是您启动该服务的方法吗? getActivity() 可能由于某种原因为空,在这种情况下,可以像 Intent intent=new Intent("com.demo.service.ServiceClass"); 那样启动服务。 this.startService(intent);
  • 可能是这样,但这是在一个片段中,这意味着我没有 start- 或 stopService 方法;我需要为此使用getActivity()。但是如果getActivity()突然返回null,只是因为启动了一个服务,那岂不是很奇怪?

标签: java android android-intent service


【解决方案1】:

调试了一段时间后发现问题: getActivity() 返回 null (就像 Ryan 说的 :)。

我使用的解决方案是从this answer 到一个类似的问题。

private Activity activity;

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    this.activity = activity;
}

并将getActivity() 替换为activity。不是很漂亮,而且它可能很容易出现错误,但它确实有效。

【讨论】:

  • 请不要那样做。你在这里泄露了一个完整的活动。
【解决方案2】:

您注册了您的偏好侦听器,但随后您的片段被分离,当您返回活动时,会创建一个新的。

您的旧片段实例仍然存在,由偏好作为侦听器持有。

您需要做的是,当您将片段从活动中分离出来时,将其取消注册为首选项侦听器,并在再次附加时再次注册它。这样可以确保您的片段具有有效的活动引用。

【讨论】:

    【解决方案3】:

    另一种方式:

    private Context mContex;
    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
          mContext = getActivity();
    
    }
    
    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
    if (s.equals("service_enabled")) {
        boolean shouldStart = sharedPreferences.getBoolean(s, false);
        Intent intent = new Intent(mContext, HUD.class);
        if (shouldStart) {  // Turn on
            mContext.startService(intent);
        } else {            // Turn off
            mContext.stopService(intent);
        }
    
    }
    

    }

    【讨论】: