调用函数时模拟器抛出异常(android studio)

Posted

技术标签:

【中文标题】调用函数时模拟器抛出异常(android studio)【英文标题】:Emulator throws exception (android studio) when function is called 【发布时间】:2020-08-01 11:50:56 【问题描述】:

我正在 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:尝试在空对象引用上调用虚拟方法“java.io.FileOutputStream android.content.Context.openFileOutput(java.lang.String, int)” 块引用

【问题讨论】:

错误是什么? 整个错误都在那里:hasteb.in/pokefeki.sql 你需要这里的错误。不一定是完整的堆栈跟踪,但您的问题必须是自包含的。 完成了,我想这就是你的意思 【参考方案1】:

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

public class WriteUserData extends AppCompatActivity 

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

但是,看看你在这里做什么:

WriteUserData saveScore = new WriteUserData();

这不是您应该使用活动的方式。它应该使用 Intent 和 startActivity() 创建,请参见此处:

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

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

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

之后,把里面的方法改成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 类后,您可以像这样从 Activity 中调用它:

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

如果您需要任何进一步的说明,请告诉我。

【讨论】:

谢谢,它工作得很好,我想让你知道(或者如果有人有同样的问题)“bring()”不应该是静态的:private void bring() WriteUserDataUtils.saveFile("userdata", "ThisTextWork", this); WriteUserDataUtils.writeToFile("ThisTextWorkToo", "aconfig", this);

以上是关于调用函数时模拟器抛出异常(android studio)的主要内容,如果未能解决你的问题,请参考以下文章

为啥在析构函数中抛出异常时不调用重载删除?

JMockit 期望 API:如何在方法/构造函数调用时抛出异常

3.2 模拟面试

使用 NSubstitute 模拟出现问题时抛出异常的方法

C++:抛出异常会调用复制构造函数?

使用appium在android浏览器上运行selenium webdriver脚本,在模拟器上启动浏览器但抛出chromedriver异常