package com.ttstd.dialer.manager; import android.annotation.SuppressLint; import android.content.Context; import android.os.Build; import android.text.TextUtils; import com.jeremyliao.liveeventbus.LiveEventBus; import com.qweather.sdk.Callback; import com.qweather.sdk.JWTGenerator; import com.qweather.sdk.QWeather; import com.qweather.sdk.basic.Lang; import com.qweather.sdk.basic.Unit; import com.qweather.sdk.parameter.weather.WeatherParameter; import com.qweather.sdk.response.error.ErrorResponse; import com.qweather.sdk.response.weather.WeatherDailyResponse; import com.qweather.sdk.response.weather.WeatherHourlyResponse; import com.qweather.sdk.response.weather.WeatherNowResponse; import com.tencent.mmkv.MMKV; import com.ttstd.dialer.BuildConfig; import com.ttstd.dialer.bean.CityInfo; import com.ttstd.dialer.config.CommonConfig; import com.ttstd.dialer.gson.GsonUtils; import com.ttstd.dialer.parser.CsvDeserializer; import com.ttstd.dialer.parser.LegacyCsvParser; import com.ttstd.dialer.utils.Logger; import com.ttstd.dialer.utils.NativeUtils; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.annotations.NonNull; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.core.ObservableEmitter; import io.reactivex.rxjava3.core.ObservableOnSubscribe; import io.reactivex.rxjava3.core.Observer; import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.schedulers.Schedulers; public class WeatherManager { private static final String TAG = "WeatherManager"; private static final String WEATHER_NOW_CACHE = "weather_now_cache_key"; private static final String WEATHER_24_HOUR_CACHE = "weather_24_hour_cache"; private static final String WEATHER_10_DAY_CACHE = "weather_10_day_cache"; private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); @SuppressLint("StaticFieldLeak") private static volatile WeatherManager INSTANCE; private Context mContext; private QWeather mQWeather; private Map LocationIDMap = new HashMap<>(); private boolean loadCsvFinish = false; private String mAdCode; private String mLocationId; private WeatherUpdateManager mWeatherUpdateManager; private WeatherManager(Context context) { this.mContext = context.getApplicationContext(); mWeatherUpdateManager = WeatherUpdateManager.Companion.getInstance(); mAdCode = mMMKV.decodeString(CommonConfig.CURRENT_LOCATION_AD_CODE_KEY, ""); initCsv(); try { // 通过SDK提供的JWTGenerator设置令牌生成器,其实现自TokenGenerator接口 JWTGenerator jwt = new JWTGenerator(NativeUtils.getQWeatherPrivateKey(), // 私钥 NativeUtils.getQWeatherProjectId(), // 项目ID NativeUtils.getQWeatherCredentialId()); // 凭据ID mQWeather = QWeather.getInstance(context, NativeUtils.getQWeatherUrl()) // 初始化服务地址 .setLogEnable(BuildConfig.DEBUG) // 启用调试日志(生产环境建议设置为 false) .setTokenGenerator(jwt); } catch (Throwable e) { Logger.e(TAG, "QWeatherUtils: " + e.getMessage()); e.printStackTrace(); } WeatherNowResponse weatherNowResponse = getWeatherNowCache(); if (weatherNowResponse != null) { mWeatherUpdateManager.publishWeatherNowUpdate(weatherNowResponse); } else { } WeatherHourlyResponse weatherHourlyResponse = getWeather24hCache(); if (weatherHourlyResponse != null) { mWeatherUpdateManager.publishWeatherHourlyUpdate(weatherHourlyResponse); } else { } WeatherDailyResponse weatherDailyResponse = getWeather10DCache(); if (weatherDailyResponse != null) { mWeatherUpdateManager.publishWeatherDailyUpdate(weatherDailyResponse); } else { } } public static void init(Context context) { if (INSTANCE == null) { synchronized (WeatherManager.class) { if (INSTANCE == null) { INSTANCE = new WeatherManager(context); } } } } public static WeatherManager getInstance() { if (INSTANCE == null) { throw new IllegalStateException("You must first initialize the WeatherManager"); } return INSTANCE; } public QWeather getQWeather() { return mQWeather; } public void setAdCode(String adCode) { mAdCode = adCode; if (loadCsvFinish) { if (!TextUtils.isEmpty(adCode)) { String locationId = LocationIDMap.get(adCode); Logger.e(this, TAG, "setAdCode: locationId = " + locationId); LiveEventBus.get(CommonConfig.LOCATION_ID_CHANGED_KEY) .post(locationId); } } } public String getAdCode() { return mAdCode; } private void initCsv() { Observable.create(new ObservableOnSubscribe>() { @Override public void subscribe(@NonNull ObservableEmitter> emitter) throws Throwable { long time = System.currentTimeMillis(); List cityInfos; if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) { cityInfos = CsvDeserializer.deserializeFromAssets(mContext, "China-City-List-latest.csv"); } else { cityInfos = LegacyCsvParser.parseFromAssets(mContext, "China-City-List-latest.csv"); } Logger.e(TAG, "subscribe: deserializeFromAssets time = " + (System.currentTimeMillis() - time) + "ms"); emitter.onNext(cityInfos); } }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer>() { @Override public void onSubscribe(@NonNull Disposable d) { Logger.e(TAG, "initCsv", "onSubscribe: "); } @Override public void onNext(@NonNull List cityInfos) { Logger.e(TAG, "initCsv", "onNext: cityInfos size = " + cityInfos.size()); Logger.e(TAG, "initCsv", "onNext: cityInfos 0 info = " + cityInfos.get(0)); LocationIDMap = cityInfos.stream() .filter(cityInfo -> cityInfo.getLocation_ID() != null) // 过滤掉 value 为 null 的条目 .collect(Collectors.toMap(CityInfo::getAD_code, CityInfo::getLocation_ID, (oldVal, newVal) -> oldVal, HashMap::new)); Logger.e(TAG, "initCsv", "onNext: LocationIDMap size = " + LocationIDMap.size()); onComplete(); } @Override public void onError(@NonNull Throwable e) { Logger.e(TAG, "initCsv", "onError: " + e.getMessage()); } @Override public void onComplete() { Logger.e(TAG, "initCsv", "onComplete: "); loadCsvFinish = true; if (!TextUtils.isEmpty(mAdCode)) { String locationId = LocationIDMap.get(mAdCode); Logger.e(TAG, "initCsv", "onComplete: locationId = " + locationId); LiveEventBus.get(CommonConfig.LOCATION_ID_CHANGED_KEY) .post(locationId); } } }); } private String getLocationID(String adCode) { if (LocationIDMap != null) { return LocationIDMap.get(adCode); } return ""; } public void refreshweather() { if (!TextUtils.isEmpty(mAdCode)) { } } public void getWeatherNowAdCode(String adCode, Callback callback) { String locationID = getLocationID(adCode); Logger.e(TAG, "getWeatherNowAdCode: locationID = " + locationID); getWeatherNow(locationID, callback); } public void getWeatherNow(String locationID, Callback callback) { WeatherParameter parameter = new WeatherParameter(locationID) .lang(Lang.ZH_HANS) .unit(Unit.METRIC); mQWeather.weatherNow(parameter, new Callback() { @Override public void onSuccess(WeatherNowResponse weatherNowResponse) { Logger.e(TAG, "getWeatherNow", "onSuccess: " + weatherNowResponse); mWeatherUpdateManager.publishWeatherNowUpdate(weatherNowResponse); mMMKV.encode(WEATHER_NOW_CACHE, GsonUtils.toJSONString(weatherNowResponse)); if (callback != null) { callback.onSuccess(weatherNowResponse); } } @Override public void onFailure(ErrorResponse errorResponse) { if (callback != null) { callback.onFailure(errorResponse); } } @Override public void onException(Throwable throwable) { if (callback != null) { callback.onException(throwable); } } }); } public void getWeather24HourAdCode(String adCode, Callback callback) { String locationID = getLocationID(adCode); Logger.e(TAG, "getWeather24HourAdCode: locationID = " + locationID); getWeather24Hour(locationID, callback); } public void getWeather24Hour(String locationID, Callback callback) { WeatherParameter parameter = new WeatherParameter(locationID) .lang(Lang.ZH_HANS) .unit(Unit.METRIC); mQWeather.weather24h(parameter, new Callback() { @Override public void onSuccess(WeatherHourlyResponse weatherHourlyResponse) { Logger.e(TAG, "getWeather24Hour", "onSuccess: " + weatherHourlyResponse); mWeatherUpdateManager.publishWeatherHourlyUpdate(weatherHourlyResponse); mMMKV.encode(WEATHER_24_HOUR_CACHE, GsonUtils.toJSONString(weatherHourlyResponse)); if (callback != null) { callback.onSuccess(weatherHourlyResponse); } } @Override public void onFailure(ErrorResponse errorResponse) { if (callback != null) { callback.onFailure(errorResponse); } } @Override public void onException(Throwable throwable) { if (callback != null) { callback.onException(throwable); } } }); } public void getWeather10DayAdCode(String adCode, Callback callback) { String locationID = getLocationID(adCode); Logger.e(TAG, "getWeather10Day: locationID = " + locationID); getWeather10Day(locationID, callback); } public void getWeather10Day(String locationID, Callback callback) { WeatherParameter parameter = new WeatherParameter(locationID) .lang(Lang.ZH_HANS) .unit(Unit.METRIC); mQWeather.weather10d(parameter, new Callback() { @Override public void onSuccess(WeatherDailyResponse weatherDailyResponse) { Logger.e(TAG, "getWeather10Day", "onSuccess: " + weatherDailyResponse); mWeatherUpdateManager.publishWeatherDailyUpdate(weatherDailyResponse); mMMKV.encode(WEATHER_10_DAY_CACHE, GsonUtils.toJSONString(weatherDailyResponse)); if (callback != null) { callback.onSuccess(weatherDailyResponse); } } @Override public void onFailure(ErrorResponse errorResponse) { if (callback != null) { callback.onFailure(errorResponse); } } @Override public void onException(Throwable throwable) { if (callback != null) { callback.onException(throwable); } } }); } public WeatherNowResponse getWeatherNowCache() { String weatherNowCache = mMMKV.decodeString(WEATHER_NOW_CACHE); if (!TextUtils.isEmpty(weatherNowCache)) { return GsonUtils.toJavaObject(weatherNowCache, WeatherNowResponse.class); } return null; } public WeatherHourlyResponse getWeather24hCache() { String weather24hCache = mMMKV.decodeString(WEATHER_24_HOUR_CACHE); if (!TextUtils.isEmpty(weather24hCache)) { return GsonUtils.toJavaObject(weather24hCache, WeatherHourlyResponse.class); } return null; } public WeatherDailyResponse getWeather10DCache() { String weather10DCache = mMMKV.decodeString(WEATHER_10_DAY_CACHE); if (!TextUtils.isEmpty(weather10DCache)) { return GsonUtils.toJavaObject(weather10DCache, WeatherDailyResponse.class); } return null; } }