如果从其子项请求无效,则库中的奇怪动画

时间:2011-12-15 21:40:17

标签: android android-imageview android-gallery android-view android-image

这是我的Gallery的适配器,我在其上显示ImageViews(页面的拇指)

我想加载图像ASync(有时这可能来自网络),所以我做了那个代码:

    public View getView(int position, View convertView, ViewGroup parent) {
        final ImageView image = convertView != null ? convertView : new ImageView(getContext());

        final PageInfo page = getItem(position);

        image.setBackgroundColor(Color.WHITE);

        image.setLayoutParams(new Gallery.LayoutParams(96, 170));

        new AsyncTask<Void, Void, Bitmap>() {
            @Override
            protected Bitmap doInBackground(Void... arg0) {
                try {
                    File thumbnail = page.thumbnail();//Thumbnail download the image if not available
                    return BitmapFactory.decodeStream(new FileInputStream(thumbnail));
                } catch (ApplicationException e) {
                    return null;
                } catch (NetworkException e) {
                    return null;
                }
            }

            protected void onPostExecute(Bitmap result) {
                if (result == null)
                    return;

                image.setImageBitmap(result);
            };
        }.executeOnExecutor(executor);

        return image;
    }

这样可行,但是如果我拖动画廊的视图(当切换到真正的Bitmap时)会“跳”到厨房内的另一个位置,这会让它变得怪异。

我该如何避免?或者我可以在不请求ViewGroup布局的情况下更改ImageView的图像吗?

编辑:关于Google开发群体的类似问题 http://code.google.com/p/android/issues/detail?id=15526

6 个答案:

答案 0 :(得分:4)

Gallery小部件有一个已知错误,导致它始终返回null convertView。这意味着每次调用getView时,您都会创建一个新的ImageView,这可能会导致您看到的问题。

第三方创建了修复回收错误的图库,在线搜索EcoGallery,您可以找到如何实现它。当您滚动图库时,它会显着提高图形性能。

答案 1 :(得分:3)

如果你没有让它正常工作,我曾经做过一个可能会有帮助的黑客。

doInBackground()结束时,就在您返回之前,请执行:

int viewsOnScreen = 3;
while(viewsOnScreen >= 1){ //adapt the numbers so that they work with your gallery, this is for a gallery with one visible child.
    viewsOnScreen = getLastVisiblePosition() - getFirstVisiblePosition();
    SystemClock.sleep(100);
}

这将等待更新您的图片,直到您只显示一个视图(或您指定的任何数字,关键是您没有在屏幕上有任何部分视图),导致& #39;跳&#39;没有注意到。如果您的问题还涉及跳转到图库中完全不同的位置,我建议您在加载之前检查您选择了哪个对象,并在加载后找到该对象所处的位置,并将setSelection()调用到该位置。

但首先尝试所有其他解决方案 ...

答案 2 :(得分:2)

如果你还没有找到解决方案,那么就是我的。

您需要CustomGallery,它几乎是1:1的默认Android图库。但是你不能扩展Gallery,你必须将整个源代码复制到你的班级。您需要对CustomAbsSpinner和CustomAdapterView类执行相同的操作。所有这些只改变一行代码...... 在CustomGallery类中,将onLayout()方法更改为:

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);

    /*
     * Remember that we are in layout to prevent more layout request from
     * being generated.
     */

    mInLayout = true;

    /*
     * Add if condition to avoid calling layout()  unnecessarily:
     * -when children calls onLayout after loading imageview
     */
    if(changed || mDataChanged)
        layout(0, false);
    mInLayout = false;
}

这将导致layout()仅在实际需要时被调用。

图库行为中还有另一个已知错误,导致notifyDataSetChanged()上的图库跳转。如果您遇到此错误,只需在CustomAdapterView类中注释掉一行:

    @Override
    public void onChanged() {
        mDataChanged = true;
        mOldItemCount = mItemCount;
        mItemCount = getAdapter().getCount();

        // Detect the case where a cursor that was previously invalidated has
        // been repopulated with new data.
        if (CustomAdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
                && mOldItemCount == 0 && mItemCount > 0) {
            CustomAdapterView.this.onRestoreInstanceState(mInstanceState);
            mInstanceState = null;
        } else {
            rememberSyncState();
        }
        checkFocus();
        //comment this line to avoid gallery snap on notyfiDataSetChanged 
        //requestLayout();
    }

无论如何,好主题马科斯!谢谢带领我找到解决方案。 如果您需要自定义类的来源,请告诉我。

编辑(由Marcos Vasconcelos撰写):

为了获得这些类的R修复,需要复制一些样式的东西。

对于那些正在搜索Android 2.2源代码的人(没有res文件夹,如果有人发现它请通知我们),可以在这里找到: http://en.newinstance.it/2010/12/01/android-sdk-2-2_r2-sources/

对于更新版本的API,这可以通过SDK Manager完成,并将位于/ sources / android -

答案 3 :(得分:1)

如果你(a)滚动得非常慢,或者(b)不回收convertView,那么它是否有用?

我会走出困境并猜测它确实......

原因是当您从之前的getItem()调用中回收ImageView时,您没有取消关联的AsyncTask。您将有多个任务更新相同的ImageView,这可能是您描述的行为。

答案 4 :(得分:1)

你可以使用LazyList的概念,它从互联网上获取图像并暂时放入本地缓存中,间接导致Gallery中的图像保存为本地保存的图像

这是链接https://github.com/thest1/LazyListhttp://androidsnips.blogspot.com/2010/08/lazy-loading-of-images-in-list-view-in.html

答案 5 :(得分:0)

您可以在开始下载实际图像之前设置默认位图。这将确保空视图不会被错误的位图设置。

// load defaultBmp in constructor.

image.setBackgroundColor(Color.WHITE);

image.setLayoutParams(new Gallery.LayoutParams(96, 170));

image.setImageBitmap(defaultBmp); // set the default bitmap (could be white). 
// execute AsyncTask here.