bindToLife() {
return this.bindToLifecycle();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case android.R.id.home:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
finishAfterTransition();
} else {
finish();
}
break;
}
return true;
}
final SupportActivityDelegate mDelegate = new SupportActivityDelegate(this);
@Override
public SupportActivityDelegate getSupportDelegate() {
return mDelegate;
}
/**
* Perform some extra transactions.
* 额外的事务:自定义Tag,添加SharedElement动画,操作非回退栈Fragment
*/
@Override
public ExtraTransaction extraTransaction() {
return mDelegate.extraTransaction();
}
@Override
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDelegate.onPostCreate(savedInstanceState);
}
/**
* Note: return mDelegate.dispatchTouchEvent(ev) || super.dispatchTouchEvent(ev);
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return mDelegate.dispatchTouchEvent(ev) || super.dispatchTouchEvent(ev);
}
/**
* 不建议复写该方法,请使用 {@link #onBackPressedSupport} 代替
*/
@Override
final public void onBackPressed() {
mDelegate.onBackPressed();
}
/**
* 该方法回调时机为,Activity回退栈内Fragment的数量 小于等于1 时,默认finish Activity
* 请尽量复写该方法,避免复写onBackPress(),以保证SupportFragment内的onBackPressedSupport()回退事件正常执行
*/
@Override
public void onBackPressedSupport() {
mDelegate.onBackPressedSupport();
}
/**
* 获取设置的全局动画 copy
*
* @return FragmentAnimator
*/
@Override
public FragmentAnimator getFragmentAnimator() {
return mDelegate.getFragmentAnimator();
}
/**
* Set all fragments animation.
* 设置Fragment内的全局动画
*/
@Override
public void setFragmentAnimator(FragmentAnimator fragmentAnimator) {
mDelegate.setFragmentAnimator(fragmentAnimator);
}
/**
* Set all fragments animation.
* 构建Fragment转场动画
*
* 如果是在Activity内实现,则构建的是Activity内所有Fragment的转场动画,
* 如果是在Fragment内实现,则构建的是该Fragment的转场动画,此时优先级 > Activity的onCreateFragmentAnimator()
*
* @return FragmentAnimator对象
*/
@Override
public FragmentAnimator onCreateFragmentAnimator() {
return mDelegate.onCreateFragmentAnimator();
}
/**
* Causes the Runnable r to be added to the action queue.
*
* The runnable will be run after all the previous action has been run.
*
* 前面的事务全部执行后 执行该Action
*/
@Override
public void post(Runnable runnable) {
mDelegate.post(runnable);
}
protected void setToolbarTitle(String title) {
getSupportActionBar().setTitle(title);
}
/**
* 设置加载数据结果
*
* @param baseQuickAdapter
* @param refreshLayout
* @param list
* @param loadType
*/
protected void setLoadDataResult(BaseQuickAdapter baseQuickAdapter, SwipeRefreshLayout refreshLayout, List list, @LoadType.checker int loadType) {
switch (loadType) {
case LoadType.TYPE_REFRESH_SUCCESS:
baseQuickAdapter.setNewData(list);
refreshLayout.setRefreshing(false);
break;
case LoadType.TYPE_REFRESH_ERROR:
refreshLayout.setRefreshing(false);
break;
case LoadType.TYPE_LOAD_MORE_SUCCESS:
if (list != null) baseQuickAdapter.addData(list);
break;
case LoadType.TYPE_LOAD_MORE_ERROR:
baseQuickAdapter.loadMoreFail();
break;
}
if (list == null || list.isEmpty() || list.size() < Constant.PAGE_SIZE) {
baseQuickAdapter.loadMoreEnd(false);
} else {
baseQuickAdapter.loadMoreComplete();
}
}
// 选择性拓展其他方法
public void loadRootFragment(int containerId, @NonNull ISupportFragment toFragment) {
mDelegate.loadRootFragment(containerId, toFragment);
}
public void start(ISupportFragment toFragment) {
mDelegate.start(toFragment);
}
/**
* @param launchMode Same as Activity's LaunchMode.
*/
public void start(ISupportFragment toFragment, @ISupportFragment.LaunchMode int launchMode) {
mDelegate.start(toFragment, launchMode);
}
/**
* It is recommended to use {@link SupportFragment#startWithPopTo(ISupportFragment, Class, boolean)}.
*
* @see #popTo(Class, boolean)
* +
* @see #start(ISupportFragment)
*/
public void startWithPopTo(ISupportFragment toFragment, Class> targetFragmentClass, boolean includeTargetFragment) {
mDelegate.startWithPopTo(toFragment, targetFragmentClass, includeTargetFragment);
}
/**
* Pop the fragment.
*/
public void pop() {
mDelegate.pop();
}
/**
* Pop the last fragment transition from the manager's fragment
* back stack.
*/
public void popTo(Class> targetFragmentClass, boolean includeTargetFragment) {
mDelegate.popTo(targetFragmentClass, includeTargetFragment);
}
/**
* If you want to begin another FragmentTransaction immediately after popTo(), use this method.
* 如果你想在出栈后, 立刻进行FragmentTransaction操作,请使用该方法
*/
public void popTo(Class> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable) {
mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable);
}
public void popTo(Class> targetFragmentClass, boolean includeTargetFragment, Runnable afterPopTransactionRunnable, int popAnim) {
mDelegate.popTo(targetFragmentClass, includeTargetFragment, afterPopTransactionRunnable, popAnim);
}
/**
* 得到位于栈顶Fragment
*/
public ISupportFragment getTopFragment() {
return SupportHelper.getTopFragment(getSupportFragmentManager());
}
/**
* 获取栈内的fragment对象
*/
public T findFragment(Class fragmentClass) {
return SupportHelper.findFragment(getSupportFragmentManager(), fragmentClass);
}
/**
* 加载多个同级根Fragment,类似Wechat, QQ主页的场景
*/
public void loadMultipleRootFragment(int containerId, int showPosition, ISupportFragment... toFragments) {
mDelegate.loadMultipleRootFragment(containerId, showPosition, toFragments);
}
/**
* show一个Fragment,hide其他同栈所有Fragment
* 使用该方法时,要确保同级栈内无多余的Fragment,(只有通过loadMultipleRootFragment()载入的Fragment)
*
* 建议使用更明确的{@link #showHideFragment(ISupportFragment, ISupportFragment)}
*
* @param showFragment 需要show的Fragment
*/
public void showHideFragment(ISupportFragment showFragment) {
mDelegate.showHideFragment(showFragment);
}
/**
* show一个Fragment,hide一个Fragment ; 主要用于类似微信主页那种 切换tab的情况
*/
public void showHideFragment(ISupportFragment showFragment, ISupportFragment hideFragment) {
mDelegate.showHideFragment(showFragment, hideFragment);
}
/**
* 初始化ActivityComponent
*/
private void initActivityComponent() {
mActivityComponent = DaggerActivityComponent.builder()
.applicationComponent(((App) getApplication()).getApplicationComponent())
.activityModule(new ActivityModule(this))
.build();
}
/**
* 初始化toolbar
*/
private void initToolBar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
if (mToolbar == null) {
throw new NullPointerException("toolbar can not be null");
}
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(showHomeAsUp());
/**toolbar除掉阴影*/
getSupportActionBar().setElevation(0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mToolbar.setElevation(0);
}
}
/**
* 贴上view
*/
private void attachView() {
if (mPresenter != null) {
mPresenter.attachView(this);
}
}
/**
* 分离view
*/
private void detachView() {
if (mPresenter != null) {
mPresenter.detachView();
}
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/base/BaseContract.java
================================================
package com.lw.wanandroid.base;
import com.trello.rxlifecycle2.LifecycleTransformer;
/**
* desc:
* author: Will .
* date: 2017/9/2 .
*/
public interface BaseContract {
interface BasePresenter {
void attachView(T view);
void detachView();
}
interface BaseView {
//显示进度中
void showLoading();
//隐藏进度
void hideLoading();
//显示请求成功
void showSuccess(String message);
//失败重试
void showFaild(String message);
//显示当前网络不可用
void showNoNet();
//重试
void onRetry();
/**
* 绑定生命周期
*
* @param
* @return
*/
LifecycleTransformer bindToLife();
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/base/BaseFragment.java
================================================
package com.lw.wanandroid.base;
import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import com.alibaba.android.arouter.launcher.ARouter;
import com.blankj.utilcode.util.NetworkUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.lw.wanandroid.R;
import com.lw.wanandroid.constant.Constant;
import com.lw.wanandroid.constant.LoadType;
import com.lw.wanandroid.di.component.DaggerFragmentComponent;
import com.lw.wanandroid.di.component.FragmentComponent;
import com.lw.wanandroid.di.module.FragmentModule;
import com.trello.rxlifecycle2.LifecycleTransformer;
import com.trello.rxlifecycle2.components.support.RxFragment;
import java.util.List;
import javax.inject.Inject;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import me.yokeyword.fragmentation.ExtraTransaction;
import me.yokeyword.fragmentation.ISupportFragment;
import me.yokeyword.fragmentation.SupportFragmentDelegate;
import me.yokeyword.fragmentation.SupportHelper;
import me.yokeyword.fragmentation.anim.FragmentAnimator;
/**
* Created by lw on 2018/1/18.
*/
public abstract class BaseFragment extends RxFragment implements ISupportFragment, BaseContract.BaseView {
private static final String STATE_SAVE_IS_HIDDEN = "STATE_SAVE_IS_HIDDEN";
@Nullable
@Inject
protected T mPresenter;
protected FragmentComponent mFragmentComponent;
private Unbinder unbinder;
private View mRootView, mErrorView, mEmptyView;
protected abstract int getLayoutId();
protected abstract void initInjector();
protected abstract void initView(View view);
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDelegate.onCreate(savedInstanceState);
initFragmentComponent();
ARouter.getInstance().inject(this);
initInjector();
attachView();
if (!NetworkUtils.isConnected()) showNoNet();
if (savedInstanceState != null) {
boolean isSupportHidden = savedInstanceState.getBoolean(STATE_SAVE_IS_HIDDEN);
FragmentTransaction ft = getFragmentManager().beginTransaction();
if (isSupportHidden) {
ft.hide(this);
} else {
ft.show(this);
}
ft.commit();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
mDelegate.onSaveInstanceState(outState);
outState.putBoolean(STATE_SAVE_IS_HIDDEN, isHidden());
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
inflaterView(inflater, container);
unbinder = ButterKnife.bind(this, mRootView);
initView(mRootView);
return mRootView;
}
@Override
public void onDestroy() {
super.onDestroy();
mDelegate.onDestroy();
unbinder.unbind();
detachView();
}
@Override
public void showLoading() {
ToastUtils.showShort("showLoading");
}
@Override
public void hideLoading() {
ToastUtils.showShort("hideLoading");
}
@Override
public void showSuccess(String successMsg) {
ToastUtils.showShort(successMsg);
}
@Override
public void showFaild(String errorMsg) {
ToastUtils.showShort(errorMsg);
}
@Override
public void showNoNet() {
ToastUtils.showShort(R.string.no_network_connection);
}
@Override
public void onRetry() {
ToastUtils.showShort("onRetry");
}
@Override
public LifecycleTransformer bindToLife() {
return this.bindToLifecycle();
}
/**
* 设置加载数据结果
*
* @param baseQuickAdapter
* @param refreshLayout
* @param list
* @param loadType
*/
protected void setLoadDataResult(BaseQuickAdapter baseQuickAdapter, SwipeRefreshLayout refreshLayout, List list, @LoadType.checker int loadType) {
switch (loadType) {
case LoadType.TYPE_REFRESH_SUCCESS:
baseQuickAdapter.setNewData(list);
refreshLayout.setRefreshing(false);
break;
case LoadType.TYPE_REFRESH_ERROR:
refreshLayout.setRefreshing(false);
break;
case LoadType.TYPE_LOAD_MORE_SUCCESS:
if (list != null) baseQuickAdapter.addData(list);
break;
case LoadType.TYPE_LOAD_MORE_ERROR:
baseQuickAdapter.loadMoreFail();
break;
}
if (list == null || list.isEmpty() || list.size() < Constant.PAGE_SIZE) {
baseQuickAdapter.loadMoreEnd(false);
} else {
baseQuickAdapter.loadMoreComplete();
}
}
/**
* 初始化FragmentComponent
*/
private void initFragmentComponent() {
mFragmentComponent = DaggerFragmentComponent.builder()
.applicationComponent(((App) getActivity().getApplication()).getApplicationComponent())
.fragmentModule(new FragmentModule(this))
.build();
}
/**
* 贴上view
*/
private void attachView() {
if (mPresenter != null) {
mPresenter.attachView(this);
}
}
/**
* 分离view
*/
private void detachView() {
if (mPresenter != null) {
mPresenter.detachView();
}
}
/**
* 设置View
*
* @param inflater
* @param container
*/
private void inflaterView(LayoutInflater inflater, @Nullable ViewGroup container) {
if (mRootView == null) {
mRootView = inflater.inflate(getLayoutId(), container, false);
}
}
final SupportFragmentDelegate mDelegate = new SupportFragmentDelegate(this);
protected FragmentActivity _mActivity;
@Override
public SupportFragmentDelegate getSupportDelegate() {
return mDelegate;
}
/**
* Perform some extra transactions.
* 额外的事务:自定义Tag,添加SharedElement动画,操作非回退栈Fragment
*/
@Override
public ExtraTransaction extraTransaction() {
return mDelegate.extraTransaction();
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
mDelegate.onAttach(activity);
_mActivity = mDelegate.getActivity();
}
@Override
public Animation onCreateAnimation(int transit, boolean enter, int nextAnim) {
return mDelegate.onCreateAnimation(transit, enter, nextAnim);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mDelegate.onActivityCreated(savedInstanceState);
}
@Override
public void onResume() {
super.onResume();
mDelegate.onResume();
}
@Override
public void onPause() {
super.onPause();
mDelegate.onPause();
}
@Override
public void onDestroyView() {
mDelegate.onDestroyView();
super.onDestroyView();
}
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
mDelegate.onHiddenChanged(hidden);
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
mDelegate.setUserVisibleHint(isVisibleToUser);
}
/**
* Causes the Runnable r to be added to the action queue.
*
* The runnable will be run after all the previous action has been run.
*
* 前面的事务全部执行后 执行该Action
*
* @deprecated Use {@link #post(Runnable)} instead.
*/
@Deprecated
@Override
public void enqueueAction(Runnable runnable) {
mDelegate.enqueueAction(runnable);
}
/**
* Causes the Runnable r to be added to the action queue.
*
* The runnable will be run after all the previous action has been run.
*
* 前面的事务全部执行后 执行该Action
*/
@Override
public void post(Runnable runnable) {
mDelegate.post(runnable);
}
/**
* Called when the enter-animation end.
* 入栈动画 结束时,回调
*/
@Override
public void onEnterAnimationEnd(Bundle savedInstanceState) {
mDelegate.onEnterAnimationEnd(savedInstanceState);
}
/**
* Lazy initial,Called when fragment is first called.
*
* 同级下的 懒加载 + ViewPager下的懒加载 的结合回调方法
*/
@Override
public void onLazyInitView(@Nullable Bundle savedInstanceState) {
mDelegate.onLazyInitView(savedInstanceState);
}
/**
* Called when the fragment is visible.
* 当Fragment对用户可见时回调
*
* Is the combination of [onHiddenChanged() + onResume()/onPause() + setUserVisibleHint()]
*/
@Override
public void onSupportVisible() {
mDelegate.onSupportVisible();
}
/**
* Called when the fragment is invivible.
*
* Is the combination of [onHiddenChanged() + onResume()/onPause() + setUserVisibleHint()]
*/
@Override
public void onSupportInvisible() {
mDelegate.onSupportInvisible();
}
/**
* Return true if the fragment has been supportVisible.
*/
@Override
final public boolean isSupportVisible() {
return mDelegate.isSupportVisible();
}
/**
* Set fragment animation with a higher priority than the ISupportActivity
* 设定当前Fragmemt动画,优先级比在SupportActivity里高
*/
@Override
public FragmentAnimator onCreateFragmentAnimator() {
return mDelegate.onCreateFragmentAnimator();
}
/**
* 获取设置的全局动画 copy
*
* @return FragmentAnimator
*/
@Override
public FragmentAnimator getFragmentAnimator() {
return mDelegate.getFragmentAnimator();
}
/**
* 设置Fragment内的全局动画
*/
@Override
public void setFragmentAnimator(FragmentAnimator fragmentAnimator) {
mDelegate.setFragmentAnimator(fragmentAnimator);
}
/**
* 按返回键触发,前提是SupportActivity的onBackPressed()方法能被调用
*
* @return false则继续向上传递, true则消费掉该事件
*/
@Override
public boolean onBackPressedSupport() {
return mDelegate.onBackPressedSupport();
}
/**
* 类似
*
* Similar to
*
* @see #startForResult(ISupportFragment, int)
*/
@Override
public void setFragmentResult(int resultCode, Bundle bundle) {
mDelegate.setFragmentResult(resultCode, bundle);
}
/**
* 类似
*
* Similar to
*
* @see #startForResult(ISupportFragment, int)
*/
@Override
public void onFragmentResult(int requestCode, int resultCode, Bundle data) {
mDelegate.onFragmentResult(requestCode, resultCode, data);
}
/**
* 在start(TargetFragment,LaunchMode)时,启动模式为SingleTask/SingleTop, 回调TargetFragment的该方法
* 类似
*
* Similar to
*
* @param args putNewBundle(Bundle newBundle)
* @see #start(ISupportFragment, int)
*/
@Override
public void onNewBundle(Bundle args) {
mDelegate.onNewBundle(args);
}
/**
* 添加NewBundle,用于启动模式为SingleTask/SingleTop时
*
* @see #start(ISupportFragment, int)
*/
@Override
public void putNewBundle(Bundle newBundle) {
mDelegate.putNewBundle(newBundle);
}
/****************************************以下为可选方法(Optional methods)******************************************************/
// 自定制Support时,可移除不必要的方法
/**
* 隐藏软键盘
*/
protected void hideSoftInput() {
mDelegate.hideSoftInput();
}
/**
* 显示软键盘,调用该方法后,会在onPause时自动隐藏软键盘
*/
protected void showSoftInput(final View view) {
mDelegate.showSoftInput(view);
}
/**
* 加载根Fragment, 即Activity内的第一个Fragment 或 Fragment内的第一个子Fragment
*
* @param containerId 容器id
* @param toFragment 目标Fragment
*/
public void loadRootFragment(int containerId, ISupportFragment toFragment) {
mDelegate.loadRootFragment(containerId, toFragment);
}
public void loadRootFragment(int containerId, ISupportFragment toFragment, boolean addToBackStack, boolean allowAnim) {
mDelegate.loadRootFragment(containerId, toFragment, addToBackStack, allowAnim);
}
public void start(ISupportFragment toFragment) {
mDelegate.start(toFragment);
}
/**
* @param launchMode Similar to Activity's LaunchMode.
*/
public void start(final ISupportFragment toFragment, @LaunchMode int launchMode) {
mDelegate.start(toFragment, launchMode);
}
/**
* Launch an fragment for which you would like a result when it poped.
*/
public void startForResult(ISupportFragment toFragment, int requestCode) {
mDelegate.startForResult(toFragment, requestCode);
}
/**
* Start the target Fragment and pop itself
*/
public void startWithPop(ISupportFragment toFragment) {
mDelegate.startWithPop(toFragment);
}
/**
* @see #popTo(Class, boolean)
* +
* @see #start(ISupportFragment)
*/
public void startWithPopTo(ISupportFragment toFragment, Class> targetFragmentClass, boolean includeTargetFragment) {
mDelegate.startWithPopTo(toFragment, targetFragmentClass, includeTargetFragment);
}
public void replaceFragment(ISupportFragment toFragment, boolean addToBackStack) {
mDelegate.replaceFragment(toFragment, addToBackStack);
}
public void pop() {
mDelegate.pop();
}
/**
* Pop the last fragment transition from the manager's fragment
* back stack.
*
* 出栈到目标fragment
*
* @param targetFragmentClass 目标fragment
* @param includeTargetFragment 是否包含该fragment
*/
public void popTo(Class> targetFragmentClass, boolean includeTargetFragment) {
mDelegate.popTo(targetFragmentClass, includeTargetFragment);
}
/**
* 获取栈内的fragment对象
*/
public T findChildFragment(Class fragmentClass) {
return SupportHelper.findFragment(getChildFragmentManager(), fragmentClass);
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/base/BasePresenter.java
================================================
package com.lw.wanandroid.base;
/**
* desc:
* author: Will .
* date: 2017/9/2 .
*/
public class BasePresenter implements BaseContract.BasePresenter {
protected T mView;
@Override
public void attachView(T view) {
this.mView = view;
}
@Override
public void detachView() {
if (mView != null) {
mView = null;
}
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/bean/Article.java
================================================
package com.lw.wanandroid.bean;
import java.util.List;
/**
* Created by lw on 2018/1/18.
*/
public class Article {
private int offset;
private int size;
private int total;
private int pageCount;
private int curPage;
private boolean over;
private List datas;
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public int getPageCount() {
return pageCount;
}
public void setPageCount(int pageCount) {
this.pageCount = pageCount;
}
public int getCurPage() {
return curPage;
}
public void setCurPage(int curPage) {
this.curPage = curPage;
}
public boolean isOver() {
return over;
}
public void setOver(boolean over) {
this.over = over;
}
public List getDatas() {
return datas;
}
public void setDatas(List datas) {
this.datas = datas;
}
public static class DatasBean {
/**
* id : 1578
* title : 这些 Drawable 的小技巧,你都了解吗?
* chapterId : 168
* chapterName : Drawable
* envelopePic : null
* link : https://juejin.im/post/5a28b2d0f265da431c703153
* author : 承香墨影
* origin : null
* publishTime : 1512660849000
* zan : null
* desc : null
* visible : 1
* niceDate : 2017-12-07
* courseId : 13
* collect : false
*/
private int id;
private String title;
private int chapterId;
private String chapterName;
private String envelopePic;
private String link;
private String author;
private String origin;
private long publishTime;
private String zan;
private String desc;
private int visible;
private String niceDate;
private int courseId;
private boolean collect;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getChapterId() {
return chapterId;
}
public void setChapterId(int chapterId) {
this.chapterId = chapterId;
}
public String getChapterName() {
return chapterName;
}
public void setChapterName(String chapterName) {
this.chapterName = chapterName;
}
public String getEnvelopePic() {
return envelopePic;
}
public void setEnvelopePic(String envelopePic) {
this.envelopePic = envelopePic;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
public long getPublishTime() {
return publishTime;
}
public void setPublishTime(long publishTime) {
this.publishTime = publishTime;
}
public String getZan() {
return zan;
}
public void setZan(String zan) {
this.zan = zan;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public String getNiceDate() {
return niceDate;
}
public void setNiceDate(String niceDate) {
this.niceDate = niceDate;
}
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
public boolean isCollect() {
return collect;
}
public void setCollect(boolean collect) {
this.collect = collect;
}
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/bean/Banner.java
================================================
package com.lw.wanandroid.bean;
/**
* Created by lw on 2018/1/19.
*/
public class Banner {
private int id;
private String url;
private String imagePath;
private String title;
private String desc;
private int isVisible;
private int order;
private int type;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getImagePath() {
return imagePath;
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public int getIsVisible() {
return isVisible;
}
public void setIsVisible(int isVisible) {
this.isVisible = isVisible;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/bean/DataResponse.java
================================================
package com.lw.wanandroid.bean;
/**
* Created by lw on 2018/1/19.
*/
public class DataResponse {
private int errorCode;
private Object errorMsg;
private T data;
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public Object getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(Object errorMsg) {
this.errorMsg = errorMsg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/bean/Friend.java
================================================
package com.lw.wanandroid.bean;
/**
* Created by lw on 2018/1/23.
*/
public class Friend {
private int id;
private String name;
private String link;
private int visible;
private int order;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/bean/HotKey.java
================================================
package com.lw.wanandroid.bean;
/**
* Created by lw on 2018/1/23.
*/
public class HotKey {
private int id;
private String name;
private String link;
private int visible;
private int order;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/bean/KnowledgeSystem.java
================================================
package com.lw.wanandroid.bean;
import android.content.Context;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.facade.service.SerializationService;
import com.lw.wanandroid.utils.GsonUtils;
import java.lang.reflect.Type;
import java.util.List;
/**
* Created by lw on 2018/1/22.
*/
@Route(path = "/service/json")
public class KnowledgeSystem implements SerializationService {
private int id;
private String name;
private int courseId;
private int parentChapterId;
private int order;
private int visible;
private List children;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
public int getParentChapterId() {
return parentChapterId;
}
public void setParentChapterId(int parentChapterId) {
this.parentChapterId = parentChapterId;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public List getChildren() {
return children;
}
public void setChildren(List children) {
this.children = children;
}
@Override
public T json2Object(String input, Class clazz) {
return GsonUtils.convertObj(input, clazz);
}
@Override
public String object2Json(Object instance) {
return GsonUtils.toJson(instance);
}
@Override
public T parseObject(String input, Type clazz) {
return GsonUtils.convertObj(input, clazz);
}
@Override
public void init(Context context) {
}
public static class ChildrenBean implements SerializationService {
/**
* id : 60
* name : Android Studio相关
* courseId : 13
* parentChapterId : 150
* order : 1000
* visible : 1
* children : []
*/
private int id;
private String name;
private int courseId;
private int parentChapterId;
private int order;
private int visible;
private List children;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCourseId() {
return courseId;
}
public void setCourseId(int courseId) {
this.courseId = courseId;
}
public int getParentChapterId() {
return parentChapterId;
}
public void setParentChapterId(int parentChapterId) {
this.parentChapterId = parentChapterId;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
public int getVisible() {
return visible;
}
public void setVisible(int visible) {
this.visible = visible;
}
public List> getChildren() {
return children;
}
public void setChildren(List children) {
this.children = children;
}
@Override
public T json2Object(String input, Class clazz) {
return GsonUtils.convertObj(input, clazz);
}
@Override
public String object2Json(Object instance) {
return GsonUtils.toJson(instance);
}
@Override
public T parseObject(String input, Type clazz) {
return GsonUtils.convertObj(input, clazz);
}
@Override
public void init(Context context) {
}
public ChildrenBean(int id, String name) {
this.id = id;
this.name = name;
}
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/bean/User.java
================================================
package com.lw.wanandroid.bean;
import java.util.List;
/**
* Created by lw on 2018/1/24.
*/
public class User {
private int id;
private String username;
private String password;
private String icon;
private int type;
private List collectIds;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public List getCollectIds() {
return collectIds;
}
public void setCollectIds(List collectIds) {
this.collectIds = collectIds;
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/constant/Constant.java
================================================
package com.lw.wanandroid.constant;
/**
* Created by lw on 2018/1/19.
*/
public class Constant {
public static final String REQUEST_BASE_URL = "http://wanandroid.com/";
/**
* 每页数量
*/
public static final int PAGE_SIZE = 20;
/**
* url key
*/
public static final String CONTENT_URL_KEY = "url";
/**
* title key
*/
public static final String CONTENT_TITLE_KEY = "title";
/**
* id key
*/
public static final String CONTENT_ID_KEY = "id";
/**
* cid key
*/
public static final String CONTENT_CID_KEY = "cid";
public static final String CONTENT_AUTHOR_KEY = "author";
/**
* childrenData key
*/
public static final String CONTENT_CHILDREN_DATA_KEY = "childrenData";
/**
* hotFriend key
*/
public static final String CONTENT_HOT_FRIEND_KEY = "hotFriend";
/**
* hot key
*/
public static final String CONTENT_HOT_KEY = "hotKey";
/**
* hot key
*/
public static final String CONTENT_HOT_NAME_KEY = "hotNameKey";
public static final String SAVE_USER_LOGIN_KEY = "user/login";
public static final String SAVE_USER_REGISTER_KEY = "user/register";
public static final String SET_COOKIE_KEY = "set-cookie";
public static final String SHARED_NAME = "_preferences";
public static final String USERNAME_KEY = "username";
public static final String PASSWORD_KEY = "password";
public static final String LOGIN_KEY = "login";
public static final String USER_KEY = "user";
public static final String BANNER_KEY = "banner";
public static final String ARTICLE_KEY = "article";
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/constant/LoadType.java
================================================
package com.lw.wanandroid.constant;
import android.support.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Created by lw on 2017-04-06.
*/
public class LoadType {
public static final int TYPE_REFRESH_SUCCESS = 1;
public static final int TYPE_REFRESH_ERROR = 2;
public static final int TYPE_LOAD_MORE_SUCCESS = 3;
public static final int TYPE_LOAD_MORE_ERROR = 4;
@IntDef({TYPE_REFRESH_SUCCESS, TYPE_REFRESH_ERROR, TYPE_LOAD_MORE_SUCCESS, TYPE_LOAD_MORE_ERROR})
@Retention(RetentionPolicy.SOURCE)
public @interface checker {
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/db/AppDatabase.java
================================================
package com.lw.wanandroid.db;
import com.raizlabs.android.dbflow.annotation.Database;
/**
* Created by lw on 2018/2/2.
*/
@Database(name = AppDatabase.NAME, version = AppDatabase.VERSION)
public class AppDatabase {
public static final String NAME = "WanAndroid-db";
public static final int VERSION = 1;
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/db/HistoryModel.java
================================================
package com.lw.wanandroid.db;
import com.raizlabs.android.dbflow.annotation.Column;
import com.raizlabs.android.dbflow.annotation.PrimaryKey;
import com.raizlabs.android.dbflow.annotation.Table;
import com.raizlabs.android.dbflow.structure.BaseModel;
import java.util.Date;
/**
* Created by lw on 2018/2/2.
*/
@Table(database = AppDatabase.class)
public class HistoryModel extends BaseModel {
@PrimaryKey(autoincrement = true)
private long id;
@Column
private String name;
@Column
private Date date;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/component/ActivityComponent.java
================================================
package com.lw.wanandroid.di.component;
import android.app.Activity;
import android.content.Context;
import com.lw.wanandroid.di.module.ActivityModule;
import com.lw.wanandroid.di.scope.ContextLife;
import com.lw.wanandroid.di.scope.PerActivity;
import com.lw.wanandroid.ui.article.ArticleContentActivity;
import com.lw.wanandroid.ui.hotsearch.SearchActivity;
import com.lw.wanandroid.ui.my.LoginActivity;
import com.lw.wanandroid.ui.my.MyBookmarkActivity;
import com.lw.wanandroid.ui.my.MyCollectionActivity;
import dagger.Component;
/**
* Created by lw on 2017/1/19.
*/
@PerActivity
@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {
@ContextLife("Activity")
Context getActivityContext();
@ContextLife("Application")
Context getApplicationContext();
Activity getActivity();
void inject(SearchActivity activity);
void inject(LoginActivity activity);
void inject(ArticleContentActivity activity);
void inject(MyCollectionActivity activity);
void inject(MyBookmarkActivity activity);
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/component/ApplicationComponent.java
================================================
package com.lw.wanandroid.di.component;
import android.content.Context;
import com.lw.wanandroid.di.module.ApplicationModule;
import com.lw.wanandroid.di.scope.ContextLife;
import com.lw.wanandroid.di.scope.PerApp;
import dagger.Component;
/**
* Created by lw on 2017/1/19.
*/
@PerApp
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
@ContextLife("Application")
Context getApplication();
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/component/FragmentComponent.java
================================================
package com.lw.wanandroid.di.component;
import android.app.Activity;
import android.content.Context;
import com.lw.wanandroid.di.module.FragmentModule;
import com.lw.wanandroid.di.scope.ContextLife;
import com.lw.wanandroid.di.scope.PerFragment;
import com.lw.wanandroid.ui.article.ArticleListFragment;
import com.lw.wanandroid.ui.home.HomeFragment;
import com.lw.wanandroid.ui.hotsearch.HotFragment;
import com.lw.wanandroid.ui.knowledgesystem.KnowledgeSystemFragment;
import com.lw.wanandroid.ui.my.MyFragment;
import dagger.Component;
/**
* Created by lw on 2017/1/19.
*/
@PerFragment
@Component(dependencies = ApplicationComponent.class, modules = FragmentModule.class)
public interface FragmentComponent {
@ContextLife("Activity")
Context getActivityContext();
@ContextLife("Application")
Context getApplicationContext();
Activity getActivity();
void inject(HomeFragment fragment);
void inject(KnowledgeSystemFragment fragment);
void inject(MyFragment fragment);
void inject(ArticleListFragment fragment);
void inject(HotFragment fragment);
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/component/ServiceComponent.java
================================================
package com.lw.wanandroid.di.component;
import android.content.Context;
import com.lw.wanandroid.di.module.ServiceModule;
import com.lw.wanandroid.di.scope.ContextLife;
import com.lw.wanandroid.di.scope.PerService;
import dagger.Component;
/**
* Created by lw on 2017/1/19.
*/
@PerService
@Component(dependencies = ApplicationComponent.class, modules = ServiceModule.class)
public interface ServiceComponent {
@ContextLife("Service")
Context getServiceContext();
@ContextLife("Application")
Context getApplicationContext();
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/module/ActivityModule.java
================================================
package com.lw.wanandroid.di.module;
import android.app.Activity;
import android.content.Context;
import com.lw.wanandroid.di.scope.ContextLife;
import com.lw.wanandroid.di.scope.PerActivity;
import dagger.Module;
import dagger.Provides;
/**
* Created by lw on 2017/1/19.
*/
@Module
public class ActivityModule {
private Activity mActivity;
public ActivityModule(Activity activity) {
mActivity = activity;
}
@Provides
@PerActivity
@ContextLife("Activity")
public Context provideActivityContext() {
return mActivity;
}
@Provides
@PerActivity
public Activity provideActivity() {
return mActivity;
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/module/ApplicationModule.java
================================================
package com.lw.wanandroid.di.module;
import android.content.Context;
import com.lw.wanandroid.base.App;
import com.lw.wanandroid.di.scope.ContextLife;
import com.lw.wanandroid.di.scope.PerApp;
import dagger.Module;
import dagger.Provides;
/**
* Created by lw on 2017/1/19.
*/
@Module
public class ApplicationModule {
private App mApplication;
public ApplicationModule(App application) {
mApplication = application;
}
@Provides
@PerApp
@ContextLife("Application")
public Context provideApplicationContext() {
return mApplication.getApplicationContext();
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/module/FragmentModule.java
================================================
package com.lw.wanandroid.di.module;
import android.app.Activity;
import android.content.Context;
import android.support.v4.app.Fragment;
import com.lw.wanandroid.di.scope.ContextLife;
import com.lw.wanandroid.di.scope.PerFragment;
import dagger.Module;
import dagger.Provides;
/**
* Created by lw on 2017/1/19.
*/
@Module
public class FragmentModule {
private Fragment mFragment;
public FragmentModule(Fragment fragment) {
mFragment = fragment;
}
@Provides
@PerFragment
@ContextLife("Activity")
public Context provideActivityContext() {
return mFragment.getActivity();
}
@Provides
@PerFragment
public Activity provideActivity() {
return mFragment.getActivity();
}
@Provides
@PerFragment
public Fragment provideFragment() {
return mFragment;
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/module/ServiceModule.java
================================================
package com.lw.wanandroid.di.module;
import android.app.Service;
import android.content.Context;
import com.lw.wanandroid.di.scope.ContextLife;
import com.lw.wanandroid.di.scope.PerService;
import dagger.Module;
import dagger.Provides;
/**
* Created by lw on 2017/1/19.
*/
@Module
public class ServiceModule {
private Service mService;
public ServiceModule(Service service) {
mService = service;
}
@Provides
@PerService
@ContextLife("Service")
public Context ProvideServiceContext() {
return mService;
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/scope/ContextLife.java
================================================
package com.lw.wanandroid.di.scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Qualifier;
/**
* Created by lw on 2017/1/19.
*/
@Qualifier
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface ContextLife {
String value() default "Application";
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/scope/PerActivity.java
================================================
package com.lw.wanandroid.di.scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Scope;
/**
* Created by lw on 2017/1/19.
*/
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/scope/PerApp.java
================================================
package com.lw.wanandroid.di.scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Scope;
/**
* Created by lw on 2017/1/19.
*/
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerApp {
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/scope/PerFragment.java
================================================
package com.lw.wanandroid.di.scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Scope;
/**
* Created by lw on 2017/1/19.
*/
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerFragment {
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/di/scope/PerService.java
================================================
package com.lw.wanandroid.di.scope;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import javax.inject.Scope;
/**
* Created by lw on 2017/1/19.
*/
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerService {
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/event/LoginEvent.java
================================================
package com.lw.wanandroid.event;
/**
* Created by lw on 2018/1/25.
*/
public class LoginEvent {
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/net/ApiService.java
================================================
package com.lw.wanandroid.net;
import com.lw.wanandroid.bean.Article;
import com.lw.wanandroid.bean.Banner;
import com.lw.wanandroid.bean.DataResponse;
import com.lw.wanandroid.bean.Friend;
import com.lw.wanandroid.bean.HotKey;
import com.lw.wanandroid.bean.KnowledgeSystem;
import com.lw.wanandroid.bean.User;
import java.util.List;
import io.reactivex.Observable;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Path;
import retrofit2.http.Query;
/**
* Created by lw on 2018/1/23.
*/
public interface ApiService {
/**
* 首页数据
* http://www.wanandroid.com/article/list/0/json
*
* @param page page
*/
@GET("/article/list/{page}/json")
Observable> getHomeArticles(@Path("page") int page);
/**
* 首页Banner
*
* @return BannerResponse
*/
@GET("/banner/json")
Observable>> getHomeBanners();
/**
* 知识体系
* http://www.wanandroid.com/tree/json
*
* @return BannerResponse
*/
@GET("/tree/json")
Observable>> getKnowledgeSystems();
/**
* 知识体系下的文章
* http://www.wanandroid.com/article/list/0/json?cid=168
*
* @param page page
* @param cid cid
*/
@GET("/article/list/{page}/json")
Observable> getKnowledgeSystemArticles(@Path("page") int page, @Query("cid") int cid);
/**
* 常用网站
* http://www.wanandroid.com/friend/json
*/
@GET("/friend/json")
Observable>> getHotFriends();
/**
* 大家都在搜
* http://www.wanandroid.com/hotkey/json
*/
@GET("/hotkey/json")
Observable>> getHotKeys();
/**
* 搜索
* http://www.wanandroid.com/article/query/0/json
*
* @param page page
* @param k POST search key
*/
@POST("/article/query/{page}/json")
@FormUrlEncoded
Observable> getSearchArticles(@Path("page") int page, @Field("k") String k);
/**
* 登录
*
* @param username username
* @param password password
* @return Deferred
*/
@POST("/user/login")
@FormUrlEncoded
Observable> login(@Field("username") String username, @Field("password") String password);
/**
* 注册
*
* @param username username
* @param password password
* @param repassword repassword
* @return Deferred
*/
@POST("/user/register")
@FormUrlEncoded
Observable> register(@Field("username") String username, @Field("password") String password, @Field("repassword") String repassword);
/**
* 收藏文章
*
* @param id id
* @return Deferred
*/
@POST("/lg/collect/{id}/json")
Observable addCollectArticle(@Path("id") int id);
/**
* 收藏站外文章
*
* @param title title
* @param author author
* @param link link
* @return Deferred
*/
@POST("/lg/collect/add/json")
@FormUrlEncoded
Observable addCollectOutsideArticle(@Field("title") String title, @Field("author") String author, @Field("link") String link);
/**
* 删除收藏文章
*
* @param id id
* @param originId -1
* @return Deferred
*/
@POST("/lg/uncollect/{id}/json")
@FormUrlEncoded
Observable removeCollectArticle(@Path("id") int id, @Field("originId") int originId);
/**
* 获取自己收藏的文章列表
*
* @param page page
* @return Deferred
*/
@GET("/lg/collect/list/{page}/json")
Observable> getCollectArticles(@Path("page") int page);
/**
* 我的书签
* http://www.wanandroid.com/lg/collect/usertools/json
*/
@GET("/lg/collect/usertools/json")
Observable>> getBookmarks();
/**
* 编辑书签
* http://www.wanandroid.com/lg/collect/updatetool/json
*/
@POST("/lg/collect/usertools/json")
@FormUrlEncoded
Observable editBookmark(@Field("id") int id, @Field("name") String name, @Field("link") String link);
/**
* 删除书签
* http://www.wanandroid.com/lg/collect/deletetool/json
*/
@POST("/lg/collect/usertools/json")
@FormUrlEncoded
Observable delBookmark(@Field("id") int id);
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/net/CookiesManager.java
================================================
package com.lw.wanandroid.net;
import java.util.List;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
/**
* Created by lw on 2018/1/25.
*/
public class CookiesManager implements CookieJar {
private static final PersistentCookieStore cookieStore = new PersistentCookieStore();
@Override
public void saveFromResponse(HttpUrl url, List cookies) {
if (cookies != null && cookies.size() > 0) {
for (Cookie item : cookies) {
cookieStore.add(url, item);
}
}
}
@Override
public List loadForRequest(HttpUrl url) {
List cookies = cookieStore.get(url);
return cookies;
}
/**
* 清除所有cookie
*/
public static void clearAllCookies() {
cookieStore.removeAll();
}
/**
* 清除指定cookie
*
* @param url
* @param cookie
* @return
*/
public static boolean clearCookies(HttpUrl url, Cookie cookie) {
return cookieStore.remove(url, cookie);
}
/**
* 获取cookies
*
* @return
*/
public static List getCookies() {
return cookieStore.getCookies();
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/net/OkHttpCookies.java
================================================
package com.lw.wanandroid.net;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import okhttp3.Cookie;
/**
* Created by lw on 2018/1/25.
*/
public class OkHttpCookies implements Serializable {
private transient final Cookie cookies;
private transient Cookie clientCookies;
public OkHttpCookies(Cookie cookies) {
this.cookies = cookies;
}
public Cookie getCookies() {
Cookie bestCookies = cookies;
if (clientCookies != null) {
bestCookies = clientCookies;
}
return bestCookies;
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeObject(cookies.name());
out.writeObject(cookies.value());
out.writeLong(cookies.expiresAt());
out.writeObject(cookies.domain());
out.writeObject(cookies.path());
out.writeBoolean(cookies.secure());
out.writeBoolean(cookies.httpOnly());
out.writeBoolean(cookies.hostOnly());
out.writeBoolean(cookies.persistent());
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
String name = (String) in.readObject();
String value = (String) in.readObject();
long expiresAt = in.readLong();
String domain = (String) in.readObject();
String path = (String) in.readObject();
boolean secure = in.readBoolean();
boolean httpOnly = in.readBoolean();
boolean hostOnly = in.readBoolean();
boolean persistent = in.readBoolean();
Cookie.Builder builder = new Cookie.Builder();
builder = builder.name(name);
builder = builder.value(value);
builder = builder.expiresAt(expiresAt);
builder = hostOnly ? builder.hostOnlyDomain(domain) : builder.domain(domain);
builder = builder.path(path);
builder = secure ? builder.secure() : builder;
builder = httpOnly ? builder.httpOnly() : builder;
clientCookies = builder.build();
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/net/PersistentCookieStore.java
================================================
package com.lw.wanandroid.net;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.Log;
import com.lw.wanandroid.base.App;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import okhttp3.Cookie;
import okhttp3.HttpUrl;
/**
* Created by lw on 2018/1/25.
*/
public class PersistentCookieStore {
private static final String LOG_TAG = "PersistentCookieStore";
private static final String COOKIE_PREFS = "Cookies_Prefs";
private final Map> cookies;
private final SharedPreferences cookiePrefs;
public PersistentCookieStore() {
cookiePrefs = App.getAppContext().getSharedPreferences(COOKIE_PREFS, 0);
cookies = new HashMap<>();
//将持久化的cookies缓存到内存中 即map cookies
Map prefsMap = cookiePrefs.getAll();
for (Map.Entry entry : prefsMap.entrySet()) {
String[] cookieNames = TextUtils.split((String) entry.getValue(), ",");
for (String name : cookieNames) {
String encodedCookie = cookiePrefs.getString(name, null);
if (encodedCookie != null) {
Cookie decodedCookie = decodeCookie(encodedCookie);
if (decodedCookie != null) {
if (!cookies.containsKey(entry.getKey())) {
cookies.put(entry.getKey(), new ConcurrentHashMap());
}
cookies.get(entry.getKey()).put(name, decodedCookie);
}
}
}
}
}
protected String getCookieToken(Cookie cookie) {
return cookie.name() + "@" + cookie.domain();
}
public void add(HttpUrl url, Cookie cookie) {
String name = getCookieToken(cookie);
//将cookies缓存到内存中 如果缓存过期 就重置此cookie
if (!cookie.persistent()) {
if (!cookies.containsKey(url.host())) {
cookies.put(url.host(), new ConcurrentHashMap());
}
cookies.get(url.host()).put(name, cookie);
} else {
if (cookies.containsKey(url.host())) {
cookies.get(url.host()).remove(name);
}
}
//讲cookies持久化到本地
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));
prefsWriter.putString(name, encodeCookie(new OkHttpCookies(cookie)));
prefsWriter.apply();
}
public List get(HttpUrl url) {
ArrayList ret = new ArrayList<>();
if (cookies.containsKey(url.host()))
ret.addAll(cookies.get(url.host()).values());
return ret;
}
public boolean removeAll() {
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
prefsWriter.clear();
prefsWriter.apply();
cookies.clear();
return true;
}
public boolean remove(HttpUrl url, Cookie cookie) {
String name = getCookieToken(cookie);
if (cookies.containsKey(url.host()) && cookies.get(url.host()).containsKey(name)) {
cookies.get(url.host()).remove(name);
SharedPreferences.Editor prefsWriter = cookiePrefs.edit();
if (cookiePrefs.contains(name)) {
prefsWriter.remove(name);
}
prefsWriter.putString(url.host(), TextUtils.join(",", cookies.get(url.host()).keySet()));
prefsWriter.apply();
return true;
} else {
return false;
}
}
public List getCookies() {
ArrayList ret = new ArrayList<>();
for (String key : cookies.keySet())
ret.addAll(cookies.get(key).values());
return ret;
}
/**
* cookies 序列化成 string
*
* @param cookie 要序列化的cookie
* @return 序列化之后的string
*/
protected String encodeCookie(OkHttpCookies cookie) {
if (cookie == null)
return null;
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
ObjectOutputStream outputStream = new ObjectOutputStream(os);
outputStream.writeObject(cookie);
} catch (IOException e) {
Log.d(LOG_TAG, "IOException in encodeCookie", e);
return null;
}
return byteArrayToHexString(os.toByteArray());
}
/**
* 将字符串反序列化成cookies
*
* @param cookieString cookies string
* @return cookie object
*/
protected Cookie decodeCookie(String cookieString) {
byte[] bytes = hexStringToByteArray(cookieString);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
Cookie cookie = null;
try {
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
cookie = ((OkHttpCookies) objectInputStream.readObject()).getCookies();
} catch (IOException e) {
Log.d(LOG_TAG, "IOException in decodeCookie", e);
} catch (ClassNotFoundException e) {
Log.d(LOG_TAG, "ClassNotFoundException in decodeCookie", e);
}
return cookie;
}
/**
* 二进制数组转十六进制字符串
*
* @param bytes byte array to be converted
* @return string containing hex values
*/
protected String byteArrayToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 2);
for (byte element : bytes) {
int v = element & 0xff;
if (v < 16) {
sb.append('0');
}
sb.append(Integer.toHexString(v));
}
return sb.toString().toUpperCase(Locale.US);
}
/**
* 十六进制字符串转二进制数组
*
* @param hexString string of hex-encoded values
* @return decoded byte array
*/
protected byte[] hexStringToByteArray(String hexString) {
int len = hexString.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16));
}
return data;
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/net/RetrofitManager.java
================================================
package com.lw.wanandroid.net;
import com.blankj.utilcode.util.NetworkUtils;
import com.lw.wanandroid.base.App;
import com.lw.wanandroid.constant.Constant;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.Cache;
import okhttp3.CacheControl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
/**
* Created by lw on 2017-04-01.
*/
public class RetrofitManager {
private static long CONNECT_TIMEOUT = 60L;
private static long READ_TIMEOUT = 10L;
private static long WRITE_TIMEOUT = 10L;
//设缓存有效期为1天
private static final long CACHE_STALE_SEC = 60 * 60 * 24 * 1;
//查询缓存的Cache-Control设置,为if-only-cache时只查询缓存而不会请求服务器,max-stale可以配合设置缓存失效时间
public static final String CACHE_CONTROL_CACHE = "only-if-cached, max-stale=" + CACHE_STALE_SEC;
//查询网络的Cache-Control设置
//(假如请求了服务器并在a时刻返回响应结果,则在max-age规定的秒数内,浏览器将不会发送对应的请求到服务器,数据由缓存直接返回)
public static final String CACHE_CONTROL_NETWORK = "Cache-Control: public, max-age=10";
// 避免出现 HTTP 403 Forbidden,参考:http://stackoverflow.com/questions/13670692/403-forbidden-with-java-but-not-web-browser
private static final String AVOID_HTTP403_FORBIDDEN = "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11";
private static volatile OkHttpClient mOkHttpClient;
/**
* 云端响应头拦截器,用来配置缓存策略
* Dangerous interceptor that rewrites the server's cache-control header.
*/
private static final Interceptor mRewriteCacheControlInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!NetworkUtils.isConnected()) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response originalResponse = chain.proceed(request);
if (NetworkUtils.isConnected()) {
//有网的时候读接口上的@Headers里的配置,可以在这里进行统一的设置
String cacheControl = request.cacheControl().toString();
return originalResponse.newBuilder()
.header("Cache-Control", cacheControl)
.removeHeader("Pragma")
.build();
} else {
return originalResponse.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + CACHE_CONTROL_CACHE)
.removeHeader("Pragma")
.build();
}
}
};
/**
* 日志拦截器
*/
private static final Interceptor mLoggingInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
return response;
}
};
/**
* 获取OkHttpClient实例
*
* @return
*/
private static OkHttpClient getOkHttpClient() {
if (mOkHttpClient == null) {
synchronized (RetrofitManager.class) {
Cache cache = new Cache(new File(App.getAppContext().getCacheDir(), "HttpCache"), 1024 * 1024 * 100);
if (mOkHttpClient == null) {
mOkHttpClient = new OkHttpClient.Builder().cache(cache)
.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
.addInterceptor(mRewriteCacheControlInterceptor)
.addInterceptor(mLoggingInterceptor)
.cookieJar(new CookiesManager())
.build();
}
}
}
return mOkHttpClient;
}
/**
* 获取Service
*
* @param clazz
* @param
* @return
*/
public static T create(Class clazz) {
Retrofit retrofit = new Retrofit.Builder().baseUrl(Constant.REQUEST_BASE_URL)
.client(getOkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();
return retrofit.create(clazz);
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/ui/article/ArticleAdapter.java
================================================
package com.lw.wanandroid.ui.article;
import android.text.Html;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.lw.wanandroid.R;
import com.lw.wanandroid.bean.Article;
import javax.inject.Inject;
/**
* Created by lw on 2018/1/19.
*/
public class ArticleAdapter extends BaseQuickAdapter {
private boolean mChapterNameVisible = true;
private boolean mIsMyColection = false;
@Inject
public ArticleAdapter() {
super(R.layout.item_article, null);
}
@Override
protected void convert(BaseViewHolder helper, Article.DatasBean item) {
helper.setText(R.id.tvAuthor, item.getAuthor());
helper.setText(R.id.tvNiceDate, item.getNiceDate());
helper.setText(R.id.tvTitle, Html.fromHtml(item.getTitle()));
helper.setText(R.id.tvChapterName, item.getChapterName());
if (mIsMyColection) item.setCollect(mIsMyColection);
helper.setImageResource(R.id.ivCollect, item.isCollect()
? R.drawable.ic_action_like : R.drawable.ic_action_no_like);
helper.addOnClickListener(R.id.tvChapterName);
helper.addOnClickListener(R.id.ivCollect);
helper.setVisible(R.id.tvChapterName, mChapterNameVisible);
}
public void setChapterNameVisible(boolean chapterNameVisible) {
this.mChapterNameVisible = chapterNameVisible;
}
public void isMyColection(boolean isMyColection) {
this.mIsMyColection = isMyColection;
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/ui/article/ArticleContentActivity.java
================================================
package com.lw.wanandroid.ui.article;
import android.content.Intent;
import android.net.Uri;
import android.view.Menu;
import android.view.MenuItem;
import android.webkit.WebView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import com.alibaba.android.arouter.facade.annotation.Autowired;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import com.just.agentweb.AgentWeb;
import com.just.agentweb.ChromeClientCallbackManager;
import com.lw.wanandroid.R;
import com.lw.wanandroid.base.BaseActivity;
import com.lw.wanandroid.constant.Constant;
import butterknife.BindView;
/**
* Created by lw on 2018/1/22.
*/
@Route(path = "/article/ArticleContentActivity")
public class ArticleContentActivity extends BaseActivity implements ArticleContentContract.View {
@Autowired
public int id;
@Autowired
public String url;
@Autowired
public String title;
@Autowired
public String author;
@BindView(R.id.webContent)
FrameLayout mWebContent;
@Override
protected int getLayoutId() {
return R.layout.activity_article_content;
}
@Override
protected void initInjector() {
mActivityComponent.inject(this);
}
@Override
protected void initView() {
AgentWeb.with(this)//传入Activity or Fragment
.setAgentWebParent(mWebContent, new LinearLayout.LayoutParams(-1, -1))//传入AgentWeb 的父控件 ,如果父控件为 RelativeLayout , 那么第二参数需要传入 RelativeLayout.LayoutParams ,第一个参数和第二个参数应该对应。
.useDefaultIndicator()// 使用默认进度条
.defaultProgressBarColor() // 使用默认进度条颜色
.setReceivedTitleCallback(mReceivedTitleCallback) //设置 Web 页面的 title 回调
.createAgentWeb()//
.ready()
.go(url);
}
@Override
protected boolean showHomeAsUp() {
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_content, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menuShare) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_article_url, getString(R.string.app_name), title, url));
intent.setType("text/plain");
startActivity(intent);
} else if (item.getItemId() == R.id.menuLike) {
if (id == 0) mPresenter.collectOutsideArticle(title, author, url);
else mPresenter.collectArticle(id);
} else if (item.getItemId() == R.id.menuBrowser) {
Intent intent = new Intent("android.intent.action.VIEW");
intent.setData(Uri.parse(url));
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}
public static void start(int id, String url, String title, String author) {
ARouter.getInstance().build("/article/ArticleContentActivity")
.withInt(Constant.CONTENT_ID_KEY, id)
.withString(Constant.CONTENT_URL_KEY, url)
.withString(Constant.CONTENT_TITLE_KEY, title)
.withString(Constant.CONTENT_AUTHOR_KEY, author)
.navigation();
}
private ChromeClientCallbackManager.ReceivedTitleCallback mReceivedTitleCallback = new ChromeClientCallbackManager.ReceivedTitleCallback() {
@Override
public void onReceivedTitle(WebView view, String title) {
setToolbarTitle(title);
}
};
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/ui/article/ArticleContentContract.java
================================================
package com.lw.wanandroid.ui.article;
import com.lw.wanandroid.base.BaseContract;
import retrofit2.http.Field;
/**
* Created by lw on 2018/1/25.
*/
public interface ArticleContentContract {
interface View extends BaseContract.BaseView {
}
interface Presenter extends BaseContract.BasePresenter {
void collectArticle(int id);
void collectOutsideArticle(String title, String author, String link);
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/ui/article/ArticleContentPresenter.java
================================================
package com.lw.wanandroid.ui.article;
import com.blankj.utilcode.util.SPUtils;
import com.lw.wanandroid.R;
import com.lw.wanandroid.base.App;
import com.lw.wanandroid.base.BasePresenter;
import com.lw.wanandroid.bean.DataResponse;
import com.lw.wanandroid.constant.Constant;
import com.lw.wanandroid.net.ApiService;
import com.lw.wanandroid.net.RetrofitManager;
import com.lw.wanandroid.ui.my.LoginActivity;
import com.lw.wanandroid.utils.RxSchedulers;
import javax.inject.Inject;
import io.reactivex.functions.Consumer;
/**
* Created by lw on 2018/1/25.
*/
public class ArticleContentPresenter extends BasePresenter implements ArticleContentContract.Presenter {
@Inject
public ArticleContentPresenter() {
}
@Override
public void collectArticle(int id) {
if (SPUtils.getInstance(Constant.SHARED_NAME).getBoolean(Constant.LOGIN_KEY)) {
RetrofitManager.create(ApiService.class)
.addCollectArticle(id)
.compose(RxSchedulers.applySchedulers())
.compose(mView.bindToLife())
.subscribe(new Consumer() {
@Override
public void accept(DataResponse response) throws Exception {
if (response.getErrorCode() == 0) {
mView.showSuccess(App.getAppContext().getString(R.string.collection_success));
} else {
mView.showFaild(App.getAppContext().getString(R.string.collection_failed, response.getErrorMsg()));
}
}
}, new Consumer() {
@Override
public void accept(Throwable throwable) throws Exception {
mView.showFaild(throwable.getMessage());
}
});
} else {
LoginActivity.start();
}
}
@Override
public void collectOutsideArticle(String title, String author, String link) {
if (SPUtils.getInstance(Constant.SHARED_NAME).getBoolean(Constant.LOGIN_KEY)) {
RetrofitManager.create(ApiService.class)
.addCollectOutsideArticle(title, author, link)
.compose(RxSchedulers.applySchedulers())
.compose(mView.bindToLife())
.subscribe(new Consumer() {
@Override
public void accept(DataResponse response) throws Exception {
if (response.getErrorCode() == 0) {
mView.showSuccess(App.getAppContext().getString(R.string.collection_success));
} else {
mView.showFaild(App.getAppContext().getString(R.string.collection_failed, response.getErrorMsg()));
}
}
}, new Consumer() {
@Override
public void accept(Throwable throwable) throws Exception {
mView.showFaild(throwable.getMessage());
}
});
} else {
LoginActivity.start();
}
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/ui/article/ArticleListContract.java
================================================
package com.lw.wanandroid.ui.article;
import com.lw.wanandroid.base.BaseContract;
import com.lw.wanandroid.bean.Article;
import com.lw.wanandroid.constant.LoadType;
/**
* Created by lw on 2018/1/23.
*/
public interface ArticleListContract {
interface View extends BaseContract.BaseView {
void setKnowledgeSystemArticles(Article article, @LoadType.checker int loadType);
void collectArticleSuccess(int position, Article.DatasBean bean);
}
interface Presenter extends BaseContract.BasePresenter {
void loadKnowledgeSystemArticles(int cid);
void refresh();
void loadMore();
void collectArticle(int position, Article.DatasBean bean);
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/ui/article/ArticleListFragment.java
================================================
package com.lw.wanandroid.ui.article;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import com.alibaba.android.arouter.facade.annotation.Autowired;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.lw.wanandroid.R;
import com.lw.wanandroid.base.BaseFragment;
import com.lw.wanandroid.bean.Article;
import com.lw.wanandroid.event.LoginEvent;
import com.lw.wanandroid.utils.RxBus;
import javax.inject.Inject;
import butterknife.BindView;
import io.reactivex.functions.Consumer;
/**
* Created by lw on 2018/1/22.
*/
@Route(path = "/article/ArticleListFragment")
public class ArticleListFragment extends BaseFragment implements ArticleListContract.View, ArticleAdapter.OnItemClickListener, ArticleAdapter.OnItemChildClickListener,
SwipeRefreshLayout.OnRefreshListener, ArticleAdapter.RequestLoadMoreListener {
@BindView(R.id.rvArticleList)
RecyclerView mRvArticleList;
@BindView(R.id.swipeRefreshLayout)
SwipeRefreshLayout mSwipeRefreshLayout;
@Autowired
public int cid;
@Inject
ArticleAdapter mArticleAdapter;
@Override
protected int getLayoutId() {
return R.layout.fragment_article_list;
}
@Override
protected void initInjector() {
mFragmentComponent.inject(this);
}
@Override
protected void initView(View view) {
/**隐藏文章类型*/
mArticleAdapter.setChapterNameVisible(false);
/**设置RecyclerView*/
mRvArticleList.setLayoutManager(new LinearLayoutManager(getContext()));
mRvArticleList.setAdapter(mArticleAdapter);
/**设置事件监听*/
mArticleAdapter.setOnItemClickListener(this);
mArticleAdapter.setOnItemChildClickListener(this);
mSwipeRefreshLayout.setOnRefreshListener(this);
mArticleAdapter.setOnLoadMoreListener(this);
/**请求数据*/
mPresenter.loadKnowledgeSystemArticles(cid);
/**登陆成功刷新*/
RxBus.getInstance().toFlowable(LoginEvent.class)
.subscribe(new Consumer() {
@Override
public void accept(LoginEvent event) throws Exception {
mPresenter.refresh();
}
});
}
@Override
public void showLoading() {
mSwipeRefreshLayout.setRefreshing(true);
}
@Override
public void onRefresh() {
mPresenter.refresh();
}
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
if (view.getId() == R.id.ivCollect) {
mPresenter.collectArticle(position, mArticleAdapter.getItem(position));
}
}
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
ArticleContentActivity.start(mArticleAdapter.getItem(position).getId(),
mArticleAdapter.getItem(position).getLink(), mArticleAdapter.getItem(position).getTitle(),
mArticleAdapter.getItem(position).getAuthor());
}
@Override
public void onLoadMoreRequested() {
mPresenter.loadMore();
}
@Override
public void setKnowledgeSystemArticles(Article article, int loadType) {
setLoadDataResult(mArticleAdapter, mSwipeRefreshLayout, article.getDatas(), loadType);
}
@Override
public void collectArticleSuccess(int position, Article.DatasBean bean) {
mArticleAdapter.setData(position, bean);
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/ui/article/ArticleListPresenter.java
================================================
package com.lw.wanandroid.ui.article;
import com.blankj.utilcode.util.SPUtils;
import com.lw.wanandroid.R;
import com.lw.wanandroid.base.App;
import com.lw.wanandroid.base.BasePresenter;
import com.lw.wanandroid.bean.Article;
import com.lw.wanandroid.bean.DataResponse;
import com.lw.wanandroid.constant.Constant;
import com.lw.wanandroid.constant.LoadType;
import com.lw.wanandroid.net.ApiService;
import com.lw.wanandroid.net.RetrofitManager;
import com.lw.wanandroid.utils.RxSchedulers;
import com.lw.wanandroid.ui.my.LoginActivity;
import javax.inject.Inject;
import io.reactivex.functions.Consumer;
/**
* Created by lw on 2018/1/23.
*/
public class ArticleListPresenter extends BasePresenter implements ArticleListContract.Presenter {
private boolean mIsRefresh;
private int mPage, mCid;
@Inject
public ArticleListPresenter() {
this.mIsRefresh = true;
}
@Override
public void loadKnowledgeSystemArticles(int cid) {
this.mCid = cid;
RetrofitManager.create(ApiService.class).getKnowledgeSystemArticles(mPage, mCid)
.compose(RxSchedulers.>applySchedulers())
.compose(mView.>bindToLife())
.subscribe(new Consumer>() {
@Override
public void accept(DataResponse dataResponse) throws Exception {
int loadType = mIsRefresh ? LoadType.TYPE_REFRESH_SUCCESS : LoadType.TYPE_LOAD_MORE_SUCCESS;
mView.setKnowledgeSystemArticles(dataResponse.getData(), loadType);
}
}, new Consumer() {
@Override
public void accept(Throwable throwable) throws Exception {
int loadType = mIsRefresh ? LoadType.TYPE_REFRESH_ERROR : LoadType.TYPE_LOAD_MORE_ERROR;
mView.setKnowledgeSystemArticles(new Article(), loadType);
}
});
}
@Override
public void refresh() {
mPage = 0;
mIsRefresh = true;
loadKnowledgeSystemArticles(mCid);
}
@Override
public void loadMore() {
mPage++;
mIsRefresh = false;
loadKnowledgeSystemArticles(mCid);
}
@Override
public void collectArticle(final int position, final Article.DatasBean bean) {
if (SPUtils.getInstance(Constant.SHARED_NAME).getBoolean(Constant.LOGIN_KEY)) {
if (bean.isCollect()) {
RetrofitManager.create(ApiService.class).removeCollectArticle(bean.getId(), -1)
.compose(RxSchedulers.applySchedulers())
.compose(mView.bindToLife())
.subscribe(new Consumer() {
@Override
public void accept(DataResponse response) throws Exception {
if (response.getErrorCode() == 0) {
bean.setCollect(!bean.isCollect());
mView.collectArticleSuccess(position, bean);
mView.showSuccess(App.getAppContext().getString(R.string.collection_cancel_success));
} else {
mView.showFaild(App.getAppContext().getString(R.string.collection_cancel_failed, response.getData()));
}
}
}, new Consumer() {
@Override
public void accept(Throwable throwable) throws Exception {
mView.showFaild(throwable.getMessage());
}
});
} else {
RetrofitManager.create(ApiService.class).addCollectArticle(bean.getId())
.compose(RxSchedulers.applySchedulers())
.compose(mView.bindToLife())
.subscribe(new Consumer() {
@Override
public void accept(DataResponse response) throws Exception {
if (response.getErrorCode() == 0) {
bean.setCollect(!bean.isCollect());
mView.collectArticleSuccess(position, bean);
mView.showSuccess(App.getAppContext().getString(R.string.collection_success));
} else {
mView.showFaild(App.getAppContext().getString(R.string.collection_failed, response.getErrorMsg()));
}
}
}, new Consumer() {
@Override
public void accept(Throwable throwable) throws Exception {
mView.showFaild(throwable.getMessage());
}
});
}
} else {
LoginActivity.start();
}
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/ui/article/ArticleTypeActivity.java
================================================
package com.lw.wanandroid.ui.article;
import android.content.Intent;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.view.Menu;
import android.view.MenuItem;
import com.alibaba.android.arouter.facade.annotation.Autowired;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import com.lw.wanandroid.R;
import com.lw.wanandroid.base.BaseActivity;
import com.lw.wanandroid.bean.KnowledgeSystem;
import java.util.List;
import butterknife.BindView;
/**
* Created by lw on 2018/1/22.
*/
@Route(path = "/article/ArticleTypeActivity")
public class ArticleTypeActivity extends BaseActivity {
@Autowired
public String title;
@Autowired
public List childrenData;
@BindView(R.id.tabArticleTypes)
TabLayout mTabArticleTypes;
@BindView(R.id.vpArticleTypes)
ViewPager mVpArticleTypes;
ArticleTypeFragmentPagerAdapter mArticleTypeFragmentPagerAdapter;
@Override
protected int getLayoutId() {
return R.layout.activity_article_type;
}
@Override
protected void initInjector() {
}
@Override
protected void initView() {
setToolbarTitle(title);
mArticleTypeFragmentPagerAdapter = new ArticleTypeFragmentPagerAdapter(getSupportFragmentManager(), childrenData);
mVpArticleTypes.setAdapter(mArticleTypeFragmentPagerAdapter);
mTabArticleTypes.setupWithViewPager(mVpArticleTypes);
}
@Override
protected boolean showHomeAsUp() {
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_type_content, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menuShare) {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT, getString(R.string.share_type_url, getString(R.string.app_name),
childrenData.get(mTabArticleTypes.getSelectedTabPosition()).getName(), childrenData.get(mTabArticleTypes.getSelectedTabPosition()).getId()));
intent.setType("text/plain");
startActivity(Intent.createChooser(intent, getString(R.string.share_title)));
} else if (item.getItemId() == R.id.menuSearch) {
ARouter.getInstance().build("/hotsearch/SearchActivity").navigation();
}
return super.onOptionsItemSelected(item);
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/ui/article/ArticleTypeFragmentPagerAdapter.java
================================================
package com.lw.wanandroid.ui.article;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import com.alibaba.android.arouter.launcher.ARouter;
import com.lw.wanandroid.bean.KnowledgeSystem;
import com.lw.wanandroid.constant.Constant;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
/**
* Created by lw on 2018/1/22.
*/
public class ArticleTypeFragmentPagerAdapter extends FragmentPagerAdapter {
@Nullable
private List mChildrenData;
private List mArticleTypeFragments;
@Inject
public ArticleTypeFragmentPagerAdapter(FragmentManager fm, List childrenData) {
super(fm);
this.mChildrenData = childrenData;
mArticleTypeFragments = new ArrayList<>();
if (mChildrenData == null) return;
for (KnowledgeSystem.ChildrenBean childrenBean : mChildrenData) {
ArticleListFragment articleListFragment = (ArticleListFragment) ARouter.getInstance()
.build("/article/ArticleListFragment")
.withInt(Constant.CONTENT_CID_KEY, childrenBean.getId())
.navigation();
mArticleTypeFragments.add(articleListFragment);
}
}
@Override
public Fragment getItem(int position) {
return mArticleTypeFragments.get(position);
}
@Override
public int getCount() {
return mArticleTypeFragments.size();
}
@Override
public CharSequence getPageTitle(int position) {
return mChildrenData.get(position).getName();
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/ui/home/HomeContract.java
================================================
package com.lw.wanandroid.ui.home;
import com.lw.wanandroid.base.BaseContract;
import com.lw.wanandroid.bean.Article;
import com.lw.wanandroid.bean.Banner;
import com.lw.wanandroid.constant.LoadType;
import java.util.List;
/**
* Created by lw on 2018/1/18.
*/
public interface HomeContract {
interface View extends BaseContract.BaseView {
void setHomeBanners(List banners);
void setHomeArticles(Article article, @LoadType.checker int loadType);
void collectArticleSuccess(int position, Article.DatasBean bean);
}
interface Presenter extends BaseContract.BasePresenter {
void loadHomeBanners();
void loadHomeArticles();
void refresh();
void loadMore();
void collectArticle(int position, Article.DatasBean bean);
void loadHomeData();
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/ui/home/HomeFragment.java
================================================
package com.lw.wanandroid.ui.home;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import com.alibaba.android.arouter.launcher.ARouter;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.lw.wanandroid.R;
import com.lw.wanandroid.base.BaseFragment;
import com.lw.wanandroid.bean.Article;
import com.lw.wanandroid.bean.Banner;
import com.lw.wanandroid.bean.KnowledgeSystem;
import com.lw.wanandroid.constant.Constant;
import com.lw.wanandroid.constant.LoadType;
import com.lw.wanandroid.event.LoginEvent;
import com.lw.wanandroid.ui.article.ArticleAdapter;
import com.lw.wanandroid.ui.article.ArticleContentActivity;
import com.lw.wanandroid.utils.GlideImageLoader;
import com.lw.wanandroid.utils.RxBus;
import com.youth.banner.BannerConfig;
import com.youth.banner.listener.OnBannerListener;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import butterknife.BindView;
import io.reactivex.functions.Consumer;
/**
* Created by lw on 2018/1/18.
*/
public class HomeFragment extends BaseFragment implements HomeContract.View, ArticleAdapter.OnItemClickListener, ArticleAdapter.OnItemChildClickListener,
SwipeRefreshLayout.OnRefreshListener, ArticleAdapter.RequestLoadMoreListener {
@BindView(R.id.rvHomeArticles)
RecyclerView mRvHomeArticles;
@BindView(R.id.swipeRefreshLayout)
SwipeRefreshLayout mSwipeRefreshLayout;
@Inject
ArticleAdapter mArticleAdapter;
private com.youth.banner.Banner mBannerAds;
private View mHomeBannerHeadView;
@Override
protected int getLayoutId() {
return R.layout.fragment_home;
}
@Override
protected void initInjector() {
mFragmentComponent.inject(this);
}
@Override
protected void initView(View view) {
/**设置RecyclerView*/
mRvHomeArticles.setLayoutManager(new LinearLayoutManager(getContext()));
mRvHomeArticles.setAdapter(mArticleAdapter);
/**设置BannerHeadView*/
mHomeBannerHeadView = LayoutInflater.from(getContext()).inflate(R.layout.layout_home_banner_head, null);
mBannerAds = (com.youth.banner.Banner) mHomeBannerHeadView.findViewById(R.id.banner_ads);
mArticleAdapter.addHeaderView(mHomeBannerHeadView);
/**设置事件监听*/
mArticleAdapter.setOnItemClickListener(this);
mArticleAdapter.setOnItemChildClickListener(this);
mSwipeRefreshLayout.setOnRefreshListener(this);
mArticleAdapter.setOnLoadMoreListener(this);
/**请求数据*/
mPresenter.loadHomeData();
/**登陆成功刷新*/
RxBus.getInstance().toFlowable(LoginEvent.class)
.subscribe(new Consumer() {
@Override
public void accept(LoginEvent event) throws Exception {
mPresenter.refresh();
}
});
}
@Override
public void showLoading() {
mSwipeRefreshLayout.setRefreshing(true);
}
@Override
public void showFaild(String errorMsg) {
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void setHomeBanners(final List banners) {
List images = new ArrayList();
List titles = new ArrayList();
for (Banner banner : banners) {
images.add(banner.getImagePath());
titles.add(banner.getTitle());
}
mBannerAds.setImages(images)
.setBannerTitles(titles)
.setBannerStyle(BannerConfig.CIRCLE_INDICATOR_TITLE_INSIDE)
.setImageLoader(new GlideImageLoader())
.start();
mBannerAds.setOnBannerListener(new OnBannerListener() {
@Override
public void OnBannerClick(int position) {
ArticleContentActivity.start(banners.get(position).getId(), banners.get(position).getUrl(),
banners.get(position).getTitle(), null);
}
});
}
@Override
public void setHomeArticles(Article article, @LoadType.checker int loadType) {
setLoadDataResult(mArticleAdapter, mSwipeRefreshLayout, article.getDatas(), loadType);
}
@Override
public void collectArticleSuccess(int position, Article.DatasBean bean) {
mArticleAdapter.setData(position, bean);
}
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
if (view.getId() == R.id.tvChapterName) {
List childrenBeans = new ArrayList<>();
childrenBeans.add(new KnowledgeSystem.ChildrenBean(mArticleAdapter.getItem(position).getChapterId(),
mArticleAdapter.getItem(position).getChapterName()));
ARouter.getInstance().build("/article/ArticleTypeActivity")
.withString(Constant.CONTENT_TITLE_KEY, mArticleAdapter.getItem(position).getChapterName())
.withObject(Constant.CONTENT_CHILDREN_DATA_KEY, childrenBeans)
.navigation();
} else if (view.getId() == R.id.ivCollect) {
mPresenter.collectArticle(position, mArticleAdapter.getItem(position));
}
}
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
ArticleContentActivity.start(mArticleAdapter.getItem(position).getId(),
mArticleAdapter.getItem(position).getLink(), mArticleAdapter.getItem(position).getTitle(),
mArticleAdapter.getItem(position).getAuthor());
}
@Override
public void onRefresh() {
mPresenter.refresh();
}
@Override
public void onLoadMoreRequested() {
mPresenter.loadMore();
}
public static HomeFragment newInstance() {
return new HomeFragment();
}
}
================================================
FILE: app/src/main/java/com/lw/wanandroid/ui/home/HomePresenter.java
================================================
package com.lw.wanandroid.ui.home;
import com.blankj.utilcode.util.SPUtils;
import com.lw.wanandroid.R;
import com.lw.wanandroid.base.App;
import com.lw.wanandroid.base.BasePresenter;
import com.lw.wanandroid.bean.Article;
import com.lw.wanandroid.bean.Banner;
import com.lw.wanandroid.bean.DataResponse;
import com.lw.wanandroid.bean.User;
import com.lw.wanandroid.constant.Constant;
import com.lw.wanandroid.constant.LoadType;
import com.lw.wanandroid.net.ApiService;
import com.lw.wanandroid.net.RetrofitManager;
import com.lw.wanandroid.utils.ArticleUtils;
import com.lw.wanandroid.utils.RxSchedulers;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import io.reactivex.Observable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function3;
/**
* Created by lw on 2018/1/18.
*/
public class HomePresenter extends BasePresenter implements HomeContract.Presenter {
private int mPage;
private boolean mIsRefresh;
@Inject
public HomePresenter() {
this.mIsRefresh = true;
}
@Override
public void loadHomeBanners() {
RetrofitManager.create(ApiService.class)
.getHomeBanners()
.compose(RxSchedulers.>>applySchedulers())
.compose(mView.>>bindToLife())
.subscribe(new Consumer>>() {
@Override
public void accept(DataResponse> dataResponse) throws Exception {
mView.setHomeBanners(dataResponse.getData());
}
}, new Consumer() {
@Override
public void accept(Throwable throwable) throws Exception {
mView.showFaild(throwable.getMessage());
}
});
}
@Override
public void loadHomeArticles() {
RetrofitManager.create(ApiService.class)
.getHomeArticles(mPage)
.compose(RxSchedulers.>applySchedulers())
.compose(mView.>bindToLife())
.subscribe(new Consumer>() {
@Override
public void accept(DataResponse dataResponse) throws Exception {
int loadType = mIsRefresh ? LoadType.TYPE_REFRESH_SUCCESS : LoadType.TYPE_LOAD_MORE_SUCCESS;
mView.setHomeArticles(dataResponse.getData(), loadType);
}
}, new Consumer() {
@Override
public void accept(Throwable throwable) throws Exception {
int loadType = mIsRefresh ? LoadType.TYPE_REFRESH_ERROR : LoadType.TYPE_LOAD_MORE_ERROR;
mView.setHomeArticles(new Article(), loadType);
}
});
}
@Override
public void refresh() {
mPage = 0;
mIsRefresh = true;
loadHomeBanners();
loadHomeArticles();
}
@Override
public void loadMore() {
mPage++;
mIsRefresh = false;
loadHomeArticles();
}
@Override
public void collectArticle(final int position, final Article.DatasBean bean) {
ArticleUtils.collectArticle(mView, position, bean);
}
@Override
public void loadHomeData() {
mView.showLoading();
String username = SPUtils.getInstance(Constant.SHARED_NAME).getString(Constant.USERNAME_KEY);
String password = SPUtils.getInstance(Constant.SHARED_NAME).getString(Constant.PASSWORD_KEY);
Observable> observableUser = RetrofitManager.create(ApiService.class).login(username, password);
Observable>> observableBanner = RetrofitManager.create(ApiService.class).getHomeBanners();
Observable> observableArticle = RetrofitManager.create(ApiService.class).getHomeArticles(mPage);
Observable.zip(observableUser, observableBanner, observableArticle, new Function3, DataResponse>, DataResponse, Map>() {
@Override
public Map apply(DataResponse response, DataResponse> dataResponse, DataResponse dataResponse2) throws Exception {
Map objMap = new HashMap<>();
objMap.put(Constant.USER_KEY, response);
objMap.put(Constant.BANNER_KEY, dataResponse.getData());
objMap.put(Constant.ARTICLE_KEY, dataResponse2.getData());
return objMap;
}
}).compose(RxSchedulers.