我有下面的代码,用来从数据库中检索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;
}
为什么要使用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我。
我不认为AsyncTask是一个很好的工具,而且它已经被废弃了,可以尝试使用RxJava,如果你不想使用外部库,那么使用java.util.concurrentcoroutines。