FileDownload-Thread mit Notification

  • 12 Antworten
  • Letztes Antwortdatum
P

Panikmeister

Neues Mitglied
0
Moin moin,

für meine App habe ich einen Worker-Thread, der mehrere Dateien herunterlädt. Ich hatte bisher einen abbrechbaren ProgressDialog, das funktionierte wunderbar.

Nun wollte ich auf Notifications umsteigen, das funktioniert soweit auch, nur würde ich gern einen Abbrechen-Button anzeigen, mit dem man den Thread stoppen kann.

Code:
builder.addAction(R.drawable.ic_action_remove, "Cancel", pIntent);

Das Problem ist, dass der Thread aus einer Klasse "DataMiner" aufgerufen wird, die NICHT von Activity erbt.


Aufbau des Threads(Pseudo-Pseudocode ;) ):

run() {

List<DownloadedData> liste;

for(.....) {
data = download();
liste.add(data);

// eine Art if(isCancelled()) {
break; <- geht aus der Download-Schleife raus und schreibt in DB.
}

}

insertIntoDatabase(liste);

}


Ich würde gern irgendwie über den Abbrechen-Button den Thread (und die Notification) canceln.

Nur muss man ja der Notification-Action ein Intent übergeben.

Muss ich meine Dataminer-Klasse jetzt von Activity erben lassen, oder kann ich da was anderen tun?

Vielen Dank im Voraus ;)
 
du machst einen konstruktor des thread mit einem context als parameter

Context context;
public workerthread(Context context)
{
this.context=context
}

und bennutzt dann diesen Context um den Intent zu kreieren. Da du aus der Klasse Dataminer diesen Thread erstellst kannst du da das gleiche machen im Konstruktor du reichst einfach den Kontext immer weiter an alle die beteiligt sind...


oder du benutzt die funktion getApplicationContext() was viel unkomplizierter ist
 
Vorsicht beim weiterreichen von Contexten!

Wehe wenn der Bildschirm dreht ;-)
 
mmmmh aktualisiert sich die referenz nciht dann automatisch auf das durchgegebene context objekt? oder zeigt der Context im Thread/Dataminer klasse dann auf den alten Speciherplatz?

Der ursprüngliche Beitrag von 15:37 Uhr wurde um 15:42 Uhr ergänzt:

allgemein geht der Context doch gar nciht verloren? verwechslest du das vielleicht mit views/surfaceviews?
 
Das Context-Objekt ist zwar ein Singleton, aber wenn das Objekt, von dem referenziert wird, null ist, räumt der GC eben auf.
(Ist eben nicht C++ :) ).

Nachtrag:

Wenn man den Bildschrim dreht, wird in der Activity zuerst die Methode OnDestroy() und dann OnCreate() aufgerufen. Spricht die Activity wird aus dem Stack geräumt, und dann neu gezeichnet. Zwischendurch räumt der GC auf.

Aus genau diesen Grund gibt es Lifecycle und Bundles.

Alles in allen ein erwartbares Verhalten. Wenn ich ein Objekt in einer Liste platt mache, ist es erst mal weg. Grundlagen Java. Einer der Gründe, warum die Programmlogik teilweise im Android Manifest gemappt wird.

http://developer.android.com/guide/topics/resources/runtime-changes.html
 
Zuletzt bearbeitet:
Ich weiß leider immer noch nicht, wie ich den Thread beenden kann.

Per AddAction wird doch nur ein Intent übergeben, eine spezielle Cancel-Funktion wird da nicht aufgerufen.

:(
 
interrupt is aber sehr instabil...

ich würde den thread in eine while schleife packen mit abbruchbedigung zum Beispiel mache ich in meinen Spiel so: eine äußere Schleife die überprüft ob das spiel vorbei ist und sich beenden kann und eine innere die überprüft ob das spiel pausiert
 
Und wie willst du ein potentiell endlos laufenden Thread beenden. Mit stop().

Einfach null setzen funktioniert nicht. Das beendet ihn nicht. Noch lustiger wird es, wenn ein zweiter Thread geöffnet wird, und beide in die gleiche Datenbank schreiben. Denn Fehler zu finden, macht richtig Spaß.

Man besten man baut nur Thread, die sich nach einer bestimmten Zeit selber beenden.

Wenn der Progressdialog beendet werden soll, wenn der Workerthread fertig ist, dann würde ich einen Handler benutzen.

Vielleicht hilft diese Seite von Google:

https://developer.android.com/training/multiple-threads/communicate-ui.html
 
Das mit der Schleife habe ich ja.

Code:
                if (isCancelled()) {
                    break;
                }

Das hatte ich initiiert mit:

Code:
            this.progressdialog = new ProgressDialog(ctx);
            this.progressdialog.setOnCancelListener(new ProgressDialog.OnCancelListener () {
                public void onCancel(DialogInterface dialog) {
                    cancel(true);
                }
            });

Allerdings stammt das aus meinem AsyncTask inkl. ProgressDialog.

Nun habe ich das mit Notifications gemacht und mit nem normalen Thread.
Das Äquivalent zu cancel(true) wird dann wohl interrupt() sein.

Aber wie kann ich das interrupt() überhaupt über die addAction() auslösen? Das ist mein Problem...:(
 
versteh wohl nicht ganz auf was du genau hinauswillst? wie man einen thread unterbricht?wiee du schon gesagt hast mit interrupt() dafür musst du das thread objekt aber auch kennen
 
Da kann ich mich nur Jaiel anschließen. Was ist das Ziel der ganze Action?

Der ganze relevante Code und die dazugehörige Fehlermeldung wären schon mal ein Anfang. Vielleicht können wir dir dann helfen.
 
Code:
public void mineArtikelThread(final Activity activity,final boolean mitBildern) {

        // PendingIntent ist im Moment wohl Quark.
        Intent intent = new Intent(context, ChefkochZutatenMiner.class);
        PendingIntent pIntent = PendingIntent.getActivity(context, 0, intent, 0);

        builder = new NotificationCompat.Builder(context);
        builder.setContentTitle("Artikel Download")
                .setContentText("Download in progress")
                .setSmallIcon(R.drawable.chefkoch_icon);
        builder.setOngoing(true);
        builder.addAction(R.drawable.ic_action_remove, "Cancel", pIntent);

///////// addAction fügt der Notification einen Cancel-Button hinzu, der nach Möglichkeit den Thread stoppen, bzw. ihn so ändert, dass die if-Bedigung 
[B]if(isCancelled()) { break; }[/B], oder ähnlich, eingeleitet wird.
////////////////////////////////////////////////


        new Thread(
                new Runnable() {
                    @Override
                    public void run() {


                        if(android.os.Debug.isDebuggerConnected()) {
                            android.os.Debug.waitForDebugger();
                        }

                        builder.setProgress(REZEPT_COUNT, progress, false);
                        builder.setNumber(artikelListe.size());
                        nm.notify(1, builder.build());

                        long start = System.currentTimeMillis();

                        String raw;

                        for(int i = 0; i < REZEPT_COUNT; i++){

                            try {
                                raw = cfDownload.crawlZufall();
                            } catch (IOException e) {
                                raw = "";
                                e.printStackTrace();
                            }

                            if(!raw.equals("")) {
                                try {
                                    HashMap<Long, Artikel_Model> artikelNeu = cfDecoder.createArtikelFromString(raw, mitBildern);
                                    for(Artikel_Model artikel : artikelNeu.values()) {
                                        artikelListe.put(artikel.getName(), artikel);
                                    }
                                } catch (JSONException e) {
                                    e.printStackTrace();
                                }
                            }


                            builder.setProgress(REZEPT_COUNT, progress++, false);
                            builder.setNumber(artikelListe.size());
                            nm.notify(1, builder.build());


                         /////////////////////////////////////
                         Hier wäre nun eine Art
                         [B]if(isCancelled()) { break; }[/B]
                         super, der aus der Download-Schleife geht und abschließend die Änderungen in die DB schreibt.
///////////////////////////////////////////////////////

                        }



                        insertArtikelListeIntoDB(artikelListe);
                        final int newArtikelCount = artikelListe.size();
                        final long elapsedTime = System.currentTimeMillis() - start;
                        builder.setContentText(String.format("Benötigte Zeit: %ds für %d neue Artikel.", elapsedTime/1000, newArtikelCount));
                        builder.setProgress(0,0,false);
                        nm.notify(1, builder.build());

                        activity.runOnUiThread(new Runnable() {
                            public void run() {
                                Toast.makeText(activity, String.format("Benötigte Zeit: %ds für %d neue Artikel.", elapsedTime/1000, newArtikelCount), Toast.LENGTH_LONG).show();
                            }
                        });
                    }
                }

        ).start();

    }

Ich habe nur keine Ahnung, wie ich aus dem PendingIntent heraus das bewerkstelligen kann.
 

Ähnliche Themen

AnnaBauer21
Antworten
0
Aufrufe
488
AnnaBauer21
AnnaBauer21
Zurück
Oben Unten