在安卓网格视图中,滚动不够流畅

3
在我的Android应用程序中,我正在从API加载图片。但是在这些图片加载到网格视图后,滚动不够流畅。我使用异步线程获取图片以避免阻塞用户界面。请问有什么建议可以提高滚动性能?

你是否重用视图并使用 ViewHolder 模式? - Geralt_Encore
1
你能否添加适配器的代码(特别是getView()方法)? - Selecsosi
我之前也遇到过这个问题,我减小了图片的尺寸,然后问题得到了完美解决。 - Ryan Sayles
3个回答

2
在单独的线程中加载图像确实有助于提高性能,但这里还有另一个重要的性能问题需要解决,那就是“视图可重用性”。一旦您在适配器中设置了图像,请确保实际上重用了适配器的getView方法提供的视图,而不是每次调用该方法时创建/填充新的布局(GridElement),这通常会导致滚动变慢,一旦所有图像都被加载后。有几种模式可用于解决此问题,您应该阅读ViewHolder,它是最常见和易于使用的模式之一... 希望这可以帮助你... 致敬

现在,滚动是好的,但是图像在向下滚动时会改变位置。我将imageView对象传递给set image以在下载后设置图像。我使用了ViewHolder来保存ImageView,但问题仍然存在。 - Kanika Maheshwari

0

getView()方法的代码:

{{{

@Override
        public View getView(final int position, View convertView, ViewGroup parent) {
                final HashMap<String, String> song = songsList.get(position);
                imageURL = song.get(VariablesList.TAG_ALBUM_IMAGE);
                View v = null;
                if (convertView != null)
                        v = convertView;
                else
                        v = inflater.inflate(R.layout.gridlayout_item, parent, false);
                final ImageView imageView = (ImageView) v.findViewById(R.id.icon_image);
                final Thread startAlbum = new Thread() {
                        public void run() {

                                imageView.setImageBitmap(AlbumList
                                                .LoadImagetoGridView(imageURL));

                                synchronized (this) {
                                        this.notifyAll();
                                }
                        }
                };

                synchronized (startAlbum) {
                        startAlbum.start();
                        try {
                                startAlbum.wait();
                        } catch (InterruptedException e) {
                                e.printStackTrace();
                        }
                }
                imageView.setOnClickListener(new View.OnClickListener() {
                        // @Override
                        public void onClick(View v) {
                                albumUrl = new StringBuffer(resources.getString(R.string.songsListURL));
                                String albumIndex = song.get("id");
                                albumName = (song.get("name"));
                                imageURL = song.get(VariablesList.TAG_ALBUM_IMAGE);
                                SongsList albumList = new SongsList(imageURL, albumUrl,
                                                albumName,albumIndex,resources);
                                Thread threadAlbumList = new Thread(albumList);
                                threadAlbumList.start();

                                synchronized (albumList) {
                                        try {
                                                albumList.wait();
                                        } catch (InterruptedException e) {
                                                e.printStackTrace();
                                        }
                                }
                                if (!NewMediaPlayer.mediaPlayer.isPlaying()) {
                                        HashMap<String, String> playingSong = NewMediaPlayer.selectedSongs
                                                        .get(0);
                                        if (playingSong != null) {
                                                String url = playingSong.get("songUrl");
                                                String songName = playingSong.get("songName");
                                                if (songName != null)
                                                        {
                                                         NewMediaPlayer.songTitleLabel.setText(albumName
                                                                        + " - " + songName);
                                                         NewMediaPlayer.songTitle.setText(albumName+"-"+songName);
                                                        }
                                                NewMediaPlayer.playSong(url);
                                        }
                                }
                        }
                });

                TextView itemAlbumName = (TextView) v.findViewById(R.id.icon_text);
                itemAlbumName.setText(song.get("name"));
                itemAlbumName.setOnClickListener(new View.OnClickListener() {
                        public void onClick(View v) {
                                HashMap<String, String> song = songsList.get(position);
                                String songIndex = song.get("id");
                                String albumName = (song.get("name"));
                                Intent in = new Intent(context, SongListActivity.class);
                                in.putExtra("albumIndex", songIndex);
                                in.putExtra("albumName", albumName);
                                in.putExtra("AlbumImage", song.get(VariablesList.TAG_ALBUM_IMAGE));
                                context.startActivity(in);
                        }
                });

                return v;
        }

}}}

在强制主UI线程等待的情况下,将setImageBitmap放在单独的线程中执行有什么意义呢? - Martin Cazares
如何在UI上加载位图图像? - Kanika Maheshwari
只是在单独的线程上执行它,基本上就是你正在做的事情,但不需要调用wait,因为这实际上是在主线程上加载它,因为你仍然在等待它的加载,最好的方法是让线程自己运行,一旦完成,然后设置图像,但必须使用handler来执行,因为为了修改视图,你需要在主线程中执行代码。现在,如果你正在从URL下载图片,请查看volley项目,它具有完美的缓存图像机制,因此,如果已经下载了图像,它只需从缓存中获取即可... - Martin Cazares
@Martin,我明白了问题所在,我需要移除线程上的等待,因为它导致滚动变慢。所以,我可以将其转移到异步线程中,而不是等待。因为我不能在主线程上获取http图像。还有其他建议吗? - Kanika Maheshwari

0

不要费力,使用通用图像加载库。它的性能很好。 在onCreate方法中, gridView.setAdapter(new ImageAdapter(this,ImagesArrayPath));

    private static class ImageAdapter extends BaseAdapter {
    private  final String[] IMAGE_URLS ;

    private LayoutInflater inflater;

    private DisplayImageOptions options;

    ImageAdapter(Context context,String source[]) {
        inflater = LayoutInflater.from(context);
        IMAGE_URLS=source;

        options = new DisplayImageOptions.Builder()
                .showImageOnLoading(R.mipmap.ico_place_holder)
                .showImageForEmptyUri(R.drawable.ic_empty)
                .showImageOnFail(R.drawable.ic_error)
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .considerExifParams(true)
                .bitmapConfig(Bitmap.Config.RGB_565)
                .build();
    }



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

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder holder;
        View view = convertView;
        if (view == null) {
            view = inflater.inflate(R.layout.item_grid_image, parent, false);
            holder = new ViewHolder();
            assert view != null;
            holder.imageView = (ImageView) view.findViewById(R.id.image);
            holder.progressBar = (ProgressBar) view.findViewById(R.id.progress);
            view.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }

        ImageLoader.getInstance()
                .displayImage(IMAGE_URLS[position], holder.imageView, options, new SimpleImageLoadingListener() {
                    @Override
                    public void onLoadingStarted(String imageUri, View view) {
                        holder.progressBar.setProgress(0);
                        holder.progressBar.setVisibility(View.VISIBLE);
                    }

                    @Override
                    public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
                        holder.progressBar.setVisibility(View.GONE);
                    }

                    @Override
                    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                        holder.progressBar.setVisibility(View.GONE);
                    }
                }, new ImageLoadingProgressListener() {
                    @Override
                    public void onProgressUpdate(String imageUri, View view, int current, int total) {
                        holder.progressBar.setProgress(Math.round(100.0f * current / total));
                    }
                });

        return view;
    }
}

static class ViewHolder {
    ImageView imageView;
    ProgressBar progressBar;
}

希望这能对你有所帮助。愉快编程!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接