提问者:小点点

当函数被调用时,模拟器抛出异常(android studio


我正在android studio上编写一个游戏,它工作得很好,但是当我把一个函数移到另一个类中时,它就开始崩溃了。

我这样做是为了让我可以在任何地方使用它,因为我只拥有一次它,而不是复制粘贴到我需要使用它的每一个类上。

我在谷歌上查看了如何解决这个问题,但没有任何工作,错误是“getExternalFilesDir”或“OpenFileOutput”返回空我想。

这是一个有两个函数的类(做的事情基本相同),但我不能使用。

import android.media.MediaScannerConnection;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class WriteUserData extends AppCompatActivity {
    
    public void writeToFile(String data, String file) {
        try {
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(openFileOutput(file + ".txt", MODE_PRIVATE));
            outputStreamWriter.write(data);
            outputStreamWriter.close();
        }
        catch (IOException e) {
            Log.e("Exception", "File write failed: " + e.toString());
        }
    }

    public void saveFile(String fileName, String addText){
        try {
            // Creates a file in the primary external storage space of the
            // current application.
            // If the file does not exists, it is created.
            File newFile = new File(this.getExternalFilesDir(null), fileName + ".txt");
            if (!newFile.exists())
                newFile.createNewFile();

            // Adds a line to the file
            BufferedWriter writer = new BufferedWriter(new FileWriter(newFile, true /*append*/));
            writer.write(addText);
            writer.close();
            // Refresh the data so it can seen when the device is plugged in a
            // computer. You may have to unplug and replug the device to see the
            // latest changes. This is not necessary if the user should not modify
            // the files.
            MediaScannerConnection.scanFile(this,
                    new String[]{newFile.toString()},
                    null,
                    null);
        } catch (IOException e) {
            Log.e("ReadWriteFile", "Error while trying to add text in " + fileName + ".txt");
        }
    }

}

还有一个地方,我试图调用函数,但却使模拟器崩溃(我删除了一些“import”代码),这样您就更容易理解了。

    private boolean showStats = true;
    private final static long Interval = 30;
    private Handler handler = new Handler();
    private int flashDisplay = 0;

    @SuppressLint("SetTextI18n")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game_over);

        // change game over screen on click
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        if(showStats){
                            getStats();
                        }
                        flashDisplay++;
                    }
                });
            }
        }, 0, Interval);
    }

    private static void bring(){
        WriteUserData saveScore = new WriteUserData();
        saveScore.saveFile("userdata", "ThisTextWork");
        saveScore.writeToFile("ThisTextWorkToo", "config");
    }

    @SuppressLint("SetTextI18n")
    private void getStats(){
        bring();
    }
}

以下是错误:

java.lang.NullPointerException:尝试在空对象引用块Quote上调用虚拟方法“java.io.FileOutputStream Android.content.context.OpenFileOutput(java.lang.String,int)”


共1个答案

匿名用户

你误解了活动的运作方式。

public class WriteUserData extends AppCompatActivity {

您正在扩展一个activity类,因此WriteUserData也是一个activity。 在这种情况下,应该将其命名为-WriteUserDataActivity

但是,看看你在这里做的事情:

WriteUserData saveScore = new WriteUserData();

你不应该这样使用activity。 应该使用意图和StartActivity()创建它,请参见此处:

https://developer.android.com/training/basics/firstapp/starting-activity

您想要做的是在单独的类中移动打开文件的逻辑,以避免代码重复。 那很好,但不应该用activity来做。 相反,您应该使用utils/helper类。 您的类不应该扩展任何东西,应该有一个私有构造函数:

public class WriteUserDataUtils { 
    private WriteUserDataUtils() { 
        // utils classes shouldn't be instanced
    }
    ... 
}

之后,将其中的方法更改为statice:

public static void writeToFile(String data, String file) {
    ...
}

public static void saveFile(String fileName, String addText) {
    ...
}

最后,您扩展activity的原因是您需要上下文来执行某些操作(例如,打开文件流)。 通过将其作为参数传递,可以很容易地解决这一问题:

public static void writeToFile(String data, String file, Context context) {
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput(file + ".txt", MODE_PRIVATE));
    ...
}

public static void saveFile(String fileName, String addText, Context context){
    try {
        File newFile = new File(context.getExternalFilesDir(null), fileName + ".txt");
    ...
}

在您将其重构为utils类之后,您可以从activity中调用它,如下所示:

private static void bring(){
    WriteUserDataUtils.saveFile("userdata", "ThisTextWork", this);
    WriteUserDataUtils.writeToFile("ThisTextWorkToo", "aconfig", this);
}

如果你需要进一步澄清,请告诉我。