模拟器在调用函数时抛出异常(Android Studio)。

huangapple go评论118阅读模式
英文:

Emulator throws exception (android studio) when function is called

问题

I'm coding a game on android studio and it works fine, but it started crashing when I moved a function to another class.

我正在使用Android Studio编写游戏,一切正常,但是当我将一个函数移到另一个类时,它开始崩溃。

I did it so I could use it everywhere by having it only once and not copy-pasting it into every class I need to use it.

我这样做是为了可以在任何地方使用它,而不是在每个需要使用它的类中都复制粘贴。

I checked on Google how to solve this problem, but nothing is working. The error is with "getExternalFilesDir" or "openFileOutput" returning null, I think.

我在Google上查找了如何解决这个问题,但是没有什么有效的方法。我认为错误与 "getExternalFilesDir" 或 "openFileOutput" 返回 null 有关。

Here is the class with two functions (doing basically the same thing) but that I can't use.

这是一个具有两个函数的类(基本上做相同的事情),但我无法使用它们。

import android.content.Context;
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 exist, 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 be seen when the device is plugged into 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 to " + fileName + ".txt");
        }
    }
}

And here is the place where I try to call the functions but it crashes the emulator (I removed some code 'import' to make it easier for you to understand).

这是我尝试调用这些函数但导致模拟器崩溃的地方(我删除了一些 'import' 代码,以便您更容易理解)。

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import androidx.appcompat.app.AppCompatActivity;
import java.util.Timer;
import java.util.TimerTask;

public class GameOverActivity extends AppCompatActivity {
    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 the 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();
    }
}

This is the error:

这是错误信息:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.FileOutputStream android.content.Context.openFileOutput(java.lang.String, int)' on a null object reference
英文:

I'm coding a game on android studio and it works fine, but it started crashing when i moved a function in another class.

I did it so I could use it everywhere by having it only once and not copy pasting on every class I need to use it.

I checked on google how to solve this problem but nothing is working, the error is with "getExternalFilesDir" or "openFileOutput" returning null i think.

Here is the class with two functions (doing basically the same thing) but that I can't use.

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");
}
}
}

and there is the place where i try to call the functions but crashes the emulator (I removed some code 'import') so it is easier for you to understand.

    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();
}
}

This is the error:

> java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.FileOutputStream android.content.Context.openFileOutput(java.lang.String, int)' on a null object reference
> Blockquote

答案1

得分: 0

你误解了活动的工作原理。

public class WriteUserData extends AppCompatActivity {

你正在扩展一个Activity类,所以WriteUserData也是一个活动。在这种情况下,它应该命名为WriteUserDataActivity

但是,看看你在这里所做的:

WriteUserData saveScore = new WriteUserData();

这不是你应该使用活动的方式。它应该使用Intent和startActivity()来创建,参见这里:

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

你想要做的是将打开文件的逻辑移到一个单独的类中以避免代码重复。这很好,但不应该使用一个活动来实现。相反,你应该使用一个Utils/Helper类。你的类不应该扩展任何东西,并且应该有一个私有构造函数:

public class WriteUserDataUtils { 
    private WriteUserDataUtils() { 
        // utils类不应该被实例化
    }
    ... 
}

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

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

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

最后,你扩展Activity的原因是因为你需要Context来执行某些操作(例如打开文件流)。这可以通过将它作为参数传递来轻松解决:

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类之后,你可以这样从活动中调用它:

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

如果需要进一步的解释,请告诉我。

英文:

You're misunderstanding how activities work.

public class WriteUserData extends AppCompatActivity {

You're extending an Activity class, so WriteUserData is also an activity. In that case, it should be named as such - WriteUserDataActivity.

However, looking at what you're doing here:

WriteUserData saveScore = new WriteUserData();

This is not how you're supposed to use an activity. It should be created with an Intent and startActivity(), see here:

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

What you wanted to do is move the logic for opening a file in a separate class to avoid code duplication. That's great, but it should not be done with an activity. Instead, you should use a Utils/Helper class. Your class shouldn't extend anything and should have a private constructor:

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

After that, change the methods inside it to be static:

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

Finally, the reason you extended an Activity is that you needed Context for some things (e.g. opening a file stream). This can easily be fixed by passing it as a parameter:

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");
...
}

After you refactored it into a utils class, you can call it from the activity like this:

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

Let me know if you need any further clarification.

huangapple
  • 本文由 发表于 2020年8月1日 19:50:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/63204882.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定