只有当 ArrayList 到达它的最后一个元素时,如何执行代码?

Posted

技术标签:

【中文标题】只有当 ArrayList 到达它的最后一个元素时,如何执行代码?【英文标题】:How to execute code only when the ArrayList has reached it's last element? 【发布时间】:2018-03-13 14:49:47 【问题描述】:

我正在运行一个 for 循环并将数据保存在其中的 firebase 上。

这是我的代码:

private int counter = 1;

pProgress.setMessage("Posting...");
pProgress.show();
pProgress.setCancelable(false);

for (int i=0; i<imageArray.size(); i++) 

    Uri file = Uri.fromFile(new File(imageArray.get(i).toString()));

    String key = database.getReference().push().getKey();

    UploadTask uploadTask = storage.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(key).child("product_image").putFile(file);
    uploadTask.addOnFailureListener(new OnFailureListener() 
        @Override
        public void onFailure(@NonNull Exception exception) 
            // Handle unsuccessful uploads
        
    ).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() 
        @Override
        public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) 

            counter++;
            if (counter == imageArray.size()) 
                  Toast.makeText(getBaseContext(), "successfully posted!", Toast.LENGTH_SHORT).show();
                  imageView.setImageResource(0);
                  pDescription.setText("");
                  pDuration.setText("");
                  pPrice.setText("");
                  label.setText("Label");
                  if (pProgress.isShowing()) 
                      pProgress.dismiss();
                  
            

            // taskSnapshot.getMetadata() contains file metadata such as size, content-type, and download URL.
            @SuppressWarnings("VisibleForTests")
            Uri downloadUrl = taskSnapshot.getDownloadUrl();
            imageUrls.add(downloadUrl.toString());
            database.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(id).child("pDescription").setValue(pDescription.getText().toString());
            database.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(id).child("pDuration").setValue(pDuration.getText().toString());
            database.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(id).child("pPrice").setValue(pPrice.getText().toString());
            if (imageUrls != null) 
                for (int i=0; i<imageUrls.size(); i++) 
                    Log.d("imageUrlsSize", String.valueOf(imageUrls.size()));
                    String idtwo = database.getReference().push().getKey();
                    database.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(id).child(idtwo).child("imageUrl").setValue(downloadUrl.toString());
                    if (imageUrls.size() > 0) 
                        imageUrls.clear();
                    
                
            
        
    );

我想显示ProgressDialog 并在数据成功上传后将其关闭。同样,我也想清除EditText 字段和ImageView

我怎样才能知道imageArray 已经结束,以便我可以关闭 ProgressDialog 并清除 edittext 以及 imageview?

请告诉我。

【问题讨论】:

【参考方案1】:

一种方法是检查回调中的计数。您可以在onFailureonSuccess 中检查它。像这样的

for (int i = 0; i < imageArray.size(); i++) 
    final int currentCount = i + 1;
    /** code **/
    onSuccess() 
        if (currentCount == imageArray.size()) // do something
    

您可能还需要将imageArray 声明为final。这样做的缺点是您将知道最后一个元素已被处理,但您将不知道是否还有其他请求仍在等待处理。更好的方法是在您的类中使用成员字段,例如

class YourClass private int currentCount = 0; 

你会在你的回调中再次计算这个,例如

for (int i = 0; i < imageArray.size(); i++) 
        onSuccess() 
            currentCount++;
            if (currentCount == imageArray.size()) // do something
        
    

【讨论】:

这两种方法都不起作用。当我将代码放入其中时,它会清空编辑文本,并且空字符串会保存在 firebase 上。 @HammadNasir 你做了什么?你能用新代码编辑你的帖子吗? @HammadNasir 将计数器更改为 0 并在 onFailure 回调中增加它。【参考方案2】:

作为一个实时数据库,没有任何时候我们可以说我们已经从数据库中加载了所有的 reconar,或者 ArrayList 已经到达了它的最后一个元素。发生这种情况是因为每时每刻都有可能发生变化,即可以添加或删除一个/多个项目。这就是 Firebase 的构建方式。

但是对您的问题的简短回答,首先将 imageUrls ArrayList 的声明移到 onSuccess() 方法中,否则由于此方法的异步行为,它将为空。其次,在您的类中定义一个名为 count 的变量,并在每次调用 onSuccess() 方法时增加它的值,并将其与列表中的 size 进行比较,如下所示:

int count = 0;
onSuccess() 
    count++;
    if(count == imageArray.size() : do somethig ? do something else)

【讨论】:

【参考方案3】:

您正在处理异步任务,因此您需要封装您的工作并使用队列和回调。试试这样的:

class Job
    private Runnable completeCallback;
    private String key;
    private Uri file;

    public Job(String key, Uri file) 
        this.key = key;
        this.file = file;
    

    public void setCompleteCallback(Runnable completeCallback) 
        this.completeCallback = completeCallback;
    

    void doWork()
        UploadTask uploadTask = storage.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(key).child("product_image").putFile(file);
        uploadTask.addOnFailureListener(new OnFailureListener() 
            @Override
            public void onFailure(@NonNull Exception exception) 
                // Handle unsuccessful uploads
                completeCallback.run();
            
        ).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() 
            @Override
            public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) 
                // taskSnapshot.getMetadata() contains file metadata such as size, content-type, and download URL.
                @SuppressWarnings("VisibleForTests")
                Uri downloadUrl = taskSnapshot.getDownloadUrl();
                imageUrls.add(downloadUrl.toString());
                database.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(id).child("pDescription").setValue(pDescription.getText().toString());
                database.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(id).child("pDuration").setValue(pDuration.getText().toString());
                database.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(id).child("pPrice").setValue(pPrice.getText().toString());
                if (imageUrls != null) 
                    for (int i=0; i<imageUrls.size(); i++) 
                        Log.d("imageUrlsSize", String.valueOf(imageUrls.size()));
                        String idtwo = database.getReference().push().getKey();
                        database.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(id).child(idtwo).child("imageUrl").setValue(downloadUrl.toString());
                        if (imageUrls.size() > 0) 
                            imageUrls.clear();
                        
                    
                
                completeCallback.run();
            
        );
    


class Queue 
    ArrayList<Job> jobs = new ArrayList<>();
    private int total;

    public void execute()
        total = imageArray.size();
        for (int i=0; i<imageArray.size(); i++) 

            Uri file = Uri.fromFile(new File(imageArray.get(i).toString()));
            String key = database.getReference().push().getKey();

            Job job = new Job(key, file);
            job.setCompleteCallback(new Runnable() 
                @Override
                public void run() 
                    jobs.remove(job);
                    updateUi();
                
            );
            jobs.add(job);
        
        for (int i = jobs.size() - 1; i >= 0; i--) 
            Job job = jobs.get(i);
            job.doWork();
        
    

    private void updateUi() 
        Log.d("UI", "Completed " + jobs.size() + "/" + total);    
    

【讨论】:

【参考方案4】:

我在Murat K的回答的帮助下想通了。

我只是转移了这段代码

database.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(id).child("pDescription").setValue(pDescription.getText().toString());
database.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(id).child("pDuration").setValue(pDuration.getText().toString());
database.getReference().child(AccessToken.getCurrentAccessToken().getUserId()).child(id).child("pPrice").setValue(pPrice.getText().toString());

退出for 循环,现在一切正常。

【讨论】:

以上是关于只有当 ArrayList 到达它的最后一个元素时,如何执行代码?的主要内容,如果未能解决你的问题,请参考以下文章

ArrayList精讲(源码分析)---Java集合

ArrayList精讲(源码分析)---Java集合

当堆栈仍然有元素时,为啥会跳过“如果堆栈不为空”条件?

只有最后一个元素被添加到数组中?

ArrayList和Vector的区别?

arrayList和vector的区别