Android snackbar 空对象引用

Android snackbar null object reference

我的应用程序有一个简单的登录页面,我要做的第一件事就是检查权限。我必须在一开始就这样做,因为 none 的应用程序功能将在没有所有权限的情况下运行。如果获得许可,登录页面将继续加载,一切正常。但是,如果权限被拒绝,我想显示一个带有一些信息和操作按钮的快餐栏,以便用户可以再次请求权限。

问题是如果用户拒绝许可我会收到错误消息:

FATAL EXCEPTION: main
Process: com.example.debug, PID: 16846
java.lang.RuntimeException: Failure delivering result ResultInfo{who=@android:requestPermissions:, request=10, result=-1, data=Intent { act=android.content.pm.action.REQUEST_PERMISSIONS (has extras) }} to activity {com.example.debug/com.example.LoginActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.view.View.getResources()' on a null object reference at android.app.ActivityThread.deliverResults(ActivityThread.java:3699)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742)
at android.app.ActivityThread.-wrap16(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5422)
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.res.Resources android.view.View.getResources()' on a null object reference at android.support.design.widget.Snackbar.make(Snackbar.java:234)at com.example.LoginActivity.onRequestPermissionsResult(LoginActivity.java:56) at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:6582)
at android.app.Activity.dispatchActivityResult(Activity.java:6460)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3695)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742) 
at android.app.ActivityThread.-wrap16(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.app.ActivityThread.main(ActivityThread.java:5422) 
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) 

当用户接受权限时,登录页面似乎可以正确加载。虽然出于某种原因它没有检查我列出的所有权限,但我会把它留到另一个问题

这是登录代码 activity:

public class LoginActivity extends AppCompatActivity {

    public static final String TAG = "LoginActivity";

    CoordinatorLayout coordinatorLayout;

    final String[] PERMISSIONS = {Manifest.permission.WRITE_EXTERNAL_STORAGE,
                                Manifest.permission.READ_EXTERNAL_STORAGE,
                                Manifest.permission.WAKE_LOCK,
                                Manifest.permission.CAMERA};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinator_layout_login);

        //If any of the permission have not been granted
        if (!hasPermission(PERMISSIONS[0]) || !hasPermission(PERMISSIONS[1]) ||
                !hasPermission(PERMISSIONS[2]) || !hasPermission(PERMISSIONS[3])){
            Log.i(TAG, "checking initial permissions");
            ActivityCompat.requestPermissions(this, PERMISSIONS, 10);
        }
    }

    public boolean hasPermission(String permission){
        Log.i(TAG, "hasPermission()");
        return (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED);
    }

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

        Log.i(TAG, "onRequestPermissionsResult");
        //If at least one permission has been denied
        if (grantResults.length > 0 && grantResults[0] == -1){
            Log.i(TAG, "granting failed - show snackbar");
            Snackbar.make(coordinatorLayout, R.string.permission_explain, Snackbar.LENGTH_INDEFINITE)
                    .setAction(R.string.snackbar_request_permission, new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            ActivityCompat.requestPermissions(LoginActivity.this, PERMISSIONS, 10);
                        }
                    })
                    .show();
        } else {
            //If all permissions have been granted
            Log.i(TAG, "Permissions granted");
            setContentView(R.layout.activity_login);

            //set username by default
            EditText usernameText = (EditText) findViewById(R.id.input_user);
            //Load some UI things
        }
    }

如果有帮助,这是我的 XML 包含协调器布局的文件:

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/coordinator_layout_login"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.example.LoginActivity"
    android:background="@color/colorPrimary">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="56dp"
        android:paddingLeft="24dp"
        android:paddingRight="24dp"
        android:descendantFocusability="beforeDescendants"
        android:focusableInTouchMode="true">

        <ImageView android:src="@drawable/ic_run_white_48dp"
            android:layout_width="wrap_content"
            android:layout_height="72dp"
            android:layout_marginBottom="24dp"
            android:layout_gravity="center_horizontal" />

        <!-- Username Label -->
        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:layout_marginBottom="8dp">
            <EditText android:id="@+id/input_user"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:inputType="text"
                android:hint="@string/hint_username" />
        </android.support.design.widget.TextInputLayout>

        <!-- Password Label -->
        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:layout_marginBottom="8dp">
            <EditText android:id="@+id/input_password"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:inputType="textPassword"
                android:hint="@string/hint_password"/>
        </android.support.design.widget.TextInputLayout>

        <android.support.v7.widget.AppCompatButton
            android:id="@+id/btn_login"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="24dp"
            android:layout_marginBottom="24dp"
            android:padding="12dp"
            android:text="@string/login_button_text"
            android:textColor="@color/colorPrimaryLight"
            android:background="@color/colorPrimaryDark"
            android:onClick="authenticateUser"/>

    </LinearLayout>
</android.support.design.widget.CoordinatorLayout>

我认为问题与我的协调器布局以及我的小吃店有关?我已经盯着这个看了好几个小时了,还是没能理解哪里出了问题

我认为 onCreate 或 onRequestPermissionResult 中有错误。您尝试查找视图 coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinator_layout_login); 这将返回 null。接下来,您在 onRequestPermissionResult 中使用它。

解决方案:

1。主视图

您可以使用另一个视图代替不存在的 coordinatorLayout。在代码中:

Snackbar.make(coordinatorLayout, R.string.permission_explain, Snackbar.LENGTH_INDEFINITE)
                .setAction(R.string.snackbar_request_permission, new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        ActivityCompat.requestPermissions(LoginActivity.this, PERMISSIONS, 10);
                    }
                })
                .show();

您可以使用 findViewById(android.R.id.content) 而不是 coordinatorLayout(为空)。最终代码将是:

Snackbar.make(findViewById(android.R.id.content), R.string.permission_explain, Snackbar.LENGTH_INDEFINITE)
                    .setAction(R.string.snackbar_request_permission, new View.OnClickListener() {
                         @Override
                         public void onClick(View view) {
                             ActivityCompat.requestPermissions(LoginActivity.this, PERMISSIONS, 10);
                         }
                    })
                    .show();

2。在寻找 coordinatorLayout

之前设置内容视图

在 onCreate 中,您在设置任何内容之前有 findViewById。例如,您可以移动线

setContentView(R.layout.activity_login);
从 onRequestPermissionsResult 到 findViewById 之前的 onCreate,因此 onCreate 方法将是:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);
    coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinator_layout_login);

    //If any of the permission have not been granted
    if (!hasPermission(PERMISSIONS[0]) || !hasPermission(PERMISSIONS[1]) ||
            !hasPermission(PERMISSIONS[2]) || !hasPermission(PERMISSIONS[3])){
        Log.i(TAG, "checking initial permissions");
        ActivityCompat.requestPermissions(this, PERMISSIONS, 10);
    }
}

我想这是给你的 NullPointerException 因为你正在这样做:

coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinator_layout_login);

但是你没有声明 setContentView() 所以它会 return NullPointerException 因为没有找到 id,尝试在这种情况下使用 coordinatorLayout Snackbar.make(coordinatorLayout, R.string.permission_explain, Snackbar.LENGTH_INDEFINITE) 尝试使用类似 getWindow().getDecorView().getRootView().

的东西

既然你要求四个权限,你不应该检查所有结果:

//If at least one permission has been denied
if (grantResults.length > 0 && grantResults[0] == -1){

而不是检查第一个?

只需使用:

public boolean arePermissionsGranted(int[] grantResults) {
    for (int result : grantResults) {
        if (result != PackageManager.PERMISSION_GRANTED) {
            return false;
        }
    }
    return true;
}

您还可以使用 PackageManager class 中的常量作为结果代码:

PackageManager.PERMISSION_GRANTED
PackageManager.PERMISSION_DENIED

http://developer.android.com/training/permissions/requesting.html