I have a simple login page for my app and the first thing I'm doing is checking for permissions. I have to do this at the very beginning because none of the apps functionality will work without all permissions. If permission is given, the login page proceeds to load and everything is fine. But if permission is denied, I want to show a snackbar with some information and an action button so users can request permission again.
The problem is I get an error if the user denies permission:
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)
When users accept permission the login page seems to load correctly. Although for some reason it doesn't check through all of my listed permissions, but I'll save that for another question
Here's the code for the login 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
}
}
And if it helps, here is my XML file containing the coordinator layout:
<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>
I'm thinking the problem has something to do with my coordinator layout in conjunction with my snackbar? I've been staring at this for hours now and no closer to understanding whats wrong
I think there's error in onCreate or in onRequestPermissionResult. You try to find view coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinator_layout_login);
and that's returning null. Next, you use it in onRequestPermissionResult.
Solutions:
You can use another view instead of non existing coordinatorLayout. In code:
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();
you could use findViewById(android.R.id.content)
instead of coordinatorLayout(which is null). The final code will be:
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();
In onCreate you have findViewById before setting any content. You could for example move line
setContentView(R.layout.activity_login);from onRequestPermissionsResult to onCreate before findViewById so onCreate method will be:
@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); } }
I guess this is giving to you NullPointerException
since you are doing this :
coordinatorLayout = (CoordinatorLayout) findViewById(R.id.coordinator_layout_login);
but you are not declared the setContentView()
so it will return NullPointerException
because doesn't find that id
, try instead of use coordinatorLayout on this case Snackbar.make(coordinatorLayout, R.string.permission_explain, Snackbar.LENGTH_INDEFINITE)
try using something like getWindow().getDecorView().getRootView()
.
Since you are asking for four permissions shouldn't you check all results in:
//If at least one permission has been denied
if (grantResults.length > 0 && grantResults[0] == -1){
instead of checking the first one?
Just use:
public boolean arePermissionsGranted(int[] grantResults) {
for (int result : grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
You could also use constants from PackageManager
class for result codes:
PackageManager.PERMISSION_GRANTED
PackageManager.PERMISSION_DENIED
http://developer.android.com/training/permissions/requesting.html
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.