| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Collection聚合了项目搭建的一些基本模块,节约开发者时间,协助项目的快速搭建,RecyclerView+Adapter+网络请求+MVP+基本Base,能够满足一个项目的基本实现,框架中暂时还没有把数据库和SharePrefence添加进去,后续会把两者跟网络请求封装在一起的 。
implementation 'com.youngman:collectionlibrary:1.1.5'
compile 'com.youngman:collectionlibrary:1.1.5'
Error:Could not find com.android.support:appcompat-v7:27.0.2. 因为library的Support Repository是27.0.2,可能跟项目有所冲突,如果sdk已经装了27还是会出现同样的错误。 解决办法:在项目根build.gradle中加入 maven { url "https://maven.google.com" }
1.PullToRefreshRecyclerView的使用
2.BaseRecyclerViewAdapter的使用
3.MVP+RxJava+Retrofit的封装使用
4.Base的使用
<com.youngmanster.collectionlibrary.refreshrecyclerview.pulltorefresh.PullToRefreshRecyclerView
android:id="@+id/recycler_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
mRecyclerView.setPullRefreshEnabled(true); mRecyclerView.setLoadMoreEnabled(true);
mRecyclerView.setPullRefreshEnabled(true); mRecyclerView.setLoadMoreEnabled(true); mRecyclerView.setRefreshView(new DefinitionAnimationRefreshHeaderView(getActivity())); mRecyclerView.setLoadMoreView(new DefinitionAnimationLoadMoreView(getActivity()));
/*** * 下拉刷新分为4个状态 */ //下拉的状态(还没到下拉到固定的高度时) public static final int STATE_PULL_DOWN=0;// //下拉到固定高度提示释放刷新的状态 public static final int STATE_RELEASE_REFRESH=1; //刷新状态 public static final int STATE_REFRESHING=2; //刷新完成 public static final int STATE_DONE=3;
/*** * 加载更多分为3个状态 */ //正在加载 public final static int STATE_LOADING = 0; //加载完成 public final static int STATE_COMPLETE = 1; //没有数据 public final static int STATE_NODATA= 2;
在initView()做自定义布局、相关动画的初始化,最后在initView()方法的最后面添加以下代码即可。
//mContainer =LayoutInflater.from(context).inflate(R.layout.layout_default_arrow_refresh, null); //把刷新头部的高度初始化为0 LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); lp.setMargins(0, 0, 0, 0); this.setLayoutParams(lp); this.setPadding(0, 0, 0, 0); addView(mContainer, new LayoutParams(LayoutParams.MATCH_PARENT, 0));//把刷新布局添加进去 setGravity(Gravity.BOTTOM); //测量高度 measure(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT); mMeasuredHeight = getMeasuredHeight();
setRefreshTimeVisible(boolean show)是用来设置是否显示刷新时间控件,在默认刷新样式中通过mRecyclerView.setRefreshTimeVisible(false)即可隐藏刷新时间,如果在自定义的布局中没有这项这个方法就可以忽略。
destroy()是用来关掉改页面时把刷新View的一些动画等释放,防止内存泄漏。
在构造函数中
onStateChangeListener=this;
onStateChange的模板样式
@Override
public void onStateChange(int state) {
//下拉时状态相同不做继续保持原有的状态
if (state == mState) return ;
//根据状态进行动画显示
switch (state){
case STATE_PULL_DOWN://跟随手指下拉的状态
//clearAnim();
//startAnim();
break;
case STATE_RELEASE_REFRESH://下拉释放
break;
case STATE_REFRESHING://正在进行刷新
//clearAnim();
//startAnim();
scrollTo(mMeasuredHeight);//这段代码需要添加
break;
case STATE_DONE://刷新完成
break;
}
mState = state;//状态的更新
}
在initView()做自定义布局、相关动画的初始化,最后在initView()方法的最后面添加以下代码即可。
//mContainer = LayoutInflater.from(context).inflate(R.layout.layout_definition_animation_loading_more, null); addView(mContainer); setGravity(Gravity.CENTER);
destroy()是用来关掉改页面时把刷新View的一些动画等释放,防止内存泄漏。
在setState()进行状态切换后的相关操作逻辑,模板样式:
@Override
public void setState(int state) {
switch (state){
case STATE_LOADING://正在加载
//loadMore_Ll.setVisibility(VISIBLE);
//noDataTv.setVisibility(INVISIBLE);
//animationDrawable= (AnimationDrawable) loadingIv.getDrawable();
//animationDrawable.start();
this.setVisibility(VISIBLE);//这段代码需要添加
break;
case STATE_COMPLETE:
//if(animationDrawable!=null){
// animationDrawable.stop();
//}
this.setVisibility(GONE);//这段代码需要添加
break;
case STATE_NODATA:
//loadMore_Ll.setVisibility(INVISIBLE);
//noDataTv.setVisibility(VISIBLE);
//animationDrawable= (AnimationDrawable) loadingIv.getDrawable();
//animationDrawable.start();
this.setVisibility(VISIBLE);//这段代码需要添加
break;
}
mState = state;//状态的更新
}
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.youngmanster.collectionlibrary.refreshrecyclerview.pulltorefresh.PullToRefreshRecyclerView
android:id="@+id/recycler_rv"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
mRecyclerView.setLoadMoreEnabled(true); mRecyclerView.setLoadMoreView(new DefinitionAnimationLoadMoreView(getActivity())); swl_Refresh.setColorSchemeResources(R.color.colorAccent); swl_Refresh.setOnRefreshListener(this);
由于PullToRefreshRecyclerView的下拉刷新和下拉加载更多完成时会自动刷新Adapter,而SwipeRefreshLayout刷新完成时需要手动进行notifyDataSetChanged刷新适配器。
View emptyView = LayoutInflater.from(getActivity()).inflate(R.layout.layout_empty,null); mRecyclerView.setEmptyView(emptyView);
mRecyclerView.setNoMoreDate(true);
mRecyclerView.setAutoRefresh();
mRecyclerView.isLoading() //是否正在加载更多 mRecyclerView.loadMoreComplete() //加载更多完成 mRecyclerView.isRefreshing() //是否正在刷新 mRecyclerView.refreshComplete(); //刷新数据完成
onRecyclerViewRefresh() onRecyclerViewLoadMore()
@Override
public void onDestroy() {
super.onDestroy();
if(mRecyclerView!=null){
mRecyclerView.destroy();
}
}
在BaseRecyclerViewAdapter中的BaseViewHolder进行布局转化,同时定义了一些比较基本的View操作,使用简单。
public class PullToRecyclerViewAdapter extends BaseRecyclerViewAdapter<String> {
public PullToRecyclerViewAdapter(Context mContext, List<String> mDatas, PullToRefreshRecyclerView pullToRefreshRecyclerView) {
super(mContext, R.layout.item_pull_refresh, mDatas, pullToRefreshRecyclerView);
}
@Override
protected void convert(BaseViewHolder baseViewHolder, String s) {
baseViewHolder.setText(R.id.title,s);
}
}
public BaseRecyclerViewAdapter(Context mContext, int mLayoutResId, List<T> mDatas, PullToRefreshRecyclerView pullToRefreshRecyclerView) {
this.mContext = mContext;
this.mLayoutResId = mLayoutResId;
this.mDatas = mDatas;
this.mRecyclerView=pullToRefreshRecyclerView;
}
public BaseRecyclerViewAdapter(Context mContext, int mLayoutResId, List<T> mDatas) {
this.mContext = mContext;
this.mLayoutResId = mLayoutResId;
this.mDatas = mDatas;
}
itemClickAdapter.setOnItemClickListener(new BaseRecyclerViewAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
showToast(mDatas.get(position).getTitle());
}
});
itemClickAdapter.setOnItemLongClickListener(new BaseRecyclerViewAdapter.onItemLongClickListener() {
@Override
public boolean onItemLongClick(View view, int position) {
showToast("进行长按操作");
return true;
}
});
//事件监听
itemClickAdapter.setOnItemClickListener(this);
itemClickAdapter.setOnItemLongClickListener(this);
//点击实现
@Override
public void onItemClick(View view, int position) {
showToast(mDatas.get(position).getTitle());
}
@Override
public boolean onItemLongClick(View view, int position) {
showToast("进行长按操作");
return true;
}
public class MultipleAdapter extends BaseRecyclerViewMultiItemAdapter<MultiItem> {
private int mHeight;
public MultipleAdapter(Context mContext, List<MultiItem> mDatas) {
super(mContext, mDatas);
mHeight = DisplayUtil.dip2px(mContext, 100);
addItemType(MultiItem.TYPE_TEXT, R.layout.item_main);
addItemType(MultiItem.TYPE_IMG, R.layout.item_img);
addItemType(MultiItem.TYPE_TEXT_IMG, R.layout.item_click);
}
@Override
protected void convert(BaseViewHolder baseViewHolder, MultiItem multiItem) {
switch (baseViewHolder.getItemViewType()) {
case MultiItem.TYPE_TEXT:
baseViewHolder.getView(R.id.card_view).getLayoutParams().height = mHeight;
baseViewHolder.setText(R.id.title, multiItem.getTitle());
break;
case MultiItem.TYPE_IMG:
baseViewHolder.setImageResource(R.id.ivImg, multiItem.getRes());
break;
case MultiItem.TYPE_TEXT_IMG:
baseViewHolder.setImageResource(R.id.ivImg, multiItem.getRes());
baseViewHolder.setText(R.id.titleTv, multiItem.getTitle());
break;
}
}
ItemTouchHelper.Callback callback=new BaseRecycleItemTouchHelper(dragAndDeleteAdapter); ItemTouchHelper itemTouchHelper=new ItemTouchHelper(callback); itemTouchHelper.attachToRecyclerView(mRecyclerView);
@Override
public void onDragAndDeleteFinished() {
mRecyclerView.postDelayed(new Runnable() {
@Override
public void run() {
dragAndDeleteAdapter.notifyDataSetChanged();
showToast("操作完成");
}
},300);
}
RxManager:对Observables 和 Subscribers管理。
RxObservableListener:对结果回调。
RxSchedulers:线程切换。
RxSubscriber:Observer的处理事件。
public class Config {
//是否为BuildConfig.DEBUG,日志输出需要
public static boolean DEBUG;
//网络请求的域名
public static String URL_DOMAIN;
//网络缓存地址
public static String URL_CACHE;
//设置Context
public static Context CONTEXT;
//设置OkHttp的缓存机制的最大缓存时间,默认为一天
public static long MAX_CACHE_SECONDS= 60 * 60 * 24;
//缓存最大的内存,默认为10M
public static long MAX_MEMORY_SIZE=10 * 1024 * 1024;
//设置网络请求json通用解析类
public static Class MClASS;
}
private void config(){
Config.DEBUG= BuildConfig.DEBUG;//这个如果是测试时,日志输出,网络请求相关信息输出
Config.URL_CACHE=AppConfig.URL_CACHE;//OkHttp缓存地址
Config.CONTEXT=this;//这个是必传
Config.MClASS= Result.class;//主要是网络请求通用数据实体类,自定义磁盘缓存需要用到
Config.URL_DOMAIN="http://api.tianapi.com/";//网络请求域名
}
public class Result<T> implements Serializable {
private int code;
private String msg;
private T newslist;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getNewslist() {
return newslist;
}
public void setNewslist(T newslist) {
this.newslist = newslist;
}
}
public interface ApiService {
/**
* 微信精选
* @param url
* @param map
* @return
*/
@GET
Observable<Result<List<WeChatNews>>> getWeChatFeaturedNews(@Url String url, @QueryMap Map<String,Object> map);
}
//通过RetrofitManager.getApiService()可以进行缓存
public class WeChatChinaNewsModel implements WeChatChinaNewsContract.Model {
@Override
public Observable<Result<List<WeChatNews>>> loadChinaNews(int page, int num) {
Map<String,Object> map= ApiClient.getRequiredBaseParam();
map.put("page",page);
map.put("num",num);
return RetrofitManager.getApiService(ApiService.class)
.getWeChatChinaNews(ApiUrl.URL_WETCHAT_CHINA_NEWS,map);
}
}
//通过RetrofitManager.getApiService()配合RequestManager.loadOnlyNetWork
public class WeChatChinaNewsPresenter extends WeChatChinaNewsContract.Presenter {
@Override
public void requestChinaNews(int page, int num) {
rxManager.addObserver(RequestManager.loadOnlyNetWork(mModel.loadChinaNews(page, num),
new RxObservableListener<Result<List<WeChatNews>>>(mView) {
@Override
public void onNext(Result<List<WeChatNews>> result) {
mView.refreshUI(result.getNewslist());
}
}));
}
}
//通过RetrofitManager.getNoCacheApiService()去掉OkHttp缓存
public class WeChatChinaNewsDefinitionModel implements WeChatChinaNewsContract.Model {
@Override
public Observable<Result<List<WeChatNews>>> loadChinaNews(int page, int num) {
Map<String,Object> map= ApiClient.getRequiredBaseParam();
map.put("page",page);
map.put("num",num);
return RetrofitManager.getNoCacheApiService(ApiService.class)
.getWeChatChinaNews(ApiUrl.URL_WETCHAT_CHINA_NEWS,map);
}
}
//RetrofitManager.getNoCacheApiService()
public class WeChatChinaNewsDefinitionPresenter extends WeChatChinaNewsContract.Presenter {
@Override
public void requestChinaNews(int page, int num) {
String filePath = AppConfig.STORAGE_DIR + "wechat/china/";
String fileName = "limttime.t";
rxManager.addObserver(RequestManager.loadFormDiskResultListLimitTime(
mModel.loadChinaNews(page, num), new RxObservableListener<Result<List<WeChatNews>>>(mView) {
@Override
public void onNext(Result<List<WeChatNews>> result) {
mView.refreshUI(result.getNewslist());
}
}, WeChatNews.class, 1, filePath, fileName));
}
}
void onNext(T result); void onComplete(); void onError(NetWorkCodeException.ResponseThrowable e);
protected RxObservableListener(BaseView view){
this.mView = view;
}
protected RxObservableListener(BaseView view, String errorMsg){
this.mView = view;
this.mErrorMsg = errorMsg;
}
public interface WeChatChinaNewsContract {
interface Model extends BaseModel{
Observable<Result<List<WeChatNews>>> loadChinaNews(int page, int num);
}
interface View extends BaseView{
void refreshUI(List<WeChatNews> weChatNews);
}
abstract class Presenter extends BasePresenter<Model,View>{
public abstract void requestChinaNews(int page,int num);
}
}
public class WeChatChinaNewsPresenter extends WeChatChinaNewsContract.Presenter {
@Override
public void requestChinaNews(int page, int num) {
rxManager.addObserver(RequestManager.loadOnlyNetWork(mModel.loadChinaNews(page, num),
new RxObservableListener<Result<List<WeChatNews>>>(mView) {
@Override
public void onNext(Result<List<WeChatNews>> result) {
mView.refreshUI(result.getNewslist());
}
}));
}
}
public class WeChatChinaNewsModel implements WeChatChinaNewsContract.Model {
@Override
public Observable<Result<List<WeChatNews>>> loadChinaNews(int page, int num) {
Map<String,Object> map= ApiClient.getRequiredBaseParam();
map.put("page",page);
map.put("num",num);
return RetrofitManager.getApiService(ApiService.class)
.getWeChatChinaNews(ApiUrl.URL_WETCHAT_CHINA_NEWS,map);
}
}
public class FragmentChinaNews extends BaseFragment<WeChatChinaNewsModel,WeChatChinaNewsPresenter> implements WeChatChinaNewsContract.View{
@Override
public void init() {
}
@Override
public void requestData() {
((WeChatChinaNewsPresenter)mPresenter).requestChinaNews(pageSize,PAGE_SIZE);
}
@Override
public void refreshUI(List<WeChatNews> newsList) {
}
@Override
public void onError(String errorMsg) {
}
}
IBaseActivity:主要提供了一个页面的基本方法、处理了MVP之间的关联、使用者可以直接继承该类使用、也可以继承该类实现扩展。
IBaseActivity<T extends BaseModel, E extends BasePresenter>已经进行MVP之间的传递和关联。
处理好页面销毁之后Observables 和 Subscribers的解绑。
getLayoutId()设置布局、init()数据初始化、requestData()请求数据,执行顺序已经在IBaseActivity做好处理。
可以继承IBaseActivity进行扩展。
public abstract class BaseActivity<T extends BaseModel,E extends BasePresenter> extends IBaseActivity{ private Unbinder unbinder;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
unbinder= ButterKnife.bind(this);
}
}
@Override
public void requestData() {
((WeChatFeaturedPresenter) mPresenter).requestFeaturedNews(pageSize, PAGE_SIZE);
}
IBaseFragment:主要提供一个页面的基本方法,处理了MVP之间的关联,该类已经加入了懒人加载的控制方式、使用者可以直接继承该类使用、也可以继承该类实现扩展。
IBaseFragment<T extends BaseModel,E extends BasePresenter>已经进行MVP之间的传递和关联。
处理好页面销毁之后Observables 和 Subscribers的解绑。
加入了懒人加载方式,只有页面显示才会调用requestData()请求数据,并只会调用一次。
getLayoutId()设置布局、init()数据初始化、requestData()请求数据,执行顺序已经在IBaseFragment做好处理。
可以继承IBaseFragment进行扩展。
public abstract class BaseFragment<T extends BaseModel,E extends BasePresenter> extends IBaseFragment {
private Unbinder unbinder;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
unbinder= ButterKnife.bind(this,mainView);
return mainView;
}
}
@Override
public void requestData() {
((WeChatChinaNewsPresenter)mPresenter).requestChinaNews(pageSize,PAGE_SIZE);
}
//不显示 public static final int STATE_NO_DATA = 0; //正在加载 public static final int STATE_LOADING = 1; //空数据 public static final int STATE_EMPTY = 2; //没有网络 public static final int STATE_DISCONNECT=3;
<?xml version="1.0" encoding="utf-8"?> <com.youngmanster.collectionlibrary.base.StateView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerInParent="true" android:id="@+id/state_view"> </com.youngmanster.collectionlibrary.base.StateView >
<include layout="@layout/layout_state"/>
stateView.showViewByState(StateView.STATE_LOADING); stateView.showViewByState(StateView.STATE_EMPTY); stateView.showViewByState(StateView.STATE_NO_DATA); stateView.showViewByState(StateView.STATE_DISCONNECT);
app:emptyText=""//设置空数据的文字提示 app:emptyImage=""//设置空数据显示的图片 app:disConnectImage=""//设置无网络的显示图片 app:disConnectText=""//设置无网络的文字提示 app:loadingText=""//设置loading的文字提示 app:loadingViewAnimation=""//设置loading的动画文件,只是ImageView app:tipTextColor=""//设置文字显示颜色 app:tipTextSize=""//设置文字的大小
// 项目的必须权限,没有这些权限会影响项目的正常运行
private static final String[] PERMISSIONS = new String[]{
Manifest.permission.READ_SMS,
Manifest.permission.RECEIVE_WAP_PUSH,
};
PermissionManager permissionManager=PermissionManager.with(this). //必须权限 setNecessaryPermissions(PERMISSIONS); //通过以下语句进行请求 permissionManager.requestPermissions();
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == PermissionManager.PERMISSION_REQUEST_CODE) {//PERMISSION_REQUEST_CODE为请求权限的请求值
//有必须权限选择了禁止
if (permissionManager.getShouldShowRequestPermissionsCode() == PermissionManager.EXIST_NECESSARY_PERMISSIONS_PROHIBTED) {
showToast("可以在这里设置重新跳出权限请求提示框");
} //有必须权限选择了禁止不提醒
else if (permissionManager.getShouldShowRequestPermissionsCode() == PermissionManager.EXIST_NECESSARY_PERMISSIONS_PROHIBTED_NOT_REMIND) {
showToast("可以在这里弹出提示框提示去应用设置页开启权限");
permissionManager.startAppSettings();
}
}
}
| Back | FazBrowse Home | New Git URL |