简体   繁体   English

从Parse下载图像和文本并添加到ArrayList会产生意想不到的结果吗?

[英]Downloading images and text from Parse and adding to ArrayList provides unexpected result?

I've been working on an app that downloads thumbnails and text from Parse and adds it to ArrayLists which are then displayed through a custom adapter for a ListView. 我一直在研究从Parse下载缩略图和文本的应用程序,并将其添加到ArrayLists,然后通过ListView的自定义适配器显示。 The issue here is, the thumbnails for the required content is sometimes misplaced. 这里的问题是,所需内容的缩略图有时会放错位置。 For example: In my profile, instead of my pic another pic downloaded from parse would be placed. 例如:在我的个人资料中,而不是我的图片将放置从解析下载的另一张图片。 How to fix it ? 怎么解决?

MainActivity.java ( Downloads the content ) 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 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;

    }

  }

You're adding each image to a list once it is downloaded. 下载后,您将每个图像添加到列表中。 Later, you're iterating over the images in order. 之后,您将按顺序迭代图像。 However, the order that they appear in the list won't necessarily be the same as the order you requested them. 但是,它们在列表中出现的顺序不一定与您请求它们的顺序相同。 They're being loaded asynchronously, meaning that the code doesn't wait for the image to finish loading before moving on to the next one. 它们是异步加载的,这意味着代码不会等待图像完成加载,然后再转到下一个。 If you start loading a large image and then start loading a small image immediately afterwards, the small one might finish downloading first. 如果您开始加载大图像,然后立即开始加载小图像,小图像可能会先完成下载。 In the resulting list, the small image would appear before the larger one, even though it was requested second. 在结果列表中,小图像将出现在较大的图像之前,即使它是第二个请求的。

To fix the order of the list of images, you could use Futures . 要修复图像列表的顺序,可以使用Futures Instead of declaring thumbnails as a List<Bitmap> , make it a List<Future<Bitmap>> . 不是将thumbnails声明为List<Bitmap> ,而是将其设为List<Future<Bitmap>> Then, add all three items to the list at the same time. 然后,同时将所有三个项目添加到列表中。

    titles.add(object.getString("Title"));
    channel.add(object.getString("Channel"));
    CompletableFuture<Bitmap> futureThumbnail = new CompletableFuture<>();
    thumbnails.add(futureThumbnail);

That guarantees all three lists will be in the same order, regardless of how long the images take to download. 无论图像下载多长时间,都可以保证所有三个列表的顺序相同。

The next step is to fill in each future with the corresponding image. 下一步是用相应的图像填写每个未来。

    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);
                ...

This method has the added benefit that you can wait for the images to finish downloading. 此方法具有额外的好处,您可以等待图像完成下载。 To wait for all the images to download and put them in a list in the right order: 要等待所有图像下载并按正确顺序将它们放入列表中:

List<Bitmap> thumbnails = new ArrayList<>();
for (Future<Bitmap> future : futureThumbnails) {
    thumbnails.add(future.get());
}

Or, if you prefer not to wait: 或者,如果您不想等待:

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); 
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM