Java 使用AsyncTask的结果在其onPostExecute内运行for循环(再次异步)

Java 使用AsyncTask的结果在其onPostExecute内运行for循环(再次异步),java,android,android-asynctask,Java,Android,Android Asynctask,我用下面的代码从数据库中检索电话号码数据。在将其呈现给用户之前,我希望将每个PhoneNumber对象与其各自的联系人(存储在另一个表中)进行匹配,以便也将检索到的电话号码的全名呈现给用户 当我需要第二次查询数据库时,问题就出现了,因为我必须异步进行查询(否则应用程序会崩溃)。我还需要在循环中为每个PhoneNumber对象执行此操作。我如何实现这一点 public List<PhoneNumber> fetchMatchingNumbers(final String phoneNu

我用下面的代码从数据库中检索电话号码数据。在将其呈现给用户之前,我希望将每个PhoneNumber对象与其各自的联系人(存储在另一个表中)进行匹配,以便也将检索到的电话号码的全名呈现给用户

当我需要第二次查询数据库时,问题就出现了,因为我必须异步进行查询(否则应用程序会崩溃)。我还需要在循环中为每个PhoneNumber对象执行此操作。我如何实现这一点

public List<PhoneNumber> fetchMatchingNumbers(final String phoneNumber) {
    new AsyncTask<Void, Void, List<PhoneNumber>>() {
        @Override
        protected List<PhoneNumber> doInBackground(Void... voids) {
            returnedNumbers = worksideDatabase.phoneNumberDao().getMatchingNumbers(phoneNumber);

            return null;
        }

        @Override
        protected void onPostExecute(List<PhoneNumber> phoneNumbers) {
            super.onPostExecute(phoneNumbers);

            // Clear the list each time the query is updated
            suggestedContactList.clear();

            for (PhoneNumber pn : returnedNumbers) {
                int id = pn.getContactId();
                String stringPN = pn.getPhoneNumber();

                // Change this to be a background thread!
                returnedFullName = worksideDatabase.contactDao().getFullNameByContactId(id);

                // TODO - match each PhoneNumber to its contact's name & surname
                SuggestedContactItem item =
                        new SuggestedContactItem(
                                returnedFullName, stringPN, pn.getPhoneNumberType());
                suggestedContactList.add(item);
            }
            adapter.notifyDataSetChanged();
        }
    }.execute();
    return returnedNumbers;
}
获取匹配号码的公共列表(最终字符串phoneNumber){
新建异步任务(){
@凌驾
受保护列表背景(无效…无效){
returnedNumbers=worksideDatabase.phoneNumberDao().getMatchingNumbers(phoneNumber);
返回null;
}
@凌驾
受保护的void onPostExecute(列出电话号码){
super.onPostExecute(电话号码);
//每次更新查询时清除列表
suggestedContactList.clear();
对于(电话号码pn:返回的号码){
int id=pn.getContactId();
字符串stringPN=pn.getPhoneNumber();
//将此更改为背景线程!
returnedFullName=worksideDatabase.contactDao().getFullNameByContactId(id);
//TODO-将每个电话号码与其联系人的姓名匹配
建议的联系人项目=
新建议的ContactItem(
returnedFullName、stringPN、pn.getPhoneNumberType());
建议联系人列表。添加(项目);
}
adapter.notifyDataSetChanged();
}
}.execute();
返回返回的数字;
}

我不认为AsyncTask是执行此任务的好工具,而且它已被弃用,请尝试使用RxJava,或者如果您不想使用外部库,请使用java.util.concurrent/coroutines

为什么要使用AsyncTask?它已经不推荐使用,而且通常现在没有人使用它。 没有理由在小部件所在的活动/片段中执行此类代码。我建议首先使用一种MV*模式。例如,最好的是MVP。您可以使用以下界面创建类演示者:

public class Presenter {

  private Activity activity;

  void attachActivity(Activity activity) {
    this.activity = activity;
  }

  void detachActivity() {
    this.activity = null;
  }

  void onPhoneNumberClick(String phoneNumber) {

  }
}
您应该在onStart()回调中将活动(片段)附加到其“presenter”,并在onStop()中分离。 当在您的“单击侦听器发生”事件中,您应该要求演示者在
onPhoneNumberClick方法。 然后你应该实现这个逻辑。您需要som异步作业。这可以通过运行新线程来实现,但是为了设置获取的数据,您必须将线程切换到main。现在,rxJava2是一种流行的机制,它可以让您在不启动线程的情况下实现异步工作。因此,使用rxJava2可以做到:

void onPhoneNumberClick(String phoneNumber) {
    Single.fromCallable(() -> interactor.getSuggestedContactItems(phoneNumber))
        .subscribeOn(Schedulers.io()) // thread from poll IO where invokation happens
        .observeOn(AndroidSchedulers.mainThread()) // thread where result observed
        .subscribe( contactItems -> {
          if (activity != null) {
            activity.setContactList(contactItems);
          }
        });
  }
在这里,您可以看到新的实体交互器。它运行并执行所有计算人员“通过一个电话号码获取建议联系人项目列表”的操作。但上面的代码只是展示了在rxJava2中切换线程进行计算和观察是多么容易

因此,最后是与您的目标互动:

class Interactor {
  private WorksideDatabase worksideDatabase;

  Interactor(WorksideDatabase worksideDatabase) {
    this.worksideDatabase = worksideDatabase;
  }

  List<SuggestedContactItem> getSuggestedContactItems(String phoneNumber) {
    List<PhoneNumber> returnedNumbers = worksideDatabase.phoneNumberDao().getMatchingNumbers(phoneNumber);
    List<SuggestedContactItem> suggestedContactItems = new ArrayList<>();
    for (PhoneNumber pn : returnedNumbers) {
      int id = pn.getContactId();
      String stringPN = pn.getPhoneNumber();

      // Change this to be a background thread!
      String returnedFullName = worksideDatabase.contactDao().getFullNameByContactId(id);

      // TODO - match each PhoneNumber to its contact's name & surname

      SuggestedContactItem item =
          new SuggestedContactItem(
              returnedFullName, stringPN, pn.getPhoneNumberType());
      suggestedContactItems.add(item);
    }
    return suggestedContactItems;
  }
}
类交互器{
私人工作空间数据库工作空间数据库;
交互器(WorksideDatabase WorksideDatabase){
this.worksideDatabase=worksideDatabase;
}
列出getSuggestedContactItems(字符串phoneNumber){
List returnedNumbers=worksideDatabase.phoneNumberDao().getMatchingNumbers(phoneNumber);
List suggestedContactItems=new ArrayList();
对于(电话号码pn:返回的号码){
int id=pn.getContactId();
字符串stringPN=pn.getPhoneNumber();
//将此更改为背景线程!
字符串returnedFullName=worksideDatabase.contactDao().getFullNameByContactId(id);
//TODO-将每个电话号码与其联系人的姓名匹配
建议的联系人项目=
新建议的ContactItem(
returnedFullName、stringPN、pn.getPhoneNumberType());
建议的联系人项目。添加(项目);
}
返回建议的联系人项目;
}
}
所以在这里你可以独立测试所有的行为。如果您同时需要电话号码和建议联系人项目的列表,则可以在Interactor中返回该对。它提供了更可靠的代码和更好的方法。
如果您有任何问题,请告诉我。

我可以在纯Java代码中同时使用RxJava和协同程序吗?我认为协同路由是Kotlin独占的?你是对的,协同路由只在Kotlin中使用,因为java使用java.util.concurrentHi Oleg中自己的并发机制。谢谢你详细的回答。事实上,我并没有使用或见过你们建议的任何方法(不是MVP,也不是rxJava2,也不是interactor)。此外,我还不知道AsyncTask在Android 11中已被弃用(尽管我认为这不是一个问题,因为他们无法完全删除它-这会破坏向后兼容性?)。我会仔细研究您提出的所有建议,然后回复您,询问您的问题,或者选择您的答案。同时,我可能会使用一个针对Java的协同程序框架,并暂时实现该功能。希望以后能用你的建议取代一切。