使用AsyncTask的结果在其onPostExecute内部运行for循环(再次Async)。

问题描述 投票:0回答:1

我有下面的代码,用来从数据库中检索PhoneNumber数据。在呈现给用户之前,我想将每个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;
}
java android android-asynctask
1个回答
2
投票

为什么要使用AsyncTask?它的使用已经被废弃了,通常,现在没有人使用它。没有理由在你的widgets所在的activityfragment中执行这样的代码。我建议一开始使用MV*模式之一。最好的是MVP模式。你可以用这样的接口创建一个类Presenter。

public class Presenter {

  private Activity activity;

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

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

  void onPhoneNumberClick(String phoneNumber) {

  }
}

你应该在onStart()回调中把你的活动(fragment)附加到它的presenter上,并在onStop()中脱离。当你的点击监听器发生事件时,你应该在onPhoneNumberClick方法中要求presenter工作,然后你应该实现这个逻辑。你需要一些异步的工作。 它可以通过运行新的线程来实现,但是你必须将你的线程切换到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);
          }
        });
  }

所以在这里你可以看到新的实体交互器 它运行并完成所有的计算人员 "通过一个电话号码得到一个SuggestedContactItem的列表"。但上面的代码只是展示了在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;
  }
}

所以在这里你可以独立测试所有的行为。如果你同时需要一个电话号码和SuggestedContactItems的列表,那么你可以在Interactor中返回Pair。这是更SOLID的代码和更好的方法。如果你有任何问题,请,DM我。


0
投票

我不认为AsyncTask是一个很好的工具,而且它已经被废弃了,可以尝试使用RxJava,如果你不想使用外部库,那么使用java.util.concurrentcoroutines。

© www.soinside.com 2019 - 2024. All rights reserved.