我有下面的代码,用于从数据库中检索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?它已被弃用,通常现在没有人使用它。没有理由在小部件所在的活动/片段中执行这样的代码。我建议先使用其中一种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((回调中将活动(片段(附加到其"present",并在onStop((中分离。当在您的点击监听器中发生事件时,您应该要求演示者在
onPhoneNumberClick方法中进行工作。然后你应该实现这个逻辑。你需要一个异步作业。它可以通过运行新的线程来实现,但随后必须将线程切换到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,则可以在交互程序中返回Pair。它有更多的SOLID代码和更好的方法。如果你有任何问题,请DM我。
我不认为AsyncTask是完成这项任务的好工具,而且它不推荐使用,请尝试使用RxJava,或者如果您不想使用外部库,则使用java.util.concurrent/coroutines