Jetzt kostenlos registrieren. Mitglieder surfen ohne Werbung auf Android-Hilfe.de!
Zurück   Android-Hilfe.de > Android Developer > Android App Entwicklung

Wie verhindere ich ruckeln beim Scrollen einer ListView mit ImageView-Elementen?

Das Thema "Wie verhindere ich ruckeln beim Scrollen einer ListView mit ImageView-Elementen?" befindet sich unter Android App Entwicklung auf Android-Hilfe.de.


Antwort

 

Themen-Optionen Ansicht
Alt 07.05.2011, 09:46   #1 (permalink)
Neuer Benutzer

Modell: HTC Desire HD

Registriert seit: 27.12.2010
Beiträge: 20
Abgegebene Danke: 4
Erhielt 0 Danke für 0 Beiträge
Frage Wie verhindere ich ruckeln beim Scrollen einer ListView mit ImageView-Elementen?

Hallo zusammen,

meine App beinhaltet eine ListActivity, die aus Elementen besteht, die wiederum 3 TextViews beinhalten für Interpret, Titel und Album, sowie eine ImageView zur Darstellung eines Albumarts.
Die Liste ist quasi so aufgebaut wie die Tracklist in der Standard Musik App.
Die Daten werden aus MediaStore per Cursor abgefragt und der Cursor mit einem modifizierten SimpleCursorAdapter an die ListView gebunden.

Hier ist der Code:
Code:
void setListAdapterOverride() {
    String[] fromColumns = new String[] {
            AudioColumns.ARTIST,
            MediaColumns.TITLE,
            AudioColumns.ALBUM,
            AudioColumns.ALBUM_ID
    };
    int[] toColumns = new int[] {
            R.id.tv_artist,
            R.id.tv_title,
            R.id.tv_album,
            R.id.iv_albumArt
    };
    cursorAdapter = new customAdapter(getBaseContext(), R.layout.listviewitem, cursor, fromColumns, toColumns);
    setListAdapter(cursorAdapter);
    if (MyDebug.Log)
        Log.d("Activity", "ListAdapter gesetzt");
}

class customAdapter extends SimpleCursorAdapter {

    int layout;
    Cursor cursor;
    String[] from;
    int[] to;

    public customAdapter(Context context, int layout, Cursor c,
            String[] from, int[] to) {
        super(context, layout, c, from, to);
        this.layout = layout;
        this.cursor = c;
        this.from = from;
        this.to = to;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;
        if (row == null) {
            LayoutInflater inflater = getLayoutInflater();
            row = inflater.inflate(R.layout.listviewitem, parent, false);
            if (MyDebug.Log)
                Log.d("Activity", "Inflate");
        }
        cursor.moveToPosition(position);
        TextView artist = (TextView) row.findViewById(to[0]);
        TextView title = (TextView) row.findViewById(to[1]);
        TextView album = (TextView) row.findViewById(to[2]);
        ImageView albumArt = (ImageView) row.findViewById(to[3]);
        artist.setText(cursor.getString(cursor.getColumnIndex(from[0])));
        title.setText(cursor.getString(cursor.getColumnIndex(from[1])));
        album.setText(cursor.getString(cursor.getColumnIndex(from[2])));

        Cursor albumArtCursor = contentResolver.query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, new String[] { MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM_ART }, MediaStore.Audio.Albums._ID + "='" + cursor.getInt(cursor.getColumnIndex(from[3])) + "'", null, null);
        albumArtCursor.moveToFirst();
        String albumArtUri = albumArtCursor.getString(albumArtCursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART));
        if (albumArtUri == null) albumArtUri = "default";
        if (!imageCache.containsKey(albumArtUri)) {
            Bitmap albumArtBitmap;
            if (!albumArtUri.equals("default")) {
                Options opts = new Options();
                opts.inJustDecodeBounds = true;
                BitmapFactory.decodeFile(albumArtUri, opts);
                Integer[] bitmapSize = new Integer[] { opts.outWidth, opts.outHeight };
                Integer scaleFactor = 1;
                while ((bitmapSize[0]/2 > 50) && (bitmapSize[1]/2 > 50)) {
                    scaleFactor++;
                    bitmapSize[0] /= 2;
                    bitmapSize[1] /= 2;
                }
                opts = new Options();
                opts.inSampleSize = scaleFactor;
                albumArtBitmap = BitmapFactory.decodeFile(albumArtUri, opts);
            } else {
                albumArtBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_mp_song_list);
            }
            imageCache.put(albumArtUri, albumArtBitmap);
        }
        albumArt.setImageBitmap(imageCache.get(albumArtUri));
        return row;
    }
}
imageCache ist eine HashMap<String, Bitmap> und dient als Cache für die Albumarts, die schon über decodeFile bearbeitet wurden, sodass sie nicht immer wieder neu decodiert werden müssen.

In einer vorherigen Version des Codes fehlte dieser imageCache nocht, d.h. das Bild wurde jedes mal aus der Datei selbst decodiert. Das machte sich vor allem dadurch bemerkbar, dass die ListView beim scrollen extrem ruckelte.

Nach Hinzufügen des imageCache ruckelt die ListView zwar nicht mehr so stark wie vorher, aber ein merkliches ruckeln ist dennoch sichtbar.

Wenn ich die Tracklist in der Musik App anschaue fällt mir auf, dass sie eigentlich gar nicht ruckelt.

Hat jemand von euch eine Idee wie ich den Code, bzw. das ganze Vorhaben noch weiter optimieren kann?

Vielen Dank
__________________
Gruß Oli - Follow me on Twitter
ChemDroid ist offline   Mit Zitat antworten
Alt 07.05.2011, 11:18   #2 (permalink)
Fortgeschrittenes Mitglied

Modell: Galaxy Nexus & Motorola Xoom

Registriert seit: 11.05.2009
Beiträge: 315
Abgegebene Danke: 34
Erhielt 80 Danke für 41 Beiträge
Standard AW: Wie verhindere ich ruckeln beim Scrollen einer ListView mit ImageView-Elementen?

Du benötigst wahrscheinlich einen Efficient List Adapter.
__________________
Meine App: Seal
Mein Webseite: sebastianapps.de
sebastian ist offline   Mit Zitat antworten
Folgender Benutzer bedankt sich bei sebastian für diesen Beitrag:
ChemDroid (09.05.2011)
Alt 07.05.2011, 11:20   #3 (permalink)
Android Guru

Registriert seit: 09.05.2009
Beiträge: 2.389
Abgegebene Danke: 36
Erhielt 307 Danke für 289 Beiträge
Standard AW: Wie verhindere ich ruckeln beim Scrollen einer ListView mit ImageView-Elementen?

evtl das laden des bildes in einen thread auslagern?
__________________
App Entwicklung
Latest apps: Media Streamer BETA | DailyCash | MoneyManager ( PRO | HD )
swordi ist offline   Mit Zitat antworten
Alt 07.05.2011, 12:52   #4 (permalink)
Neuer Benutzer

Modell: HTC Desire HD

Registriert seit: 27.12.2010
Beiträge: 20
Abgegebene Danke: 4
Erhielt 0 Danke für 0 Beiträge
Standard AW: Wie verhindere ich ruckeln beim Scrollen einer ListView mit ImageView-Elementen?

Zitat:
Zitat von sebastian Beitrag anzeigen
Du benötigst wahrscheinlich einen Efficient List Adapter.
Hm also noch nen ViewHolder einbauen... Danke werde ich mal ausprobieren.

Das laden des Bildes in nen externen Thread verlegen habe ich schon ausprobiert, aber leider kann nur der UI-Thread die ImageView ändern...
__________________
Gruß Oli - Follow me on Twitter
ChemDroid ist offline   Mit Zitat antworten
Alt 07.05.2011, 14:06   #5 (permalink)
Android Experte

Modell: Samsung Galaxy Nexus

Registriert seit: 16.11.2009
Beiträge: 819
Abgegebene Danke: 1
Erhielt 215 Danke für 117 Beiträge
Standard AW: Wie verhindere ich ruckeln beim Scrollen einer ListView mit ImageView-Elementen?

Zitat:
Zitat von ChemDroid Beitrag anzeigen
Das laden des Bildes in nen externen Thread verlegen habe ich schon ausprobiert, aber leider kann nur der UI-Thread die ImageView ändern...
Handler.post() könnte helfen... Also "<visibility> Handler handler = new Handler();" als Member-Variable, dann im Ladethread handler.post( new Runnable(){....} ); aufrufen. Der Runnable-Code wird dann bei nächster Gelegenheit im UI-Thread ausgeführt.
Allerdings bleibt noch das Problem, dass die Item-View ggf. schon gar nicht mehr existiert oder für ein anderes Item verwendet wird bis der Bildlade-Thread fertig ist, gerade bei schnellem Scrollen.
Der Bild-Cache kann sich übrigens schnell als gelungener Schuss ins Knie entpuppen, v.a. auf etwas älteren/schwächeren Geräten, bei denen der Heap pro App auf 16MB begrenz ist. Bei 'ner etwas größeren Liste ist ein OutOfMemory vorprogrammiert...
Mort ist offline   Mit Zitat antworten
Alt 07.05.2011, 21:07   #6 (permalink)
Android Experte
 
Benutzerbild von Haggy

Modell: Nexus S

Registriert seit: 03.08.2009
Beiträge: 542
Abgegebene Danke: 19
Erhielt 77 Danke für 50 Beiträge
Standard AW: Wie verhindere ich ruckeln beim Scrollen einer ListView mit ImageView-Elementen?

Mort hat das ganze schon richtig erkannt. Möchte nur noch hinzufügen, dass du zu viel in deiner getView()-Methode machst. Zu viel was den UI-Thread beschäftigt. Um das richtig smooth zu bekommen, wirst du nicht drum rum kommen, das Suchen, Laden und Dekodieren des Bildes in einen Thread auszulagern und per MessageHandler den UI-Thread darüber zu informieren, dass das gewünschte Bild nun im imageCache zur Verfügung steht (als Bitmap gleich am besten). So bleibt die Liste auf Zack und die Bilder erscheinen wenn sie geladen sind (solange eben nichts oder ein statischer Platzhalter). Richtig ist aber, dass du auf jeden Fall prüfen musst, ob deine ImageView noch existent ist. Ich würde hierbei davon abraten, die ImageView in irgendeiner Form an den Cache durchzureichen. Das erzeugt nur Speicherlecks. Eleganter ist, eine eindeutige ID als Tag zu setzen und wenn das Bild geladen ist, zu überprüfen ob das Tag noch dasselbe ist. So kannst du erkennen ob du die richtige ImageView vor dir hast. Dann noch was Allgemeines zu Caches, vor Allem bei großen Daten wie Bilder - vermeide, wenn möglich, einfache HashMaps oder Arrays als Cache. Da geht dir, wie Mort schon meinte, schneller der Speicher aus als du scrollen kannst. Elegante Alternative sind Softreferences oder WeakReferences. Android hat dir bereits eine WeakHashmap gebaut, die sich prima für Caches eignet (Doku lesen nicht vergessen).
__________________

Check and Done! · GPS Timer · Sag "Danke" mit Dropbox · Standard, mit weichem d!
Haggy ist offline   Mit Zitat antworten
Folgender Benutzer bedankt sich bei Haggy für diesen Beitrag:
ChemDroid (09.05.2011)
Alt 09.05.2011, 18:16   #7 (permalink)
Neuer Benutzer

Modell: HTC Desire HD

Registriert seit: 27.12.2010
Beiträge: 20
Abgegebene Danke: 4
Erhielt 0 Danke für 0 Beiträge
Problem gelöst / Frage beantwortet AW: Wie verhindere ich ruckeln beim Scrollen einer ListView mit ImageView-Elementen?

Vielen Dank für eure Antworten

Ich habe es nun mit Hilfe der LazyList aus diesem Beitrag gelöst.

Der Code ist ein wenig zu lang um ihn hier zu posten, also falls sich jemand für den Code interessiert, twittert mir einfach oder schreibt mir ne Nachricht, ich melde mich dann
__________________
Gruß Oli - Follow me on Twitter
ChemDroid ist offline   Mit Zitat antworten
Antwort

Stichworte
cursor, image-caching, listview, optimierung, simplecursoradapter

Themen-Optionen
Ansicht


Ähnliche Themen

Thema Autor Forum Antworten Letzter Beitrag
SMS: Wie verhindere ich versehentliches Senden? ALF-Berlin Kommunikation 14 06.06.2011 11:51
Kontakt ruckeln beim Scrollen - aber nicht wenn man über den App Drawer geht. soldiers Motorola Defy Forum 3 24.02.2011 17:59
Wie bekomme ich daten aus einer ListView? MilesTeg Android App Entwicklung 2 04.12.2010 19:19
Ruckeln beim Scrollen in Telefonbuch LarsD HTC Desire Forum 5 01.06.2010 09:47
Starkes Ruckeln beim Kontakte scrollen KarlArsch HTC Hero / T-Mobile G2 Touch Forum 10 05.08.2009 18:24




Du liest gerade: "Wie verhindere ich ruckeln beim Scrollen einer ListView mit ImageView-Elementen?" unter "Android App Entwicklung" auf Android-Hilfe.de.


Powered by vBulletin®
Copyright ©2000 - 2012, vBulletin Solutions, Inc.
Search Engine Friendly URLs by vBSEO
© Android-Hilfe.de 2012 - All rights reserved.