Android -在后台下载和存储数据

eivgtgni  于 2024-01-04  发布在  Android
关注(0)|答案(1)|浏览(194)

我的应用程序依赖于从网络下载数据。数据下载并存储在Room中,但它可以随时更改,因此必须在每次启动应用程序时下载数据(如果互联网连接可用)。此外,数据在适配器中呈现,因此与下载不同(MainActivity)。问题是应用程序会冻结下载、存储和阅读过程,即使数据没有更改。
我创建了以下类:
道:

  1. @Dao
  2. public interface AppDao {
  3. @Insert(onConflict = OnConflictStrategy.REPLACE)
  4. void insertHolidayDay(HolidayDay day);
  5. @Query("DELETE FROM holiday_day")
  6. void deleteAllHolidayDays();
  7. @Insert(onConflict = OnConflictStrategy.REPLACE)
  8. void insertHoliday(Holiday holiday);
  9. @Query("DELETE FROM holiday")
  10. void deleteAllHolidays();
  11. @Insert(onConflict = OnConflictStrategy.REPLACE)
  12. void insertFloatingHoliday(FloatingHoliday floatingHoliday);
  13. @Query("DELETE FROM floating_holiday")
  14. void deleteAllFloatingHolidays();
  15. }

字符串
数据库名称:

  1. @Database(entities = {Holiday.class, FloatingHoliday.class, HolidayDay.class}, version = 1)
  2. public abstract class AppDatabase extends RoomDatabase {
  3. public abstract AppDao appDao();
  4. }


存储库:

  1. public class AppRepository {
  2. private final AppDao holidayDao;
  3. private final MediatorLiveData<List<HolidayDay>> mergedHolidays = new MediatorLiveData<>();
  4. private List<HolidayDay> fixedHolidaysCache;
  5. private List<FloatingHoliday> floatingHolidaysCache;
  6. public AppRepository(final Application application) {
  7. final AppDatabase database = Room.databaseBuilder(application, AppDatabase.class, "uhc")
  8. .enableMultiInstanceInvalidation()
  9. .allowMainThreadQueries()
  10. .build();
  11. holidayDao = database.appDao();
  12. loadHolidays();
  13. }
  14. @Transaction
  15. public void updateCalendarData(@NonNull final UnusualCalendar calendar) {
  16. holidayDao.deleteAllHolidays();
  17. holidayDao.deleteAllHolidayDays();
  18. holidayDao.deleteAllFloatingHolidays();
  19. calendar.getFixed()
  20. .stream()
  21. .map(HolidayDay::getHolidays)
  22. .flatMap(Collection::stream)
  23. .forEach(holidayDao::insertHoliday);
  24. calendar.getFixed().forEach(holidayDao::insertHolidayDay);
  25. calendar.getFloating().forEach(holidayDao::insertFloatingHoliday);
  26. }
  27. private void loadHolidays() {
  28. final LiveData<List<HolidayDay>> fixedHolidays = holidayDao.getAllHolidayDays();
  29. final LiveData<List<FloatingHoliday>> floatingHolidays = holidayDao.getAllFloatingHolidays();
  30. mergedHolidays.addSource(fixedHolidays, fixed -> {
  31. fixedHolidaysCache = fixed;
  32. mergeHolidays();
  33. });
  34. mergedHolidays.addSource(floatingHolidays, floating -> {
  35. floatingHolidaysCache = floating;
  36. mergeHolidays();
  37. });
  38. }
  39. private void mergeHolidays() {
  40. // magic here
  41. }
  42. }


SharedViewModel:

  1. public class SharedViewModel extends ViewModel {
  2. public static final ViewModelInitializer<SharedViewModel> INITIALIZER = new ViewModelInitializer<>(SharedViewModel.class, creationExtras -> {
  3. final UHCApplication uhcApplication = (UHCApplication) creationExtras.get(ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY);
  4. assert uhcApplication != null;
  5. return new SharedViewModel(uhcApplication.getAppRepository());
  6. });
  7. private final AppRepository repository;
  8. public SharedViewModel(final AppRepository repository) {
  9. this.repository = repository;
  10. }
  11. public void updateData(final UnusualCalendar calendar) {
  12. CompletableFuture.runAsync(() -> repository.updateCalendarData(calendar));
  13. }
  14. }


下载MainActivity:

  1. public class MainActivity extends AppCompatActivity {
  2. private AlertDialog alertDialog;
  3. private final List<HolidayDay> holidayDays = new ArrayList<>();
  4. private MutableLiveData<Boolean> internet;
  5. private volatile boolean downloading;
  6. @Override
  7. protected void onCreate(final Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_main);
  10. configureObservers();
  11. if (Boolean.TRUE.equals(internet.getValue()) && !downloading) {
  12. initiateDownload();
  13. }
  14. // Observe the holiday data
  15. sharedViewModel.getAllHolidayDays().observe(this, days -> {
  16. if (!days.isEmpty()) {
  17. holidayDays.addAll(days);
  18. } else if (Boolean.FALSE.equals(internet.getValue())) {
  19. showNoInternetAlert();
  20. }
  21. });
  22. }
  23. private void initiateDownload() {
  24. downloading = true;
  25. CompletableFuture.supplyAsync(new Downloader()) // just a HttpsUrlConnection + gson
  26. .thenAcceptAsync(data -> {
  27. sharedViewModel.updateData(data);
  28. downloading = false;
  29. });
  30. }
  31. private void configureObservers() {
  32. internet = new MutableLiveData<>(Util.isNetworkAvailable(this));
  33. internet.observe(this, isConnected -> {
  34. if (Boolean.TRUE.equals(isConnected) && alertDialog != null && alertDialog.isShowing() && !downloading) {
  35. CompletableFuture.supplyAsync(new Downloader.UnusualCalendarDownloader())
  36. .thenAccept(sharedViewModel::updateData);
  37. alertDialog.dismiss();
  38. }
  39. });
  40. final ConnectivityManager connectivityManager =
  41. (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
  42. Util.NETWORK_CAPABILITIES.stream()
  43. .map(new NetworkRequest.Builder()::addTransportType)
  44. .map(NetworkRequest.Builder::build)
  45. .forEach(x -> connectivityManager.registerNetworkCallback(x, new ConnectivityManager.NetworkCallback() {
  46. @Override
  47. public void onAvailable(@NonNull final Network network) {
  48. super.onAvailable(network);
  49. internet.postValue(true);
  50. }
  51. @Override
  52. public void onLost(@NonNull final Network network) {
  53. super.onLost(network);
  54. internet.postValue(false);
  55. }
  56. }));
  57. }
  58. private void showNoInternetAlert() {
  59. final AlertDialog.Builder alert = new AlertDialog.Builder(this);
  60. alert.setTitle(R.string.no_internet_connection);
  61. alert.setCancelable(false);
  62. alert.setMessage(R.string.no_internet);
  63. alertDialog = alert.show();
  64. }
  65. }


CompletableFuture是从java9.util.concurrent导入的。我不能依赖OnConflictStrategy.REPLACE,因为条目有时会消失,我也想从数据库中删除它们。
我更喜欢的解决方案是让应用程序一直响应,并允许数据在存储和读取时动态更新(用户可以看到它们更新)。
我想更新SharedViewModel中的列表,但它没有解决冻结问题。

rsaldnfx

rsaldnfx1#

在我看来,有些东西只是简单地阻塞了主线程,最有可能的是,它是一个数据库操作。默认情况下,Android不会让你这样做,但如果你在一个单独的线程中发出请求,例如,但告诉主线程等待它完成,它可以阻塞主线程。我建议打开调试器,寻找程序在没有冻结的情况下工作的最后一个地方。
你的构造器看起来很奇怪。

  1. public SharedViewModel(final AppRepository repository) {
  2. this.repository = repository;
  3. } return repository.getHoliday(id)

字符串

相关问题