Android gridview 滚动加载图像错误
Android gridview scrolling bad loading image
我正在使用 Picasso 将我的所有图像加载到 Gridview 和 DBFlow 中以保存在本地数据库中。但是当我第一次下载图像并且在 gridview 中滚动时,我遇到了问题。下一张图片有之前的图片,1 秒后加载好图片。我必须滚动 5 次或更多次,当所有图像都加载后,我没有遇到这个问题,但这是第一次。
你有优化我的代码的想法吗?
网格视图
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="130dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"
android:background="@color/colorAppBackground"/>
项目网格
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="130dp">
<ImageView
android:id="@+id/iv_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop"/>
<TextView
android:id="@+id/text_thumb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:textColor="@android:color/white"
android:background="#99000000"/>
</RelativeLayout>
Activity
public class GalleryActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
Bundle bundle = getIntent().getExtras();
int idAccount = bundle.getInt("idAccount");
callAdminPictures(idAccount);
}
public void callAdminPictures(final int idAccount){
// Build REST Adapter
Retrofit restAdapter = new Retrofit.Builder()
.baseUrl(Globals.SERVER_NAME)
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
// Create the App Service
ApplicationService appService = restAdapter.create(ApplicationService.class);
// Call Get admin pictures WS
Call<AdminPictures> getAdminPicturesWS = appService.getAdminPictures(idAccount);
getAdminPicturesWS.enqueue(new Callback<AdminPictures>() {
@Override
public void onResponse(Call<AdminPictures> call, Response<AdminPictures> response) {
AdminPictures apResponse = response.body();
List<PictureInfos> pictureInfos = apResponse.getPicturesList();
for (PictureInfos infos : pictureInfos) {
if (infos.exists()) {
infos.update();
} else {
infos.save();
}
}
List<PictureInfos> tablePictureInfos = new Select()
.from(PictureInfos.class)
.where(PictureInfos_Table.idAccount.is("" + idAccount))
.orderBy(PictureInfos_Table.idPicture, false)
.queryList();
GridView gridView = (GridView) findViewById(R.id.gridview);
gridView.setAdapter(new ImageAdapter(GalleryActivity.this, tablePictureInfos));
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(GalleryActivity.this, "" + position, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onFailure(Call<AdminPictures> call, Throwable t) {
if (t.getMessage() != null) {
Log.e("AdminPictures WS Fail", t.getMessage());
}
}
});
}
适配器
public class ImageAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mLayoutInflater;
private List<PictureInfos> mPInfoList;
private boolean mToSave;
public ImageAdapter(Context context, List<PictureInfos> pInfoList) {
mContext = context;
mPInfoList = pInfoList;
mLayoutInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return mPInfoList.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view;
final ImageView imageView;
final TextView legend;
if(convertView == null){
view = mLayoutInflater.inflate(R.layout.thumbnail_gallery, parent, false);
}else{
view = convertView;
}
imageView = (ImageView) view.findViewById(R.id.iv_thumbnail);
legend = (TextView) view.findViewById(R.id.text_thumb);
final File file = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES), mPInfoList.get(position).getFilename());
mToSave = !file.exists();
Target target = new Target() {
@Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
if(mToSave) {
new Thread(new Runnable() {
@Override
public void run() {
try {
FileOutputStream fileOutput = new FileOutputStream(file);
Log.i("catch", mPInfoList.get(position).getFilename());
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutput);
fileOutput.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
imageView.setImageBitmap(bitmap);
if (mPInfoList.get(position).getFilename() != null) {
legend.setText(mPInfoList.get(position).getLegend());
}
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
String pic = Globals.SERVER_NAME+Globals
.ACCOUNT_SERVER_PATH+mPInfoList
.get(position).getFolderPath()+"/"+
VgzTools.addSuffix(mPInfoList.get(position).getFilename(), "-thumb");
imageView.setTag(target);
if(!file.exists()){
Picasso.with(mContext)
.load(pic)
.into(target);
mToSave = true;
}else{
Picasso.with(mContext)
.load(file)
.into(target);
mToSave = false;
}
return view;
}
我的猜测是,因为您没有明确清除 getView()
中的 imageView,它会在回收时保留当前图像(IE - 当它作为 convertView
传入时)。 Picasso 最终会调用 onBitmapLoaded()
,但在那之前,您只剩下 'old' 图像。
尝试明确清除图像。
在 getView() 里面放这行
imageView.setImageDrawable(null);
由于视图回收,上一张图片即将到来。对于每个项目,您并不总是获得新视图,而是回收视图以节省内存。因此,一旦您滚动了最初可见的项目,您将获得上一个项目的视图,其中已经设置了图像。所以你必须明确地删除它。
我正在使用 Picasso 将我的所有图像加载到 Gridview 和 DBFlow 中以保存在本地数据库中。但是当我第一次下载图像并且在 gridview 中滚动时,我遇到了问题。下一张图片有之前的图片,1 秒后加载好图片。我必须滚动 5 次或更多次,当所有图像都加载后,我没有遇到这个问题,但这是第一次。
你有优化我的代码的想法吗?
网格视图
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gridview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="130dp"
android:numColumns="auto_fit"
android:verticalSpacing="10dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:gravity="center"
android:background="@color/colorAppBackground"/>
项目网格
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="130dp">
<ImageView
android:id="@+id/iv_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="centerCrop"/>
<TextView
android:id="@+id/text_thumb"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:textColor="@android:color/white"
android:background="#99000000"/>
</RelativeLayout>
Activity
public class GalleryActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
Bundle bundle = getIntent().getExtras();
int idAccount = bundle.getInt("idAccount");
callAdminPictures(idAccount);
}
public void callAdminPictures(final int idAccount){
// Build REST Adapter
Retrofit restAdapter = new Retrofit.Builder()
.baseUrl(Globals.SERVER_NAME)
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
// Create the App Service
ApplicationService appService = restAdapter.create(ApplicationService.class);
// Call Get admin pictures WS
Call<AdminPictures> getAdminPicturesWS = appService.getAdminPictures(idAccount);
getAdminPicturesWS.enqueue(new Callback<AdminPictures>() {
@Override
public void onResponse(Call<AdminPictures> call, Response<AdminPictures> response) {
AdminPictures apResponse = response.body();
List<PictureInfos> pictureInfos = apResponse.getPicturesList();
for (PictureInfos infos : pictureInfos) {
if (infos.exists()) {
infos.update();
} else {
infos.save();
}
}
List<PictureInfos> tablePictureInfos = new Select()
.from(PictureInfos.class)
.where(PictureInfos_Table.idAccount.is("" + idAccount))
.orderBy(PictureInfos_Table.idPicture, false)
.queryList();
GridView gridView = (GridView) findViewById(R.id.gridview);
gridView.setAdapter(new ImageAdapter(GalleryActivity.this, tablePictureInfos));
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(GalleryActivity.this, "" + position, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onFailure(Call<AdminPictures> call, Throwable t) {
if (t.getMessage() != null) {
Log.e("AdminPictures WS Fail", t.getMessage());
}
}
});
}
适配器
public class ImageAdapter extends BaseAdapter {
private Context mContext;
private LayoutInflater mLayoutInflater;
private List<PictureInfos> mPInfoList;
private boolean mToSave;
public ImageAdapter(Context context, List<PictureInfos> pInfoList) {
mContext = context;
mPInfoList = pInfoList;
mLayoutInflater = LayoutInflater.from(context);
}
@Override
public int getCount() {
return mPInfoList.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view;
final ImageView imageView;
final TextView legend;
if(convertView == null){
view = mLayoutInflater.inflate(R.layout.thumbnail_gallery, parent, false);
}else{
view = convertView;
}
imageView = (ImageView) view.findViewById(R.id.iv_thumbnail);
legend = (TextView) view.findViewById(R.id.text_thumb);
final File file = new File(mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES), mPInfoList.get(position).getFilename());
mToSave = !file.exists();
Target target = new Target() {
@Override
public void onBitmapLoaded(final Bitmap bitmap, Picasso.LoadedFrom from) {
if(mToSave) {
new Thread(new Runnable() {
@Override
public void run() {
try {
FileOutputStream fileOutput = new FileOutputStream(file);
Log.i("catch", mPInfoList.get(position).getFilename());
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutput);
fileOutput.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
imageView.setImageBitmap(bitmap);
if (mPInfoList.get(position).getFilename() != null) {
legend.setText(mPInfoList.get(position).getLegend());
}
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
};
String pic = Globals.SERVER_NAME+Globals
.ACCOUNT_SERVER_PATH+mPInfoList
.get(position).getFolderPath()+"/"+
VgzTools.addSuffix(mPInfoList.get(position).getFilename(), "-thumb");
imageView.setTag(target);
if(!file.exists()){
Picasso.with(mContext)
.load(pic)
.into(target);
mToSave = true;
}else{
Picasso.with(mContext)
.load(file)
.into(target);
mToSave = false;
}
return view;
}
我的猜测是,因为您没有明确清除 getView()
中的 imageView,它会在回收时保留当前图像(IE - 当它作为 convertView
传入时)。 Picasso 最终会调用 onBitmapLoaded()
,但在那之前,您只剩下 'old' 图像。
尝试明确清除图像。
在 getView() 里面放这行
imageView.setImageDrawable(null);
由于视图回收,上一张图片即将到来。对于每个项目,您并不总是获得新视图,而是回收视图以节省内存。因此,一旦您滚动了最初可见的项目,您将获得上一个项目的视图,其中已经设置了图像。所以你必须明确地删除它。