Do you have to have file I/O inside the Activity class? - android

I have code that is inside my Activity class to load and save a file. It works fine. The code saves the contents of cFavretClass. I'm trying to clean up the code, so I moved the file i/o into the cFavret Class.
I cannot get the code to compile. Now I get an error saying openFileOutput is undefined in type cFavrets.
I'm assuming that this method was declared in Googles Activity Class?
Does this mean all file I/O must be in the activity class?
boolean Save()
{
String FILENAME = "hello_file";
try {
FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE );
fos.write(buffer);
fos.close();
}
// just catch all exceptions and return false
catch (Throwable t) {
return false;
}
return true;
}
boolean Load()
{
String FILENAME = "hello_file";
try {
FileInputStream fos = openFileInput(FILENAME);
buffer[0]=0;
fos.read(buffer);
fos.close();
}
// just catch all exceptions and return false
catch (Throwable t) {
// maybe file does not exist, try creating it
return false;
}
return true;
}

Does this mean all file I/O must be in the activity class?
No, but the method in question is called from a context - just pass a context into the constructor of this cFavretClass (or to the method itself, if you prefer):
Context mContext;
public cFavretClass(Context context) {
mContext = context;
}
...
// in your methods:
mContext.openFileOutput(FILENAME);

As JRaymond explained, openFileOutput is a method of Context of which Activity is derived. This method is special insofar as it allows you to create files, which are private to your application.
You can use the normal Java I/O classes too, to write to the external storage (SD-Card) but those files will be readable by everybody.

Related

ObjectInputStream readObject() erratic behavior?

I am currently making an app for our group in high school. We decided to make a personal financing app that organizes your spendings.
I am trying to use internal storage for storing data. I have created an InternalStorage class just for that (it was someone else's answer to a question like mine but I forgot from where. Whoops.), having write and read methods accordingly.
However, while debugging I found some implausible behavior.
public final class InternalStorage {
private static String key = "billify";
public static void write(Context context, List<Bill> billList){
try{
FileOutputStream fos = context.openFileOutput(key, Context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(billList);
oos.close();
fos.close();
}catch(IOException e){
Toast.makeText(context,"Internal storage write error: IOException", Toast.LENGTH_LONG).show();
}
}
public static List<Bill> read(Context context){
try {
FileInputStream fis = context.openFileInput(key);
ObjectInputStream ois = new ObjectInputStream(fis);
List<Bill> a = (List<Bill>) ois.readObject();//jumps from here
return a;
}catch(Exception e){
e.printStackTrace();
Toast.makeText(context,"Internal storage read error",Toast.LENGTH_LONG).show();
return null;//jumps to here w/o triggering previous two lines.
}
}
}
I have put breakpoints in all the lines of code from read(), and from what I saw, the code ran ois.readObject(), then without running e.printStackTrace() and Toast, jumped straight back to return null.
Does anybody know what's going on?
Edit:
if(z.getClass() == cls){
ArrayList<Bill> a = (ArrayList<Bill>) z;//Jumps from here now
return a;
}
return null;
Doing a checked cast still makes the same thing happen-the classes are same, but doing the cast still makes it jump to the previous, last null.

android file system persistance

Hi Iam having serious issues try to persist some serializable objects to a file on the local android file system. Iam getting a Bad file descriptor error and I think it is to do with my methods for creating the file. the file and checking if the file exists. i create a private file object in the class. Then, on write or read. I check file existance with the following code.
#Override
public boolean fileExists() {
File file = context.getFileStreamPath(filename);
return file.exists();
}
this doesnt instantiate my file object called "objectfile"!! but does check the "filename" exists.
to create the file I call this method if "filename" doesnt exist.
public void createFile()
{
objectfile = new File(context.getFilesDir(), filename);
objectfile.setReadable(true);
objectfile.setWritable(true);
}
Iam not sure if this will give me back my previously created file which would be ideally what I want to do. Is there a way i can just get the old file or create a new one and pass it to "objectfile" variable in the constructor??
Iam also wondering what the best way to do this is??
Or should i just use the mysqlite db? using object file persistance doesn't seem to be working out for me right now and iam working to a deadline. Also this method is mention in the gooogle docs so I thought it would be legit was to do it.
http://developer.android.com/training/basics/data-storage/files.html
here is my method for reading the serializable objects
public synchronized ArrayList<RoomItem> readObjects() {
final ArrayList<RoomItem> readlist = new ArrayList<>();
if(!fileExists())
return readlist;
if(objectfile == null)
createFile();
try {
finputstream = new FileInputStream(objectfile);
instream = new ObjectInputStream(finputstream);
readwritethread = new Thread(new Runnable() {
#Override
public void run() {
try {
final ArrayList<RoomItem> readitems = (ArrayList<RoomItem>) instream.readObject();
instream.close();
finputstream.close();
handler.post(new Runnable() {
#Override
public void run() {
listener.updateList(readitems);
}
});
} catch(IOException e)
{
e.printStackTrace();
}
catch(ClassNotFoundException e)
{
e.printStackTrace();
Log.d("read failed", "file read failed");
}
}
});
}
catch(Exception e)
{
e.printStackTrace();
}
timeOutReadWrite(readwritethread);
readwritethread.start();
try {
readwritethread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d("read from file", "file read");
return readlist;
if anyone could suggest any improvements id really appreciate it. I use a handler to pass back to my activity and implement a listener interface on my activity thats call the activity when all the obj are read. Thanks again!
1#: Yes, it will return the original file you created.
2#: Depends on the thing you want to store, seems File is more flex from description
hope helpful.
We have used
FileOutputStream fos = context.openFileOutput("file.ser", Context.MODE_PRIVATE);
to write our serialized files.This will carete files in /data/data/app.package.name/files/. In fact, this path is returned by getFilesDir().
And while deserializing, use
//make sure you pass the same file that was passed to openFileOutput()..
FileInputStream fis = context.openFileInput("file.ser");
Also, to avoid confusing between file names you can use name of class that is being serialized.
Ex:
public static <T> void serialize(final Context context, final T objectToSerialize) {
....
....
Strin fileName = objectToSerialize.getClass().getSimpleName();
...
}
Do this and keep the method in util so it can be used for any type of objects (T type) to serialize.

null exception when writing file to internal storage from separate class

I have two activities that I want to call the time class bellow but every time i call that class it throws up an exception. But if i put the timeWrite() method in the Activity it works well but if I put it in the time class and then try to call it to write the file it throws up exception.
public class time extends AlphabetActivity{
private int time;
public void timeWrite(int time) {
try {
String timeVal = String.valueOf(time);
FileOutputStream timeStream = openFileOutput("time_file.txt", Context.MODE_PRIVATE);
timeStream.write(timeVal.getBytes());}
timeStream.close();
catch (Exception e) {
e.printStackTrace();}}
It seems like something is wrong with inheritance and I am just not understanding what I am doing wrong.
try {
String timeVal = String.valueOf(time);
FileOutputStream timeStream = openFileOutput("time_file.txt", Context.MODE_PRIVATE);
timeStream.write(timeVal.getBytes());
}
timeStream.close();
catch (Exception e) {
e.printStackTrace();}
}
Your code will compile if you write:
try {
String timeVal = String.valueOf(time);
FileOutputStream timeStream = openFileOutput("time_file.txt", Context.MODE_PRIVATE);
timeStream.write(timeVal.getBytes());
timeStream.close();
}catch (Exception e) {
e.printStackTrace();
}
If think this sytanx is wrong, does this code compile ?
Please read this, I know, long but you have to study now or later:
https://docs.oracle.com/javase/tutorial/essential/exceptions/
same
http://www.tutorialspoint.com/java/java_exceptions.htm
if you write file to the external storge, mind to add the READ and WRITE_EXTERNAL_STORAGE permission to the manifest

Android writing custom objects to file

I have a custom object class Record that implements Parcelable and I'm creating a ListView via ArrayAdapter<Record> I want to be able to save that list so that it automatically loads the next time the user opens the app. The list is populated dynamically and I'm calling my save method everytime a record is added. Then I have a SharedPreference with a boolean value that I set to true so that I know the user has saved some data to load the next time the app is open. Here are my save and load methods:
public void writeRecordsToFile(ArrayAdapter<Record> records) {
String fileName = Environment.getExternalStorageDirectory().getPath() + "/records.dat";
try {
File file = new File(fileName);
if(!file.exists()){
file.createNewFile();
}
ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(file));
stream.writeObject(records);
stream.flush();
stream.close();
}
catch (IOException e){
Log.e("MyApp","IO Exception: " + e);
}
writeSavedState();
}
the writeSavedState() is for my SP
public void readRecordsList() {
String fileName = Environment.getExternalStorageDirectory().getPath() + "/records.dat";
try {
ObjectInputStream inputStream = new ObjectInputStream(getApplicationContext().openFileInput(fileName));
adapter = (ArrayAdapter<Record>)inputStream.readObject();
inputStream.close();
}
catch (Exception e){
Log.e("MyApp" , "File Not Found: " + e);
}
}
When I first open the app I get a message:
E/MyApp﹕ File Not Found: java.lang.IllegalArgumentException: File /storage/emulated/0/records.dat contains a path separator
and then when I add a Record to my list I get the message:
E/MyApp﹕ IO Exception: java.io.IOException: open failed: EACCES (Permission denied)
The second message I'm assuming I'm getting because of the first message. This is my first time working with I/O in Android so any help would be appreciated!
EDIT
After adding the permissions to the manifest I'm now only getting an error:
E/MyApp﹕ IO Exception: java.io.NotSerializableException: android.widget.ArrayAdapter
As I said, my custom object is Parcelable and the rest of this is being done in my MainActivity. Do I need to make a new class that is Serializable to build my ArrayAdapter?
I would suggest to save the records in internal storage in private mode,which can be accessed by your app only.If you store it in External storage, there is no guarantee that it will be available next time you load your app.
Also, you should save array of record objects rather than ArrayAdapter object.
Parcel and Parcelable are fantastically quick, but its documentation says you must not use it for general-purpose serialization to storage, since the implementation varies with different versions of Android (i.e. an OS update could break an app which relied on it). So use Serializable in this case instead of Parcalable (from this SO thread)
You can use global variables to pass data from one activity to another. Also you can read/ write records when app starts using global class which extends Applicaion class.
You can try following code,
public class GlobalClass extends Application {
public static Object objectToBePassed; // global variable
final static private RECORDS_FILENAME = "myRecords.txt"
#Override
public void onCreate(){
super.onCreate();
readRecordsFromFile(); // read records when app starts
}
public boolean writeRecordsToFile(ArrayList<Record> records){
FileOutputStream fos;
ObjectOutputStream oos=null;
try{
fos = getApplicationContext().openFileOutput(RECORDS_FILENAME, Context.MODE_PRIVATE);
oos = new ObjectOutputStream(fos);
oos.writeObject(records);
oos.close();
return true;
}catch(Exception e){
Log.e(getClassName(), "Cant save records"+e.getMessage());
return false;
}
finally{
if(oos!=null)
try{
oos.close();
}catch(Exception e){
Log.e(getClassName(), "Error while closing stream "+e.getMessage());
}
}
}
private boolean readRecordsFromFile(){
FileInputStream fin;
ObjectInputStream ois=null;
try{
fin = getApplicationContext().openFileInput(RECORDS_FILENAME);
ois = new ObjectInputStream(fin);
ArrayList<Record> records = (ArrayList<Record>) ois.readObject();
ois.close();
Log.v(getClassName(), "Records read successfully");
return true;
}catch(Exception e){
Log.e(getClassName(), "Cant read saved records"+e.getMessage());
return false;
}
finally{
if(ois!=null)
try{
ois.close();
}catch(Exception e){
Log.e(getClassName(), "Error in closing stream while reading records"+e.getMessage());
}
}
}
}
So to pass any object from activity A to activity B, use following code in activity A ,
Intent intent = new Intent(this,B.class);
GlobalClass.objectToBePassed = obj;
startActivity(intent);
in activity B,
MyClass object = (MyClass) GlobalClass.objectToBePassed;
so to pass a Record class object, replace MyClass with Record.

Serialization of Application Object

At first I have strong Java knowledege, but however just started with Android.
My Android app is downloading some fairly complex data (texts, dates, images) which I am saving in a custom object. The data need to be refresh from time to time. However usually the data downloaded will not change.
In order to keep the data in memory I am using the Application Object. Unfortunately, it looks like the application object instance is destroyed when the app is killed.
Hence, I was wondering if it would be of good practice to serialize and save my custom object (which is contained in the application object) in the internal storage during onPause(). Obviously, I would then first read from the file in onResume() before reloading from the internet. The idea is also to enable offline viewing.
In longer term the plan is to move the code downloading the date in a background service. As there seems to be many different ways to keep application state in Android, I would like to be be sure that this is the correct way to go.
Try using those methods class to save the Object(s) (implements serialize) you need:
public synchronized boolean save(String fileName, Object objToSave)
{
try
{
// save to file
File file = new File(CONTEXT.getDir("filesdir", Context.MODE_PRIVATE) + "/file.file");
if (file.exists())
{
file.delete();
}
file.getParentFile().mkdirs();
file.createNewFile();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeObject(objToSave);
oos.close();
return true;
}
catch (FileNotFoundException e)
{
e.printStackTrace();
return false;
}
catch (IOException e)
{
e.printStackTrace();
return false;
}
}
public synchronized Object load(String fileName)
{
try
{
File file = new File(CONTEXT.getDir("filesdir", Context.MODE_PRIVATE) + "/file.file");
if (!file.exists())
{
return null;
}
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
savedObj = ois.readObject();
ois.close();
return savedObj;
}
catch (FileNotFoundException e)
{
e.printStackTrace();
return null;
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
You'll need to cast the Object you load().
CONTEXT is an Activity or ApplicationContext to get access to the cachedir.
Your could use Environment.getExternalStorageState() instead to get a directory path. DOn't forget to add it "/filename".

Categories

Resources