首页 > 解决方案 > 由于 Intent 中的 NullPointerException,Android 画廊应用程序在安装后无法启动

问题描述

我是 Java 新手并使用 Android Studio。我的应用程序在安装后不会启动。检查源代码和 XML,我似乎找不到任何错误。请帮我检查下面的代码

MainActivity.java

public class MainActivity extends AppCompatActivity {

    ArrayList<File> list;
    GridView gridView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        gridView = (GridView)findViewById(R.id.image_grid);

        list = imageReader(Environment.getExternalStorageDirectory());

        gridView.setAdapter(new gridAdapter());

        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {

                Intent intent = new Intent(MainActivity.this, FullImageActivity.class);
                intent.putExtra("img", list.get(i).toString());

                startActivity(intent);
            }
        });



    }

    public class gridAdapter extends BaseAdapter{

        @Override
        public int getCount() {
            return list.size();
        }

        @Override
        public Object getItem(int i) {
            return list.get(i);
        }

        @Override
        public long getItemId(int i) {
            return 0;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            View convertView = null;

            if (convertView == null) {

                convertView = getLayoutInflater().inflate(R.layout.row_layout, viewGroup, false);
                ImageView myImage = (ImageView) convertView.findViewById(R.id.my_image);
                myImage.setImageURI(Uri.parse(list.get(i).toString()));
            }

            return convertView;
        }
    }

    private ArrayList<File> imageReader(File externalStorageDirectory) {

        ArrayList<File> b = new ArrayList<>();

        File[] files = externalStorageDirectory.listFiles();

        for (int i =0; i<files.length; i++){

            if (files[i].isDirectory()){

                b.addAll(imageReader(files[i]));

            }else {

                if (files[i].getName().endsWith(".jpg")) {

                    b.add(files[i]);
                }
            }
        }
        return b;
    }
}

这是activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <GridView
        android:id="@+id/image_grid"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:numColumns="auto_fit"
        android:columnWidth="100dp"
        android:verticalSpacing="100dp"
        android:horizontalSpacing="10dp"
        android:stretchMode="spacingWidthUniform" />

</RelativeLayout>

这是 FullImageActivity.java

public class FullImageActivity extends AppCompatActivity {

    ImageView fullImage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_full_image);

        fullImage = (ImageView)findViewById(R.id.full_image);

        String data = getIntent().getExtras().getString("img");

        fullImage.setImageURI(Uri.parse(data));
    }
}

activity_full_image.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FullImageActivity">

    <ImageView
        android:id="@+id/full_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/wp"
        />

</RelativeLayout>

row_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <ImageView
        android:id="@+id/my_image"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/wp"
        />

</RelativeLayout>

如果我的问题得到关注,我会很高兴,因为它深深地侵蚀了我。

这是 LOGCAT

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference
                                                                                   at com.jkjworks.galleryextra.FullImageActivity.onCreate(FullImageActivity.java:19)
                                                                                   at android.app.Activity.performCreate(Activity.java:7030


#2 更新清单和BUILD.GRADLE

这是清单

  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application

        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"/>
            <activity android:name=".FullImageActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>     

这是APP级别的Build.gradle

  android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "com.domain.galleryextra"
        minSdkVersion 16
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    //noinspection GradleCompatible

    implementation 'com.android.support:appcompat-v7:27.1.1'
    implementation 'com.android.support:design:27.1.1'
    compile 'com.android.support:multidex:1.0.3'
    implementation 'com.android.support.constraint:constraint-layout:1.1.0'
    implementation 'com.google.android.gms:play-services-ads:12.0.1'
    implementation 'com.android.support:support-vector-drawable:27.0.1'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'    

标签: javaandroidxml

解决方案


你确定list.get(i)不是null吗?我会设置一个断点并分析 的返回值,list.get(i)以确保您传递的是有效数据。

另外,使用intent.getStringExtra("img")而不是getIntent().getExtras().getString("img")

您的问题是getIntent()正在接收NULL并且您正在尝试访问它,从而导致NullPointerException发生。

Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference
                                                                                   at com.merizekworks.galleryextra.FullImageActivity.onCreate(FullImageActivity.java:19)

编辑(关于如何调试的快速细分) 您可以做的最好的事情是通过调试器逐步执行您的代码。如果您从未这样做过,它实际上很容易做到,并且会帮助您了解问题所在。

MainActivity改变这个:

public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
    Intent intent = new Intent(MainActivity.this, FullImageActivity.class);
    intent.putExtra("img", list.get(i).toString());
    startActivity(intent);
}

对此,帮助我们调试更容易一点:

public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
    Intent intent = new Intent(MainActivity.this, FullImageActivity.class);
    File selectedFile = list.get(i); //PUT BREAKPOINT ON THIS LINE
    String filePath = selectedFile.toString();
    intent.putExtra("img", filePath );
    startActivity(intent);
}

注意:如果您不熟悉调试代码,那么我强烈建议您花几分钟时间阅读这篇文章。在我看来,它是程序员拥有的最有价值的工具。单击此处了解如何在 Android Studio 中进行调试

断点设置(左侧红圈)

左边的红圈是断点,代码会在这里停止执行,你可以分析每个变量,如上图所示。您甚至可以在您的应用程序正在运行并且执行被断点暂停时“评估表达式”。这样做可以让您抓取内存中当前的任何对象并对其进行测试。

例如,使用上面设置的断点,我们可以使用“调试”选项卡中的“评估表达式”按钮:

如何在 AndroidStudio 中设置断点和调试

这是一篇关于如何使用 AndroidStudio 调试器的文章中如何评估表达式的快速屏幕截图(此处为完整指南):

如何在 AndroidStudio 中使用 Evaluate Expression


更新#2

请注意,如果您使用 API 23 或更高版本,则必须确保您有权从 Android 设备读取/写入。

在您的AndroidManifest.xml内部Manifest标签中包括以下内容:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

然后这是我在项目中使用的解决方案,对我来说效果很好,特别是如果您计划请求多个权限。

public class MainActivity extends AppCompatActivity {
    private final String TAG = "DEBUG";
    private Activity activity;
    private ArrayList<File> list;
    private GridView gridView;

    private final int REQUEST_PERMISSIONS_CODE = 1;
    private String[] PERMISSIONS = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
    };

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        int totalGrantedCount = 0;
        for(int x=0; x < grantResults.length; x++){
            if (grantResults[x] == PackageManager.PERMISSION_GRANTED){
                totalGrantedCount++;
            }
        }

        if(totalGrantedCount == grantResults.length){
            startApp();
        }else{
            boolean somePermissionsForeverDenied = false;
            for(String permission: permissions){
                if(ActivityCompat.shouldShowRequestPermissionRationale(this, permission)){
                    //denied
                    Log.d(TAG, "PERMISSIONS: DENIED " + permission);
                }else{
                    if(ActivityCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED){
                        //allowed
                        Log.d(TAG, "PERMISSIONS: ALLOWED " + permission);
                    } else{
                        //set to never ask again
                        somePermissionsForeverDenied = true;
                    }
                }
            }
            if(somePermissionsForeverDenied){
                final AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
                alertDialogBuilder.setTitle("Permissions Required")
                        .setMessage("You have forcefully denied some of the required permissions " +
                                "for this action. Please open settings, go to permissions and allow them manually.")
                        .setPositiveButton("Settings", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
                                        Uri.fromParts("package", getPackageName(), null));
                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                startActivity(intent);
                            }
                        })
                        .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                            }
                        })
                        .setCancelable(false)
                        .create()
                        .show();
            }else{
                new AlertDialog.Builder(this)
                        .setTitle("PERMISSIONS DENIED")
                        .setMessage("Unable to proceed, this application requires that permissions be accepted to operate correctly. \r\n\r\n YOU MUST APPROVE ALL PERMISSIONS BEFORE CONTINUING.")
                        .setPositiveButton("TAP HERE TO CLOSE AND TRY AGAIN.", new DialogInterface.OnClickListener(){
                            public void onClick(DialogInterface dialog, int which){
                                activity.finish();
                                System.exit(0);
                            }
                        })
                        .setIcon(android.R.drawable.ic_dialog_alert)
                        .setCancelable(false)
                        .show();
            }
        }
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.activity = this;

        //REQUIRED FOR API 23+ - REQUEST FOR PERMISSIONS - ONLY REQUIRED TO BE DONE ONCE PER APP INSTALL.
        int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);

        if (permission != PackageManager.PERMISSION_GRANTED) {
            // We don't have permission so prompt the user
            ActivityCompat.requestPermissions(
                    this,
                    PERMISSIONS,
                    REQUEST_PERMISSIONS_CODE);
        }else{
            startApp();
        }

    }

    public void startApp(){
        gridView = (GridView)findViewById(R.id.image_grid);
        list = imageReader(Environment.getExternalStorageDirectory());
        gridView.setAdapter(new gridAdapter());
        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {

                Intent intent = new Intent(MainActivity.this, FullImageActivity.class);
                intent.putExtra("img", list.get(i).toString());

                startActivity(intent);
            }
        });
    }

    public class gridAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            return list.size();
        }

        @Override
        public Object getItem(int i) {
            return list.get(i);
        }

        @Override
        public long getItemId(int i) {
            return 0;
        }

        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            View convertView = null;

            if (convertView == null) {

                convertView = getLayoutInflater().inflate(R.layout.row_layout, viewGroup, false);
                ImageView myImage = (ImageView) convertView.findViewById(R.id.my_image);
                myImage.setImageURI(Uri.parse(list.get(i).toString()));
            }

            return convertView;
        }
    }

    private ArrayList<File> imageReader(File externalStorageDirectory) {

        ArrayList<File> b = new ArrayList<>();

        File[] files = externalStorageDirectory.listFiles();

        for (int i =0; i<files.length; i++){

            if (files[i].isDirectory()){

                b.addAll(imageReader(files[i]));

            }else {

                if (files[i].getName().endsWith(".jpg")) {

                    b.add(files[i]);
                }
            }
        }
        return b;
    }
}

推荐阅读