Objekt serialisieren/deserialisieren und in einer SQLite-Datenbank speichern

  • Antworten:10
Gelöschter Account
  • Forum-Beiträge: 464

14.01.2015, 17:19:55 via Website

Hi,
um wieder den Einstieg in die Android Programmierung zu schaffen, bin ich gerade dabei eine App zu programmieren.
Bei der App muss ich ein Objekt in eine SQLite Datenbank speichern. Im Internet hab ich gelesen, dass dies durch Serialisierung möglich ist. Bei mir funktioniert es jedoch leider noch nicht.

Hier mein Code:

Klasse, in der das Objekt serialisiert wird: (Ich hab den Code aus Platzgründen gekürzt)

//import.....

public class HinzufuegenActivity extends Activity implements OnClickListener {

    Dialog d1;
    Benachrichtigung b;
    Benachrichtigung b2;

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

      //Unwichtiger Code entfernt

    }


    public void benachrichtigungHinzufuegen() {
        if (rbSchnell.isChecked()) {
        b = new Benachrichtigung(this,"schnell",edTitel.getText().toString());
        if(objektDeserialisieren(objektSerialisieren())) {
        b2.showNotification();
        }
//      finish();

        }
        else {
        b = new Benachrichtigung(this,"erweitert",edTitel.getText().toString(),edErinnerungstext.getText().toString(),rbDauerhaft.isChecked());
        if(objektDeserialisieren(objektSerialisieren())) {
        b2.showNotification();
        }
//      finish();
        }


    }


    public String objektSerialisieren() {
         String serializedObject = "";
         try {
             ByteArrayOutputStream bo = new ByteArrayOutputStream();
             ObjectOutputStream so = new ObjectOutputStream(bo);
             so.writeObject(b);
             so.flush();
             serializedObject = bo.toString();
         } catch (Exception e) {
             System.out.println(e);
         }

        return serializedObject;

    }


    public boolean objektDeserialisieren(String serializedObject) {

        try {
             byte b[] = serializedObject.getBytes(); 
             ByteArrayInputStream bi = new ByteArrayInputStream(b);
             ObjectInputStream si = new ObjectInputStream(bi);
             b2 = (Benachrichtigung) si.readObject();
             return true;
         } catch (Exception e) {
             d1 = new Dialog(this,e.toString());
             d1.showDialog();
             return false;
         }


    }
}

Hier die Klasse des Objekts, das ich speichern will: (auch gekürzt)

import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;

public class Benachrichtigung {



    private Context con;
    private String typ;
    private String titel;
    private String text;
    private boolean onGoing;
    private int id;

    public Benachrichtigung(Context pCon, String pTyp, String pTitel, String pText, boolean pOnGoing) {
        con = pCon;
        typ = pTyp;
        titel = pTitel;
        text = pText;
        onGoing = pOnGoing;
    }

    public Benachrichtigung(Context pCon, String pTyp, String pTitel) {
        con = pCon;
        typ = pTyp;
        titel = pTitel;
        text ="";
        onGoing = true;
    }


}

Das Problem tritt in der Methode objektDeserialisieren (Der Aufruf dieser Methode geschieht in "benachrichtigungHinzufuegen") auf. Da läuft irgendetwas schief und es wird der catch-Teil aufgerufen. Die Exception e beinhaltet "java.io.EOFException". Ob die Serialisierung funktioniert und nur die Deserialisierung nicht, kann ich nicht sagen. Wenn ich aber den zurückgelieferten String in einem AlertDialog zeige, ist der Dialog leer. Ist das normal?
Hat jemand eine Idee, warum die Deserialisierung nicht funktioniert?

— geändert am 14.01.2015, 17:28:07

Du hast zum Apfel gegriffen? Gott möge dir verzeihen.

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

14.01.2015, 17:30:27 via Website

Steht irgendwas im LOgCat?

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Gelöschter Account
  • Forum-Beiträge: 464

14.01.2015, 17:36:40 via App

Ich konnte die APP bisher leider nur auf meinem Handy testen, da die App als Mindestanforderung Android Lollipop benötigt (werde ich bald ändern) und der Emulator von Eclipse bei dieser API irgendwie nicht funktioniert. Ich kann das aber mal mit einem anderen Emulator testen. Kann den überhaupt etwas im LogCat stehen, wenn die APP nicht abstürzt?

Du hast zum Apfel gegriffen? Gott möge dir verzeihen.

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

14.01.2015, 17:46:53 via Website

Log Cat funktioniert auch mit einem Handy über USB Debugging, da brauchst du keinen Emulator.

Ja es kann was im LogCat stehen, z.b. irgendwelche exceptions aus System.out.println(e);

LG

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Gelöschter Account
  • Forum-Beiträge: 464

14.01.2015, 18:06:32 via Website

Ok hab es jetzt geschafft. Das steht im LogCat
01-14 18:03:45.261: I/System.out(22968): java.io.NotSerializableException: package.notification_bar_reminder.Benachrichtigung
01-14 18:03:51.126: W/InputEventReceiver(22968): Attempted to finish an input event but the input event receiver has already been disposed.

Du hast zum Apfel gegriffen? Gott möge dir verzeihen.

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

14.01.2015, 18:14:47 via Website

Wenn du danach googelst findest du die Lösung:
Die Exception bedeutet dass dein Objet nicht serialisert werden kann.
Um das zu beheben muss deine Klasse das Interface serializeble implementieren.

bsp: http://stackoverflow.com/questions/12963445/serialization-readobject-writeobject-overides/12963580#12963580

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Gelöschter Account
  • Forum-Beiträge: 464

14.01.2015, 18:39:49 via Website

Ich hab die Benachrichtigungs-Klasse entsprechend angepasst. Leider immer noch diesselbe Fehlermeldung und LogCat. :( Hier der Code:

import android.app.AlertDialog;
import java.io.IOException;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;

public class Benachrichtigung implements java.io.Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private NotificationOpenHandler openHandler;

    private Context con;
    private String typ;
    private String titel;
    private String text;
    private boolean onGoing;
    private int id;

    public Benachrichtigung(Context pCon, String pTyp, String pTitel, String pText, boolean pOnGoing) {
        con = pCon;
        typ = pTyp;
        titel = pTitel;
        text = pText;
        onGoing = pOnGoing;
    }

    public Benachrichtigung(Context pCon, String pTyp, String pTitel) {
        con = pCon;
        typ = pTyp;
        titel = pTitel;
        text ="";
        onGoing = true;
    }


    private void writeObject(java.io.ObjectOutputStream stream)
            throws IOException {
        stream.writeObject(con);
        stream.writeObject(typ);
        stream.writeObject(titel);
        stream.writeObject(text);
        stream.writeBoolean(onGoing);
    }


    private void readObject(java.io.ObjectInputStream stream)
            throws IOException, ClassNotFoundException {
        con = (Context) stream.readObject();
        typ = (String) stream.readObject();
        titel =(String) stream.readObject();
        text = (String) stream.readObject();
        onGoing = stream.readBoolean();
    }

— geändert am 14.01.2015, 18:42:30

Du hast zum Apfel gegriffen? Gott möge dir verzeihen.

Antworten
Gelöschter Account
  • Forum-Beiträge: 464

15.01.2015, 15:10:13 via Website

Muss ich die beiden neuen Methoden eigentlich noch irgendwo aufrufen?

Du hast zum Apfel gegriffen? Gott möge dir verzeihen.

Antworten
Sven R.
  • Forum-Beiträge: 1.904

15.01.2015, 16:07:49 via App

Warscheinlich ist der Context nicht serializable.

— geändert am 15.01.2015, 16:08:09

Wenn dir mein Beitrag gefällt, kannst dich einfach mit dem 👍 "Danke"-Button auf der Website dieses Forums bedanken. 😀

Why Java? - Because I can't C#

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

15.01.2015, 17:25:25 via Website

Du kannst keinen Context serialisieren, diesen musst du nach dem Lesen wieder setzten, also setter Methode schreiben dafür

auch brauchst du die Methoden nicht:

private void writeObject(java.io.ObjectOutputStream stream)
throws IOException {
stream.writeObject(con);
stream.writeObject(typ);
stream.writeObject(titel);
stream.writeObject(text);
stream.writeBoolean(onGoing);
}

private void readObject(java.io.ObjectInputStream stream)
        throws IOException, ClassNotFoundException {
    con = (Context) stream.readObject();
    typ = (String) stream.readObject();
    titel =(String) stream.readObject();
    text = (String) stream.readObject();
    onGoing = stream.readBoolean();
}

Das macht Java schon selbst. Man kann das machen, in spezial fällen. Das erinnert schon eher an ein Parcelable so ;)

Damit deine Object geschrieben werden kann also die Felder transient deklarieren:

private transient NotificationOpenHandler openHandler;

private transient Context con;

Nach dem Lesen sind diese aber halt null, daher halt setter schreiben. Oder noch besser diese wegzulassen, Beans lassen sich einfach besser in einer DB schreiben ohne solche spielerein, führt auch zu besserem Code Design.

Windmate HD, See you @ IO 14 , Worked on Wundercar, Glass V3, LG G Watch, Moto 360, Android TV

Antworten
Gelöschter Account
  • Forum-Beiträge: 464

15.01.2015, 18:34:27 via Website

Danke für die Antworten. :)
Leider funktioniert es immer noch nicht ganz, einen Schritt sind wir aber (glaube ich) weiter.
Jetzt kommt nicht mehr die alte Fehlermeldung, sondern diese:
"java.io.StreamCorruptedException".
Das steht im LogCat:
"01-15 18:13:48.408: W/InputEventReceiver(29935): Attempted to finish an input event but the input event receiver has already been disposed."
(Das kam auch schon vorher im LogCat (siehe oben)).

Hier ist der angepasste Code:

Benachrichtigungs-Klasse (gekürzt);

public class Benachrichtigung implements java.io.Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private transient NotificationOpenHandler openHandler;

    private transient Context con;
    private String typ;
    private String titel;
    private String text;
    private boolean onGoing;
//  private int id;

    public Benachrichtigung(Context pCon, String pTyp, String pTitel, String pText, boolean pOnGoing) {
        con = pCon;
        typ = pTyp;
        titel = pTitel;
        text = pText;
        onGoing = pOnGoing;
    }

    public Benachrichtigung(Context pCon, String pTyp, String pTitel) {
        con = pCon;
        typ = pTyp;
        titel = pTitel;
        text ="";
        onGoing = true;
    }

    public void setContext (Context pCon) {
        con = pCon;
    }

Klasse, in der das Objekt serialisiert/deserialisiert werden soll:

public class HinzufuegenActivity extends Activity implements OnClickListener {

Dialog d1;
Benachrichtigung b;
Benachrichtigung b2;

//Unwichtiger Code entfernt

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

    //Unwichtiger Code entfernt

}



public void benachrichtigungHinzufuegen() {
    if (rbSchnell.isChecked()) {
    b = new Benachrichtigung(this,"schnell",edTitel.getText().toString());
    if(objektDeserialisieren(objektSerialisieren())) {
    b2.setContext(this); 
        b2.showNotification();
    }

// finish();

    }
    else {
    b = new             Benachrichtigung(this,"erweitert",edTitel.getText().toString(),edErinnerungstext.getText().toString(),rbDauerhaft.isChecked());
    if(objektDeserialisieren(objektSerialisieren())) {
    b2.setContext(this); 
            b2.showNotification();
    }

// finish();
}

}


public String objektSerialisieren() {
     String serializedObject = "";
     try {
         ByteArrayOutputStream bo = new ByteArrayOutputStream();
         ObjectOutputStream so = new ObjectOutputStream(bo);
         so.writeObject(b);
         so.flush();
         serializedObject = bo.toString();
     } catch (Exception e) {
         System.out.println(e);
     }

    return serializedObject;

}


public boolean objektDeserialisieren(String serializedObject) {

    try {
         byte b[] = serializedObject.getBytes(); 
         ByteArrayInputStream bi = new ByteArrayInputStream(b);
         ObjectInputStream si = new ObjectInputStream(bi);
         b2 = (Benachrichtigung) si.readObject();
         return true;
     } catch (Exception e) {
         d1 = new Dialog(this,e.toString());
         d1.showDialog();
         return false;
     }


}

}

Schon mal danke für die Hilfe

Du hast zum Apfel gegriffen? Gott möge dir verzeihen.

Antworten