-4

Today I started my first Android App-Project and - of course - I'm stuck with a problem. I want to make a really simple app do get into the the whole programming thing, and I'm in my holidays right now so I thought it would be interesting to save the times when I go to bed/when I wake up. So it shouldnt be so hard and nearly everything works like I want it to. Now the problem is, that I save my dates in an ArrayList, so they show up in a ListView. I read that I can't save ArrayLists in SharedPrefs, I didn't understand the SQLite thing, so I decided to use the FileOutputStream etc. I read about it on the internet and tried to do everything like they did but it simply doesnt work. There isn't an error in the console but if I close and reopen the app, all my elements are gone. Anyone who can help me? :) (I dont know which part of the code is important and which isn't, so here's the whole code)

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

}

EDIT: updated the code. Now my Error is "java.io.FileNotFoundException: /mnt/sdcard/SleepApp/save.sav: open failed: EACCES (Permission denied)". Any ideas?

  • Take every line of this code, put it aside. Write a program that saves **any** data to a file using `FileOutputStream`. Then, if that works, modify it to save **any** date. Then, once that works, come back to this program and see if you can fix it yourself. – durron597 Aug 12 '15 at 22:30
  • Does it print a stack trace? – user253751 Aug 12 '15 at 22:40
  • Take the advise above, also look at Android Activity Lifecycle. Unlike a typical Java program where the entry point in java is public void main(string[] args), Android does not work like this, but you could say its kind of equivalent would be onCreate() – Mark Aug 12 '15 at 22:46
  • Before I tried it in main, I had the exact same code in onCreate(). Didn't work so I simply tried if this would change anything – GamingGears Aug 12 '15 at 22:53

2 Answers2

1

Your code is a bit all over the place. Here are the major things:

  1. What you should do is create 2 methods:

    • saveDataToFile.
    • LoadDataFromFile.
  2. looking at the API you may notice that in shared preferences you can invoke putStringSet.
    This may very well be handy. check it out.

  3. Try to always specify the type of object you are retaining in you lists. In your case it's a string, so it should look like this:

    ArrayList<String> data = new ArrayList<>();
    
  4. Delete the "main" method. Not gonna get into the details but basically it's useless here. Just make sure you copy the functionality of it to the "LoadDataFromFile" method first.

  5. I guess you set "onCLick" attribute in your activity's layout xml file to invoke "buttonOnClick" and "buttonOnClick1". Change the functions names to something more user friendly, like "saveButtonClick" and "loadButtonClick". In each one of them call the respected method you created in section 1.
  6. Last problem you have is that even if you do save and load the data correctly it will never be displayed because you override the object of the data you want to display. what you should do instead of overriding is clearing previous data and adding new data. It should look like this:

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

Hope these notes will give you some directions. If you have any questions I'll do my best to clarify.

EDIT: (to your edit)
You get the error because of two reason:

  1. Need permissions to write to file. Basically add the following to your manifest:

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

    More info here.

  2. The file and path does not exist. You cannot simply write the name of the file, but provide a full path. To do that first save your device external storage root path using the following:

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

    Then in your FileInputStream and FileOutputStream use the root path and file name, separated by "/", like so:

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

    Another thing you must do when writing to file in sub directories is to invoke mkdir or mkdirs on the missing parents to create the missing parent or parents. For example:

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

Good luck.

Shahar.bm
  • 169
  • 8
  • Alright! Thanks man! Many tips, and I'll try them all. I already had the after the Array but deleting it didn't change anything so I left it like that. Like I mentioned earlier, I already tried it without the main class but it didnt work so I simply tried it. And the buttons arent save and load, they are fall asleep and wake up, but I get your point :) But where am I supposed to add the data.clear...? – GamingGears Aug 12 '15 at 23:15
  • And let me explain real quick: I have to ListViews with one button per List. The first List contains the Strings from Array "data" and the second list contains "data1". My names aren't that userfriendly but I didn't expect that I'd have to share it with you so I thought it would be irrelevant – GamingGears Aug 12 '15 at 23:22
  • Well I tried to use all your tips and changed a few things but it still doesnt work. Same Problem as always. Heres my code: http://pastebin.com/Y2n2w8Et – GamingGears Aug 12 '15 at 23:36
0

You must create your own class/object, then implement to Parcelable interface, to keep using this, and pass when you send with a bundle, or just con save on activity/fragment recreated, to get again.

Look this answer: Android: How to implement Parcelable to my objects?

Another answer: Save ArrayList to SharedPreferences

Regards.

Community
  • 1
  • 1
Max Pinto
  • 1,463
  • 3
  • 16
  • 29
  • 1
    Thanks! But I think that the FileOutputStream is a really nice possibilty and I'm just using it wrong. You don't know what I'd have to change? This is my code now: http://pastebin.com/Y2n2w8Et – GamingGears Aug 12 '15 at 23:43
  • I see your code, bit i havent used this kind of method to save data. I recmend to use sqlite. If you dont want to manially create your db' tables and methods so use greendao or ormlite, both are good. And believe me you should try to learn this, is not complicares. Regards – Max Pinto Aug 13 '15 at 00:04