需求:新項目只需5分鐘接入,以後直接開擼,不用關心網絡、圖片、模式、穩定等問題,支持mvp一個activity對應多個presenter。 適用本身的纔是最好的!java
2019-09-06 更新 1.0.1.7 圖片加載,ImageView擴展,fragment懶加載android
2019-06-24 更新 1.0.1.5 anko ui註解初始化+自定義ConverterFactorygit
2019-06-17 更新 kotlin-mvp temeplegithub
2019-06-14 更新 kotlin接入express
2019-06-05 更新 遊手好閒之使用MotionLayout實現高德地圖bottomSheets效果
apache
2019-05-31 更新 1.0.1.3升級到androidxjson
2019-05-29 最新,新鮮temeple出爐,請拉到最後看效果api
...緩存
1.0.1.7
主要新增,圖片加載庫圖片加載,任意選擇加載引擎 打造統一的圖片加載框架,融合Glide(4.x),Fresco,不侵入業務代碼,一套API兼容兩種加載庫
bash
@Override
public AppSetting getAppSetting() {
return getAppSettingBuilder()
.isDebug(true)
.build();
}
@Override
public AppImageLoadSetting getImageLoadSetting() {
return AppImageLoadSetting
.builder()
.imageLoaderConfig(getImageLoaderConfig())
.isCrossFade(true)
.errorholder(R.mipmap.ic_launcher_round)
.placeholder(R.mipmap.ic_logo)
.build();
}
複製代碼
1.0.1.5
主要新增anko支持,經過註解解耦使用AnkoUi,不須要手動初始化,直接使用ankoUi
@AnkoInject(ui = xxAnkoUi::class)
複製代碼
@AnkoVariable
internal var ui : xxAnkoUi? = null
複製代碼
而後可直接使用ui
這個變量,以下:
GankAnkoActivity
@AnkoInject(ui = GankActivityUi::class)
@Route(path = RouterPageContant.KT_ANKO)
@CreatePresenter(presenter = [GankPresenter::class])
class GankAnkoActivity : BaseAnkoActivity(), GankContract.IView {
@PresenterVariable
internal var mPresenter: GankPresenter? = null
@AnkoVariable
internal var ui : GankActivityUi? = null
@SuppressLint("NewApi")
override fun init(savedInstanceState: Bundle?) {
setSupportActionBar(ui?.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.title = "KtGankActivity"
}
override fun loadData() {
mPresenter?.getFuliDataRepository("20", "1")
}
override fun bindData(data: MutableList<GirlsData>?) {
val jsonStr = JSON.toJSONString(data)
ui?.textInfo?.text = jsonStr
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item?.itemId) {
android.R.id.home -> {
finish()
return true
}
}
return super.onOptionsItemSelected(item)
}
}
複製代碼
GankAnkoFragment
@AnkoInject(ui = GankFragmentUi::class)
@CreatePresenter(presenter = [TestGankPresenter::class])
class GankAnkoFragment: BaseAnkoFragment(), GankContract.IView {
@PresenterVariable
internal var mPresenter: TestGankPresenter? = null
@AnkoVariable
internal var ui : GankFragmentUi? = null
override fun init(savedInstanceState: Bundle?) {
}
override fun initImmersionBar() {
ImmersionBar.with(this)
.transparentStatusBar()
.fitsSystemWindows(true)
.statusBarColor(R.color.colorPrimary)
.statusBarDarkFont(true, 0.2f)
.init()
}
override fun loadData() {
mPresenter?.getFuliDataRepository("10", "1")
}
override fun bindData(data: MutableList<GirlsData>?) {
val jsonStr = JSON.toJSONString(data)
ui?.textInfo?.text = jsonStr
}
}
複製代碼
1.0.1.4
SugarHandleSubscriber
用於接口請求時候僅處理onNext()
,由於在SugarRepository
裏面的customObservable(Observable observable)
函數裏面統一處理了錯誤異常抓取,通常狀況下不須要再處理OnError
固然能夠重載函數的時候作處理.doOnError(throwable -> {
LogUtils.i("doOnError------" + throwable);
if (mIView != null) {
mIView.showLoadFailed();
}
if (rxErrorHandler != null){
//統一異常抓取
rxErrorHandler.getHandlerFactory().handleError((Throwable) throwable);
}
});
複製代碼
SugarHandleSubscriber
@Override
public void getFuliDataRepository(String size, String index) {
mModel.getFuliDataRepository(size, index)
.subscribe(new SugarHandleSubscriber<List<GirlsData>>() {
@Override
public void onNext(List<GirlsData> girlsData) {
mView.bindData(girlsData);
}
});
}
複製代碼
mModel.getFuliDataRepository(size, index)
.subscribe({
mView.bindData(it)
})
複製代碼
1.0.1.4
版本以後 Presenter
不支持在Activity/Fragment
後寫泛型,只支持註解@CreatePresenter(presenter = GankPresenter.class)
public class GankActivity extends BaseActivity implements GankContract.IView{
@PresenterVariable
GankPresenter mPresenter;
}
複製代碼
@CreatePresenter(presenter = [GankPresenter::class])
class KtGankActivity : BaseActivity(), GankContract.IView{
@PresenterVariable
internal var mPresenter: GankPresenter? = null
}
複製代碼
RetrofitUrlManager retrofit動態綁定url
Gloading 深度解耦Android App中全局加載中、加載失敗及空數據視圖
RxPermissions Android runtime permissions powered by RxJava2
圖片有壓縮,能夠下載demo apk進行體驗
demo-debug.apk
3種選擇
一、 git clone https://github.com/wobiancao/sugar.git
implementation project(':sugarlibrary')
二、 implementation 'com.wobiancao:sugarlibrary:{version}'
三、 allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
implementation 'com.github.wobiancao:sugar:{version}'
複製代碼
Retrofit
請求,rxbus等)ImmersionBar
ToastUtils
你能夠不用設置,有默認的RxErroHandler rxjava異常獲取
RetrofitUrlManager
Gloading
你能夠不用設置,有默認的BaseLoadingDialog
你能夠不用設置,有默認的AppConfigureDelegate
public class DemoConfigure extends SugarConfigure {
public DemoConfigure(Application application) {
super(application);
}
@Override
public ResponseErrorListener getErrorResponse() {
return new ResponseErrorListener() {
@Override
public void handleResponseError(Context context, Throwable t) {
LogUtils.i("捕獲異常---" + t.getMessage());
ToastUtils.show("發生異常---" + t.getMessage());
}
};
}
@Override
public int getStatusColor() {
return R.color.colorPrimary;
}
@Override
public AppHttpSetting getHttpSetting() {
return AppHttpSetting
.builder()
.with(mApplication)
//設置初始的baseUrl host
.setBaseUrl(Gank.HOST)
//動態修改baseUrl 具體看https://github.com/JessYanCoding/RetrofitUrlManager
.putDomain(Wan.DOMAN, Wan.HOST)
//是否打印網絡請求日誌 默認否
.setHttpLog(true)
//百度Stetho便可 網絡監測等 默認否
.setHttpMoniter(true)
//設置緩存時間 默認60s
.setCacheMaxTime(65)
//設置鏈接超時 默認20s
.connectTimeout(20)
//設置讀取超時 默認20s
.readTimeout(20)
//設置寫入超時 默認20s
.writeTimeout(20)
//請求header
.addHeaderInterceptor(getHeader())
//添加請求明文公共參數
.addCustomHeaderInterceptor(getCustomHeader())
//token過時等請求成功處理 通常不須要處理
// .addExceptionInterceptor(getExceptionInterceptor())
//其它攔截
// .addInterceptor(xx)
// .addNetworkInterceptor(xxx)
// 配置本身的緩存
// .cache(xx)
//甚至另外寫一套本身的okhttp builder 也行
// .setOkHttpBuilder(xxx)
.build();
}
@Override
public IToastStyle getToastStyle() {
return new ToastStyle();
}
}
複製代碼
DemoApplication
public class DemoApplication extends LibApplication<DemoConfigure> {
@Override
protected void initConfigure() {
mConfigure = new DemoConfigure(this);
}
@Override
protected void init() {
}
}
複製代碼
問題:
咱們使用RetrofitUrlManager
解決了retorfit動態配置baseUrl的問題,可是每一個域名或者說每一個接口返回參數封裝等的可能不統一(這種狀況通常不會出如今公司項目)好比我這個app要展現Gank.io
和WanAndroid
的界面,這樣就是兩個網絡請求封裝,使用sugar能夠快速解決此類問題;SugarRepository
/**
* @author wobiancao
* @date 2019/5/20
* desc :
*/
public class SugarRepository {
/**
* 0 沒loading 1 dialog形式 2page形式
*/
protected final static int LOADING_TYPE_NULL = 0;
/**
* 0 沒loading 1 dialog形式 2page形式
*/
protected final static int LOADING_TYPE_DIALOG = 1;
/**
* 0 沒loading 1 dialog形式 2page形式
*/
protected final static int LOADING_TYPE_PAGE = 2;
protected BaseIView mIView;
public SugarRepository(BaseIView IView) {
mIView = IView;
}
protected Observable addObservable(Observable observable) {
if (mIView == null) {
return null;
}
return customObservable(observable);
}
protected Observable addObservable(Observable observable, int loadingType) {
if (mIView == null) {
return null;
}
return customObservable(observable)
.doOnSubscribe(disposable -> {
if (loadingType > 0) {
if (loadingType == LOADING_TYPE_DIALOG) {
mIView.showDialogLoading();
} else {
mIView.showLoading();
}
}
});
}
private Observable customObservable(Observable observable) {
return observable
.compose(mIView.getProvider().bindToLifecycle())
.retryWhen(new RetryWithDelay(2, 2))
.subscribeOn(Schedulers.io())
.subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.doFinally(() -> {
if (mIView != null) {
mIView.hideDialogLoading();
}
})
.doOnNext(o -> {
LogUtils.e("doOnNext------" + o);
if (mIView != null) {
mIView.showLoadSuccess();
}
})
.doOnError(throwable -> {
LogUtils.e("doOnError------" + throwable);
if (mIView != null) {
mIView.showLoadFailed();
}
});
}
}
複製代碼
addObservable(Observable observable)不會使用任何loading效果, addObservable(Observable observable, int loadingType) loadingType : 0 沒loading 、1 dialog形式 、2 page形式
Repository首先有個契約類,RepositoryContract
xxxModel爲須要增長的一個域名接口,統一配置apiService、請求函數、相應的transformer
/**
* @author wobiancao
* @date 2019-05-21
* desc :
*/
public class RepositoryContract {
/**
* gank.io
*/
public interface GankModel {
Gank getService();
/**
* Transformer 須要處理api返回值包裝的加上便可
* @param <T>
* @return
*/
<T> ObservableTransformer<GirlsResult<T>, T> gankTransformer();
Observable<List<GirlsData>> getFuliDataRepository(String size, String index);
}
/**
* wanandroid
*/
public interface WanModel{
Wan getService();
/**
* Transformer 須要處理api返回值包裝的加上便可
* @param <T>
* @return
*/
<T> ObservableTransformer<WanResult<T>, T> wanTransformer();
Observable<WanData> getWanArticleList(String index);
}
}
複製代碼
/**
* @author wobiancao
* @date 2019/5/20
* desc :
*/
public class GankRepository extends SugarRepository implements RepositoryContract.GankModel {
public GankRepository(BaseIView IView) {
super(IView);
}
@Override
public Gank getService() {
return AppHttpClient.getInstance().initService(Gank.class);
}
@Override
public <T> ObservableTransformer<GirlsResult<T>, T> gankTransformer() {
return upstream -> upstream
.flatMap((Function<GirlsResult<T>, ObservableSource<T>>) tGirlsResult -> {
if (tGirlsResult == null) {
return Observable.error(new HttpException("返回值爲null"));
}
if (!tGirlsResult.error) {
return Observable.just(tGirlsResult.results);
} else {
return Observable.error(new HttpException("接口異常"));
}
});
}
@Override
public Observable<List<GirlsData>> getFuliDataRepository(String size, String index) {
return addObservable(getService()
.getFuliData(size, index)
.compose(gankTransformer()), LOADING_TYPE_PAGE);
}
}
複製代碼
以後會寫相應的Template
⬅️已寫好)WanActivity
舉例WanContract契約
、WanPresenter
好了,完了,結束。WanContract
/**
* @author wobiancao
* @date 2019-05-21
* desc :
*/
public class WanContract {
public interface PView{
void getWanArticleList(String index);
}
public interface IView extends BaseIView {
/**
* 綁定列表數據
* @param data
*/
void bindData(WanData data);
}
}
複製代碼
WanPresenter
/**
* @author wobiancao
* @date 2019-05-21
* desc :
*/
public class WanPresenter extends BasePresenter<WanContract.IView, WanRepository> implements WanContract.PView {
@Override
protected void initRepository() {
mModel = new WanRepository(mView);
}
@Override
public void getWanArticleList(String index) {
mModel.getWanArticleList(index)
.subscribe(new ErrorHandleSubscriber<WanData>(rxErrorHandler) {
@Override
public void onNext(WanData wanData) {
mView.bindData(wanData);
}
});
}
}
複製代碼
WanActivity
/**
* @author wobiancao
* @date 2019-05-21
* desc :
*/
@CreatePresenter(presenter = WanPresenter.class)
public class WanActivity extends BaseActivity<WanPresenter> implements WanContract.IView {
@PresenterVariable
WanPresenter mPresenter;
TextView mInfoView;
Toolbar mToolbar;
@Override
protected int getContentView() {
return R.layout.gank_activity_list;
}
@Override
public void init(Bundle savedInstanceState) {
mInfoView = findViewById(R.id.tv_info);
mToolbar = findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle("WanAndroid");
}
}
@Override
public void loadData() {
mPresenter.getWanArticleList("1");
}
@Override
public void bindData(WanData data) {
String jsonStr = new Gson().toJson(data);
mInfoView.setText(jsonStr);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case android.R.id.home:
finish();
break;
}
return super.onOptionsItemSelected(item);
}
}
複製代碼
支持多個presenter
EasyMvp一個簡單強大且靈活的MVP框架
@CreatePresenter(presenter = WanPresenter.class)
public class WanActivity extends BaseActivity<WanPresenter> implements WanContract.IView
複製代碼
獲取presenter變量兩種方式
一、經過註解
@PresenterVariable
WanPresenter mPresenter;
複製代碼
二、經過getPresenter()函數1.0.1.4
以後不支持
xxActivity extends BaseActivity<xxPresenter>...
xxPresenter getPresenter()
複製代碼
@CreatePresenter(presenter = {xxPresenter1.class, xxPresenter2.class})
xxActivity extends BaseActivity...
@PresenterVariable
xxPresenter1 mPresenter1;
@PresenterVariable
xxPresenter2 mPresenter2;
複製代碼
本庫github地址 sugar 簡單便捷 快速開發Android項目,集合流行框架封裝mvp + rxjava2 + retrofit2 + rxlifecycle2 + arouter...
把兩個文件夾放入{Android Studio installation dir}\plugins\android\lib\templates\activities\
路徑下
重啓Android studio便可使用
Copyright 2019, wobiancao
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
複製代碼