MVPHulk是一款採用當前最新技術RxJava+Rxlifecycle+Okhttp+Retrofit+Dagger封裝的一個MVP框架java
1.支持接口多狀態、單狀態返回值配置;支持服務器地址配置;攔截器相關配置等 2.支持support、AndroidX兩個版本 3.支持單Activity、列表Activity、單Fragment、列表Fragment、單DialogFragment, 結合BaseRecyclerViewAdapterHelper+SmartRefreshLayout的封裝,讓咱們只須要關注業務邏輯的實現;對於複雜業務場景可根據基類進行擴展 4.支持接口狀態不一樣顯示不一樣狀態界面和可執行操做,支持自定義狀態界面,可集成(lottie)[github.com/airbnb/lott…]讓界面更酷炫 5.支持模版開發,MVPHulkTemplate讓開發者減小重複的操做,解放雙手android
1.MVPHulk上手文檔git
2.MVPHulkTemplate使用文檔github
3.MVPHulk源碼下載api
1.項目的build.gradle安全
allprojects {
repositories {
maven { url "https://jitpack.io" }
google()
jcenter()
}
}
複製代碼
2.app的build.gradlebash
在android下添加服務器
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
複製代碼
//1.0.0版本
api 'com.madreain:hulk:1.0.0'
//androidx版本
api 'com.madreain:hulk:1.0.0-andx'
//dagger2
annotationProcessor rootProject.ext.dependencies["dagger2-compiler"]
annotationProcessor rootProject.ext.dependencies["dagger2-android-processor"]
//butterknife
api rootProject.ext.dependencies["butterknife"]
annotationProcessor rootProject.ext.dependencies["butterknife-compiler"]
//arouter
annotationProcessor rootProject.ext.dependencies["arouter-compiler"]
複製代碼
⚠️注意:由於涉及到的第三方庫比較多,dex的方法數量被限制在65535以內,這就是著名的64K(64*1024)事件, 需引入MultiDex來解決這個問題,建立好Application,記得在AndroidManifest.xml中修改application的namerestful
記得修改application的style網絡
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowBackground">@color/windowBackground</item>
<item name="colorControlNormal">@color/windowBackground</item>
<item name="colorControlActivated">@color/colorAccent</item>
</style>
複製代碼
Glide的引用,需建立ids.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="glide_tag" type="id" />
</resources>
複製代碼
app的build.gradle需引入相關dagger2庫,-項目配置介紹中已配置,此部份內容自行參考
1.)BuilderModule的建立(全部的activity、fragment都要在這裏進行註冊)(⚠️注意:我在Demo裏是放在了包名下面,我在項目開發中會使用到Template模版開發)
參考代碼
@Module
public abstract class BuilderModule {
//全部的activity、fragment都要在這裏進行註冊
}
複製代碼
2.)Appcomponent的建立
參考代碼
@Singleton
@Component(modules = {AndroidSupportInjectionModule.class, ApiModule.class, BuilderModule.class})
public interface Appcomponent extends IAppComponent {
//HulkUnionApplication是繼承HulkApplication建立
void inject(HulkUnionApplication mvpHulkApplication);
Retrofit getRetrofit();
}
複製代碼
⚠️注意:DaggerAppComponent的生成make project一下就行
3.)以及注入初始化代碼。 app級別的固然在application裏面出初始化
參考代碼
public class HulkUnionApplication extends HulkApplication {
private static Appcomponent appcomponent;
public static Appcomponent getAppcomponent() {
return appcomponent;
}
@Override
public void onCreate() {
super.onCreate();
MultiDex.install(this);
}
@Override
public void initHulkConfig() {
//DaggerAppComponent的生成make project一下就行
appcomponent = DaggerAppcomponent.builder().apiModule(new com.madreain.hulk.application.ApiModule()).build();
}
}
複製代碼
1.)在config.gradle中配置開啓日誌、開啓切換環境、BASEURL的相關參數
參考代碼
OPEN_LOG = true
OPEN_CHANGE = true
BASE_URL = " http://www.mxnzp.com"
CODE_SUCCESS = "1"
//增刪改查返回網絡請求成功,由於不支持集合,這裏採用,分割
CODELIST_SUCCESS = "1,0"
複製代碼
⚠️注意:優先級:CODE_SUCCESS>CODELIST_SUCCESS,針對項目只須要設置其中一個就行
參考代碼
//定義網絡請求成功返回碼 baseurl 日誌打印 切換環境 在代碼中BuildConfig.BASE_URL去使用
buildConfigField "String", "CODE_SUCCESS", getCodeSuccess()
buildConfigField "String", "CODELIST_SUCCESS", getCodeListSuccess()
buildConfigField "String", "BASE_URL", getBaseUrl()
buildConfigField "boolean", "OPEN_LOG", getOpenLog()
buildConfigField "boolean", "OPEN_CHANGE", getOpenChange()
複製代碼
def getOpenLog() {
return "${OPEN_LOG}"
}
def getOpenChange() {
return "${OPEN_CHANGE}"
}
def getBaseUrl() {
return "\"" + String.valueOf(BASE_URL).trim() + "/\""
}
def getCodeSuccess() {
return "\"" + String.valueOf(CODE_SUCCESS)+ "\""
}
def getCodeListSuccess() {
return "\"" + String.valueOf(CODELIST_SUCCESS)+ "\""
}
複製代碼
2.)網絡請求的相關攔截器
參考代碼
public class RequestHeaderInterceptor implements Interceptor {
//統一請求頭的封裝根據自身項目添加
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Request request = chain.request();
Request authorised;
Headers headers = new Headers.Builder()
.add("test", "test")
.build();
authorised = request.newBuilder().headers(headers).build();
return chain.proceed(authorised);
}
}
複製代碼
參考代碼
public class SessionInterceptor implements IReturnCodeErrorInterceptor {
//和接口定義互踢的相關參數返回,而後在todo方法進行跳轉
@Override
public boolean intercept(String code) {
//這裏的-100表示互踢的返回參數
return "-100".equals(code);
}
@Override
public void todo(IView iView, String returnCode, String msg) {
}
}
複製代碼
參考代碼
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
複製代碼
⚠️注意:可進行擴展設置多種攔截器,可參考OkHttp攔截器
3.)默認佔位圖、默認頭像佔位圖
到此爲止,繼承HulkApplication的配置項就完成了,這裏還設置了Glide、ARouter、SmartRefreshLayout,完整代碼參考以下
public class HulkUnionApplication extends HulkApplication {
private static Appcomponent appcomponent;
public static Appcomponent getAppcomponent() {
return appcomponent;
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
@Override
public void initHulkConfig() {
//DaggerAppComponent的生成make project一下就行
appcomponent = DaggerAppcomponent.builder().apiModule(new com.madreain.hulk.application.ApiModule()).build();
//消息攔截器
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
//配置項
HulkConfig.builder()
.setApplication(this)
//這裏只須要選擇設置一個
.setRetSuccess(BuildConfig.CODE_SUCCESS)
// .setRetSuccessList(BuildConfig.CODELIST_SUCCESS)
.setBaseUrl(BuildConfig.BASE_URL)
.setChangeBaseUrl(BuildConfig.OPEN_CHANGE)
.setOpenLog(BuildConfig.OPEN_LOG)
.addOkHttpInterceptor(new RequestHeaderInterceptor())//請求頭攔截器
.addOkHttpInterceptor(BuildConfig.OPEN_LOG, logging)//okhttp請求日誌開關+消息攔截器.md
.addRetCodeInterceptor(new SessionInterceptor())// returnCode非正常態攔截器
.setGlidePlaceHolder(new ColorDrawable(Color.parseColor("#ffffff")))//默認佔位圖--顏色
.setGlideHeaderPlaceHolder(getResources().getDrawable(R.mipmap.ic_launcher))//默認頭像佔位圖
.setRetrofit(appcomponent.getRetrofit())
.build();
appcomponent.inject(this);
//application 上下文
Utils.init(this);
//Glide設置tag
ViewTarget.setTagId(R.id.glide_tag);
//log日子開關
initLog();
//ARouter
initArouter();
}
private void initArouter() {
//ARouter的初始化
ARouter.init(this);
}
private void initLog() {
//測試環境
if (BuildConfig.OPEN_LOG) {
ARouter.openLog(); // 打印日誌
ARouter.openDebug(); // 開啓調試模式(若是在InstantRun模式下運行,必須開啓調試模式!線上版本須要關閉,不然有安全風險)
}
}
//static 代碼段能夠防止內存泄露
static {
//啓用矢量圖兼容
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
//設置全局的Header構建器
SmartRefreshLayout.setDefaultRefreshHeaderCreator(new DefaultRefreshHeaderCreator() {
@Override
public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) {
layout.setPrimaryColorsId(R.color.colorPrimary, android.R.color.white);//全局設置主題顏色
return new ClassicsHeader(context);//.setTimeFormat(new DynamicTimeFormat("更新於 %s"));//指定爲經典Header,默認是 貝塞爾雷達Header
}
});
//設置全局的Footer構建器
SmartRefreshLayout.setDefaultRefreshFooterCreator(new DefaultRefreshFooterCreator() {
@Override
public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) {
//指定爲經典Footer,默認是 BallPulseFooter
return new ClassicsFooter(context).setDrawableSize(20);
}
});
}
}
複製代碼
public interface ApiService {
@GET("api/address/list")
Flowable<BaseRes<List<CityListListData>>> getCityList();
}
複製代碼
public class ARouterUri {
public static final String MainActivity = "/mvphulk/ui/MainActivity";
}
複製代碼
接下來,咱們要真正的進入業務開發階段了
@Module
public abstract class BuilderModule {
@ContributesAndroidInjector(modules = MainModule.class)
abstract MainActivity mainActivity();
@ContributesAndroidInjector(modules = HomeModule.class)
abstract HomeFragment homeFragment();
}
複製代碼
參考官方文檔ARouter使用指南
Activity需設置路由
@Route(path = ARouterUri.CityListActivity)
複製代碼
1.)添加請求接口相關權限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
複製代碼
2.)補充對象的相關參數
參考以下,這裏需注意@Keep的做用,就是保持哪些類或者哪些元素不被混淆
@Keep
public class CityListListData {
private String code;
private String name;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
複製代碼
3.)ApiService配置相關接口
參考以下
public interface ApiService {
@GET("api/address/list")
Flowable<BaseRes<List<CityListListData>>> getCityList();
}
複製代碼
⚠️注意:項目中,仍是建議GET、HEAD、POST、DELETE、PUT、DELETE,遵循restful風格
4.)繼承自BaseModel的對應Model增長接口調用的方法
參考以下
public class CityListModel extends BaseModel<ApiService> implements CityListContract.Model {
@Inject
public CityListModel() {
super();
}
@Override
public Flowable<BaseRes<List<CityListListData>>> loadListDatas(int pageNo) {
return apiService.getCityList();//接口調用 apiService.xxx
}
}
複製代碼
5.)繼承自BasePresenter的對應Presenter放開相對應的方法
參考以下
public class CityListPresenter extends BasePresenter<CityListModel, CityListContract.View> {
@Inject
CityListPresenter() {
}
@Override
public void onStart() {
loadPageListData(1);
}
@Override
public void onDestroy() {
model.onDestroy();
}
public void loadPageListData(final int pageNum) {
model.loadListDatas(pageNum)
.compose(Transformer.retrofit(view))
.subscribeWith(new RSubscriberList<List<CityListListData>>(view, pageNum) {
@Override
public void _onNext(List<CityListListData> datas) {
view.showListData(datas, pageNum);
}
@Override
public void retry() {
loadPageListData(pageNum);
}
});
}
}
複製代碼
⚠️注意:RSubscriberList(適用於List界面,可刷新加載更多)、RSubscriber(適用於單界面)
Transformer中retrofit(BaseRes類中的泛型 -即有result)、retrofitBaseRes(接口響應只有BaseRes,內部的泛型爲null)
6.)繼承自BaseAdapter的Adapter設置相關數據展現
參考以下
public class CityListAdapter<V extends IView> extends BaseAdapter<CityListListData, CityListActivity> {
@Inject
public CityListAdapter() {
super(R.layout.item_activity_city_list, new ArrayList<>());
}
@Override
protected void convert(HulkViewHolder helper, CityListListData data) {
helper.setText(R.id.tv, data.getName());
}
}
複製代碼
7.)繼承自BaseListActivity的Activity類的設置
設置是否可刷新加載,默認均可以
setLoadMoreEnable(true);
setRefreshEnable(true);
複製代碼
Activity類完整代碼參考以下
@Route(path = ARouterUri.CityListActivity)
public class CityListActivity extends BaseListActivity<CityListPresenter, CityListAdapter<CityListActivity>, CityListListData> implements CityListContract.View {
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.smartRefreshLayout)
SmartRefreshLayout smartRefreshLayout;
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
@Override
public int getLayoutId() {
return R.layout.activity_city_list;
}
@Override
public void _init(Bundle savedInstanceState) {
setSupportActionBarWithBack(toolbar);
toolbar.setTitle("list展現能刷新能加載更多");
presenter.onStart();
}
@Override
public void loadPageListData(int pageNo) {
presenter.loadPageListData(pageNo);
}
@Override
public SmartRefreshLayout getSmartRefreshLayout() {
return smartRefreshLayout;
}
@Override
public RecyclerView getRecyclerView() {
return recyclerView;
}
@Override
public RecyclerView.LayoutManager getLayoutManager() {
return new LinearLayoutManager(this);
}
@Override
public View getReplaceView() {
return smartRefreshLayout;
}
}
複製代碼
接口調用到數據顯示的代碼參考CityList城市
到此爲止,程序能夠跑起來,想展現的界面也能展現出來了