【问题标题】:Android snackbar null object referenceAndroid 快餐栏空对象引用
【发布时间】:2016-03-28 23:26:44
【问题描述】:

我的应用有一个简单的登录页面,我要做的第一件事就是检查权限。我必须在一开始就这样做,因为没有所有权限,任何应用程序功能都无法工作。如果获得许可,登录页面将继续加载,一切都很好。但如果权限被拒绝,我想显示一个带有一些信息和操作按钮的小吃栏,以便用户可以再次请求权限。

问题是如果用户拒绝权限,我会得到一个错误:

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) 

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

这是登录活动的代码:

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>

我认为问题与我的协调器布局和我的小吃店有关?我已经盯着这个看了好几个小时了,并没有更进一步了解什么是错的

【问题讨论】:

  • 你试过getString(R.string.permission_explain); ?
  • 检查当时coordinatorLayout是否为null。

标签: android android-activity android-permissions android-coordinatorlayout android-snackbar


【解决方案1】:

我认为 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 到 onCreate 之前 findViewById 所以 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);
    }
}

【讨论】:

    【解决方案2】:

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

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

    但您没有声明setContentView(),因此它将返回NullPointerException,因为没有找到id,请尝试在这种情况下使用Snackbar.make(coordinatorLayout, R.string.permission_explain, Snackbar.LENGTH_INDEFINITE)而不是使用coordinatorLayout@尝试使用getWindow().getDecorView().getRootView()之类的东西。

    【讨论】:

      【解决方案3】:

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

      //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 类中的常量作为结果代码:

      PackageManager.PERMISSION_GRANTED
      PackageManager.PERMISSION_DENIED
      

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

      【讨论】:

      • 什么是最有效的方法来检查是否有任何grantResults == -1 而无需手动列出它们?
      • @Simon - 方法 arePermissionsGranted 对于具有 en.wikipedia.org/wiki/KISS_principle
      猜你喜欢
      • 2016-07-04
      • 2016-03-04
      • 2020-11-04
      • 2019-02-28
      • 1970-01-01
      • 2017-05-30
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多