我一直致力于从Parse下载缩略图和文本的应用程序,并将其添加到ArrayLists,然后通过ListView的自定义适配器显示。这里的问题是,所需内容的缩略图有时会放错位置。例如:在我的个人资料中,而不是我的图片将放置从解析下载的另一张图片。如何解决?
MainActivity.java(下载内容)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (isParseInitialized == false) {
Parse.initialize(new Parse.Configuration.Builder(this)
.applicationId("AppId")
.clientKey("ClientKey")
.server("https://parseapi.back4app.com")
.build()
);
isParseInitialized = true;
}
catchVideos();
progressBar = (ProgressBar) findViewById(R.id.progressBar);
context = this;
listView = (ListView) findViewById(R.id.listView);
customAdapter = new CustomAdapter(MainActivity.this, titles, thumbnails, channel);
//progressBar.setVisibility(View.INVISIBLE);
final Handler handler = new Handler();
Runnable run = new Runnable() {
@Override
public void run() {
handler.postDelayed(this, 1000);
if (tapped == true) {
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>("Content");
query.whereEqualTo("Title", title);
query.findInBackground(new FindCallback<ParseObject>() {
@Override
public void done(List<ParseObject> objects, ParseException e) {
if(e == null) {
for (ParseObject object : objects) {
Log.i("Info", object.getString("url"));
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(object.getString("url")));
startActivity(intent);
}
}
}
});
tapped = false;
}
}
};
handler.post(run);
}
public void catchVideos(){
ParseQuery<ParseObject> query = new ParseQuery<ParseObject>("Content");
query.whereNotEqualTo("Status", null);
query.orderByDescending("createdAt");
query.findInBackground(new FindCallback<ParseObject>() {
@Override
public void done(List<ParseObject> objects, ParseException e) {
if(e == null) {
if (!titles.isEmpty()) {
titles.clear();
}
if (!channel.isEmpty()) {
channel.clear();
}
if (!thumbnails.isEmpty()) {
thumbnails.clear();
}
for (ParseObject object : objects) {
titles.add(object.getString("Title"));
channel.add(object.getString("Channel"));
ParseFile file = (ParseFile) object.get("Thumbnail");
file.getDataInBackground(new GetDataCallback() {
@Override
public void done(byte[] data, ParseException e) {
if (e == null) {
Bitmap thumbnail = BitmapFactory.decodeByteArray(data, 0, data.length);
thumbnails.add(thumbnail);
listView.setAdapter(customAdapter);
progressBar.setVisibility(View.INVISIBLE);
}
}
});
customAdapter.notifyDataSetChanged();
Log.i("Info", object.getString("Title"));
Log.i("Info", object.getString("url"));
}
}
}
});
}
CustomAdapter.java
public class CustomAdapter extends BaseAdapter{
ArrayList<String> result;
ArrayList<String> channelName;
Context context;
ArrayList<Bitmap> imageId;
private static LayoutInflater inflater=null;
public CustomAdapter(MainActivity mainActivity, ArrayList<String> titles, ArrayList<Bitmap> thumbnails, ArrayList<String> channel) {
// TODO Auto-generated constructor stub
result=titles;
channelName=channel;
context=mainActivity;
imageId=thumbnails;
inflater = ( LayoutInflater )context.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return result.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
public class Holder
{
TextView tv;
TextView channelText;
ImageView img;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
Holder holder=new Holder();
View rowView;
rowView = inflater.inflate(R.layout.custom_row, null);
holder.tv=(TextView) rowView.findViewById(R.id.textView1);
holder.channelText = (TextView) rowView.findViewById(R.id.channel);
holder.img=(ImageView) rowView.findViewById(R.id.imageView1);
try {
holder.img.setImageBitmap(imageId.get(position));
} catch (Exception e) {
e.printStackTrace();
}
holder.tv.setText(result.get(position));
holder.channelText.setText(channelName.get(position));
rowView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
//Toast.makeText(context, "You Clicked "+ result.get(position), Toast.LENGTH_LONG).show();
//Launch URL
MainActivity.tapped = true;
MainActivity.title = result.get(position);
}
});
return rowView;
}
}
答案 0 :(得分:0)
下载后,您将每个图像添加到列表中。之后,您将按顺序迭代图像。但是,它们在列表中出现的顺序不一定与您请求它们的顺序相同。它们是异步加载的,这意味着代码不会等待图像完成加载,然后再转到下一个。如果您开始加载大图像,然后立即开始加载小图像,小图像可能会先完成下载。在结果列表中,小图像将出现在较大的图像之前,即使它是第二次请求。
要修复图片列表的顺序,您可以使用Futures
。不要将thumbnails
声明为List<Bitmap>
,而是将其设为List<Future<Bitmap>>
。然后,同时将所有三个项目添加到列表中。
titles.add(object.getString("Title"));
channel.add(object.getString("Channel"));
CompletableFuture<Bitmap> futureThumbnail = new CompletableFuture<>();
thumbnails.add(futureThumbnail);
无论图像下载多长时间,都可以保证所有三个列表的顺序相同。
下一步是用相应的图像填写每个未来。
ParseFile file = (ParseFile) object.get("Thumbnail");
file.getDataInBackground(new GetDataCallback() {
@Override
public void done(byte[] data, ParseException e) {
if (e == null) {
Bitmap thumbnail = BitmapFactory.decodeByteArray(data, 0, data.length);
future.complete(thumbnail);
...
此方法的另一个好处是您可以等待图像完成下载。等待所有图像下载并按正确顺序将它们放入列表中:
List<Bitmap> thumbnails = new ArrayList<>();
for (Future<Bitmap> future : futureThumbnails) {
thumbnails.add(future.get());
}
或者,如果您不想等待:
List<Bitmap> thumbnails = new ArrayList<>();
Bitmap defaultValue = null; // or preferably some other default value
for (Future<Bitmap> future : futureThumbnails) {
thumbnails.add(future.isDone() ? future.get() : defaultValue);
}