首先看一下效果动图:
数据来源是公司的一个api,网址就不贴了,数据格式大概是这样:
数据Bean:
-
public class BaseBean implements Serializable { private String Code; private String Message; public String getCode() { return Code; } public void setCode(String code) { Code = code; } public String getMessage() { return Message; } public void setMessage(String message) { Message = message; } public boolean isSuccessful() { return TextUtils.equals("1", getCode()); } }
-
public class Areas extends BaseBean { private Map<String, List<Cities>> Area; private List<Cities> HotCities; private String Version; public Map<String, List<Cities>> getArea() { return Area; } public void setArea(Map<String, List<Cities>> area) { Area = area; } public List<Cities> getHotCities() { return HotCities; } public void setHotCities(List<Cities> hotCities) { HotCities = hotCities; } public String getVersion() { return Version; } public boolean isSucceed() { return "1".equals(Version); } public void setVersion(String version) { Version = version; } }
-
@Entity(tableName = "city_table") public class Cities { /** * Province : 四川省 * ProvinceId : 23 * City : 阿坝藏族羌族自治州 * CityId : 2362 * District : 阿坝藏族羌族自治州 * DistrictId : 2362 * PinYin : aba */ @PrimaryKey(autoGenerate = true) private int Id; private int CityId; private String Province; private int ProvinceId; private String City; private String District; private int DistrictId; private String PinYin; /** * 忽略该属性 */ @Ignore private List<Cities> mtags; /** * 忽略该属性 */ @Ignore public int position; /** * @param tag 属于哪个字母 * @param tagid -9 代表当前定位城市标题、热门城市标题、 字母组标题 * -8 代表当前定位城市 * -7 热门城市 */ public static Cities newCities(String tag, int tagid) { Cities cit = new Cities(); cit.setDistrict(tag); cit.setId(tagid); return cit; } public static Cities newCities(String tag, int tagid,int position) { Cities cit = new Cities(); cit.setDistrict(tag); cit.setId(tagid); cit.position = position; return cit; } public int getId() { return Id; } public int getViewType() { int cityid; switch (Id) { case -9: cityid = 0; break; case -8: cityid = 1; break; case -7: cityid = 2; break; case -10: cityid = 4; break; default: cityid = 3; break; } return cityid; } public void setId(int id) { Id = id; } public List<Cities> getMtags() { return mtags; } public void setMtags(List<Cities> mtags) { this.mtags = mtags; } public String getProvince() { return Province; } public void setProvince(String Province) { this.Province = Province; } public int getProvinceId() { return ProvinceId; } public void setProvinceId(int ProvinceId) { this.ProvinceId = ProvinceId; } public String getCity() { return City; } public void setCity(String City) { this.City = City; } public int getCityId() { return CityId; } public void setCityId(int CityId) { this.CityId = CityId; } public String getDistrict() { return District; } public void setDistrict(String District) { this.District = District; } public int getDistrictId() { return DistrictId; } public void setDistrictId(int DistrictId) { this.DistrictId = DistrictId; } public String getPinYin() { return PinYin; } public void setPinYin(String PinYin) { this.PinYin = PinYin; } }
可以看出在city类中配置了一些属性,主要是为了缓存它,整个的设计框架采用的是ViewModel+LiveData+Room,关于这个框架之前我已经详细写过一篇了,所以,这里不做详述;
实现的主要思路是:
1.使用retrofit+rxjava+okhttp3进行网络请求,
api接口:
public interface CitiesService {
/**
* 选择城市相关的网络请求
*/
@FormUrlEncoded
@POST("api地址")
Observable<Areas> getCities(@Field("version") String version);
}
网络获取工具
public class NetWork {
private static SparseArray<NetWork> retrofitManagers = new SparseArray<>();
private Retrofit mRetrofit;
private NetWork(int hostType) {
Gson gson = new GsonBuilder()
//配置你的Gson
.setDateFormat("yyyy-MM-dd hh:mm:ss")
.create();
mRetrofit = new Retrofit.Builder()
.client(getFreeClient())
.baseUrl(Constant.getHost(hostType))
.addConverterFactory(ScalarsConverterFactory.create())//直接将数据转换为String
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
private OkHttpClient getFreeClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
X509TrustManager[] trustManager = new X509TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws
CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws
CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
}
};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManager, new SecureRandom());
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
if (sslSocketFactory != null)
builder.sslSocketFactory(sslSocketFactory);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(logging);
builder.connectTimeout(20, TimeUnit.SECONDS);
builder.writeTimeout(20, TimeUnit.SECONDS).readTimeout(20, TimeUnit.SECONDS);
builder.retryOnConnectionFailure(true);
return builder.build();
}
public static NetWork getInstance(int hostType) {
NetWork retrofitManager = retrofitManagers.get(hostType);
if (retrofitManager == null) {
retrofitManager = new NetWork(hostType);
retrofitManagers.put(hostType, retrofitManager);
return retrofitManager;
}
return retrofitManager;
}
/**
* @param service 服务接口
* @return T
*/
public <T> T createService(final Class<T> service) {
return mRetrofit.create(service);
}
}
这里为了避免有多个retrofit生成,造成内存不足,使用了SparyArray去将每一个网络工具实例类存储 ,可以达到复用的效果;
2.数据库存储
BaseDb:数据库配置:
@Database(entities = {Cities.class}, version = 1)
public abstract class BaseDB extends RoomDatabase {
public abstract CityDao cityDao();
private static BaseDB INSTANCE;
private static final Object sLock = new Object();
public static BaseDB getInstance(Context context) {
synchronized (sLock) {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
BaseDB.class, "city").allowMainThreadQueries().build();
}
return INSTANCE;
}
}
}
数据库操作类:CityDao
@Dao
public interface CityDao {
@Query("SELECT COUNT(1) from city_table")
int getDBDataCount();
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertCitys(List<Cities> cities);
@Query("SELECT * from city_table where PinYin like '%' + :searStr +'%' or District like '%'+:searStr+ '%'" )
List<Cities> getAllCitiesData(String searStr);
}
viewModel类:数据的容器
public class BaseViewModel<T> extends ViewModel {
//Disposable 容器,拿到一个Disposable就执行clear,解除订阅事件
private final CompositeDisposable mDisposable = new CompositeDisposable();
//LiveData封装类,添加/消除数据源
private MutableLiveData<T> mTMutableLiveData = new MutableLiveData<>();
//LiveData的set,post方法,同步,异步设置数据
protected void setValue(T value) {
mTMutableLiveData.setValue(value);
}
protected void postValue(T value) {
mTMutableLiveData.postValue(value);
}
//添加一个Disposable到集合中
protected void add(Di