【问题标题】:Android Studio: Error of java.lang.NullPointerException when the headlessfragment calledAndroid Studio:调用headlessfragment时java.lang.NullPointerException的错误
【发布时间】:2017-01-25 05:31:48
【问题描述】:

我有一个主 Activity 和一个无头片段。
无头Fragment应该是获取手机的IMEI号进行记录并返回给主Activity。
我有这个错误几个小时了,我似乎无法摆脱它。

这是日志:

E/AndroidRuntime: FATAL EXCEPTION: main
                      Process: com.androidproject.example, PID: 5418
                      java.lang.RuntimeException: Unable to start activity ComponentInfo{com.androidproject.example/com.androidproject.example.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.app.Activity.getApplicationContext()' on a null object reference
                          at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
                          at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
                          at android.app.ActivityThread.-wrap11(ActivityThread.java)
                          at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
                          at android.os.Handler.dispatchMessage(Handler.java:102)
                          at android.os.Looper.loop(Looper.java:148)
                          at android.app.ActivityThread.main(ActivityThread.java:5417)
                          at java.lang.reflect.Method.invoke(Native Method)
                          at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
                          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
                       Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.app.Activity.getApplicationContext()' on a null object reference
                          at com.androidproject.example.HeadlessFragment.loadIMEI(HeadlessFragment.java:110)
                          at com.androidproject.example.MainActivity.onCreate(MainActivity.java:40)
                          at android.app.Activity.performCreate(Activity.java:6237)
                          at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
                          at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
                          at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
                          at android.app.ActivityThread.-wrap11(ActivityThread.java) 
                          at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
                          at android.os.Handler.dispatchMessage(Handler.java:102) 
                          at android.os.Looper.loop(Looper.java:148) 
                          at android.app.ActivityThread.main(ActivityThread.java:5417) 
                          at java.lang.reflect.Method.invoke(Native Method) 
                          at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
                          at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
    Application terminated.

这是 MainActivity 中的相关代码部分:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mDeviceCode = (TextView)findViewById(R.id.device_code);

        // Initializing headless fragment
        mFragment =
                (HeadlessFragment) getFragmentManager()
                        .findFragmentByTag("IMEILoader");

        if(mFragment == null) {
            mFragment = new HeadlessFragment();
            getFragmentManager().beginTransaction()
                    .add(mFragment, "IMEILoader").commit();
        }
        if(mFragment != null){
            mNumber = mFragment.loadIMEI(); //Here's the error
            mDeviceCode.setText(Html.fromHtml("<b>IMEI</b>: " + mFragment.loadIMEI()));
        }

HeadlessFragment 代码如下:

    //Called when the 'loadIMEI' function is triggered.
    public String loadIMEI() {

        if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_PHONE_STATE)
                != PackageManager.PERMISSION_GRANTED) {
            // READ_PHONE_STATE permission has not been granted.
            requestPermissions();
        } else {
            // READ_PHONE_STATE permission is already been granted.
            RecordedIMEI = permissionGrantedActions();
        }
        if(RecordedIMEI != null) {
            Log.i("loadIMEIService", "IMEI number returned!");
        }
        return RecordedIMEI;
    }

    public String permissionGrantedActions() {


        //Get IMEI Number of Phone
        TelephonyManager tm =(TelephonyManager)getActivity().getSystemService(Context.TELEPHONY_SERVICE);

        String IMEINumber = tm.getDeviceId();

        //RecordedIMEI = IMEINumber;

        if(IMEINumber != null) {
            Log.i("IMEI Loader", "IMEI number recorded!");
        }
        return IMEINumber;
    }
}

我尝试了不同的方法,但没有运气。我认为getActivity().getApplicationContext() 没有指向任何地方,这意味着在无头片段附加到 mainactivity 之前调用它?
我已经坚持了很长一段时间,需要一些帮助。

【问题讨论】:

  • onDetach()屏蔽这条线mActivity = null;
  • @IntelliJAmiya 它仍然给我同样的错误。
  • 你尝试了什么?那里的答案说“解决方案是在getActivity()之前,检查isAdded()是否为真,如果不是真的,这意味着片段已经分离,调用getActivity()将返回null”......你有很多对 getActivity() 的调用次数,这对于分离的 Fragment 不起作用,这是有充分理由的
  • 什么是“无头片段”?片段被设计为可重用的 UI 元素,因此您本质上只是想要需要 Context 的静态实用程序类?

标签: java android android-fragments nullpointerexception


【解决方案1】:

我认为你对这个“无头片段”的想法是错误的,因为......

Fragment 表示 Activity 中的一种行为或用户界面的一部分。

您似乎想要一个包含 Context 并可以调用一些权限事物的静态实用程序类。从代码和其他答案中删除extends Fragment,这基本上就是你剩下的。

把它变成一个单例,你就不需要到处使用 Context 参数了。

(未经测试的代码)

可能无法完全正常工作。例如,不确定ActivityCompat.OnRequestPermissionsResultCallback 的工作原理...

但它公开了您需要的功能,而无需解决 Fragment 生命周期。

public final class IMEILoader {
    public static IMEILoader mInstance;
    private Context mContext;

    private IMEILoader() {}
    private IMEILoader(Context c) {
        this.mContext = c;
    }

    // Singleton pattern
    public static IMEILoader getInstance(Context c) {
        if (!(c instanceof ActivityCompat.OnRequestPermissionsResultCallback)) {
            throw new Exception("Passed context not implementing permission callbacks");
        }
        if (mInstance == null) mInstance = new IMEILoader(c);
        return mInstance;
    }

    public String load() {
        String recordedIMEI = null;

        if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.READ_PHONE_STATE)
            != PackageManager.PERMISSION_GRANTED) {
            // READ_PHONE_STATE permission has not been granted.
            requestPermissions();
        } else {
            // READ_PHONE_STATE permission is already been granted.
            recordedIMEI = permissionGrantedActions();
        }
        if(recordedIMEI != null) {
            Log.i("loadIMEIService", "IMEI number returned!");
        }
        return recordedIMEI;
    }    

    public String permissionGrantedActions() {
        return null;
    }


}

你可以在 Activity 中使用它

class FooActivity extends AppCompatActivity impelements ActivityCompat.OnRequestPermissionsResultCallback {
    private IMEILoader loader;
    ...  

    public void onCreate(Bundle b) {
        ...
        loader = IMEILoader.getInstance(MainActivity.this);
        String blah = loader.load();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        ...

    }

【讨论】:

  • 现在测试这个。为什么在这里使用无头片段不正确?仅供参考。
  • 我把它写成一个单独的类,但你可以嵌套它。无论如何,我个人从未使用过无头片段。据我所知,这两种设计都是做同样事情的方法。不过,您可以在所有活动中使用这个类,它是我从 Android 中独立学习的一种 Java 模式。 luboganev.github.io/blog/headless-fragments
  • 用户权限有点问题。有没有办法使用上述方法做到这一点?
  • 不确定你的意思。 ActivityCompat.checkSelfPermission 是一个接受 Context 的静态方法。这就是我要展示的全部内容。
  • 我认为它应该可以正常工作。我有一个错误。 @Override 错误“方法不覆盖其超类中的方法”对于此方法 public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults){....}。有什么反馈吗?
【解决方案2】:

更改此行

 mNumber = mFragment.loadIMEI();

 mNumber = mFragment.loadIMEI(MainActivity.this);

你的功能应该是这样的。

public String loadIMEI(Context context) {
        //Context context = getActivity().getApplicationContext();
        //Activity activity = context instanceof Activity ? (Activity) context : null;
        //mActivity = activity;
        // Check if the READ_PHONE_STATE permission is already available.
        //this.context = getActivity().getApplicationContext();

        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE)
                != PackageManager.PERMISSION_GRANTED) {
            // READ_PHONE_STATE permission has not been granted.
            requestPermissions();
        } else {
            // READ_PHONE_STATE permission is already been granted.
            RecordedIMEI = permissionGrantedActions();
        }
        if(RecordedIMEI != null) {
            Log.i("loadIMEIService", "IMEI number returned!");
        }
        return RecordedIMEI;
    }

【讨论】:

  • 这就是我之前的方式。为了安全起见,我再次尝试了它,但它给了我同样的错误。
  • 代码已更新。我留下了注释掉的部分,这些部分是我试图让它工作的东西,我认为它可能会有所帮助。
  • requestPermissionspermissionGrantedActions 也使用 getActivity(),顺便说一句
  • @cricket_007 但他正在从 Activity 类调用此方法:)
  • 我认为这解决了上述错误!但是,它给了我一个指向这一行的新错误“ RecordedIMEI = permissionGrantedActions(); ”,以及这个在permissionGrantedActions() "TelephonyManager tm =(TelephonyManager)getActivity().getSystemService(Context.TELEPHONY_SERVICE);"
猜你喜欢
  • 1970-01-01
  • 2017-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-03
相关资源
最近更新 更多