简体   繁体   English

Android Studio:headlessfragment调用时,java.lang.NullPointerException错误

[英]Android Studio: Error of java.lang.NullPointerException when the headlessfragment called

I have a main Activity and a headless Fragment. 我有一个主要的活动和一个无头的片段。
The headless Fragment is supposed to get the IMEI number of the phone to be recorded and returned to the main Activity. 无头片段应获取要记录的电话的IMEI编号,并返回到主活动。
I had this bug for a few hours now and I can't seem to shake it off. 我已经有几个小时的错误了,我似乎无法摆脱它。

Here's the logcat: 这是logcat:

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.

And here's the relevant part of the code in the MainActivity: 这是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()));
        }

And here's the HeadlessFragment code: 这是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;
    }
}

I tried different things but no luck. 我尝试了不同的事情,但没有运气。 I think getActivity().getApplicationContext() is pointing no where, which means this is being called before headless fragment is attached to mainactivity? 我认为getActivity().getApplicationContext()没有指向任何地方,这意味着在将无头片段附加到mainactivity之前调用了此方法吗?
I've been stuck on this for quite some time and need some help. 我已经坚持了很长时间,需要一些帮助。

I think you're going about this "headless Fragment" idea wrong since... 我认为您正在错误地考虑“无头碎片”的想法,因为...

A Fragment represents a behavior or a portion of user interface in an Activity. 片段表示活动中的行为或用户界面的一部分。

You seem to want a static utility class that holds a Context and can call some permission things. 您似乎想要一个拥有Context并可以调用一些权限的静态实用程序类。 Take away the extends Fragment from the code and other answer(s), and this is basically what you are left with. 从代码和其他答案中除去extends Fragment ,基本上就是剩下的了。

Turn it into a singleton, and you don't need the Context parameter everywhere. 将其变成单例,您不需要到处都使用Context参数。

(code untested) (代码未经测试)

May not completely work. 可能无法完全正常工作。 For example, not sure how the ActivityCompat.OnRequestPermissionsResultCallback works... 例如,不确定ActivityCompat.OnRequestPermissionsResultCallback工作方式...

But it exposes the functionality you need without working around a Fragment lifecycle. 但是,它无需解决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;
    }


}

And you can use that in the Activity like 您可以在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) {
        ...

    }

Change This Line 更改此行

 mNumber = mFragment.loadIMEI();

To

 mNumber = mFragment.loadIMEI(MainActivity.this);

And your function would be like 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;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM