-
Notifications
You must be signed in to change notification settings - Fork 398
Home
XDroidMvp也许是目前最好的mvp框架,至少是使用难度最低、维护成本最小的mvp框架。
使用,仅需四步:
clone 'XDroid'库到本地:
git clone https://github.com/limedroid/XDroidMvp.git
将mvp
作为依赖库,在您的app module 中 添加如下依赖:
compile project(':mvp')
拷贝conf.gradle
到您的项目根目录,并修改项目gradle文件下引入:
apply from: "conf.gradle"
并添加:
allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
}
修改XDroidConf
配置类,主要针对log、cache、router、imageloader。若采用默认配置,此步骤可略过.
简而言之:P充当V和M的中间人,当V中需要M时,才会有P.
XActivity、XFragment、XLazyFragment是对V的封装, XPresent是对P的封装。 可直接继承这些类,简化操作.
适合V中不需要M的情况,如网络api操作、数据缓存等.
此时getP()
会返回null,换而言之,在v中不需要调用getP()
方法
public class NoPActivity extends XActivity{
@Override
public Object newP() {
return null;
}
}
适合绝大多数情况
此时在P中可通过getV()
获取对应的V,
在V中可通过getP()
获取对应的P
V的定义:
public class SinglePActivity extends XActivity<PSingle>{
@Override
public PSingle newP() {
return new PSingle();
}
}
P的定义:
public class PSingle extends XPresent<SinglePActivity>{
}
此种情况也时常出现,和上面一样, 在P中可通过
getV()
获取对应的V, 在V中可通过getP()
获取对应的P
public interface ICommonV extends IView<PMulti>{
void showError(Exception e); //这是示例方法
}
BActivity的定义:
public class BActivity extends XActivity<PMulti> implements ICommonV {
@Override
public void initData(Bundle savedInstanceState) {
getP().loadData();
}
@Override
public int getLayoutId() {
return 0;
}
@Override
public PMulti newP() {
return new PMulti();
}
@Override
public void showError(Exception e) {
}
}
CActivity的定义:
public class CActivity extends XActivity<PMulti> implements ICommonV{
@Override
public void initData(Bundle savedInstanceState) {
getP().loadData();
}
@Override
public int getLayoutId() {
return 0;
}
@Override
public PMulti newP() {
return new PMulti();
}
@Override
public void showError(Exception e) {
}
}
public class PMulti extends XPresent<ICommonV>{
//这是示例方法
public void loadData(){
getV().showError(new IllegalStateException(""));
}
}
在V中调用
getRxPermissions()
即可获取到RxPermissions
实例。
getRxPermissions()
.request(Manifest.permission.CAMERA)
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean granted) {
if (granted){
//TODO 许可
}else{
//TODO 未许可
}
}
});
VDelegate
中放置一些常用的方法,如显示加载中对话框。。。
getvDelegate().toastShort("");
getvDelegate().gone(true,null);
getvDelegate().toastLong("");
...
即只有一个viewType的Adapter,这时只需要继承
SimpleListAdapter
public class AListAdapter extends SimpleListAdapter<String, AListAdapter.ViewHolder> {
public AListAdapter(Context context) {
super(context);
}
@Override
protected ViewHolder newViewHolder(View convertView) {
return new ViewHolder(convertView);
}
@Override
protected int getLayoutId() {
return R.layout.item_single;
}
@Override
protected void convert(ViewHolder holder, String item, int position) {
}
public static class ViewHolder {
public ViewHolder(View convertView) {
KnifeKit.bind(this, convertView);
}
}
}
即具有多个viewType的Adapter,这时只需要继承
XListAdapter
public class CListAdapter extends XListAdapter<String> {
public CListAdapter(Context context) {
super(context);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
String item = data.get(position);
CListAdapter.ViewHolder holder = null;
if (convertView == null) {
convertView = View.inflate(context, R.layout.item_single, null);
holder = new ViewHolder(convertView);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
return convertView;
}
public static class ViewHolder {
public ViewHolder(View convertView) {
KnifeKit.bind(this, convertView);
}
}
}
即具有一个viewType的Adapter,此时可继承
SimpleRecAdapter
public class BRecAdapter extends SimpleRecAdapter<String, BRecAdapter.ViewHolder> {
public BRecAdapter(Context context) {
super(context);
}
@Override
public ViewHolder newViewHolder(View itemView) {
return new ViewHolder(itemView);
}
@Override
public int getLayoutId() {
return R.layout.item_single;
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (getRecItemClick() != null) {
getRecItemClick().onItemClick(position, data.get(position), 0, holder);
}
}
});
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
KnifeKit.bind(this, itemView);
}
}
}
即具有多个viewType的Adapter,此时可继承
RecyclerAdapter
public class DRecAdapter extends RecyclerAdapter<String,DRecAdapter.ViewHolder> {
public DRecAdapter(Context context) {
super(context);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_single, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
KnifeKit.bind(this, itemView);
}
}
}
XRecyclerView & XRecyclerContentLayout & XStateController 的使用详见:
https://github.com/limedroid/ARecyclerView
https://github.com/limedroid/XStateController
//初始化
ILFactory.getLoader().init(context);
//从Asset中加载
ILFactory.getLoader().loadAssets(imageView, assetPath, null);
//从file中加载
ILFactory.getLoader().loadFile(imageView, new File(filePath), null);
//加载网络图片
ILFactory.getLoader().loadNet(imageView, urlPath, null);
//加载网络图片,设置监听
ILFactory.getLoader().loadNet(context, urlPath, null, new LoadCallback() {
@Override
public void onLoadReady(Bitmap bitmap) {
//图片下载成功
}
});
//从res中加载
ILFactory.getLoader().loadResource(imageView, resIds, null);
//清除内存缓存
ILFactory.getLoader().clearMemoryCache(context);
//继续加载
ILFactory.getLoader().resume(context);
//暂停加载
ILFactory.getLoader().pause(context);
//清理磁盘文件缓存
new Thread() {
@Override
public void run() {
super.run();
ILFactory.getLoader().clearDiskCache(context);
}
}.start();
需要注意的是:
clearDiskCache()
必须在线程中调用
扩展加载条件如动画、加载中图片、加载失败图片、缩放方式等,可以通过Options类进行扩展.
ILFactory.getLoader().loadNet(imageView, urlPath,
new ILoader.Options(loadingResId, loadErrorResId).scaleType(ImageView.ScaleType.FIT_CENTER));
框架中内置了Glide的实现,如果需要使用其他图片加载框架,如picasso等,按如下步骤进行:
如果想使用picasso,则可以写一个
PicassoLoader
,病实现ILoader
接口。具体实现可参照GlideLoader
public class GlideLoader implements ILoader{
void init(Context context){}
void loadNet(ImageView target, String url, Options options){}
void loadNet(Context context, String url, Options options, LoadCallback callback{}
void loadResource(ImageView target, int resId, Options options){}
void loadAssets(ImageView target, String assetName, Options options){}
void loadFile(ImageView target, File file, Options options){}
void clearMemoryCache(Context context){}
void clearDiskCache(Context context){}
void resume(Context context){}
void pause(Context context){}
}
public static ILoader getLoader() {
if (loader == null) {
synchronized (ILFactory.class) {
if (loader == null) {
loader = new PicassoLoader();//此次修改为picassoloader
}
}
}
return loader;
}
必要说明:
- 使用框架net部分有一个必要条件:实体需要实现IModel接口
- 支持多个baseUrl,并可对每个url配置自己的provider
- 可配置公共provider
- 核心api类:XApi
使用示例:
Api.getGankService().getGankData(type, PAGE_SIZE, page)
.compose(XApi.<GankResults>getApiTransformer()) //统一异常处理
.compose(XApi.<GankResults>getScheduler()) //线程调度
.compose(getV().<GankResults>bindToLifecycle()) //内存泄漏处理
.subscribe(new ApiSubcriber<GankResults>() {
@Override
protected void onFail(NetError error) {
getV().showError(error);
}
@Override
public void onNext(GankResults gankResults) {
getV().showData(page, gankResults);
}
});
NetProvider是对一个网络请求的基本配置,一个baseUrl对应一个provider,多个baseUrl也可对应一个公共的provider.
public interface NetProvider {
Interceptor[] configInterceptors(); //配置拦截器
void configHttps(OkHttpClient.Builder builder); //配置https
CookieJar configCookie(); //配置cookie
RequestHandler configHandler(); //配置通用请求handler
long configConnectTimeoutMills(); //配置连接超时时长,单位毫秒
long configReadTimeoutMills(); //配置读超时时长,单位毫秒
boolean configLogEnable(); //配置是否打印log
boolean handleError(NetError error); //公共异常处理
}
XApi.registerProvider(provider);
XApi.registerProvider(gankUrl,provider);
- 首先根据baseUrl,获取其对应的provider
- 如果provider为空,则将通用provider赋值给provider
- 若provider为空,则抛出异常
即优先级:局部provider > 公共provider
XApi.getInstance().getRetrofit(API_BASE_URL, true).create(GankService.class);
其他操作,可参照demo。
不带参数的UI跳转
Router.newIntent(context) //context表示当前上下文
.to(EndActivity.class) //to()指定目标context
.launch();
可使用put()方法指定跳转参数
Router.newIntent(context)
.to(EndActivity.class)
.putString("arg_name","xdroid")
.launch();
通过
requestCode()
方法指定请求码
Router.newIntent(context)
.to(EndActivity.class)
.putString("arg_name","xdroid")
.requestCode(100)
.launch();
通过
anim()
指定动画
Router.newIntent(context)
.to(EndActivity.class)
.putString("arg_name","xdroid")
.anim(enterAnim,exitAnim)
.launch();
通过
addFlags()
方法指定flag
Router.newIntent(context)
.to(EndActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.launch();
通过
options()
方法指定场景动画
Router.newIntent(context)
.to(EndActivity.class)
.options(ActivityOptionsCompat.makeBasic())
.launch();
对于事件订阅,框架实现了最简单的rxBus,当然也可以使用EventBus.使用rxBus需要遵循如下步骤:
@Override
public boolean useEventBus() {
return true;
}
如创建一个登录事件LoginEvent
public class LoginEvent implements IBus.IEvent{
@Override
public int getTag() {
return 10; //事件唯一tag
}
}
BusProvider.getBus().toObservable(LoginEvent.class)
.subscribe(new Action1<LoginEvent>() {
@Override
public void call(LoginEvent loginEvent) {
//TODO 事件处理
}
});
BusProvider.getBus().post(new LoginEvent());
XDroid定义了ICache
接口
public interface ICache {
void put(String key, Object value); //存
Object get(String key); //取
void remove(String key); //删除
boolean contains(String key); //检验是否存在
void clear(); //删除所有
}
并实现了DiskCache
、MemoryCache
,其内部分别借助 DiskLruCache
、LruCache
实现。
SharedPref
是对SharedPreferences的封装,包含了一系列的get
&put
方法、remove
等。
推荐实践:创建一个新类,将键名作为常量,并封装对应的put&get静态方法,方便全局使用。如:
public String getUserName(){
return getString(KEY.USER_NAME , null);
}
可以在
XDroidConf
中配置缓存文件名称,默认是config
MemoryCache
内部采用LruCache
实现,是ICache
的实现类。
推荐实践:创建一个新类,将键名作为常量,并封装对应的put&get静态方法,方便全局使用。
DiskCache
内部采用DiskLruCache
实现,是文件缓存方式,其在基本缓存的基础上,增加了有效期,可以用于Api数据缓存。
void put(String key, String value);
void put(String key, String value, long expireMills);
String get(String key);
void remove(String key);
boolean contains(String key);
void clear();
实现了上述方法。
可以在
XDroidConf
中配置缓存目录名称,默认是cache
自定义缓存只需要实现ICache
即可。
Codec
加密工具类囊括了几乎所有常用的加密算法,包括MD5、SHA、AES、DES、RSA等,具体操作可以阅读源码发现,这里不再赘述。
- 框架不再采用常见的堆工具类的方式,而是将所有常用的方法进行分类,聚合为一个类文件,实现了最大程度的精简。
- 工具类中包括Package(包管理)、Dimens(尺寸)、Random(随机数)、File(文件操作)、IO(IO操作)、Date(时间)、NetWork(网络)、Empty(空检测)等几个子分类。
- 工具类中内置了很多很靠谱的实现,如文件的md5等,还有更多彩蛋可以阅读相关源码。
框架对log进行了美化输出,目前支持:
- text
- json
- xml
- throwable
具体的可调用:
XLog.json(json) //格式化json并输出
其他使用类似。
XDroidConf目前支持log、cache、router、imageloader、devMode几个部分的配置。
public static final boolean LOG = true; //配置是否显示log
public static final String LOG_TAG = "XDroid"; //配置log的tag
public static final String CACHE_SP_NAME = "config"; //配置sharedPref的文件名
public static final String CACHE_DISK_DIR = "cache"; //配置缓存文件夹名称
public static final int ROUTER_ANIM_ENTER = Router.RES_NONE; //配置enterAnimation
public static final int ROUTER_ANIM_EXIT = Router.RES_NONE; //配置exitAnimation
public static final int IL_LOADING_RES = ILoader.Options.RES_NONE; //配置图片加载loding占位图
public static final int IL_ERROR_RES = ILoader.Options.RES_NONE; //配置图片加载失败占位图
public static final boolean DEV = true; //配置当前是否是开发阶段
- 1 Mvp篇
- 2 Base篇
- 3 ImageLoader篇
- 4 Net篇
- 5 Router篇
- 6 RxBus篇
- 7 Cache篇
- 8 Kit篇
- 9 Log篇
- 10 XDroidConf篇