【问题标题】:Saving an ArrayList doesnt work [closed]保存 ArrayList 不起作用[关闭]
【发布时间】:2015-11-05 17:25:49
【问题描述】:

今天我开始了我的第一个 Android 应用项目,当然,我遇到了一个问题。我想制作一个非常简单的应用程序来完成整个编程工作,而且我现在正处于假期中,所以我认为节省睡觉/醒来的时间会很有趣。所以它不应该这么难,几乎所有的东西都像我想要的那样工作。 现在的问题是,我将日期保存在 ArrayList 中,因此它们会显示在 ListView 中。我读到我无法在 SharedPrefs 中保存 ArrayLists,我不了解 SQLite 的东西,所以我决定使用 FileOutputStream 等。我在互联网上阅读了它并尝试像他们一样做所有事情,但它根本不起作用.控制台中没有错误,但如果我关闭并重新打开应用程序,我的所有元素都消失了。 谁能帮助我? :) (我不知道代码的哪一部分重要,哪一部分不重要,所以这里是整个代码)

package com.gaminggears.sleeplist.sleep;


import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Path;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

public class MainActivity extends AppCompatActivity{

    private ListView dataListView;
    private ListView dataListView1;
    private ArrayAdapter arrayAdapter;

    File file = new File("/mnt/sdcard/SleepApp/save.sav");
    File dir = new File("/mnt/sdcard/SleepApp");

    Date date = new Date();
    SimpleDateFormat ft = new SimpleDateFormat ("E d-M-y kk:mm");

    ArrayList<String> data = new ArrayList<String>();
    ArrayList<String> data1 = new ArrayList<String>();


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

        if(!dir.exists()){
            file.mkdir();
        }

        loadDataFromFile();

        dataListView1 = (ListView) findViewById(R.id.listView2);
        dataListView = (ListView) findViewById(R.id.listView);


        arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, data);
        dataListView.setAdapter(arrayAdapter);

        arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, data1);
        dataListView1.setAdapter(arrayAdapter);

        System.out.println("\t\t" + data);
    }


    public void sleepClick(View v) {
        data.add(ft.format(date));
        arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, data);
        dataListView.setAdapter(arrayAdapter);
        saveDataToFile();
    }

    public void wakeUpClick(View v){
        data1.add(ft.format(date));
        arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, data1);
        dataListView1.setAdapter(arrayAdapter);
        saveDataToFile();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

   public void saveDataToFile(){
        try{
            FileOutputStream sF = new FileOutputStream(file);
            ObjectOutputStream save = new ObjectOutputStream(sF);
            save.writeObject(data);
            save.writeObject(data1);
            save.close();
        } catch(Exception exc){
            exc.printStackTrace();
        }
    }

    public void loadDataFromFile(){
        try{
            FileInputStream saveFile = new FileInputStream(file);
            ObjectInputStream save = new ObjectInputStream(saveFile);
            data.clear();
            data.addAll((ArrayList) save.readObject());

            data1.clear();
            data1.addAll((ArrayList) save.readObject());
            save.close();
        } catch(Exception exc) {
            exc.printStackTrace();
        }
    }

}

编辑:更新了代码。现在我的错误是“java.io.FileNotFoundException:/mnt/sdcard/SleepApp/save.sav:打开失败:EACCES(权限被拒绝)”。有什么想法吗?

【问题讨论】:

  • 把这段代码的每一行,放在一边。编写一个程序,使用FileOutputStream任何数据保存到文件中。然后,如果可行,修改它以保存 any 日期。然后,一旦成功,回到这个程序,看看你是否可以自己修复它。
  • 它是否打印堆栈跟踪?
  • 按照上面的建议,还要看看 Android Activity Lifecycle。与典型的 Java 程序不同,Java 中的入口点是 public void main(string[] args),Android 不能这样工作,但你可以说它的等价物是 onCreate()
  • 在我在 main 中尝试之前,我在 onCreate() 中有完全相同的代码。没用,所以我只是尝试了这是否会改变任何事情

标签: java android arraylist fileoutputstream


【解决方案1】:

您的代码有点乱。以下是主要内容:

  1. 你应该做的是创建2个方法:

    • 保存数据到文件。
    • 从文件加载数据。
  2. 查看 API,您可能会注意到在共享首选项中您可以调用 putStringSet
    这很可能很方便。看看这个。

  3. 尝试始终指定要保留在列表中的对象的类型。在你的情况下,它是一个字符串,所以它应该是这样的:

    ArrayList<String> data = new ArrayList<>();
    
  4. 删除“main”方法。不打算详细说明,但基本上在这里没用。只需确保先将其功能复制到“LoadDataFromFile”方法即可。

  5. 我猜你在活动的布局 xml 文件中设置了“onCLick”属性来调用“buttonOnClick”和“buttonOnClick1”。将函数名称更改为对用户更友好的名称,例如“saveButtonClick”和“loadButtonClick”。在它们中的每一个中调用您在第 1 节中创建的受人尊敬的方法。
  6. 您遇到的最后一个问题是,即使您正确保存和加载数据,它也永远不会显示,因为您覆盖了要显示的数据的对象。您应该做的而不是覆盖是清除以前的数据并添加新数据。它应该是这样的:

    data.clear();
    data.addAll((ArrayList) save.readObject());
    

希望这些笔记能给你一些指导。如果您有任何问题,我会尽力澄清。

编辑:(对您的编辑)
您收到错误的原因有两个:

  1. 需要写入文件的权限。 基本上将以下内容添加到您的清单中:

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

    更多信息here

  2. 文件和路径不存在。您不能简单地写下文件名,而是提供完整路径。为此,首先使用以下命令保存您的设备外部存储根路径:

    private static final String ROOT_PATH = Environment.getExternalStorageDirectory();
    private static final String FILE_NAME = "SaveFile.sav";
    

    然后在你的 FileInputStream 和 FileOutputStream 中使用根路径和文件名,用“/”分隔,像这样:

    new FileInputStream(ROOT_PATH + "/" + FILE_NAME);
    

    在子目录中写入文件时必须做的另一件事是调用 mkdirmkdirs 在丢失的父级上创建丢失的父级或父级.例如:

    File file = new File(ROOT_PATH + "/" + "SOME_FOLDER");
    file.mkdirs();
    

祝你好运。

【讨论】:

  • 好的!谢啦!很多技巧,我会全部尝试。我已经在 Array 之后有了 ,但是删除它并没有改变任何东西,所以我就这样离开了。就像我之前提到的,我已经在没有主类的情况下尝试过,但它没有用,所以我只是尝试了一下。按钮不是保存和加载,它们是睡着了然后醒来,但我明白你的意思:) 但是我应该在哪里添加 data.clear...?
  • 让我快速解释一下:我必须在 ListViews 中每个 List 一个按钮。第一个列表包含来自数组“data”的字符串,第二个列表包含“data1”。我的名字不是那么好用,但我没想到我必须与你分享,所以我认为这无关紧要
  • 好吧,我尝试使用您的所有提示并更改了一些内容,但仍然无法正常工作。一如既往的问题。这是我的代码:pastebin.com/Y2n2w8Et
【解决方案2】:

您必须创建自己的类/对象,然后实现 Parcelable 接口,以继续使用它,并在您与捆绑包一起发送时传递,或者只是保存重新创建的活动/片段,以再次获取。

看这个答案:Android: How to implement Parcelable to my objects?

另一个答案: Save ArrayList to SharedPreferences

问候。

【讨论】:

  • 谢谢!但我认为 FileOutputStream 是一个非常好的可能性,我只是用错了。你不知道我要改变什么?这是我现在的代码:pastebin.com/Y2n2w8Et
  • 我看到了你的代码,有点我没有使用这种方法来保存数据。我建议使用 sqlite。如果您不想手动创建数据库表和方法,请使用 greendao 或 ormlite,两者都很好。相信我,您应该尝试学习这一点,这并不复杂。问候
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-10
  • 2014-06-14
  • 1970-01-01
  • 2013-05-15
  • 2015-06-15
  • 2013-10-29
  • 1970-01-01
相关资源
最近更新 更多