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
我的应用程序有一个简单的登录页面,我要做的第一件事就是检查权限。我必须在一开始就这样做,因为 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