NOVINKA! E-learningové kurzy umělé inteligence. Nyní AI za nejlepší ceny. Zjisti více:
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

Diskuze: Android - Uložení ArrayListu do souboru na SD kartě

V předchozím kvízu, Online test znalostí Java, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Jaroslav Zakouřil:4.11.2017 19:08

Potřebuji uložit do souboru nejlépe na SD kartě ArrayList s objekty třídy Prvek

public class Prvek {
private String sbr;
private Path patC;
private Path patB;
private int zac;
private int kon;
private Paint barL;
private Paint barR;
private boolean akt;
private boolean zvl;
private int por;
...
}

nazvaný prvekU a ArrayList s objekty třídy Bod

public class Bod {
private int sl;
private float[] sou;
...
}

nazvaný bodU, a to v rozhraní třídy,

public class CanvasView extends View {
...
},

kde metodou

public boolean onTouchEvent(Mo­tionEvent event) {
...
}
ovládám pomocí dotyků na určitých místech displeje pohyb různých prvků složených z bodů ve 3D prostoru.
Podle různých tutoriálů a přikladů jsem odzkoušel uložení řetězce nebo pole bytů a obojí fungovalo. Když jsem ale zkusil do ObjectOutputStreamu zapsat ArrayList objektů Prvek nebo pole objektů Prvek, vždy došlo k chybě.

Nejdřív jsem použil následující kód pro zápis do ObjectOutputStre­amu:

FileOutputStream fos = new FileOutputStre­am("prvky.dat");
ObjectOutputStream oos = new ObjectOutputStre­am(fos);
oos.writeObjec­t(prvekU);
oos.close();

K chybě došlo už na prvním řádku, takže se ani nevytvořil stream. Pátral jsem dál a našel jinou verzi prvního řádku kódu :

FileOutputStream fos = context.openFi­leOutput("prvky­.dat",Context­.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStre­am(fos);
oos.writeObjec­t(prvekU);
oos.close();

Tentokrát první řádek prošel, ale došlo k chybě na 3.řádku při zápisu Arraylistu do oos.
Jak už jsem napsal, vyzkoušel jsem to i s textovým řetězcem a s polem bytů(Ascii znaků) a obojí fungovalo. K chybě dochází u ArrayListu objektů Prvek nebo u pole objektů Prvek. Zkoušel jsem také deklarovat objekt Prvek jako Serializable, což jsem našel zase jinde, ale ani to nepomohlo.
Prosím, poraďte, jak to mám udělat správně. Předem díky !!

 
Odpovědět
4.11.2017 19:08
Avatar
Robert Michalovič:6.11.2017 6:34
  1. Při dotazu jehož součástí je zdrojový kód je vhodné používat podporu formátování zdrojového kótu. Tebou uvedený zdroják není pro některé lidi snadno prohlédnutelný.
  2. Při ukládání objektu(instance) je nutno třídě implementovat Serializaci

https://docs.oracle.com/…lizable.html

public class Prvek implements java.io.Serializable {
 // JE NUTNO JESTE PRIDAT  serialVersionUID
private static final long serialVersionUID = -2010768942658426810L;
 private String sbr;
 private Path patC;
 private Path patB;
 private int zac;
 private int kon;
 private Paint barL;
 private Paint barR;
 private boolean akt;
 private boolean zvl;
 private int por;
 ...
 }

a to same proved i u Bod

public class Bod implements java.io.Serializable {
 // JE NUTNO JESTE PRIDAT  serialVersionUID
private static final long serialVersionUID = -2010768942658426811L;
 private int sl;
 private float[] sou;
 ...
 }

Po té by už mělo fungovat i to tvé první řešení

FileOutputStream fos = new FileOutputStream("prvky.dat");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(prvekU);
oos.close();
  1. Typ media( SD karta,Flash disk, SSD nebo harddisk ) nehraje naprosto žádnou roli při ukládání. JVM pouze přebírá správu těchto medií od OS.
 
Nahoru Odpovědět
6.11.2017 6:34
Avatar
Odpovídá na Robert Michalovič
Jaroslav Zakouřil:7.11.2017 11:42

Děkuji za rychlou reakci. Zkopíroval jsem do deklarace objektu Prvek implementaci Serializace + následující řádek s uvedenou konstantou serialVersionUID přesně tak, jak jsi mi poradil. Bohužel vůbec nic se nezměnilo. K chybám dochází úplně stejně jak jsem popsal, a to při obou variantách prvního řádku.

//1.
        FileOutputStream fos = context.openFileOutput("prvky.dat",
//2.
        FileOutputStream fos = new FileOutputStream("prvky.dat");

Při prvním způsobu se alespoň vytvoří FileOutputStream a k chybě dojde až při zápisu do ObjectOutputStre­amu. Ve druhém případě se ani nevytvoří FileOutputStream. Přesto děkuji za snahu pomoci. Budu pátrat dál. Jarda

 
Nahoru Odpovědět
7.11.2017 11:42
Avatar
Robert Michalovič:7.11.2017 14:31

Pokud ti toto nepomohlo pak je problém v nečem jiném. Např. práva přístupu, špatná kompilace, buildování, bug v JDK apod.. Ukládání/Načítání vlastních objektů(instancí) do souboru je skutečně jednoduché a stačí pouze implementovat serializaci.
Mimochodem bez vypsání dané výjimky se velmi obtížně odhaduje kde je chyba. Většinou je ve výpisu výjimky vypsáno v čem je problém.
Podařilo se ti tam uložit obyčejný řetezec, či text přes znakový proud do stejného úložiště?
Proč nezvěřejníš celý kód ? Věř tomu že tvůj zdroják není fakt žádné know-how, jedná se o velmi trapně jednoduchou záležitost.

Takto jednoduše ten zdroj v čistě v JAVE vypadá. Zkus to spustit případně upravit pro Android a uvidíš co to udělá.

import java.io.*;
class NeprimObjektTrida1 implements Serializable{
        private static final long serialVersionUID = 49774409446745068L;
        private int cislo1,cislo2;
        NeprimObjektTrida1(int cis1,int cis2){ // konstruktor
                this.cislo1 = cis1; this.cislo2 = cis2; }
        public String toString(){ return "cislo1 ="+cislo1+"\tcislo2 ="+cislo2;}
}
public class O13_StreamObjekty {
        public static void main(String [] args) throws IOException, ClassNotFoundException {
                NeprimObjektTrida1 objektCislo = new NeprimObjektTrida1(48,35);
                FileOutputStream souborObjekt = new FileOutputStream("souborObj.bin");
                ObjectOutputStream objektUkladani = new ObjectOutputStream(souborObjekt);
                objektUkladani.writeObject(objektCislo);
                souborObjekt.close();
        }
}
 
Nahoru Odpovědět
7.11.2017 14:31
Avatar
Odpovídá na Robert Michalovič
Jaroslav Zakouřil:12.11.2017 14:17

Tak jsem to vyřešil následovně: Zjistil jsem, že objekt třídy Prvek nešel uložit do souboru, přestože jsem ho deklaroval podle Tvého návodu takto

public class PrvekU implements java.io.Serializable {
    private static final long serialVersionUID = -2010768942658426810L;

,
asi proto, že obsahoval objekty tříd Path a Paint. Tak jsem tyto objekty z něj odebral, takže tam zbyly objekty tříd String, int, a boolean. Teď už třída Prvek uložit do souboru jde. Ty objekty Path a Paint vlastně není třeba mít uložené, protože se mohou inicializovat až po načtení objektu Prvek a pak do něj přidat.
Takže mne to přece jen posunulo vpřed. Děkuji !

 
Nahoru Odpovědět
12.11.2017 14:17
Avatar
Robert Michalovič:14.11.2017 7:41

Když ti to funguje jak chceš pak je to OK. Nicméně pokud Path,Paint jsou opět tvoje třídy pak i těm je nutno implementovat Serizalizaci a přidat serialVersionUID a mělo by to taky fungovat. Obecně řečeno pokud máš objekty v objektu (tvz. kompozici) a chceš jejich stavy ukládat je nutno všem těm objektům implemtovat serializaci.

Pro příště doporučuji přidávej i výpis vyjímky + i zdroj + importy.

 
Nahoru Odpovědět
14.11.2017 7:41
Avatar
Odpovídá na Robert Michalovič
Jaroslav Zakouřil:14.11.2017 10:14

Tu serializaci na objekty Prvek a Bod jsem implementoval tak, že jsem jednoduše zkopíroval Tvůj kód, ale nerozumím mu. Vysvětli mi, prosím, jak jsi došel k té konstantě serialVersionUID, jak jsi získal to dlouhé číslo ? Díky.

 
Nahoru Odpovědět
14.11.2017 10:14
Avatar
Robert Michalovič:16.11.2017 7:08

Jednoduše řečeno : Pokud používáš při vývoji IDE, a k definici třídy dáš implementovat serializaci

class NeprimObjektTrida1 implements Serializable

pak ti samo IDE hodí Error nebo Warning a požaduje vytvoření proměnné "serialVersionUID" a definování její hodnoty s několika možnostmi generování.

Odborně řečeno : ( viz. https://docs.oracle.com/…lizable.html)

The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassEx­ception. A serializable class can declare its own serialVersionUID explicitly by declaring a field named "serialVersionUID" that must be static, final, and of type long:

Při serializaci je každé serializované třídě definovaný identifikátor, který pak slouží JVM u nacitani ze souboru (tvz. deserializaco) k ověření(porovnání) že se jedná o tu stejnou třídu. Kdyby se lišily pak asi JVM vyvolá vyjímku, ale tento test jsem si nikdy nevyzkoušel.

 
Nahoru Odpovědět
16.11.2017 7:08
Avatar
Odpovídá na Robert Michalovič
Jaroslav Zakouřil:20.11.2017 14:51

To je na mne bohužel až příliš odborné. Aplikace vyvíjím v Android Studiu, tu serializaci jsem implementoval tak, jak jsi mi poradil,
l

public class PrvekU implements java.io.Serializable {
    private static final long serialVersionUID = -2010768942658426810L;

ale než jsem to udělal, napsalo mi Studio pouze hlášku :
"Unfurtunately, Pohyb_prvku has stoped. OK". (Pohyb_prvku je název aplikace.) Někdy používám debugging, ale ani Debugger mi nic nenapíše, pouze vidím tu hlášku a nemůžu udělat nic než aplikaci ukončit.

 
Nahoru Odpovědět
20.11.2017 14:51
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 9 zpráv z 9.