приложение медленно с изображениями в Android - PullRequest
3 голосов
/ 09 августа 2011

Я делаю приложение для изображений, чтобы показать их в GridView, я получаю 20 изображений с сервера.Разрешение каждого изображения составляет 720 * 540. Я использовал синтаксический анализ JSON для получения URL-адреса и использовал приведенный ниже код для преобразования в растровое изображение для установки изображений.

public static Bitmap loadImageFromUrl(String url) {
    InputStream inputStream;Bitmap b;
    try {
        inputStream = (InputStream) new URL(url).getContent();
        BitmapFactory.Options bpo=  new BitmapFactory.Options();
        if(bpo.outWidth>500) {
            bpo.inSampleSize=8;
            b=BitmapFactory.decodeStream(inputStream, null,bpo );
        } else {
            bpo.inSampleSize=2;
            b=BitmapFactory.decodeStream(inputStream, null,bpo );
        }
        return  b;
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

мое приложение работает нормально, но оно слишкоммного времени для загрузки изображений.Так что мое приложение стало медленным.Должен ли я уменьшить разрешение изображений?

как выйти из проблемы?

Ответы [ 5 ]

7 голосов
/ 09 августа 2011

Если вы выполняете сетку для загрузки 20 изображений с таким разрешением, я бы предложил следующее:

  1. Определенно уменьшите размер изображений. Если вы не настроили таргетинг на планшет, все будет в порядке, поскольку большинство смартфонов не могут достичь этого разрешения с 20 изображениями.

  2. Кэшируйте изображения, если можете.

  3. Загрузите изображения в другой ветке. Сохраните HashMap, чтобы вам было легко, просто поместите все изображения с именами файлов изображений или другими идентификаторами в качестве ключей. отправьте сообщение вашему обработчику, когда изображения будут загружены, и обновите представление после его декодирования. Вы можете получить ваши взгляды напрямую. Просто не забудьте проверить, если они все еще в окне. Таким образом, изображения будут отображаться один за другим быстро. Я не думаю, что многопоточность изображений поможет, просто убедитесь, что вы используете другой поток для «проталкивания изображений» и обновления основного потока пользовательского интерфейса. Пользовательский опыт будет значительно улучшен.

Надеюсь, это поможет.

--- некоторые реализации, у меня сейчас нет полного кода со мной ---

Имейте структуру данных, чтобы соответствовать представлениям с входящими данными. Очень удобно здесь.

private HashMap<String,ImageView> pictures;

Когда вы получите список URL изображений, выполните их итерацию:

 pictures.put(id,view);
        try{
            FileInputStream in = openFileInput(id);
            Bitmap bitmap = null;
            bitmap = BitmapFactory.decodeStream(in, null, null);
        view.setImageBitmap(bitmap);
        }catch(Exception e){
            new Thread(new PictureGetter(this,mHandler,id)).start();
        }

(Здесь средство получения изображений просто извлечет изображение, если оно еще не кэшировано, и кэширует его)

Код для обновления вида изображения:

 if(id!=null){
        ImageView iv = pictures.get(id);
        if(iv!=null){
            try{
                FileInputStream in = openFileInput(id);
                Bitmap bitmap = null;
                bitmap = BitmapFactory.decodeStream(in, null, null);
                iv.setImageBitmap(bitmap);
            }catch(Exception e){
        }
    }
1 голос
/ 21 октября 2014

У меня та же проблема в моем приложении для Android.Когда вы декодируете растровое изображение из изображения большого размера и устанавливаете его как imageBitmap в виде изображения, вероятно, ваше приложение будет работать медленно, и после нескольких попыток вы получите «исключение из-за нехватки памяти»

Два возможных способаВы можете попытаться решить эту проблему: 1 - Уменьшить размер растрового изображения при декодировании из файла. 2 - Использовать библиотеку изображений.

Я предпочел второй способ и использовал Universal Image Loader.https://github.com/nostra13/Android-Universal-Image-Loader

String url = "file://" + your_file_path
com.nostra13.universalimageloader.core.ImageLoader.getInstance().displayImage(url, ivPicture, options);
1 голос
/ 09 августа 2011

Я предполагаю, что большая часть времени загрузки происходит из-за большого количества изображений в сочетании с размером изображений.

Существует 2 возможных решения:

  1. Измените размеры изображений или уменьшите качество изображений, чтобы размер файла был ниже 75 КБ или около того.

  2. Используйте многопоточность для одновременного получения нескольких изображений.Это может не помочь, если пользовательское соединение действительно медленное, но если вы объедините это с достаточно маленьким размером файла, это может просто помочь.Возможно, вы захотите определить текущую пропускную способность устройства и указать количество потоков, на которых вы работаете.

Например: 20 изображений по 75 КБ каждое и доступное соединение 200 КБ / с = 3 или 4 одновременных потока.

Надеюсь, это поможет.

0 голосов
/ 07 сентября 2014

Библиотека Пикассо

Решение вместо того, чтобы использовать растровое изображение для загрузки изображения, напрямую использовать потрясающую библиотеку под названием Picasso, это просто супер быстро, я знаю, что вам действительно нравится это, вы можете сделать это следующим образом

Добавьте файл фляги Пикассо в ваш проект (Загрузите файл фляги Пикассо здесь) Используйте Пикассо, чтобы загрузить изображение вот так

Picasso.with(context).load(new File(title)).centerCrop()
    .resize(150, 150).error(R.drawable.ic_launcher).into(image);  

где title - путь к изображению, которое вы хотите загрузить. Обрезка, изменение размера, ошибка не обязательны.

0 голосов
/ 23 ноября 2011
 public class clothImageLoader {

// the simplest in-memory cache implementation. This should be replaced with
// something like SoftReference or BitmapOptions.inPurgeable(since 1.6)
// public static HashMap<String, Bitmap> cache = new HashMap<String,
// Bitmap>();

private static File cacheDir;

public clothImageLoader(Context context) {
    // Make the background thead low priority. This way it will not affect
    // the UI performance
    photoLoaderThread.setPriority(Thread.NORM_PRIORITY - 1);

    // Find the dir to save cached images
    if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
        // cacheDir=new
        // File(android.os.Environment.getExternalStorageDirectory(),"LazyList");
        cacheDir = new File(ConstValue.MY_ClothBitmap_DIR);
    else
        cacheDir = context.getCacheDir();
    if (!cacheDir.exists())
        cacheDir.mkdirs();
}

final int stub_id = R.drawable.icon;

public void DisplayImage(String url, Activity activity, ImageView imageView) {
    if (ConstValue.ClothRoomcache.containsKey(url))
        imageView.setImageBitmap(ConstValue.ClothRoomcache.get(url));
    else {
        queuePhoto(url, activity, imageView);
        imageView.setImageResource(stub_id);
    }
}

private void queuePhoto(String url, Activity activity, ImageView imageView) {
    // This ImageView may be used for other images before. So there may be
    // some old tasks in the queue. We need to discard them.
    photosQueue.Clean(imageView);
    PhotoToLoad p = new PhotoToLoad(url, imageView);
    synchronized (photosQueue.photosToLoad) {
        photosQueue.photosToLoad.push(p);
        photosQueue.photosToLoad.notifyAll();
    }

    // start thread if it's not started yet
    if (photoLoaderThread.getState() == Thread.State.NEW)
        photoLoaderThread.start();
}

private Bitmap getBitmap(String url) {
    // I identify images by hashcode. Not a perfect solution, good for the
    // demo.
    String filename = String.valueOf(url.hashCode());
    File f = new File(cacheDir, filename);

    // from SD cache
    Bitmap b = decodeFile(f);
    if (b != null)
        return b;

    // from web
    try {
        Bitmap bitmap = null;
        /*
         * InputStream is=new URL(url).openStream(); OutputStream os = new
         * FileOutputStream(f); Utils.CopyStream(is, os); os.close();
         */
        URL url1 = new URL(url);
        bitmap = decodeFile(f);
        /* Open a connection to that URL. */
        URLConnection ucon = url1.openConnection();

        /*
         * Define InputStreams to read from the URLConnection.
         */
        InputStream is = ucon.getInputStream();
        // FlushedInputStream a = new FlushedInputStream(is);
        BufferedInputStream bis = new BufferedInputStream(is);

        /*
         * Read bytes to the Buffer until there is nothing more to read(-1).
         */
        ByteArrayBuffer baf = new ByteArrayBuffer(5000);
        int current = 0;
        while ((current = bis.read()) != -1) {
            baf.append((byte) current);
        }

        /* Convert the Bytes read to a String. */
        FileOutputStream fos = new FileOutputStream(f);
        fos.write(baf.toByteArray());
        fos.flush();
        fos.close();

        bitmap = decodeFile(f);
        return bitmap;
    } catch (Exception ex) {
        ex.printStackTrace();
        return null;
    }
}

// decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f) {
    try {
        // decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(new FileInputStream(f), null, o);
        // Find the correct scale value. It should be the power of 2.
        final int REQUIRED_SIZE = ConstValue.bmpSize;
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) {
            if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE)
                break;
            width_tmp /= 2;
            height_tmp /= 2;
            scale++;
        }

        // decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
    } catch (FileNotFoundException e) {
    }
    return null;
}

// Task for the queue
private class PhotoToLoad {
    public String url;
    public ImageView imageView;

    public PhotoToLoad(String u, ImageView i) {
        url = u;
        imageView = i;
    }
}

PhotosQueue photosQueue = new PhotosQueue();

public void stopThread() {
    photoLoaderThread.interrupt();
}

// stores list of photos to download
class PhotosQueue {
    private Stack<PhotoToLoad> photosToLoad = new Stack<PhotoToLoad>();

    // removes all instances of this ImageView
    public void Clean(ImageView image) {
        for (int j = 0; j < photosToLoad.size();) {
            if (photosToLoad.get(j).imageView == image)
                photosToLoad.remove(j);
            else
                ++j;
        }
    }
}

class PhotosLoader extends Thread {
    public void run() {
        try {
            while (true) {
                // thread waits until there are any images to load in the
                // queue
                if (photosQueue.photosToLoad.size() == 0)
                    synchronized (photosQueue.photosToLoad) {
                        photosQueue.photosToLoad.wait();
                    }
                if (photosQueue.photosToLoad.size() != 0) {
                    PhotoToLoad photoToLoad;
                    synchronized (photosQueue.photosToLoad) {
                        photoToLoad = photosQueue.photosToLoad.pop();

                        // photoToLoad=photosQueue.photosToLoad.get(0);
                        // photosQueue.photosToLoad.remove(photoToLoad);
                    }
                    Bitmap bmp = getBitmap(photoToLoad.url);
                    ConstValue.ClothRoomcache.put(photoToLoad.url, bmp);
                    if (((String) photoToLoad.imageView.getTag()).equals(photoToLoad.url)) {
                        BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad.imageView);
                        Activity a = (Activity) photoToLoad.imageView.getContext();
                        a.runOnUiThread(bd);
                    }
                }
                if (Thread.interrupted())
                    break;
            }
        } catch (InterruptedException e) {
            // allow thread to exit
        }
    }
}

PhotosLoader photoLoaderThread = new PhotosLoader();

// Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable {
    Bitmap bitmap;
    ImageView imageView;

    public BitmapDisplayer(Bitmap b, ImageView i) {
        bitmap = b;
        imageView = i;
    }

    public void run() {
        if (bitmap != null)
            imageView.setImageBitmap(bitmap);
        else
            imageView.setImageResource(stub_id);
    }
}

public static void clearCache() {
    // clear memory cache
    ConstValue.ClothRoomcache.clear();

    // clear SD cache
    File[] files = cacheDir.listFiles();
    for (File f : files)
        f.delete();
}

public class FlushedInputStream extends FilterInputStream {
    public FlushedInputStream(InputStream inputStream) {
        super(inputStream);
    }

    @Override
    public long skip(long n) throws IOException {
        long totalBytesSkipped = 0L;
        while (totalBytesSkipped < n) {
            long bytesSkipped = in.skip(n - totalBytesSkipped);
            if (bytesSkipped == 0L) {
                int a = read();
                if (a < 0) {
                    break; // we reached EOF
                } else {
                    bytesSkipped = 1; // we read one byte
                }
            }
            totalBytesSkipped += bytesSkipped;
        }
        return totalBytesSkipped;
    }
}

}

при вызове метода в методе getView gridView:

holder.image.setTag(ChoseInfo.get(position).getLink());
        imageLoader.DisplayImage(ChoseInfo.get(position).getLink(), activity, holder.image);

ChoseInfo.get (позиция) .getLink ())

Здесь getLink() - интернет-ссылка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...