Merge pull request 'ユーザーデータをキャッシュするように' (#86) from feature/cache_parent_data into main

Reviewed-on: #86
This commit is contained in:
Fujimatsu 2024-06-24 03:05:14 +00:00
commit a312dcffa7
9 changed files with 176 additions and 25 deletions

View File

@ -1,5 +1,9 @@
package one.nem.kidshift.data;
import java.util.concurrent.CompletableFuture;
import one.nem.kidshift.model.ParentModel;
/**
* データの同期など, ユーザーからの操作に基づかない処理を行う
*/
@ -12,6 +16,6 @@ public interface KSActions {
/**
* 親ユーザー情報同期
*/
void syncParent();
CompletableFuture<ParentModel> syncParent();
}

View File

@ -3,6 +3,7 @@ package one.nem.kidshift.data;
import java.util.concurrent.CompletableFuture;
import one.nem.kidshift.model.ParentModel;
import one.nem.kidshift.model.callback.ParentModelCallback;
public interface ParentData {
@ -11,7 +12,7 @@ public interface ParentData {
* 親ユーザー情報取得
* @return 親ユーザー情報
*/
CompletableFuture<ParentModel> getParent();
CompletableFuture<ParentModel> getParent(ParentModelCallback callback);
/**
* 親ユーザー情報更新

View File

@ -7,6 +7,7 @@ public interface UserSettings {
ApiSetting getApiSetting();
TaskSetting getTaskSetting();
AppCommonSetting getAppCommonSetting();
SharedPrefCache getCache();
interface AppCommonSetting {
boolean isLoggedIn();
@ -19,6 +20,11 @@ public interface UserSettings {
void setChildMode(boolean childMode);
}
interface SharedPrefCache {
ParentModel getParent();
void setParent(ParentModel parent);
}
interface ApiSetting {
String getApiBaseUrl();
void setApiBaseUrl(String url);

View File

@ -1,17 +1,30 @@
package one.nem.kidshift.data.impl;
import java.util.concurrent.CompletableFuture;
import javax.inject.Inject;
import one.nem.kidshift.data.KSActions;
import one.nem.kidshift.data.UserSettings;
import one.nem.kidshift.data.retrofit.KidShiftApiService;
import one.nem.kidshift.data.retrofit.model.parent.ParentInfoResponse;
import one.nem.kidshift.model.ParentModel;
import one.nem.kidshift.utils.KSLogger;
import retrofit2.Call;
import retrofit2.Response;
public class KSActionsImpl implements KSActions {
private UserSettings userSettings;
private KidShiftApiService kidShiftApiService;
private KSLogger logger;
@Inject
public KSActionsImpl(UserSettings userSettings) {
public KSActionsImpl(UserSettings userSettings, KidShiftApiService kidShiftApiService, KSLogger logger) {
this.userSettings = userSettings;
this.kidShiftApiService = kidShiftApiService;
this.logger = logger;
logger.setTag("KSActions");
}
@Override
@ -25,7 +38,33 @@ public class KSActionsImpl implements KSActions {
}
@Override
public void syncParent() {
public CompletableFuture<ParentModel> syncParent() {
logger.info("syncParent called and started");
return CompletableFuture.supplyAsync(() -> {
logger.info("fetching...");
Call<ParentInfoResponse> call = kidShiftApiService.getParentInfo();
try {
Response<ParentInfoResponse> response = call.execute();
if (!response.isSuccessful()) {
logger.error("Error fetching parent info: " + response.errorBody().string());
throw new RuntimeException("Error fetching parent info: " + response.errorBody().string());
}
ParentInfoResponse responseBody = response.body();
ParentModel parent = new ParentModel();
// TODO: 詰め替えをどこかにまとめる, 他のプロパティも処理する
parent.setInternalId(responseBody.getId());
parent.setEmail(responseBody.getEmail());
parent.setDisplayName(responseBody.getEmail()); // Workaround
logger.info("Parent fetched with status: " + response.code());
logger.debug("Parent: " + parent);
// Save to cache
userSettings.getCache().setParent(parent);
logger.info("Parent saved to cache");
return parent;
} catch (Exception e) {
logger.error("Error fetching parent info");
throw new RuntimeException(e);
}
});
}
}

View File

@ -7,11 +7,14 @@ import java.util.concurrent.CompletableFuture;
import javax.inject.Inject;
import one.nem.kidshift.data.KSActions;
import one.nem.kidshift.data.ParentData;
import one.nem.kidshift.data.UserSettings;
import one.nem.kidshift.data.retrofit.KidShiftApiService;
import one.nem.kidshift.data.retrofit.model.parent.ParentInfoResponse;
import one.nem.kidshift.model.ParentModel;
import one.nem.kidshift.model.callback.ParentModelCallback;
import one.nem.kidshift.utils.KSLogger;
import retrofit2.Call;
import retrofit2.Response;
@ -21,35 +24,40 @@ public class ParentDataImpl implements ParentData {
private UserSettings userSettings;
private KSLogger logger;
private KSActions ksActions;
@Inject
public ParentDataImpl(KidShiftApiService kidshiftApiService, UserSettings userSettings) {
public ParentDataImpl(KidShiftApiService kidshiftApiService, UserSettings userSettings, KSLogger logger, KSActions ksActions) {
this.kidshiftApiService = kidshiftApiService;
this.userSettings = userSettings;
this.logger = logger;
this.ksActions = ksActions;
logger.setTag("ParentData");
}
// 一旦キャッシュを返して, その後非同期でAPIから取得更新があればコールバックで通知
@Override
public CompletableFuture<ParentModel> getParent() {
return CompletableFuture.supplyAsync(() -> {
Response<ParentInfoResponse> parentInfoResponse;
Call<ParentInfoResponse> response = kidshiftApiService.getParentInfo();
try {
parentInfoResponse = response.execute();
ParentInfoResponse responseBody = parentInfoResponse.body();
ParentModel parent = new ParentModel();
assert parentInfoResponse != null;
parent.setInternalId(responseBody.getId());
parent.setEmail(responseBody.getEmail());
parent.setDisplayName(responseBody.getEmail()); // Workaround
// TODO: 他のプロパティも処理する
return parent;
} catch (IOException e) {
throw new RuntimeException(e);
public CompletableFuture<ParentModel> getParent(ParentModelCallback callback) {
// Start thread to fetch parent info
new Thread(() -> {
logger.info("Fetching parent info...");
ParentModel refreshedParent = ksActions.syncParent().join();
if (refreshedParent == null) {
callback.onFailed("Failed to fetch parent info");
} else {
// Workaround, TODO: Compare with existing parent
callback.onUpdated(refreshedParent);
}
});
}).start();
return CompletableFuture.supplyAsync(() -> userSettings.getCache().getParent());
}
@Override
public void updateParent(ParentModel parent) {
}
}

View File

@ -8,6 +8,7 @@ import java.util.Objects;
import javax.inject.Inject;
import one.nem.kidshift.data.UserSettings;
import one.nem.kidshift.model.ParentModel;
import one.nem.kidshift.utils.SharedPrefUtils;
import one.nem.kidshift.utils.factory.SharedPrefUtilsFactory;
@ -35,6 +36,44 @@ public class UserSettingsImpl implements UserSettings {
return new AppCommonSettingImpl();
}
@Override
public SharedPrefCache getCache() {
return new SharedPrefCacheImpl();
}
public class SharedPrefCacheImpl implements UserSettings.SharedPrefCache {
transient
SharedPrefUtils sharedPrefUtils;
ParentModel parent;
SharedPrefCacheImpl() {
sharedPrefUtils = sharedPrefUtilsFactory.create("user_settings");
SharedPrefCacheImpl sharedPrefCache = sharedPrefUtils.getObject("shared_pref_cache", SharedPrefCacheImpl.class);
if (sharedPrefCache != null) {
parent = sharedPrefCache.getParent();
} else {
parent = null;
}
}
private void save() {
sharedPrefUtils.saveObject("shared_pref_cache", this);
}
@Override
public ParentModel getParent() {
return parent;
}
@Override
public void setParent(ParentModel parent) {
this.parent = parent;
save();
}
}
public class AppCommonSettingImpl implements UserSettings.AppCommonSetting {
transient

View File

@ -0,0 +1,16 @@
package one.nem.kidshift.data.modules;
import dagger.Binds;
import dagger.Module;
import dagger.hilt.InstallIn;
import dagger.hilt.components.SingletonComponent;
import one.nem.kidshift.data.KSActions;
import one.nem.kidshift.data.impl.KSActionsImpl;
@Module
@InstallIn(SingletonComponent.class)
public abstract class KSActionsModule {
@Binds
public abstract KSActions bindKSActions(KSActionsImpl impl);
}

View File

@ -16,6 +16,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import javax.inject.Inject;
@ -24,6 +25,7 @@ import one.nem.kidshift.data.ChildData;
import one.nem.kidshift.data.ParentData;
import one.nem.kidshift.model.ChildModel;
import one.nem.kidshift.model.ParentModel;
import one.nem.kidshift.model.callback.ParentModelCallback;
/**
* A simple {@link Fragment} subclass.
@ -85,8 +87,35 @@ public class SettingMainFragment extends Fragment {
Bundle savedInstanceState) {
// Inflate the layout for this fragment
//親の名前アドレス表示
ParentModel parent = parentData.getParent().join();
CompletableFuture<ParentModel> completableFuture = parentData.getParent(new ParentModelCallback() {
@Override
public void onUnchanged() {
// TODO
}
@Override
public void onUpdated(ParentModel parent) {
// TODO
}
@Override
public void onFailed(String message) {
// TODO
}
});
/*
TODO:
- コールバックの処理を実装
- 結果に応じてRecyclerViewを更新する
- キャッシュ受け取りの時にjoinでUIスレッドをブロックしないように
- Placeholderの表示?
- エラーハンドリング
- onFailed時にそれを通知
*/
ParentModel parent = completableFuture.join();
if (parent == null) {
parent = new ParentModel(); // Workaround非ログインデバッグ用

View File

@ -0,0 +1,9 @@
package one.nem.kidshift.model.callback;
import one.nem.kidshift.model.ParentModel;
public interface ParentModelCallback {
void onUnchanged();
void onUpdated(ParentModel parent);
void onFailed(String message);
}