我的应用程序依赖于从网络下载数据。数据下载并存储在Room中,但它可以随时更改,因此必须在每次启动应用程序时下载数据(如果互联网连接可用)。此外,数据在适配器中呈现,因此与下载不同(MainActivity)。问题是应用程序会冻结下载、存储和阅读过程,即使数据没有更改。
我创建了以下类:
道:
@Dao
public interface AppDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertHolidayDay(HolidayDay day);
@Query("DELETE FROM holiday_day")
void deleteAllHolidayDays();
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertHoliday(Holiday holiday);
@Query("DELETE FROM holiday")
void deleteAllHolidays();
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertFloatingHoliday(FloatingHoliday floatingHoliday);
@Query("DELETE FROM floating_holiday")
void deleteAllFloatingHolidays();
}
字符串
数据库名称:
@Database(entities = {Holiday.class, FloatingHoliday.class, HolidayDay.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract AppDao appDao();
}
型
存储库:
public class AppRepository {
private final AppDao holidayDao;
private final MediatorLiveData<List<HolidayDay>> mergedHolidays = new MediatorLiveData<>();
private List<HolidayDay> fixedHolidaysCache;
private List<FloatingHoliday> floatingHolidaysCache;
public AppRepository(final Application application) {
final AppDatabase database = Room.databaseBuilder(application, AppDatabase.class, "uhc")
.enableMultiInstanceInvalidation()
.allowMainThreadQueries()
.build();
holidayDao = database.appDao();
loadHolidays();
}
@Transaction
public void updateCalendarData(@NonNull final UnusualCalendar calendar) {
holidayDao.deleteAllHolidays();
holidayDao.deleteAllHolidayDays();
holidayDao.deleteAllFloatingHolidays();
calendar.getFixed()
.stream()
.map(HolidayDay::getHolidays)
.flatMap(Collection::stream)
.forEach(holidayDao::insertHoliday);
calendar.getFixed().forEach(holidayDao::insertHolidayDay);
calendar.getFloating().forEach(holidayDao::insertFloatingHoliday);
}
private void loadHolidays() {
final LiveData<List<HolidayDay>> fixedHolidays = holidayDao.getAllHolidayDays();
final LiveData<List<FloatingHoliday>> floatingHolidays = holidayDao.getAllFloatingHolidays();
mergedHolidays.addSource(fixedHolidays, fixed -> {
fixedHolidaysCache = fixed;
mergeHolidays();
});
mergedHolidays.addSource(floatingHolidays, floating -> {
floatingHolidaysCache = floating;
mergeHolidays();
});
}
private void mergeHolidays() {
// magic here
}
}
型
SharedViewModel:
public class SharedViewModel extends ViewModel {
public static final ViewModelInitializer<SharedViewModel> INITIALIZER = new ViewModelInitializer<>(SharedViewModel.class, creationExtras -> {
final UHCApplication uhcApplication = (UHCApplication) creationExtras.get(ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY);
assert uhcApplication != null;
return new SharedViewModel(uhcApplication.getAppRepository());
});
private final AppRepository repository;
public SharedViewModel(final AppRepository repository) {
this.repository = repository;
}
public void updateData(final UnusualCalendar calendar) {
CompletableFuture.runAsync(() -> repository.updateCalendarData(calendar));
}
}
型
下载MainActivity:
public class MainActivity extends AppCompatActivity {
private AlertDialog alertDialog;
private final List<HolidayDay> holidayDays = new ArrayList<>();
private MutableLiveData<Boolean> internet;
private volatile boolean downloading;
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
configureObservers();
if (Boolean.TRUE.equals(internet.getValue()) && !downloading) {
initiateDownload();
}
// Observe the holiday data
sharedViewModel.getAllHolidayDays().observe(this, days -> {
if (!days.isEmpty()) {
holidayDays.addAll(days);
} else if (Boolean.FALSE.equals(internet.getValue())) {
showNoInternetAlert();
}
});
}
private void initiateDownload() {
downloading = true;
CompletableFuture.supplyAsync(new Downloader()) // just a HttpsUrlConnection + gson
.thenAcceptAsync(data -> {
sharedViewModel.updateData(data);
downloading = false;
});
}
private void configureObservers() {
internet = new MutableLiveData<>(Util.isNetworkAvailable(this));
internet.observe(this, isConnected -> {
if (Boolean.TRUE.equals(isConnected) && alertDialog != null && alertDialog.isShowing() && !downloading) {
CompletableFuture.supplyAsync(new Downloader.UnusualCalendarDownloader())
.thenAccept(sharedViewModel::updateData);
alertDialog.dismiss();
}
});
final ConnectivityManager connectivityManager =
(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
Util.NETWORK_CAPABILITIES.stream()
.map(new NetworkRequest.Builder()::addTransportType)
.map(NetworkRequest.Builder::build)
.forEach(x -> connectivityManager.registerNetworkCallback(x, new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(@NonNull final Network network) {
super.onAvailable(network);
internet.postValue(true);
}
@Override
public void onLost(@NonNull final Network network) {
super.onLost(network);
internet.postValue(false);
}
}));
}
private void showNoInternetAlert() {
final AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle(R.string.no_internet_connection);
alert.setCancelable(false);
alert.setMessage(R.string.no_internet);
alertDialog = alert.show();
}
}
型CompletableFuture
是从java9.util.concurrent
导入的。我不能依赖OnConflictStrategy.REPLACE
,因为条目有时会消失,我也想从数据库中删除它们。
我更喜欢的解决方案是让应用程序一直响应,并允许数据在存储和读取时动态更新(用户可以看到它们更新)。
我想更新SharedViewModel中的列表,但它没有解决冻结问题。
1条答案
按热度按时间rsaldnfx1#
在我看来,有些东西只是简单地阻塞了主线程,最有可能的是,它是一个数据库操作。默认情况下,Android不会让你这样做,但如果你在一个单独的线程中发出请求,例如,但告诉主线程等待它完成,它可以阻塞主线程。我建议打开调试器,寻找程序在没有冻结的情况下工作的最后一个地方。
你的构造器看起来很奇怪。
字符串