Android 属性文件无法正确加载

Android properties file won't load correctly

我正在尝试使用属性文件在重新启动时存储我的应用程序的某些属性。我想我已经关注了 this explanation in the Android Developer documentation. Starting with one property, I can see the property being set, stored in a file (config.properties) in my app's internal storage and I can see the file being read when the app starts. However, even though the property was read from the file, it doesn't seem to be loaded by the Properties API as I would expect from the load method.

为什么 属性 即使从文件中读取也没有正确加载?

这是我的代码:

包装器 MyProperties class 包装 java.util.Properties:

public class MyProperties {
    public static final String PROPERTY_NAME = "propertyName";

    private Properties properties = null;
    private File propertiesFile = null;
    private InputStream inputStream = null;
    private OutputStream outputStream = null;

    public MyProperties(Context context) throws IOException {
        properties = new Properties();
        propertiesFile = new File(context.getFilesDir(),"config.properties");
        Log.d(MainActivity.LOG_TAG, "config file exists: "+propertiesFile.exists());
        propertiesFile.createNewFile();
        inputStream = new FileInputStream(propertiesFile);
        BufferedReader br = new BufferedReader(new FileReader(propertiesFile));
        String line = br.readLine();
        Log.d(MainActivity.LOG_TAG, "Properties file start");
        while(line !=null){
            Log.d(MainActivity.LOG_TAG, line);
            line = br.readLine();
        }
        Log.d(MainActivity.LOG_TAG, "Properties file end");

        outputStream = new FileOutputStream(propertiesFile);
        properties.load(inputStream);
    }

    public String getProperty(String propertyName) {
        Log.d(MainActivity.LOG_TAG, "Fetching property '"+propertyName+"' with value '"+properties.getProperty(propertyName)+"'.");
        return properties.getProperty(propertyName);
    }

    public void setProperty(String propertyName, String propertyValue) {
        Log.d(MainActivity.LOG_TAG, "Setting property '"+propertyName+"' to '"+propertyValue+"'.");
        properties.setProperty(propertyName, propertyValue);
    }

    public void close() {
        try {
            Log.d(MainActivity.LOG_TAG, "Closing properties");
            properties.store(outputStream, null);
            inputStream.close();
            outputStream.close();
        } catch (IOException ioe) {
            Log.e(MainActivity.LOG_TAG, "Exception while closing properties.", ioe);
        }
    }
}

我的 MainActivity class(为简洁起见进行了编辑):

public class MainActivity extends AppCompatActivity {
    public static final String LOG_TAG = "my.app";

    private MyProperties myProperties;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        try {
            if (myProperties == null) {
                myProperties = new MyProperties(getApplicationContext());
            }
        } catch (IOException e) {
            Log.e(LOG_TAG, "Exception while instantiating properties.", e);
            throw new RuntimeException(e);
        }
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

    @Override
    public void onStart() {
        super.onStart();
        String propertyValue = getPropertyValue();
        Log.d(LOG_TAG, "property value: '" + propertyValue + "'");
    }

    private String getPropertyValue() {
        String propertyValue = myProperties.getProperty(MyProperties.PROPERTY_NAME);
        if (propertyValue == null) {
            Log.d(LOG_TAG, "Property '"+ MyProperties.PROPERTY_NAME+"' not set.");
            myProperties.setProperty(MyProperties.PROPERTY_NAME, "propertyValue");
            propertyValue = myProperties.getProperty(MyProperties.PROPERTY_NAME);
        }
        return propertyValue;
    }

    @Override
    public void onStop() {
        Log.d(LOG_TAG, "Stopping");
        myProperties.close();
        super.onStop();
    }
}

我的应用程序在启动时显示属性文件为空,属性 propertyName 最初未设置,然后 设置为propertyValue:

2021-03-29 07:40:36.561 9696-9696/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2021-03-29 07:40:36.563 9696-9696/? E/Zygote: accessInfo : 1
2021-03-29 07:40:36.664 9696-9696/? I/my.app: Late-enabling -Xcheck:jni
2021-03-29 07:40:38.475 9696-9696/my.app I/FirebaseInitProvider: FirebaseApp initialization successful
2021-03-29 07:40:38.733 9696-9696/my.app W/my.app: Accessing hidden method Landroid/graphics/drawable/Drawable;->getOpticalInsets()Landroid/graphics/Insets; (light greylist, linking)
2021-03-29 07:40:38.733 9696-9696/my.app W/my.app: Accessing hidden field Landroid/graphics/Insets;->left:I (light greylist, linking)
2021-03-29 07:40:38.733 9696-9696/my.app W/my.app: Accessing hidden field Landroid/graphics/Insets;->right:I (light greylist, linking)
2021-03-29 07:40:38.733 9696-9696/my.app W/my.app: Accessing hidden field Landroid/graphics/Insets;->top:I (light greylist, linking)
2021-03-29 07:40:38.733 9696-9696/my.app W/my.app: Accessing hidden field Landroid/graphics/Insets;->bottom:I (light greylist, linking)
2021-03-29 07:40:38.756 9696-9696/my.app D/my.app: config file exists: true
2021-03-29 07:40:38.758 9696-9696/my.app D/my.app: Properties file start
2021-03-29 07:40:38.758 9696-9696/my.app D/my.app: Properties file end
2021-03-29 07:40:38.791 9696-9696/my.app I/MultiWindowDecorSupport: updateCaptionType >> com.android.internal.policy.MultiWindowDecorSupport@6ed79bb, isFloating: false, isApplication: true, hasWindowDecorCaption: false, hasWindowControllerCallback: true
2021-03-29 07:40:38.791 9696-9696/my.app D/MultiWindowDecorSupport: setCaptionType = 0
2021-03-29 07:40:38.888 9696-9696/my.app W/my.app: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)
2021-03-29 07:40:38.893 9696-9696/my.app W/my.app: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (light greylist, reflection)
2021-03-29 07:40:39.034 9696-9725/my.app W/System: A resource failed to call close. 
2021-03-29 07:40:39.036 9696-9727/my.app I/my.app: Background concurrent copying GC freed 6682(1333KB) AllocSpace objects, 5(100KB) LOS objects, 51% free, 1471KB/2MB, paused 1.108ms total 110.073ms
2021-03-29 07:40:39.475 9696-9696/my.app W/my.app: Accessing hidden method Landroid/widget/TextView;->getTextDirectionHeuristic()Landroid/text/TextDirectionHeuristic; (light greylist, linking)
2021-03-29 07:40:39.609 9696-9696/my.app D/my.app: Fetching property 'propertyName' with value 'null'.
2021-03-29 07:40:39.609 9696-9696/my.app D/my.app: Property 'propertyName' not set.
2021-03-29 07:40:39.609 9696-9696/my.app D/my.app: Setting property 'propertyName' to 'propertyValue'.
2021-03-29 07:40:39.610 9696-9696/my.app D/my.app: Fetching property 'propertyName' with value 'propertyValue'.
2021-03-29 07:40:39.610 9696-9696/my.app D/my.app: property value: 'propertyValue'
...

然后我按主页按钮将应用移至后台。然后我按下 Overview 按钮和 select 我的应用程序。以下是显示 属性 仍然设置的日志:

...
2021-03-29 07:40:46.848 9696-9696/my.app D/ViewRootImpl@de343f7[MainActivity]: stopped(false) old=true
2021-03-29 07:40:46.864 9696-9696/my.app D/my.app: Fetching property 'propertyName' with value 'propertyValue'.
2021-03-29 07:40:46.864 9696-9696/my.app D/my.app: property value: 'propertyValue'
...

然后我关闭应用程序(按概览按钮,在应用程序上向上滑动)。当我重新启动应用程序时,属性是从属性文件中读取的,但是 propertyName 属性 似乎没有正确加载,即使它是从文件中读取的:

<restart my.app>

2021-03-29 07:42:02.170 10196-10196/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2021-03-29 07:42:02.174 10196-10196/? E/Zygote: accessInfo : 1
2021-03-29 07:42:02.182 10196-10196/? I/my.app: Late-enabling -Xcheck:jni
2021-03-29 07:42:03.444 10196-10196/my.app I/FirebaseInitProvider: FirebaseApp initialization successful
2021-03-29 07:42:03.597 10196-10196/my.app W/my.app: Accessing hidden method Landroid/graphics/drawable/Drawable;->getOpticalInsets()Landroid/graphics/Insets; (light greylist, linking)
2021-03-29 07:42:03.598 10196-10196/my.app W/my.app: Accessing hidden field Landroid/graphics/Insets;->left:I (light greylist, linking)
2021-03-29 07:42:03.598 10196-10196/my.app W/my.app: Accessing hidden field Landroid/graphics/Insets;->right:I (light greylist, linking)
2021-03-29 07:42:03.598 10196-10196/my.app W/my.app: Accessing hidden field Landroid/graphics/Insets;->top:I (light greylist, linking)
2021-03-29 07:42:03.598 10196-10196/my.app W/my.app: Accessing hidden field Landroid/graphics/Insets;->bottom:I (light greylist, linking)
2021-03-29 07:42:03.615 10196-10196/my.app D/my.app: config file exists: true
2021-03-29 07:42:03.617 10196-10196/my.app D/my.app: Properties file start
2021-03-29 07:42:03.617 10196-10196/my.app D/my.app: #Mon Mar 29 07:40:44 GMT+02:00 2021
2021-03-29 07:42:03.617 10196-10196/my.app D/my.app: propertyName=propertyValue
2021-03-29 07:42:03.618 10196-10196/my.app D/my.app: Properties file end
2021-03-29 07:42:03.642 10196-10196/my.app I/MultiWindowDecorSupport: updateCaptionType >> com.android.internal.policy.MultiWindowDecorSupport@6ed79bb, isFloating: false, isApplication: true, hasWindowDecorCaption: false, hasWindowControllerCallback: true
2021-03-29 07:42:03.643 10196-10196/my.app D/MultiWindowDecorSupport: setCaptionType = 0
2021-03-29 07:42:03.718 10196-10196/my.app W/my.app: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (light greylist, reflection)
2021-03-29 07:42:03.722 10196-10196/my.app W/my.app: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (light greylist, reflection)
2021-03-29 07:42:03.846 10196-10205/my.app W/System: A resource failed to call close. 
2021-03-29 07:42:04.076 10196-10196/my.app W/my.app: Accessing hidden method Landroid/widget/TextView;->getTextDirectionHeuristic()Landroid/text/TextDirectionHeuristic; (light greylist, linking)
2021-03-29 07:42:04.178 10196-10196/my.app D/my.app: Fetching property 'propertyName' with value 'null'.
2021-03-29 07:42:04.178 10196-10196/my.app D/my.app: Property 'propertyName' not set.
2021-03-29 07:42:04.178 10196-10196/my.app D/my.app: Setting property 'propertyName' to 'propertyValue'.
2021-03-29 07:42:04.178 10196-10196/my.app D/my.app: Fetching property 'propertyName' with value 'propertyValue'.
2021-03-29 07:42:04.179 10196-10196/my.app D/my.app: property value: 'propertyValue'

您正在使用 BufferedReader 从文件中读取数据,但是 line 变量只是在循环中记录,它没有通过 setProperty 或其他解析调用恢复数据。 Property class 在开始时以值完成并在您的应用程序存在期间一直保存在内存中(因此在 home/back 期间保持不变),但在杀死它后内存被清理并下一个入口只是打印存储的值,而不是将它们映射到 Property 对象

查看官方 Data and file storage overview - there is a table in there with possibilities and it seems like you should use App Preferences link, which is pointing on SharedPreferences,与您的方法非常相似,但可能更有效(使用 apply() 而不是 commit()

编辑:由于评论,我们发现一些错误的流使用(一次多次)与早期记录和读取相关,接下来尝试将其传递给数据对象的解析方法