SQLite im Thread

L

linuxanton

Neues Mitglied
0
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
 
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.
 
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
 
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.
 
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.
 
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.
 
Eventuell sollte man darüber nachdenken, das als Service zu Implementieren.
 
  • Danke
Reaktionen: strider
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
 
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.
 
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.
 
Du kannst den Context des Services benutzen.
 
Ja das eröffnet natürlich gleich neue Möglichkeiten. Dann werde ich das so testen.

Merci vielmal.
Linuxanton
 
Viel Erfolg!
 
  • Danke
Reaktionen: linuxanton
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 :)
 

Ähnliche Themen

R
Antworten
6
Aufrufe
1.016
swa00
swa00
D
  • djsnoopy
Antworten
6
Aufrufe
617
djsnoopy
D
S
Antworten
8
Aufrufe
512
swa00
swa00
Zurück
Oben Unten