ViewPager Bildergallerie Performance Probleme

P

Pommes9485

Fortgeschrittenes Mitglied
6
Guten Tag,

ich habe hier ein 14 Zoll Tablet mit einer Auflösung von 1920*1080 stehen, für das ich unter anderem eine Gallerie erstellen möchte. Dabei habe ich bereits die ViewPager und das FragmentStatePagerAdapter für mich entdeckt. Allerdings stehe ich noch vor dem Problem, dass die Bilder beim Swipen etwas laggen. Es sieht einfach nicht smooth aus. In der Gallery App des Tablets funktioniert das aber, daher müsste es ja für mich auch machbar sein. Ich habe schon einige Performance Optimierungen mitgemacht, welche aber nicht viel geholfen haben (wenn überhaupt). Hier also der Code:

Der View pro Seite:

Code:
package com.mb.app.pfarrer.fotos;

import android.app.Fragment;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageView;

import com.mb.app.pfarrer.R;

import java.io.File;


public class FotoViewFragment extends Fragment {
    View rootView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.imagesliderview, container, false);

        ((ImageView) rootView.findViewById(R.id.imageView8)).setImageBitmap(decodeSampledBitmap(1920 / 2, 1080 / 2, getArguments().getString("fotopath")));
        this.rootView = rootView;
        return rootView;
    }

    public static Bitmap decodeSampledBitmap(int reqWidth, int reqHeight, String path) {

        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(path, options);
    }


    public static int calculateInSampleSize(
            BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 2;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }
    @Override
    public void onDestroy()
    {
        super.onDestroy();
        ((ImageView) rootView.findViewById(R.id.imageView8)).setImageBitmap(null);
        Log.i("Fragment", "zerstört");
    }
}

Das Layout mit dem Pager:
Code:
package com.mb.app.pfarrer.fotos;

import android.app.Fragment;
import android.app.FragmentManager;
import android.os.Bundle;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.mb.app.pfarrer.FileManager;
import com.mb.app.pfarrer.R;

import java.io.File;


/**
* Created by mberg on 03.11.2015.
*/
public class FotoPagerFragment extends Fragment implements View.OnClickListener {
    File fotos[];

    ScreenSlidePagerAdapter mAdapter;

    ViewPager mPager;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fotoviewfragment, container, false);

        fotos = FileManager.getFotos(getArguments().getString("albumname"));
Log.i("Length", fotos.length+"");
        mAdapter = new ScreenSlidePagerAdapter(this.getActivity().getFragmentManager());

        mPager = (ViewPager)rootView.findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);
        //mPager.setOffscreenPageLimit(fotos.length);

        rootView.findViewById(R.id.foreward).setOnClickListener(this);
        rootView.findViewById(R.id.backward).setOnClickListener(this);

        return rootView;
    }

    @Override
    public void onClick(View v) {
        if(v.getId()==R.id.foreward)
        {
            mPager.setCurrentItem(mPager.getCurrentItem()+1);
        }
        else
        {
            mPager.setCurrentItem(mPager.getCurrentItem()-1);

        }
    }

    private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
        FotoViewFragment fvf;
        public ScreenSlidePagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {

            Bundle b = new Bundle();
            b.putString("fotopath", fotos[position].getAbsolutePath());
             fvf = new FotoViewFragment();
            fvf.setArguments(b);
            return fvf;
        }

        @Override
        public int getCount() {
            return fotos.length;
        }
    }
}

Ich habe auch den inSampleSize Wert schon mal vergrößert (bis 16), was aber von Swipen her keinen Unterschied gemacht hat.
Habt ihr noch Ideen? Ist da ein totaler Performance Killer drinne?`
Hardware Acceleration ist bereits eingeschaltet.
 
So große Bitmaps zu decoden dauert halt. Kannst du versuchen mal 5 Bitmaps gleichzeitig im Speicher zu haben und einfach immer nachzuladen?
Also so 2 Bilder Rechts und 2 Links wenn der User in irgendeine Richtung swiped dann sofort das nächste nachladen und das am weitesten entfernte aus dem Speicher holen?

Dann sollte man aber auch auf OOM Exceptions acht geben.
 
Ich habe schon einen großen Heap aktiviert. Über die Vorgehensweise hatte ich auch schon nachgedacht, hatte aber gehofft, das würde das Adapter selber übernehmen. Sollte aber machbar sein, denke ich.

Oder gibt es dazu schon irgendwelche fertigen Konzepte? Ich war wirklich enttäuscht, dass ich nichts dazu gefunden habe, was man einfach nutzen kann, die Darstellung eine Bildergalerie ist doch kein seltener Fall, oder?
 
Normalerweise macht man das so das Bilder vorgeladen werden und es kommt dann nur zum Stocken falls der User zu schnell scrollt und die Bilder erst nachladen müssen...
 
  • Danke
Reaktionen: Pommes9485
Du muss das Laden und Decoden der Bilder in einen Thread auslagern. Am besten mit ein ThreadPool. Dann kann man relativ viele Bilder "gleichzeitig" laden (bis über 100 MB, bei neueren Geräte). Aber es würde schon ein AsyncThread helfen.
 
Ich habe mich jetzt erstmal an der 1. Lösung versucht, allerdings bekomme ich beim Zurückscrollen den Fehler, dass das Fragment bereits Active ist.
Hier mein Code:
Code:
private class ScreenSlidePagerAdapterList extends FragmentStatePagerAdapter {
        int oldPosition=0;
        FotoViewFragment[] list;
        public ScreenSlidePagerAdapterList(FragmentManager fm) {
            super(fm);
            list = new FotoViewFragment[5];

        }

        @Override
        public Fragment getItem(int position) {

            if(oldPosition<position)
                forwardShift(position);
            else if(oldPosition>position)
                backwardShift(position);
            else
            loadList();

            oldPosition = position;
            return list[2];
        }
        private void loadList()
        {
            for(int i=2; i<list.length; i++) {
                Bundle b = new Bundle();
                b.putString("fotopath", fotos[i-2].getAbsolutePath());
                FotoViewFragment fvf;

                fvf = new FotoViewFragment();
                fvf.setArguments(b);
                list[i]= fvf;
            }
        }
        private void forwardShift(int newPosition)
        {
            for(int i=0; i<list.length-1; i++)
                list[i] = list[i+1];

            Bundle b = new Bundle();
            b.putString("fotopath", fotos[newPosition].getAbsolutePath());
            FotoViewFragment fvf;
            fvf = new FotoViewFragment();
            fvf.setArguments(b);

            list[list.length-1] = fvf;
        }
        private void backwardShift(int newPosition)
        {
            for(int i=list.length-1; i>0; i--)
                list[i] = list[i-1];
            Bundle b = new Bundle();
            FotoViewFragment fvf;

            b.putString("fotopath", fotos[newPosition].getAbsolutePath());
            fvf = new FotoViewFragment();
            fvf.setArguments(b);

            list[0] = fvf;


        }
        @Override
        public int getCount() {
            return fotos.length;
        }
    }
 

Ähnliche Themen

S
Antworten
4
Aufrufe
1.038
Sempervivum
S
R
Antworten
3
Aufrufe
1.679
Ritartet
R
N
Antworten
8
Aufrufe
1.028
NerkJ
N
Zurück
Oben Unten