【问题标题】:How to avoid android application crash, when setOwnerActivity(Activity activity) in custom DialogFragment causes nullpointerException?当自定义DialogFragment中的setOwnerActivity(Activity activity)导致nullpointerException时,如何避免android应用程序崩溃?
【发布时间】:2019-12-07 10:58:36
【问题描述】:

我在使用 Sharedpreferences 和 DialogFragment 时遇到了一个非常奇怪的异常:

Unable to start activity ComponentInfo{com.example.barta1.site_patrol/com.example.barta1.site_patrol.MainActivity}: 
java.lang.NullPointerException: Attempt to invoke virtual method
 'void android.app.Dialog.setOwnerActivity(android.app.Activity)'
 on a null object reference  -  
android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2679)

我真的不知道是什么原因导致了这个错误,但是发生这种情况后,我永远无法启动 我的应用程序再次崩溃,并出现上述相同的异常。 MainActivity 是我在应用程序中的启动活动,附加了一个 DialogFragment,我用它来登录用户。如果用户未登录(“登录”状态保存在 sharedpreference 对象中),我会显示此对话框片段。

我的 MainActivity 是这样的:

public class MainActivity extends AppCompatActivity implements LoginDialogFragment.NoticeDialogListener {
    //...
    private LoginDialogFragment dialogFragment;
    SharedPreferences pref;
    SharedPreferences.Editor edit;
    //...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        pref = getSharedPreferences("Globals", MODE_PRIVATE);
        edit = pref.edit();

        boolean isloggedin = pref.getBoolean("Loggedin", false);


        if (!isloggedin) {
            //if not logged in show the login dialog
            showLoginDialog();
        } 
        else {
            //... doing some network calls...
        }
    }

    public void showLoginDialog() {
        dialogFragment = new LoginDialogFragment();
        dialogFragment.show(getFragmentManager(), "LoginDialogFragment");
    }

    /***
     * Network calls if dialog dismissed
     * Login dialog can only be closed if logging in is successful
     * (if loginname and password matches). 
     */
    @Override
    public void onDismiss() {
        //... some network related jobs
    }

}


这里是片段类:

public class LoginDialogFragment extends DialogFragment {

    public interface NoticeDialogListener{
         void onDismiss();
    }

    NoticeDialogListener mListener;
    Activity activity;
    AlertDialog dialog;
    SharedPreferences pref;
    SharedPreferences.Editor edit;


    @Override
    public void onAttach(Context context) {

        super.onAttach(context);

        try{
            activity = (Activity) context;
            mListener = (NoticeDialogListener) activity;
            pref = activity.getSharedPreferences("Globals", MODE_PRIVATE);
            edit = pref.edit();

        } catch (ClassCastException e){
            throw new ClassCastException(activity.toString() + "must implement NoticeDialogListener");
        }
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {

        String username = pref.getString("Username", null);

        if(username==null) {

            LayoutInflater inflater = getActivity().getLayoutInflater();
            View view = inflater.inflate(R.layout.dialog_signin, null);

            final AutoCompleteTextView actv_username =  view.findViewById(R.id.username);
            final EditText password =  view.findViewById(R.id.password);

            dialog = new AlertDialog.Builder(new ContextThemeWrapper(getContext(), R.style.AlertDialogCustom))
                    .setView(view)
                    .setTitle("Bejelentkezés")
                    .setPositiveButton("OK", null)
                    .create();


            dialog.setOnShowListener(new DialogInterface.OnShowListener() {
                @Override
                public void onShow(DialogInterface dialogInterface) {
                    final Button button = ( dialog).getButton(AlertDialog.BUTTON_POSITIVE);
                    button.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            String passw = password.getText().toString();
                            String user = actv_username.getText().toString();
                            try {
                                if (user.length() < 4 || passw.length() < 4) {
                                    Toast.makeText(getContext(), "Too short user/pass.", Toast.LENGTH_SHORT).show();
                                    dialog.show();
                                } else {
                                    //login to account, if success dismiss.
                                    login(user, passw, dialog);
                                }


                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            //  dialog.dismiss();
                        }
                    });
                }
            });
            dialog.setCanceledOnTouchOutside(false);

            // set the DialogFragment to make the dialog unable to dismiss with back button
            // (because not working if called on the dialog directly)
            this.setCancelable(false);
            return dialog;
        } // end of - if username == null.

        return null;
    }

    public void login(final String username, String password, final AlertDialog dialog){

          //... some network call
          //... if successful: 
          //              edit.putString("Username", username);
          //              edit.commit();
          //              edit.putBoolean("Loggedin", true);
          //              edit.commit();
          //              dialog.dismiss();
          //              dialog.setOnShowListener(null);
          //     
          //     else 
          //              Toast.makeText(getContext(),"Wrong login credentials", 
          //                   Toast.LENGTH_SHORT).show();
    }


    @Override
    public void onDismiss(DialogInterface dialog) {
        mListener.onDismiss();
        dismissAllowingStateLoss();
    }

重新安装软件包后,我无法重新创建此异常(即使我杀死了应用程序进程,并从最近的应用程序启动它),最终用户不知何故设法做到了这一点,重新启动应用程序立即崩溃(见上面的例外。)。看起来父活动以某种方式变为空(可能在保存状态后无法恢复)。

以后如何避免这种情况?有没有简单的方法来处理这种情况?

如果有人可以向我解释何时调用了来自 android 库的“setOwnerActivity(Activity activity)”,那也将是一个很大的帮助,这样我就可以确定出了什么问题。

感谢您的帮助。

【问题讨论】:

  • 您不能从 onCreateDialog() 返回 null。取消或中止 Dialog 显示为时已晚。请改为使用username 签入showLoginDialog()
  • Awww 男人。这是有史以来最快的答案。你是对的,这导致了异常。非常感谢!

标签: java android nullpointerexception sharedpreferences dialogfragment


【解决方案1】:

正如 Mike M. 所说,

您不能从 onCreateDialog() 返回 null。取消或中止对话框显示为时已晚。

并且在创建片段之前进行用户名检查显然可以解决问题。此外,LoggedIn 字段现在看起来是多余的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-25
    • 1970-01-01
    相关资源
    最近更新 更多