1. Nimm jetzt an unserem 2. ADVENT-Gewinnspiel teil - Alle Informationen findest Du hier!

SQLite im Thread

Dieses Thema im Forum "Android App Entwicklung" wurde erstellt von linuxanton, 20.04.2012.

  1. linuxanton, 20.04.2012 #1
    linuxanton

    linuxanton Threadstarter Neuer Benutzer

    Beiträge:
    11
    Erhaltene Danke:
    0
    Registriert seit:
    05.03.2012
    Hallo,

    ich hole mir über AMF Daten übers Netzwerk in meine Applikation. Das alles passiert in einem Thread. Anschliessend sollen die Daten in eine Datenbank kommen. Da es sich nicht nur um einzelne Datensätze handelt, muss auch das in einen Thread. Aber was ich auch google, ich finde nichts passendes, wie ich eine Datenbank ohne Context öffne und im Thread abarbeiten kann.

    Ich kann ja auch nicht so einfach den Context mit in den Thread übergeben. Wenn der UI Task neu gestartet wird ist der alte Context ja auch weg ...

    Vielleicht weiss von euch jemand Rat.

    Danek schon mal.
    Linuxanton
     
  2. v Ralle v, 20.04.2012 #2
    v Ralle v

    v Ralle v Android-Lexikon

    Beiträge:
    913
    Erhaltene Danke:
    199
    Registriert seit:
    27.08.2010
    Du hast das richtig erkannt, man kann nicht einfach eine Activity nutzen. Das wurde ganz schnell zu Memory Leaks führen, weil die ganze Acitivity im Speicher gehalten wird, obwohl sie schon beendet wurde.

    Bei der Datenbank darf man allerdings den ApplicationContext verwenden. Irgendwo haben dies auch mal Google Entwickler bestätigt.
     
  3. linuxanton, 23.04.2012 #3
    linuxanton

    linuxanton Threadstarter Neuer Benutzer

    Beiträge:
    11
    Erhaltene Danke:
    0
    Registriert seit:
    05.03.2012
    Und wie mache ich das dann rein technisch?

    Hier mal mein Codeauszug:

    Code:
    public class MyActivity extends Activity
    {
       private Thread syncThread;
    @Override
    	protected void onCreate(Bundle savedInstanceState) {
                       ....
    
              syncThread = (Thread) getLastNonConfigurationInstance();
              
           }
    
           public void starteThread(View view)
           {
              syncThread = new SyncThread();
              syncThread.setzeContext(this);
    	  syncThread.start();
           }
           static public class SyncThread extends Thread {
    		private SyncAMF syncamf;
    		private DBManager dbmanager;
    		private Context mContext;
    		private AMFSchredder amfSchredder;
    		@Override
    		public void run() {
    			// Netzwerk, Files ...
    		}
    		public void setzeContext(Context context)
    		{
    			mContext=context;
    		}
    		
    }
    
    In der Klasse mit dem Thread kann ich ja so nicht auf den Kontext zugreifen. Also muss ich ihn von aussen reingeben. Die Frage ist aber, was passiert, wenn die Activity neu gestartet wird oder eine andere Activity gestartet wird mit dem Thread? Wass passiert, wenn die starteThread-Methode nochmal aufgerufen wird? Fragen über Fragen ...


    Danke.
    Linuxanton
     
  4. v Ralle v, 23.04.2012 #4
    v Ralle v

    v Ralle v Android-Lexikon

    Beiträge:
    913
    Erhaltene Danke:
    199
    Registriert seit:
    27.08.2010
    Sieht alles etwas kompliziert aus...

    Wenn die Activity neustartet und du den alten Context verwendest, hast du den ersten Memory Leak. Versuchst du dann was am UI zu ändern, bekommst du eine Exception.

    getLastNonConfigurationInstance() ist übrigens deprecated. Verwende dazu am besten ein Fragment mit retainInstance(true).

    Du musst dich jedenfalls darum kümmern, wie du merkst, ob der Thread schon gestartet wurde. Ich vermute mal ganz stark, dass du nicht bei jedem Orientation Change ihn neu starten willst (wobei der alte noch im Hintergrund läuft). Ich empfehle dir den Ansatz mit dem Fragment oder, wenn der Thread wirklich nur einmal laufen soll, eine static Variable und die checkst du auf null.
     
  5. linuxanton, 23.04.2012 #5
    linuxanton

    linuxanton Threadstarter Neuer Benutzer

    Beiträge:
    11
    Erhaltene Danke:
    0
    Registriert seit:
    05.03.2012
    soweit komm ich nicht mal. Ich bekomm den Kontext nicht mal in der von mir beschriebenen Weise in die innere Klasse. Wenns so kompliziert aussieht, kannst du mir bestimmt einen einfacheren Weg zeigen?

    Der Thread mit dem Sync muss auf jeden Fall auch noch laufen, wenn die Activity weg ist.
     
  6. v Ralle v, 23.04.2012 #6
    v Ralle v

    v Ralle v Android-Lexikon

    Beiträge:
    913
    Erhaltene Danke:
    199
    Registriert seit:
    27.08.2010
    Ich habe leider keine Zeit im Moment das runterzuschreiben. Die einfachste Methode wäre sicher diese (aber definitiv auch die schlechteste):

    Code:
    	private static MyThread instance;
    	
    	@Override
    	public void onCreate(Bundle savedInstanceState) {
    		// ...
    		if (instance == null) {
    			instance = new MyThread();
    			instance.start();
    		}
    	}
    	
    	private static class MyThread extends Thread {
    		// ...
    	}
    Wenn du den Activity Context brauchst, musst du ihn bei jedem onCreate (noch besser onResume) setzen und bei onDestroy (noch besser onPause) entfernen. Wenn du nur Datenbankoperationen machst, kannst du den ApplicationContext verwenden, den übergibst du beim initialisieren.
     
  7. DieGoldeneMitte, 23.04.2012 #7
    DieGoldeneMitte

    DieGoldeneMitte Android-Lexikon

    Beiträge:
    1,230
    Erhaltene Danke:
    256
    Registriert seit:
    05.02.2010
    Phone:
    Nexus 5X
    Tablet:
    Nexus 7 (2013)
    Eventuell sollte man darüber nachdenken, das als Service zu Implementieren.
     
    strider bedankt sich.
  8. linuxanton, 24.04.2012 #8
    linuxanton

    linuxanton Threadstarter Neuer Benutzer

    Beiträge:
    11
    Erhaltene Danke:
    0
    Registriert seit:
    05.03.2012
    Könnte man machen, ist hier aber nicht notwendig. Am Thread führt trotzdem kein weg dran vorbei, denn ein Service läuft per Default immer im main-thread. Und da will ich ihn ja gerade weghaben ...

    Servus
    Linuxanton
     
  9. strider, 24.04.2012 #9
    strider

    strider Erfahrener Benutzer

    Beiträge:
    208
    Erhaltene Danke:
    45
    Registriert seit:
    30.09.2011
    Phone:
    Nexus S
    Du kannst im Service Threads starten und dann hast du keine Probleme mehr wenn der UI Task neu gestartet wird, den Service kannst du weiterlaufen lassen bis die Aufgabe erledigt ist. Und der neue UI Task kann beim Service auch nachfragen ob da noch was altes läuft.
     
  10. linuxanton, 24.04.2012 #10
    linuxanton

    linuxanton Threadstarter Neuer Benutzer

    Beiträge:
    11
    Erhaltene Danke:
    0
    Registriert seit:
    05.03.2012
    Wie sieht es aber dann mit der Referenz auf Kontext aus?

    Momentan sieht das so aus:

    Code:
    
    class MyActivity extends Activity
    {
    private Thread syncThread;
    
    @Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.sync);
    		handler = new Handler();
    		// Check if the thread is already running
    		syncThread = (Thread) getLastNonConfigurationInstance();
    	}
            public void synchronisiere(View view) {
    		if(syncThread == null)
    		{
    		syncThread = new SyncThread(getApplicationContext());	
    		syncThread.start();
    		}
    	}
    
            @Override
    	public Object onRetainNonConfigurationInstance() {
    		return syncThread;
    	}
    
    static public class SyncThread extends Thread {
    		private SyncAMF syncamf;
    		private DBManager dbmanager;
    		public Context mContext;
    		
    		SyncThread(Context context)
    		{
    			mContext=context;
    		}
    		@Override
    		public void run() {
    			
    		dbmanager = new DBManager(mContext);
                    // do some stuff        		
    			
    		}
                   }
    
    }
    
    
    Egal ob Thread, Service, Thread im Service: Ich brauche immer den Context wegen der Datenbank. Mir erschliesst sich die Idee noch nicht ganz, wieso die Datenbank einen Kontext braucht. Aber egal.

    Den Context per Konstruktor zu übergeben war die einzige Möglichkeit, die ich gefunden habe und die auch funktioniert. Und um static komme ich bei der Inner-Class nicht herum. Denn nur dann ist gewährleistet, dass es eine Instanz der inneren Klasse geben kann, wenn die umschliessende Klasse weg ist.
     
  11. strider, 24.04.2012 #11
    strider

    strider Erfahrener Benutzer

    Beiträge:
    208
    Erhaltene Danke:
    45
    Registriert seit:
    30.09.2011
    Phone:
    Nexus S
    Du kannst den Context des Services benutzen.
     
  12. linuxanton, 24.04.2012 #12
    linuxanton

    linuxanton Threadstarter Neuer Benutzer

    Beiträge:
    11
    Erhaltene Danke:
    0
    Registriert seit:
    05.03.2012
    Ja das eröffnet natürlich gleich neue Möglichkeiten. Dann werde ich das so testen.

    Merci vielmal.
    Linuxanton
     
  13. strider, 24.04.2012 #13
    strider

    strider Erfahrener Benutzer

    Beiträge:
    208
    Erhaltene Danke:
    45
    Registriert seit:
    30.09.2011
    Phone:
    Nexus S
    Viel Erfolg!
     
    linuxanton bedankt sich.
  14. MichaelS, 25.04.2012 #14
    MichaelS

    MichaelS Fortgeschrittenes Mitglied

    Beiträge:
    370
    Erhaltene Danke:
    51
    Registriert seit:
    14.08.2009
    Ich persönlich mach für sowas gerne ein Singleton mit Context Abhängigkeit :)
    der MainThread baut ihn auf und dann kann man ja methoden anbieten wie SaveItemXY(...) und diese Methode greift im Thread auf die DB zu und wirft dann ein event wenn es erfolgrich oder fehlerhaft war.

    Wenn die App neu gestartet wird, ändert sich der Context und das Singleton wird neu aufgebaut :)
     

Diese Seite empfehlen