ray*_*ang 23 android android-gridview android-view
我有一个GridView显示一些图标.
在我从Android开发者网站上有效地阅读这个显示位图之前,我正在从getView()适配器直接解码本地路径中的位图,如下所示:
public View getView(int position, View convertView, ViewGroup parent) {
...
ImageView icon = ...... (from getTag() of convertView)
icon.setImageBitmap(BitmapUtil.decode(iconPath));
...
}
Run Code Online (Sandbox Code Playgroud)
这种方式无论如何工作正常,我称之为[直接模式],getView()方法的输出日志应该是:
getView(0) // measure kid's layout.
getView(0)
getView(1)
getView(2)
...
getView(n) // when scrolling gridview.
getView(n+1)
...
getView(n+3) // scrolling again.
getView(n+4)
...
Run Code Online (Sandbox Code Playgroud)
然后我试图将代码更改为有效显示位图的文章中提到的[Loader Mode] ,如下所示:
public View getView(int position, View convertView, ViewGroup parent) {
...
ImageView icon = ...... (from getTag() of convertView)
loadIcon(icon, iconPath);
...
}
Run Code Online (Sandbox Code Playgroud)
在loadIcon():
...
final CacheImageLoader loader = new CacheImageLoader(getActivity(), imageView, imageUrl, savePath);
final AsyncDrawable asyncDrawable = new AsyncDrawable(getResources(), placeHolderBitmap, loader);
imageView.setImageDrawable(asyncDrawable);
Run Code Online (Sandbox Code Playgroud)
在Loader的听众中:
@Override
public void onLoadComplete(Loader<Bitmap> arg0, Bitmap arg1) {
...
ImageView imageView = imageViewReference.get();
if (result != null && imageView != null) {
imageView.setImageBitmap(result);
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,它与训练代码相同,实际上,这种方式也可以正常工作.但是,我发现了一些不同的东西,在这种模式下getView(),适配器中的方法被调用了太多次,但是,这些重复调用此方法始终使用"position"参数== 0,这意味着etView(0, X, X)重复调用g .
getView(0) // measure kid's layout.
getView(0)
getView(1)
getView(2)
...
getView(0) // loader completed then imageView.setImageBitmap(result);
getView(0) // same as above
getView(0)
getView(0)
...
getView(n) // when scrolling gridview.
getView(n+1)
getView(n+2)
getView(0) // loader completed then imageView.setImageBitmap(result);
getView(0) // same as above
getView(0)
...
getView(n+3) // scrolling again.
getView(n+4)
getView(0) // loader completed then imageView.setImageBitmap(result);
getView(0) // same as above
getView(0)
Run Code Online (Sandbox Code Playgroud)
这不好,因为我正在使用装载机getView().我检查了源代码,发现它们最初是imageView.setImageBitmap(result)在loader的onLoadComplete方法中调用的 ,并在ImageView:
/**
* Sets a drawable as the content of this ImageView.
*
* @param drawable The drawable to set
*/
public void setImageDrawable(Drawable drawable) {
...
int oldWidth = mDrawableWidth;
int oldHeight = mDrawableHeight;
updateDrawable(drawable);
if (oldWidth != mDrawableWidth || oldHeight != mDrawableHeight) {
requestLayout();
}
invalidate();
}
}
Run Code Online (Sandbox Code Playgroud)
这里requestLayout()是View的方法,并始终在View.class中的[Direct Mode]或[Loader Mode]中执行:
public void requestLayout() {
mPrivateFlags |= FORCE_LAYOUT;
mPrivateFlags |= INVALIDATED;
if (mLayoutParams != null) {
mLayoutParams.onResolveLayoutDirection(getResolvedLayoutDirection());
}
if (mParent != null && !mParent.isLayoutRequested()) {
mParent.requestLayout();
}
}
Run Code Online (Sandbox Code Playgroud)
然而不同之处在于:在[直接模式]中, mParent.requestLayout()调用一次,但在[Loader模式]中,每次调用时imageView.setImageBitmap(result);, mParent.requestLayout()也会调用,这意味着mParent.isLayoutRequested()返回false,并通过调用mParent.requestLayout();将导致GridView测量其子项的布局obtainView()第一个孩子,然后导致getView(0, X, X):
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
...
mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
final int count = mItemCount;
if (count > 0) {
final View child = obtainView(0, mIsScrap);
...
Run Code Online (Sandbox Code Playgroud)
所以,我的问题是:如果我使用[加载器模式],为什么要mParent.isLayoutRequested()返回false?还是只是一个正常的情况?
isLayoutRequested是在那里告诉你一个布局是否已经等待这个View.也就是说,在requestLayout调用之后,isLayoutRequested将返回true直到下一个布局传递完成.这种检查的唯一原因requestLayout是为了避免反复呼叫requestLayout父母,无论如何要进行布局.isLayoutRequested这里是一只红鲱鱼:它不是onMeasure被反复召唤的原因.
根本问题是ImageView每当您更改其drawable时请求新布局.这有两个原因: -
adjustViewBounds已设置.这可能反过来影响其他视图的大小,具体取决于布局:ImageView本身没有足够的信息可以知道.ImageView.onMeasureImageView根据比例模式,负责计算必须调整大小以适应范围的多少.如果新的drawable与旧drawable的尺寸不同,则ImageView 必须再次测量以重新计算所需的比例.你只能通过保存加载器Bitmap返回的s 的本地缓存来解决拥有太多加载器的问题.缓存可能拥有所有的Bitmap,如果你知道有没有那么多,或者只是在S ñ最近使用的.在您的getView首先检查Bitmap缓存中是否存在该项目,如果存在,则返回ImageView已设置为该项目Bitmap.只有当它不在缓存中时才需要使用加载器.
小心:如果对基础数据的改变,你现在需要确保在同一时间调用缓存中无效invalidate的GridView或通知通过ContentResolver.我已经在我的应用程序中使用了一些自制代码来实现这一点,它对我来说很有效,但Square的优秀人员有一个名为Picasso的开源库,如果您愿意,可以为您完成所有艰苦的工作.
| 归档时间: |
|
| 查看次数: |
10201 次 |
| 最近记录: |