jpg Downloaden und Anzeigen, nächstes Bild schonmal downloaden

  • Antworten:13
  • Bentwortet
Dominic Schaffner
  • Forum-Beiträge: 10

26.09.2013, 10:57:47 via Website

Hallo,

steige gerade in das Programmiern von Android-Apps ein. Als eine der ersten kleinen Testapps versuche ich zur Zeit eine App zu schreiben, die Bilder aus dem Internet läd und anzeigt. Beim klicken auf das Bild soll das nächste Bild angezeigt werden. Komkret heißt das, dass beim Start das Bild mit der url: "irgendEineUrl/1.jpg" angezeigt wird, das nächste Bild wäre also entsprechend "irgendEineUrl2.jpg"

Das war soweit kein Problem und sieht bei mir in etwa so aus:

1public class MainActivity extends Activity {
2
3 public int page = 1;
4 ImageView bild;
5
6 class ClickListener implements OnClickListener {
7
8 @Override
9 public void onClick(View v) {
10 NextImage nextImage = new NextImage(bild, MainActivity.this);
11 nextImage.execute(page);

12 }
13 }
14 }
15
16 @Override
17 protected void onCreate(Bundle savedInstanceState) {
18 super.onCreate(savedInstanceState);
19 setContentView(R.layout.activity_main);
20
21 bild = (ImageView) findViewById(R.id.mangaPage);
22 NextImage nextImage = new NextImage(bild, this);
23 nextImage.execute(page);
24

25 ClickListener bitmapClick = new ClickListener();
26 bild.setOnClickListener(bitmapClick);
27 }


mit

1public class NextImage extends AsyncTask<Integer, Void, Bitmap> {
2
3 ImageView imageView;
4 MainActivity main;
5
6 public NextImage(ImageView imageView, MainActivity main) {
7 this.imageView = imageView;
8 this.main = main;
9 }
10
11 @Override
12 protected Bitmap doInBackground(Integer... page) {
13 String url;
14 Bitmap bitmap = null;
15 url = "irgendEineUrl" + page[0] + ".jpg"
16 try {
17 InputStream in = new BufferedInputStream(new URL(url).openStream());
18 bitmap = BitmapFactory.decodeStream(in);
19 in.close();
20 } catch (Exception e) {
21
22 e.printStackTrace();
23 }
24 return bitmap;
25 }
26
27 @Override
28 protected void onPostExecute(Bitmap result) {
29 main.page++;
30 imageView.setImageBitmap(result);
31
32 }

Soweit funktioniert das auch alles. Jetzt wollte ich meine App erweitern, so dass sie sofort mit dem Download des nächsten Bildes anfängt, sobald das letzte Bild angezeigt wird. Eben um die Zeit zum Download zu nutzen, während der Nutzer das letzte Bild bertrachtet und somit die Wartezeit bei schlechter Internetverbindung zu verbessern.
Meine Grundidee war folgende: Ich definiere in der MainActivity einfach eine Variable Bitmap nextImage = null
In der Klasse NextImage erweitere ich die Methode onPostExcecute, indem ich dort eine weitere AsyncTasc starte, welche das nächste Bild schonmal downloaded und in die Variable nextImage der MainActivity speichert.
Die oben gezeigt doInBackground müsste dann durch eine if Abrfage erweitert werden, so dass der Download nur stattfindet, wenn die Variable nextImage noch den Wert null hat. Ansonsten kann einfach direkt der Wert dieser Variable zurückgegeben werden.

Klappt so auch einigermaßen. Einziges Poblem: Reicht die Zeit bis zum nächsten Klick des Nutzers nicht aus, um das nächste Bild zu downloaden, hat die Variable nexImage natürlich noch den Wert null und somit beginnt der Download nochmals von vorne und der extra früher gestartete Download läuft theoretisch weiter, bleibt jedoch ungenutzt. Die Wartezeit auf das nächste Bild wird in diesem Fall also sogar länger.
Kann man meine Grundidee so anpassen, dass dieses Problem umgangen wird? Oder habt ihr bessere Vorschläge mein Vorhaben umzusetzen?

Meine Frage ist jetzt doch länger geworden als gedacht... Schonmal danke im Vorraus!

Antworten
Mac Systems
  • Forum-Beiträge: 1.727

26.09.2013, 11:28:47 via Website

Schau dir mal das Konzept einer Queue (Warteschlange) an. Man stellt aufgaben ein und jemand erledigt diese

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

Dominic Schaffner

Antworten
Dominic Schaffner
  • Forum-Beiträge: 10

27.09.2013, 10:22:36 via Website

Schonmal danke für diesen ersten Hinweis. Habe das Internet mal ein bisschen danch druchforstet. FIFo klingt ja genau nach dem, was ich brauche. Doch leider weiß ich trotzdem nicht, wie ich das impelentieren kann.
Habe mir das jetzt folgendermaßen vorgestellt: Baue mir einen Thread, der z.B. eine linkedList übergeben bekommt. In dieser linkedList speichere ich Objekte, über welche ich die auszuführenden Methoden übergebe. Also z.B. die Methode, die ein besimmtes Bild runterläd oder die Methode, die ein Bild zeichnen soll.
Mein Threads könnte dann so aussehen:
1public class QueueThread extends Thread {
2
3 LinkedList<Method> myLinkedList;
4
5 public QueueThread() {
6 start();
7 }
8
9 @Override
10 public void run() {
11 while (myLinkedList.size()==0) {
12 synchronized (myLinkedList) {
13 try {
14 myLinkedList.wait();
15 } catch (InterruptedException e) {
16 // TODO Auto-generated catch block
17 e.printStackTrace();
18 }
19 }
20 }
21
22 myLinkedList.removeFirst().run();
23 run();
24 }
25
26}
27 }

Dann müsste ich in meinem Haupt-Thread nur noch die linkedList mit Objekten des Typs Method füttern, bei welchen ich die Methode run() mit den gewünschten Methoden überschreibe und ein notify schicke.
Methoden übergeben habe ich noch nie, Sollte aber so funktionieren? "Method" (aus meiner LinkedList) könnte dann einfach ein Inerface sein mit der einzigen Methode public void run();
Ein großes Problem bleibt bei meinem Ansatz: Das Anzeigen eines Bildes kann ich ja eigenltich nur vom Haupt-Thread ausfürhen. Kann mein Queue-Thread den Hauptthread auffordern, eine Methode aufzurufen?

Habe ein bisschen das Gefühl, als hätte ich mich bei meinen Überlegungen etwas verrannt. Bin ich jetzt vollkommen auf dem falschen Weg?

Antworten
Lucas
  • Forum-Beiträge: 717

27.09.2013, 11:16:54 via App

Ich programmierte zwar kein Java sondern nur VB
Aber theoretisch könntest du ja noch nen Boolean (falls es das in Java gibt) definieren, der bei fertigem download auf True gesetzt wird.
Wenn nun der User auf das Bild klickt, wird erstmal geprüft, ob der Boolean auf false oder true steht
wenn er auf true steht, dann wird das nächste Bild angezeigt, weil der download schon fertig ist, wenn false dann wird eben gewartet, bis der download fertig ist.

Antworten
Dominic Schaffner
  • Forum-Beiträge: 10

27.09.2013, 12:04:36 via Website

Das würde funktionieren, müsste dafür noch nicht mal den Umweg über einen Boolean machen. Ich könnte auch einfach in einer if-Abfrage kontrollieren, ob das Bild noch den Wert null hat. Doch ich sehe folgendes Problem: Das "wird eben gewartet" stelle ich mir sehr schwer vor, da der Hauptthread ja immer auf Benutzerinteraktion reagieren soll. Wenn ich das alles richtig verstanden habe, würde Android dann die App beenden mit der Meldung, dass die App nicht reagiert. Dann hätte ich den Download auch direkt im Hauptthread durchführen können.
Oder sehe ich das falsch?

Lässt man das Warten weg, würde ein Klick eben so lange ignoriert, bis der Download fertig ist. Man müsste also so lange klicken, bis endlich was passiert

— geändert am 27.09.2013, 12:05:21

Antworten
Lucas
  • Forum-Beiträge: 717

27.09.2013, 12:37:12 via App

Oder du machst es so, dass eben ein Lesezeichen angezeigt wird, dann dürfte sich die APP ja nicht aufhängen

Antworten
Dominic Schaffner
  • Forum-Beiträge: 10

27.09.2013, 12:41:59 via Website

Hmmm verstehe nicht ganz, wie mich das weiter bringen soll. Klar kann ich ein Lesezeichen anzeigen lassen. Aber wie realisiere ich, dass anschließend das neue Bild angezeigt wird, sobald der Download fertig ist? Das Problem hat sich dann meiner Meinung nach nur verschoben?!

Antworten
Lucas
  • Forum-Beiträge: 717

27.09.2013, 12:47:59 via App

Dann mach halt mal als vorübergehende Lösung so ne Benachrichtigung, die sagt das man kurz warten soll, und dann nochmal klicken soll

— geändert am 27.09.2013, 12:49:44

Antworten
Dominic Schaffner
  • Forum-Beiträge: 10

27.09.2013, 12:50:15 via Website

Kein Problem, trotzdem schonmal danke :D

Findet sich sicher noch eine Lösung.

Antworten
Dominic Schaffner
  • Forum-Beiträge: 10

27.09.2013, 13:48:57 via Website

falls meine Gedanken vorher nicht total daneben lagen, besteht mein Hauptproblem darin, meinem Thread zu sagen, dass eine Methode im Haupt-Thread ausgeführt werden soll. AsyncTask bietet hierfür ja die Methode onProgressUpdate() also ist sowas auf jeden Fall möglich. Doch wie implementiere ich eine Methode, die ähnlich wie onProgressUpdate zwischendurch aufgerufen werden kann?

Antworten
impjor
  • Forum-Beiträge: 1.793

27.09.2013, 13:53:52 via App

1. Vom Stil her würde ich das letzte run(); durch eine Schleife ersetzen.
2. Du machst keine <Method> LinkedList, da es die Klasse schon gibt. Besser <Runnable> oder eigenes Interface.
2. Um auf den UI-Thread zuzugreigen kannst du Activity#runOnUiThread() oder einen Handler verwenden.

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Dominic Schaffner

Antworten
Dominic Schaffner
  • Forum-Beiträge: 10

27.09.2013, 14:17:16 via Website

impjor
1. Vom Stil her würde ich das letzte run(); durch eine Schleife ersetzen.
2. Du machst keine <Method> LinkedList, da es die Klasse schon gibt. Besser <Runnable> oder eigenes Interface.
2. Um auf den UI-Thread zuzugreigen kannst du Activity#runOnUiThread() oder einen Handler verwenden.

LG

Jeah, vielen Dank! Das sollte mich eigentlich weiter bringen.

Zu 1.: Das bekomm ich noch grade so hin.
Zu 2.: Huch, stimmt die Klasse gibt es. Sollte eigentlich ein Interface sein und in der einfachsten Form etwa so aussehen:

1package mrdo87.onepiecemanga;
2
3public interface Method {
4
5 public void run();
6
7}

sollte ich wohl noch umbenennen..

Zu 3.: das klingt doch nach den Begriffen, nach denen ich gesucht habe. Ich werde mein Glück versuchen. Vielen Dank :grin:

Antworten
impjor
  • Forum-Beiträge: 1.793

27.09.2013, 23:35:59 via App

Wie gesagt, warum ein eigenes Interface Method (oder was auch immer), wenn du direkt Runnable benutzen kannst?

Viel Erfolg!

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Mac Systems

Antworten
Dominic Schaffner
  • Forum-Beiträge: 10

29.09.2013, 17:14:20 via Website

hat jetzt alles geklappt! Vielen Dank nochmal für die Tipps!

Antworten