implements CMusic.IVMusic {
17 |
18 |
19 | public static MusicFragment newInstance() {
20 | MusicFragment fragment = new MusicFragment();
21 | Bundle args = new Bundle();
22 | fragment.setArguments(args);
23 | return fragment;
24 | }
25 |
26 | @Override
27 | protected void initView() {
28 |
29 |
30 | }
31 |
32 | @Override
33 | public int getLayoutRes() {
34 | return R.layout.fragment_music;
35 | }
36 |
37 | @Override
38 | public void createPresenter() {
39 | mPresenter = new PMusicImpl(mContext, this);
40 | }
41 |
42 | @Override
43 | public void showLoading() {
44 | }
45 |
46 | @Override
47 | public void hideLoading() {
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/luliang/devmvp/utils/rxhelper/RxTransformer.java:
--------------------------------------------------------------------------------
1 | package com.luliang.devmvp.utils.rxhelper;
2 |
3 |
4 | import android.support.annotation.NonNull;
5 |
6 | import com.luliang.devmvp.mvp.base.BaseModel;
7 | import com.luliang.devmvp.utils.LogUtils;
8 |
9 | import io.reactivex.Observable;
10 | import io.reactivex.ObservableSource;
11 | import io.reactivex.ObservableTransformer;
12 | import io.reactivex.android.schedulers.AndroidSchedulers;
13 | import io.reactivex.disposables.Disposable;
14 | import io.reactivex.functions.Consumer;
15 | import io.reactivex.schedulers.Schedulers;
16 |
17 |
18 | /**
19 | * Created by Liang_Lu on 2016/12/20.
20 | *
21 | * 控制操作线程的辅助类
22 | */
23 |
24 | public class RxTransformer {
25 |
26 | /**
27 | * 无参数
28 | *
29 | * @param 泛型
30 | * @return 返回Observable
31 | */
32 | public static ObservableTransformer switchSchedulers(BaseModel baseModel) {
33 | return upstream -> upstream
34 | .subscribeOn(Schedulers.io())
35 | .unsubscribeOn(Schedulers.io())
36 | .doOnSubscribe(disposable -> baseModel.mDisposable.add(disposable))
37 | .subscribeOn(AndroidSchedulers.mainThread())
38 | .observeOn(AndroidSchedulers.mainThread());
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/luliang/devmvp/mvp/presenter/PBookImpl.java:
--------------------------------------------------------------------------------
1 | package com.luliang.devmvp.mvp.presenter;
2 |
3 | import android.content.Context;
4 |
5 | import com.luliang.devmvp.mvp.base.BasePresenter;
6 | import com.luliang.devmvp.mvp.bean.BookBean;
7 | import com.luliang.devmvp.mvp.contract.CBook;
8 | import com.luliang.devmvp.mvp.model.MBookImpl;
9 | import com.luliang.devmvp.utils.rxhelper.RxObservable;
10 |
11 | import java.util.Map;
12 |
13 | /**
14 | * Created by Liang_Lu on 2017/12/21.
15 | * P层 此类只用于处理业务逻辑 然后把最终的结果回调给V层
16 | */
17 |
18 | public class PBookImpl extends BasePresenter implements CBook.IPBook {
19 |
20 |
21 | public PBookImpl(Context mContext, CBook.IVBook mView) {
22 | super(mContext, mView, new MBookImpl());
23 | }
24 |
25 |
26 | @Override
27 | public void pBook() {
28 | mView.showLoading();
29 | mModel.mBook(new RxObservable() {
30 |
31 | @Override
32 | public void onSuccess(BookBean bean) {
33 | mView.hideLoading();
34 | mView.vBookSuccess(bean);
35 | }
36 |
37 | @Override
38 | public void onFail(String reason) {
39 | mView.hideLoading();
40 | mView.vBookError(reason);
41 | }
42 | });
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/MvpFragment/root/src/app_package/MvpFragment.java.ftl:
--------------------------------------------------------------------------------
1 | package ${packageName}.mvp.view.fragment;
2 |
3 | import ${packageName}.R;
4 | import ${packageName}.utils.LoadingHelper;
5 | import ${packageName}.mvp.base.BaseFragment;
6 | import ${packageName}.mvp.contract.${ContractName};
7 | import ${packageName}.mvp.presenter.${PresenterName};
8 | import android.os.Bundle;
9 |
10 | /**
11 | * Created by Liang_Lu on 2017/12/21.
12 | * @author LuLiang
13 | * @github https://github.com/LiangLuDev
14 | */
15 |
16 | public class ${FragmentName} extends BaseFragment<${PresenterName}> implements ${ContractName}.${IViewName}{
17 |
18 |
19 | @Override
20 | protected void initView() {
21 |
22 |
23 | }
24 |
25 | public static ${FragmentName} newInstance() {
26 | ${FragmentName} fragment = new ${FragmentName}();
27 | Bundle args = new Bundle();
28 | fragment.setArguments(args);
29 | return fragment;
30 | }
31 |
32 | @Override
33 | public int getLayoutRes() {
34 | return R.layout.fragment_${fragment_layout};
35 | }
36 |
37 | @Override
38 | public void createPresenter() {
39 | mPresenter = new ${PresenterName}(mContext, this);
40 | }
41 |
42 | @Override
43 | public void showLoading() {
44 | }
45 |
46 | @Override
47 | public void hideLoading() {
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/luliang/devmvp/api/DevMvpApi.java:
--------------------------------------------------------------------------------
1 | package com.luliang.devmvp.api;
2 |
3 | import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
4 |
5 | import java.util.concurrent.TimeUnit;
6 |
7 | import okhttp3.OkHttpClient;
8 | import okhttp3.logging.HttpLoggingInterceptor;
9 | import retrofit2.Retrofit;
10 | import retrofit2.converter.gson.GsonConverterFactory;
11 |
12 | /**
13 | * Created by Liang_Lu on 2017/8/31.
14 | */
15 |
16 | public class DevMvpApi {
17 | private static Retrofit mRetrofit;
18 |
19 | /**
20 | * Retrofit初始化
21 | *
22 | *
23 | * @return
24 | */
25 | public static Retrofit createApi() {
26 | OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder().
27 | connectTimeout(10, TimeUnit.SECONDS)
28 | .readTimeout(10, TimeUnit.SECONDS)
29 | .writeTimeout(10, TimeUnit.SECONDS);
30 |
31 | httpClientBuilder.addInterceptor(new HttpLoggingInterceptor()
32 | .setLevel(HttpLoggingInterceptor.Level.BODY));
33 | mRetrofit = new Retrofit.Builder()
34 | .client(httpClientBuilder.build())
35 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
36 | .addConverterFactory(GsonConverterFactory.create())
37 | .baseUrl(Url.BASE_URL)
38 | .build();
39 | return mRetrofit;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/luliang/devmvp/utils/rxhelper/RxObservable.java:
--------------------------------------------------------------------------------
1 | package com.luliang.devmvp.utils.rxhelper;
2 |
3 | import com.luliang.devmvp.mvp.base.IDevMvpCallBack;
4 | import com.luliang.devmvp.utils.LogUtils;
5 | import com.luliang.devmvp.utils.ToastUtils;
6 |
7 | import io.reactivex.Observer;
8 | import io.reactivex.disposables.Disposable;
9 |
10 | /**
11 | * Created by Liang_Lu on 2017/12/21.
12 | */
13 |
14 | public abstract class RxObservable implements Observer, IDevMvpCallBack {
15 |
16 | public RxObservable() {
17 | }
18 |
19 |
20 | // /**
21 | // * 失败回调
22 | // *
23 | // * @param errorMsg 错误信息
24 | // */
25 | // protected abstract void onError(String errorMsg);
26 | //
27 | // /**
28 | // * 成功回调
29 | // *
30 | // * @param data 结果
31 | // */
32 | // protected abstract void onSuccess(T data);
33 | //
34 |
35 |
36 | @Override
37 | public void onSubscribe(Disposable d) {
38 | LogUtils.print("RxObservable", d + "");
39 | }
40 |
41 | @Override
42 | public void onError(Throwable e) {
43 | String error = RxException.handleException(e).getMessage();
44 | ToastUtils.show(error);
45 | // onError(error);
46 | this.onFail(error);
47 | }
48 |
49 |
50 | @Override
51 | public void onNext(T value) {
52 | //可以根据需求对code统一处理
53 | // onSuccess(value);
54 | this.onSuccess(value);
55 | }
56 |
57 |
58 | @Override
59 | public void onComplete() {
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/luliang/devmvp/mvp/view/activity/BookActivity.java:
--------------------------------------------------------------------------------
1 | package com.luliang.devmvp.mvp.view.activity;
2 |
3 | import android.view.View;
4 | import android.widget.Button;
5 | import android.widget.TextView;
6 |
7 | import com.luliang.devmvp.R;
8 | import com.luliang.devmvp.mvp.base.BaseActivity;
9 | import com.luliang.devmvp.mvp.bean.BookBean;
10 | import com.luliang.devmvp.mvp.contract.CBook;
11 | import com.luliang.devmvp.mvp.presenter.PBookImpl;
12 |
13 |
14 | /**
15 | * Created by Liang_Lu on 2017/12/21.
16 | * V层 用于数据和页面UI展示(Fragment Dialog 同理)
17 | */
18 |
19 | public class BookActivity extends BaseActivity implements CBook.IVBook {
20 |
21 | private TextView mTv;
22 | private Button mBtn;
23 |
24 | @Override
25 | protected void initView() {
26 | super.initView();
27 | mBtn = findViewById(R.id.btn);
28 | mTv = findViewById(R.id.tv);
29 | mBtn.setOnClickListener(new View.OnClickListener() {
30 | @Override
31 | public void onClick(View v) {
32 | mPresenter.pBook();
33 | }
34 | });
35 |
36 | }
37 |
38 | @Override
39 | public int setContentViewId() {
40 | return R.layout.activity_book;
41 | }
42 |
43 | @Override
44 | public void createPresenter() {
45 | mPresenter = new PBookImpl(mContext, this);
46 | }
47 |
48 |
49 | @Override
50 | public void showLoading() {
51 |
52 | }
53 |
54 | @Override
55 | public void hideLoading() {
56 |
57 | }
58 |
59 | @Override
60 | public void vBookSuccess(BookBean bean) {
61 | mTv.setText("网络请求成功");
62 | }
63 |
64 | @Override
65 | public void vBookError(String reason) {
66 | mTv.setText(reason);
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/luliang/devmvp/mvp/base/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.luliang.devmvp.mvp.base;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.support.v7.widget.Toolbar;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 | import butterknife.ButterKnife;
12 |
13 | /**
14 | * Created by Liang_Lu on 2017/12/21.
15 | */
16 |
17 | public abstract class BaseActivity extends AppCompatActivity {
18 | public Context mContext;
19 | public T mPresenter;
20 |
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);//子类的super.OnCreate必须在setContentView后调用
24 | mContext = this;
25 | if (setContentViewId() != 0) {
26 | setContentView(setContentViewId());
27 | } else {
28 | throw new RuntimeException("layoutResID==-1 have u create your layout?");
29 | }
30 | createPresenter();
31 | ButterKnife.bind(this);
32 | initView();
33 | }
34 |
35 | /**
36 | * 初始化方法
37 | */
38 | protected void initView() {
39 |
40 | }
41 |
42 | /**
43 | * 获取contentView 资源id
44 | */
45 | public abstract int setContentViewId();
46 |
47 | /**
48 | * 创建presenter实例
49 | */
50 | public abstract void createPresenter();
51 |
52 | /**
53 | * activity跳转(无参数)
54 | *
55 | * @param className
56 | */
57 | public void startActivity(Class> className) {
58 | Intent intent = new Intent(mContext, className);
59 | startActivity(intent);
60 | }
61 |
62 | /**
63 | * activity跳转(有参数)
64 | *
65 | * @param className
66 | */
67 | public void startActivity(Class> className, Bundle bundle) {
68 | Intent intent = new Intent(mContext, className);
69 | intent.putExtras(bundle);
70 | startActivity(intent);
71 | }
72 |
73 |
74 | @Override
75 | protected void onDestroy() {
76 | super.onDestroy();
77 | if (mPresenter != null) {
78 | mPresenter.onDestroy();//页面销毁 网络请求同销毁
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/com/luliang/devmvp/utils/GsonUtils.java:
--------------------------------------------------------------------------------
1 | package com.luliang.devmvp.utils;
2 |
3 | import android.text.TextUtils;
4 |
5 | import com.google.gson.Gson;
6 | import com.google.gson.JsonArray;
7 | import com.google.gson.JsonElement;
8 | import com.google.gson.JsonParser;
9 | import com.google.gson.JsonSyntaxException;
10 |
11 | import org.json.JSONException;
12 | import org.json.JSONObject;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | /**
18 | * 封装的是使用Gson解析json的方法
19 | *
20 | * @author Administrator
21 | */
22 | public class GsonUtils {
23 |
24 | /**
25 | * 把一个json字符串变成对象
26 | *
27 | * @param json
28 | * @param cls
29 | * @return
30 | */
31 | public static T parseJsonToBean(String json, Class cls) {
32 | Gson gson = new Gson();
33 | T t = null;
34 | try {
35 | t = gson.fromJson(json, cls);
36 | } catch (Exception e) {
37 | e.printStackTrace();
38 | return null;
39 | }
40 | return t;
41 | }
42 |
43 | //解析json数组
44 | public static List fromJsonArray(String json, Class clazz) {
45 | List lst = null;
46 | try {
47 | lst = new ArrayList();
48 |
49 | JsonArray array = new JsonParser().parse(json).getAsJsonArray();
50 | for (final JsonElement elem : array) {
51 | lst.add(new Gson().fromJson(elem, clazz));
52 | }
53 | } catch (JsonSyntaxException e) {
54 | e.printStackTrace();
55 | return null;
56 | }
57 |
58 | return lst;
59 | }
60 |
61 |
62 | /**
63 | * 对象转为json字符串
64 | *
65 | * @param target
66 | * @return
67 | */
68 | public static String toJson(Object target) {
69 | Gson gson = new Gson();
70 | return gson.toJson(target);
71 | }
72 |
73 |
74 | /**
75 | * 获取json串中某个字段的值,注意,只能获取同一层级的value
76 | *
77 | * @param json
78 | * @param key
79 | * @return
80 | */
81 | public static String getFieldValue(String json, String key) {
82 | if (TextUtils.isEmpty(json))
83 | return null;
84 | if (!json.contains(key))
85 | return "";
86 | JSONObject jsonObject = null;
87 | String value = null;
88 | try {
89 | jsonObject = new JSONObject(json);
90 | value = jsonObject.getString(key);
91 | } catch (JSONException e) {
92 | e.printStackTrace();
93 | return "";
94 | }
95 |
96 | return value;
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | def cfg = rootProject.ext.configuration
4 | def libs = rootProject.ext.libraries
5 |
6 | android {
7 | compileSdkVersion cfg.compileVersion
8 | buildToolsVersion cfg.buildToolsVersion
9 | defaultConfig {
10 | applicationId "com.luliang.devmvp"
11 | minSdkVersion cfg.minSdk
12 | targetSdkVersion cfg.targetSdk
13 | versionCode cfg.versionCode
14 | versionName cfg.versionName
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 | }
17 |
18 | packagingOptions {
19 | exclude 'META-INF/rxjava.properties'
20 | }
21 |
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
26 | }
27 | }
28 |
29 | compileOptions {
30 | targetCompatibility 1.8
31 | sourceCompatibility 1.8
32 | }
33 |
34 | lintOptions {
35 | abortOnError false
36 | }
37 | }
38 |
39 | dependencies {
40 | implementation fileTree(include: ['*.jar'], dir: 'libs')
41 |
42 | //noinspection GradleCompatible
43 | implementation "com.android.support:appcompat-v7:${libs.supportVersion}"
44 | implementation "com.android.support.constraint:constraint-layout:${libs.constraint_layout}"
45 | implementation "com.android.support:design:${libs.supportVersion}"
46 | implementation "com.android.support:support-v13:${libs.supportVersion}"
47 | implementation "com.android.support:support-vector-drawable:${libs.supportVersion}"
48 | testImplementation 'junit:junit:4.12'
49 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
50 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
51 | /**
52 | * RxJava
53 | */
54 | implementation "io.reactivex.rxjava2:rxjava:${libs.rxjava}"
55 | implementation "io.reactivex.rxjava2:rxandroid:${libs.rxandroid}"
56 |
57 | /**
58 | * retrofit2
59 | */
60 | implementation "com.squareup.retrofit2:retrofit:${libs.retrofit}"
61 | implementation "com.squareup.retrofit2:adapter-rxjava:${libs.retrofit}"
62 | implementation "com.squareup.retrofit2:converter-gson:${libs.retrofit}"
63 | implementation "com.jakewharton.retrofit:retrofit2-rxjava2-adapter:${libs.rxjava2_adapter}"
64 |
65 | /**
66 | * okhttp
67 | */
68 | implementation "com.squareup.okhttp3:okhttp:${libs.okhttp3}"
69 | implementation "com.squareup.okhttp3:logging-interceptor:${libs.logging}"
70 |
71 | /**
72 | * butterknife
73 | */
74 | implementation "com.jakewharton:butterknife:${libs.butterknife}"
75 | annotationProcessor "com.jakewharton:butterknife-compiler:${libs.butterknife}"
76 | }
77 |
--------------------------------------------------------------------------------
/app/src/main/java/com/luliang/devmvp/mvp/base/BaseFragment.java:
--------------------------------------------------------------------------------
1 | package com.luliang.devmvp.mvp.base;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.support.v4.app.Fragment;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 |
12 | import com.luliang.devmvp.utils.ToastUtils;
13 |
14 | import butterknife.ButterKnife;
15 |
16 |
17 | /**
18 | * Created by Liang_Lu on 2017/9/29.
19 | * Fragment基类
20 | */
21 |
22 | public abstract class BaseFragment extends Fragment {
23 |
24 | protected Context mContext;
25 | public View mRootView;
26 | public T mPresenter;
27 |
28 | /**
29 | * 获得全局的,防止使用getActivity()为空
30 | *
31 | * @param context
32 | */
33 | @Override
34 | public void onAttach(Context context) {
35 | super.onAttach(context);
36 | this.mContext = context;
37 | }
38 |
39 | @Nullable
40 | @Override
41 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle
42 | savedInstanceState) {
43 |
44 | if (mRootView == null) {
45 | if (getLayoutRes() != 0) {
46 | mRootView = LayoutInflater.from(mContext)
47 | .inflate(getLayoutRes(), container, false);
48 | ButterKnife.bind(this, mRootView);
49 | createPresenter();
50 | initView();
51 | } else {
52 | throw new RuntimeException("layoutResID==-1 have u create your layout?");
53 | }
54 | }
55 |
56 | return mRootView;
57 | }
58 |
59 | /**
60 | * 创建presenter实例
61 | */
62 | public abstract void createPresenter();
63 |
64 |
65 | /**
66 | * 初始化
67 | */
68 | protected abstract void initView();
69 |
70 |
71 | /**
72 | * 吐司
73 | *
74 | * @param text
75 | */
76 | public void showToast(String text) {
77 | ToastUtils.show(text);
78 | }
79 |
80 | /**
81 | * activity跳转(无参数)
82 | *
83 | * @param className
84 | */
85 |
86 | public void startActivity(Class> className) {
87 | Intent intent = new Intent(mContext, className);
88 | startActivity(intent);
89 | }
90 |
91 | /**
92 | * activity跳转(有参数)
93 | *
94 | * @param className
95 | */
96 | public void startActivity(Class> className, Bundle bundle) {
97 | Intent intent = new Intent(mContext, className);
98 | intent.putExtras(bundle);
99 | startActivity(intent);
100 | }
101 |
102 | /**
103 | * 传入布局文件
104 | *
105 | * @return
106 | */
107 | public abstract int getLayoutRes();
108 |
109 | @Override
110 | public void onDestroy() {
111 | super.onDestroy();
112 | if (mPresenter != null) {
113 | mPresenter.onDestroy();//页面销毁网络请求也取消
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/app/src/main/java/com/luliang/devmvp/utils/LogUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 venshine.cn@gmail.com
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.luliang.devmvp.utils;
17 |
18 | import android.util.Log;
19 |
20 | import com.luliang.devmvp.BuildConfig;
21 |
22 |
23 | /**
24 | * Log日志打印操作
25 | *
26 | * @author Weiss
27 | */
28 | public class LogUtils {
29 |
30 | private static final boolean DEBUG = BuildConfig.DEBUG;
31 |
32 | /**
33 | * 获取当前类名
34 | *
35 | * @return
36 | */
37 | private static String getClassName() {
38 | // 这里的数组的index,即2,是根据你工具类的层级取的值,可根据需求改变
39 | StackTraceElement thisMethodStack = (new Exception()).getStackTrace()[2];
40 | String result = thisMethodStack.getClassName();
41 | int lastIndex = result.lastIndexOf(".");
42 | result = result.substring(lastIndex + 1, result.length());
43 | return result;
44 | }
45 |
46 | /**
47 | * System.out.print打印
48 | *
49 | * @param logString
50 | */
51 | public static void print(String logString) {
52 | if (DEBUG) {
53 | System.out.println(getClassName() + " : " + logString);
54 | }
55 | }
56 |
57 |
58 | /**
59 | * System.out.print打印
60 | *
61 | * @param logString
62 | * @param tag
63 | */
64 | public static void print(String tag, String logString) {
65 | if (DEBUG) {
66 | System.out.println(tag + " : " + logString);
67 | }
68 | }
69 |
70 |
71 | public static void w(String logString) {
72 | if (DEBUG) {
73 | Log.w(getClassName(), logString);
74 | }
75 | }
76 |
77 | /**
78 | * debug log
79 | *
80 | * @param msg
81 | */
82 | public static void d(String tag, String msg) {
83 | if (DEBUG) {
84 | Log.d(tag, msg);
85 | }
86 | }
87 |
88 | /**
89 | * error log
90 | *
91 | * @param msg
92 | */
93 | public static void e(String tag, String msg) {
94 | if (DEBUG) {
95 | Log.e(tag, msg);
96 | }
97 | }
98 |
99 | /**
100 | * debug log
101 | *
102 | * @param msg
103 | */
104 | public static void d(String msg) {
105 | if (DEBUG) {
106 | Log.d(getClassName(), msg);
107 | }
108 | }
109 |
110 | /**
111 | * debug log
112 | *
113 | * @param msg
114 | */
115 | public static void i(String msg) {
116 | if (DEBUG) {
117 | Log.i(getClassName(), msg);
118 | }
119 | }
120 |
121 | /**
122 | * error log
123 | *
124 | * @param msg
125 | */
126 | public static void e(String msg) {
127 | if (DEBUG) {
128 | Log.e(getClassName(), msg);
129 | }
130 | }
131 |
132 | public static void i(String tag, String logString) {
133 | if (DEBUG) {
134 | Log.i(tag, logString);
135 | }
136 | }
137 |
138 |
139 | public static void w(String tag, String logString) {
140 | if (DEBUG) {
141 | Log.w(tag, logString);
142 | }
143 | }
144 |
145 | }
146 |
--------------------------------------------------------------------------------
/app/src/main/java/com/luliang/devmvp/utils/rxhelper/RxException.java:
--------------------------------------------------------------------------------
1 | package com.luliang.devmvp.utils.rxhelper;
2 |
3 | import com.google.gson.JsonParseException;
4 | import com.google.gson.JsonSerializer;
5 | import com.google.gson.JsonSyntaxException;
6 |
7 | import org.apache.http.conn.ConnectTimeoutException;
8 | import org.json.JSONException;
9 |
10 | import java.io.IOException;
11 | import java.io.NotSerializableException;
12 | import java.net.ConnectException;
13 | import java.net.SocketTimeoutException;
14 | import java.net.UnknownHostException;
15 | import java.text.ParseException;
16 |
17 | import retrofit2.HttpException;
18 |
19 | /**
20 | * Created by LiangLu on 2017/10/23.
21 | * 异常类型
22 | */
23 |
24 | public class RxException extends Exception {
25 |
26 | private final int code;
27 | private String message;
28 |
29 | public RxException(Throwable throwable, int code) {
30 | super(throwable);
31 | this.code = code;
32 | this.message = throwable.getMessage();
33 | }
34 |
35 | public int getCode() {
36 | return code;
37 | }
38 |
39 | @Override
40 | public String getMessage() {
41 | return message;
42 | }
43 |
44 | public static RxException handleException(Throwable e) {
45 | RxException ex;
46 | if (e instanceof HttpException) {
47 | HttpException httpException = (HttpException) e;
48 | ex = new RxException(httpException, httpException.code());
49 | try {
50 | ex.message = httpException.response().errorBody().string();
51 | } catch (IOException e1) {
52 | e1.printStackTrace();
53 | ex.message = e1.getMessage();
54 | }
55 | return ex;
56 | } else if (e instanceof SocketTimeoutException) {
57 | ex = new RxException(e, ERROR.TIMEOUT_ERROR);
58 | ex.message = "网络连接超时,请检查您的网络状态,稍后重试!";
59 | return ex;
60 | } else if (e instanceof ConnectException) {
61 | ex = new RxException(e, ERROR.TIMEOUT_ERROR);
62 | ex.message = "网络连接异常,请检查您的网络状态,稍后重试!";
63 | return ex;
64 | } else if (e instanceof ConnectTimeoutException) {
65 | ex = new RxException(e, ERROR.TIMEOUT_ERROR);
66 | ex.message = "网络连接超时,请检查您的网络状态,稍后重试!";
67 | return ex;
68 | } else if (e instanceof UnknownHostException) {
69 | ex = new RxException(e, ERROR.TIMEOUT_ERROR);
70 | ex.message = "网络连接异常,请检查您的网络状态,稍后重试!";
71 | return ex;
72 | } else if (e instanceof NullPointerException) {
73 | ex = new RxException(e, ERROR.NULL_POINTER_EXCEPTION);
74 | ex.message = "空指针异常";
75 | return ex;
76 | } else if (e instanceof javax.net.ssl.SSLHandshakeException) {
77 | ex = new RxException(e, ERROR.SSL_ERROR);
78 | ex.message = "证书验证失败";
79 | return ex;
80 | } else if (e instanceof ClassCastException) {
81 | ex = new RxException(e, ERROR.CAST_ERROR);
82 | ex.message = "类型转换错误";
83 | return ex;
84 | } else if (e instanceof JsonParseException
85 | || e instanceof JSONException
86 | || e instanceof JsonSyntaxException
87 | || e instanceof JsonSerializer
88 | || e instanceof NotSerializableException
89 | || e instanceof ParseException) {
90 | ex = new RxException(e, ERROR.PARSE_ERROR);
91 | ex.message = "解析错误";
92 | return ex;
93 | } else if (e instanceof IllegalStateException) {
94 | ex = new RxException(e, ERROR.ILLEGAL_STATE_ERROR);
95 | ex.message = e.getMessage();
96 | return ex;
97 | } else {
98 | ex = new RxException(e, ERROR.UNKNOWN);
99 | ex.message = "未知错误";
100 | return ex;
101 | }
102 | }
103 |
104 | /**
105 | * 约定异常
106 | */
107 | public static class ERROR {
108 | /**
109 | * 未知错误
110 | */
111 | public static final int UNKNOWN = 1000;
112 | /**
113 | * 连接超时
114 | */
115 | public static final int TIMEOUT_ERROR = 1001;
116 | /**
117 | * 空指针错误
118 | */
119 | public static final int NULL_POINTER_EXCEPTION = 1002;
120 |
121 | /**
122 | * 证书出错
123 | */
124 | public static final int SSL_ERROR = 1003;
125 |
126 | /**
127 | * 类转换错误
128 | */
129 | public static final int CAST_ERROR = 1004;
130 |
131 | /**
132 | * 解析错误
133 | */
134 | public static final int PARSE_ERROR = 1005;
135 |
136 | /**
137 | * 非法数据异常
138 | */
139 | public static final int ILLEGAL_STATE_ERROR = 1006;
140 |
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### DevMvp-快速开发框架
2 |
3 | #### 序言
4 | > 每个程序员看到一堆烂代码都有一颗重构的心。烂代码写起来嘴上 笑嘻嘻,心里mmp。特别是有代码洁癖的人。重构不易且行且珍惜,此框架将减少开发时间。如果你们的项目结构跟我的不一样,这也不用担心,你看了我这个,简单修改一下模板,照样能生成你想要的代码。
5 | #### MVP架构
6 | > 相信大家对于MVP耳熟能详了,理解的直接往下看,如果概念比较模糊,可以网上查一查理解理解,我这边简单的介绍一下,可以配合下图来理解
7 | > - **View层:** View层也是视图层,只负责对数据的展示,提供友好的界面与用户进行交互。开发中通常将Activity或者Fragment作为View层。
8 | > - **Model层:** Model层也是数据层。它区别于MVC架构中的Model,在这里Model它负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等。
9 | > - **Presenter层:** 是连接View层与Model层的桥梁并对业务逻辑进行处理。在MVP架构中Model与View无法直接进行交互。所以在Presenter层它会从Model层获得所需要的数据,进行一些适当的处理后交由View层进行显示。这样通过Presenter将View与Model进行隔离,使得View和Model之间不存在耦合,同时也将业务逻辑从View中抽离
10 | 
11 | #### 项目介绍
12 | > 项目采用MVP架构,使用RxAndroid2+Retrofit开源框架封装,结合Android Studio模板快速生成MVP基础代码。新项目或者重构项目值得拥有。此开发框架是我2017年底重构项目开发的,使用了几个月,项目重构完成了,完美使用,特别省事省时省心
13 | #### 项目结构
14 | ```
15 | DevMvp
16 | ├─api//URL、接口管理、网络请求封装类
17 | ├─mvp//项目主体
18 | │ ├─base//基础类封装
19 | ├─bean//实体类
20 | │ ├─contract//契约类 用于统一管理view和presenter的接口
21 | │ ├─model//M层-数据处理
22 | │ ├─presenter//P层-逻辑业务处理
23 | │ └─view//V层-页面渲染
24 | │ ├─activity
25 | ├─adapter
26 | │ └─fragment
27 | ...//类似Dialog、PopupWindow也可以放在view下
28 | └─utils//工具类
29 | └─rxhelper//Rx封装工具
30 | ```
31 | #### 代码详解
32 | ##### 1.api-网络请求
33 | Retrofit网络请求封装,项目里面只是对Retrofit网络请求基本参数,需要header、cache等参数,可在网上查查资料,这类文章介绍很多。[Retrofit 2.0使用文档](https://blog.csdn.net/carson_ho/article/details/73732076)
34 | - DevMvpApi -Retrofit初始化
35 | ```java
36 | public static Retrofit createApi() {
37 | OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder().
38 | connectTimeout(10, TimeUnit.SECONDS)
39 | .readTimeout(10, TimeUnit.SECONDS)
40 | .writeTimeout(10, TimeUnit.SECONDS);
41 |
42 | httpClientBuilder.addInterceptor(new HttpLoggingInterceptor()
43 | .setLevel(HttpLoggingInterceptor.Level.BODY));
44 | mRetrofit = new Retrofit.Builder()
45 | .client(httpClientBuilder.build())
46 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
47 | .addConverterFactory(GsonConverterFactory.create())
48 | .baseUrl(Url.BASE_URL)
49 | .build();
50 | return mRetrofit;
51 | }
52 | ```
53 | - DevMvpService-接口管理
54 | 这边直接使用BookBean对象接收返回值
55 | ```java
56 | @GET(Url.BOOK_CLASSIFY)
57 | Observable bookClassify();
58 | ```
59 | ##### 2.contract-契约类,v层和p层接口管理
60 | - CBook-测试契约类
61 | Contract用于存放mvp三层接口类 放在一起便于管理,不用生成太多的类(因为model没有需要处理的数据,所以没有使用接口,可自行生成实现)
62 | ```java
63 | interface IPBook extends IBasePresenter {
64 | void pBook();
65 | }
66 | interface IVBook extends IBaseView {
67 | void vBookSuccess(BookBean bean);
68 | void vBookError(String reason);
69 | }
70 | ```
71 | ##### 3.model-M层
72 | - BaseModel-M层基类
73 | 网络请求初始化和网络请求取消处理
74 | ```java
75 | public CompositeDisposable mDisposable = new CompositeDisposable();
76 | /**
77 | * 初始化调用网络请求
78 | * @return
79 | */
80 | public DevMvpService apiService() {
81 | return DevMvpApi.createApi().create(DevMvpService.class);
82 | }
83 | /**
84 | * 取消网络请求
85 | */
86 | public void onDestroy() {
87 | if (mDisposable != null) {
88 | mDisposable.isDisposed();
89 | mDisposable.clear();
90 | }
91 | }
92 | ```
93 | - MBookImpl-M层数据处理
94 | 由于不需要对数据进行处理,我就直接返回给P层,如果数据可能会从数据库、缓存、网络获取,需要在这里进行处理。
95 | ```java
96 | public void mBook(RxObservable rxObservable) {
97 | apiService()
98 | .bookClassify()
99 | .compose(RxTransformer.switchSchedulers(this))
100 | .subscribe(rxObservable);
101 | }
102 |
103 | ```
104 | ##### 4.presenter-P层
105 | - BasePresenter-P层基类
106 | 连接V层和M层
107 | ```java
108 | public class BasePresenter {
109 | protected V mView;
110 | protected M mModel;
111 | protected Context mContext;
112 |
113 | public BasePresenter(Context mContext, V mView, M mModel) {
114 | this.mView = mView;
115 | this.mModel = mModel;
116 | this.mContext = mContext;
117 | }
118 |
119 | public void onDestroy() {
120 | if (mModel!=null) {
121 | mModel.onDestroy();
122 | }
123 | }
124 | }
125 | ```
126 |
127 | - PBookImpl-P层业务逻辑处理
128 |
129 | ```java
130 | /**
131 | * Created by Liang_Lu on 2017/12/21.
132 | * P层 此类只用于处理业务逻辑 然后把最终的结果回调给V层
133 | */
134 |
135 | public class PBookImpl extends BasePresenter implements CBook.IPBook {
136 | public PBookImpl(Context mContext, CBook.IVBook mView) {
137 | super(mContext, mView, new MBookImpl());
138 | }
139 | @Override
140 | public void pBook() {
141 | mView.showLoading();
142 | mModel.mBook(new RxObservable() {
143 | @Override
144 | public void onSuccess(BookBean bean) {
145 | mView.hideLoading();
146 | mView.vBookSuccess(bean);
147 | }
148 | @Override
149 | public void onFail(String reason) {
150 | mView.hideLoading();
151 | mView.vBookError(reason);
152 | }
153 | });
154 | }
155 | }
156 | ```
157 | ##### 5.view-V层
158 | - BaseActivity-V层基类(BaseFragment类似)
159 | 在基类跟P层建立连接,这里可以根据项目需求丰富BaseActivity。这里只把添加基础必备功能。
160 | ```java
161 | public abstract class BaseActivity extends AppCompatActivity {
162 | public Context mContext;
163 | public T mPresenter;
164 |
165 | @Override
166 | protected void onCreate(Bundle savedInstanceState) {
167 | super.onCreate(savedInstanceState);
168 | mContext = this;
169 | if (setContentViewId() != 0) {
170 | setContentView(setContentViewId());
171 | } else {
172 | throw new RuntimeException("layoutResID==-1 have u create your layout?");
173 | }
174 | createPresenter();
175 | ButterKnife.bind(this);
176 | initView();
177 | }
178 | /**
179 | * 初始化方法
180 | */
181 | protected void initView() {
182 | }
183 | /**
184 | * 获取contentView 资源id
185 | */
186 | public abstract int setContentViewId();
187 | /**
188 | * 创建presenter实例
189 | */
190 | public abstract void createPresenter();
191 | /**
192 | * activity跳转(无参数)
193 | *
194 | * @param className
195 | */
196 | public void startActivity(Class> className) {
197 | Intent intent = new Intent(mContext, className);
198 | startActivity(intent);
199 | }
200 | /**
201 | * activity跳转(有参数)
202 | *
203 | * @param className
204 | */
205 | public void startActivity(Class> className, Bundle bundle) {
206 | Intent intent = new Intent(mContext, className);
207 | intent.putExtras(bundle);
208 | startActivity(intent);
209 | }
210 | @Override
211 | protected void onDestroy() {
212 | super.onDestroy();
213 | if (mPresenter != null) {
214 | mPresenter.onDestroy();//页面销毁 网络请求同销毁
215 | }
216 | }
217 | }
218 | ```
219 | - BookActivity-V层页面渲染处理
220 | V层只需要操作页面控件,网络数据显示到页面上等等。
221 | ```java
222 | /**
223 | * Created by Liang_Lu on 2017/12/21.
224 | * V层 用于数据和页面UI展示(Fragment Dialog 同理)
225 | */
226 | public class BookActivity extends BaseActivity implements CBook.IVBook {
227 | private TextView mTv;
228 | private Button mBtn;
229 | @Override
230 | protected void initView() {
231 | super.initView();
232 | mBtn = findViewById(R.id.btn);
233 | mTv = findViewById(R.id.tv);
234 | mBtn.setOnClickListener(new View.OnClickListener() {
235 | @Override
236 | public void onClick(View v) {
237 | mPresenter.pBook();
238 | }
239 | });
240 | }
241 | @Override
242 | public int setContentViewId() {
243 | return R.layout.activity_book;
244 | }
245 | @Override
246 | public void createPresenter() {
247 | mPresenter = new PBookImpl(mContext, this);
248 | }
249 | @Override
250 | public void showLoading() {
251 | }
252 | @Override
253 | public void hideLoading() {
254 | }
255 | @Override
256 | public void vBookSuccess(BookBean bean) {
257 | mTv.setText("网络请求成功");
258 | }
259 | @Override
260 | public void vBookError(String reason) {
261 | mTv.setText(reason);
262 | }
263 | }
264 | ```
265 | #### 基础设置模板详解(Fragment类似)
266 | ##### globals.xml.ftl-声明全局变量
267 | ```xml
268 |
269 | <#assign Collection=extractLetters(ActivityClass)>//从输入的title中获取输入字符
270 | <#assign collection_name=Collection?lower_case>//获取到的字符转成小写
271 |
272 | //作为activity的layout的命名
273 | //作为activity类名
274 | //作为presenter类名
275 | //作为model类名
276 | //契约类-contract类名
277 | //契约类-view层接口名
278 | //契约类-presenter层接口名
279 | //项目包名(此处填写为自己的项目包名)
280 |
281 | ```
282 | ##### recipe.xml.ftl-文件生成指定目录
283 | > PS.这里需要注意一下,这里的根目录(root)是包名的那个目录,此项目例:com.luliang.devmvp
284 | ```xml
285 |
286 |
287 |
289 |
290 |
291 |
293 |
295 |
297 |
299 |
301 |
302 |
303 | ```
304 | ##### template.xml-创建模板页面设置
305 | > 这里主要设置模板名称、分类、生成模板需要填写的信息等等
306 | ```xml
307 |
314 |
315 |
316 |
317 |
318 |
319 |
325 |
326 |
327 |
333 |
334 |
335 | template_blank_activity.png
336 |
337 |
338 |
339 |
340 | ```
341 | #### Mvp基础代码生成设置详解
342 | > 文件的名称对应-文件生成指定目录文件(recipe.xml.ftl)里面的名称。
343 | ##### MvpActivity.java.ftl-类基础文件代码生成设置
344 | > MvpContract.java.ftl、MvpModel.java.ftl、MvpPresenter.java.ftl几个文件类似,就不一一列出来
345 | > ${ContractName} 等,对应全局变量文件(globals.xml.ftl)的变量。
346 | ```java
347 | package ${packageName}.mvp.view.activity;
348 |
349 | import ${packageName}.R;
350 | import ${packageName}.mvp.base.BaseActivity;
351 | import ${packageName}.mvp.contract.${ContractName};
352 | import ${packageName}.mvp.presenter.${PresenterName};
353 | import android.os.Bundle;
354 | /**
355 | * Created by Liang_Lu on 2017/12/21.
356 | * @author LuLiang
357 | * @github https://github.com/LiangLuDev
358 | */
359 |
360 | public class ${ActivityName} extends BaseActivity<${PresenterName}> implements ${ContractName}.${IViewName}{
361 |
362 | @Override
363 | protected void initView() {
364 | super.initView();
365 | }
366 | @Override
367 | public int setContentViewId() {
368 | return R.layout.activity_${activity_layout};
369 | }
370 | @Override
371 | public void createPresenter() {
372 | mPresenter = new ${PresenterName}(mContext, this);
373 | }
374 |
375 | @Override
376 | public void showLoading() {
377 | }
378 | @Override
379 | public void hideLoading() {
380 | }
381 | }
382 |
383 | ```
384 | ##### activity_main.xml.ftl-布局基础文件代码生成设置
385 | ```xml
386 |
392 |
393 | <#if isTitleBar>
394 |
395 | #if>
396 |
397 | ```
398 | ##### AndroidManifest.xml.ftl-Activity声明文件设置
399 | > PS.声明只针对于Activity,Fragment不需要此文件
400 | ```xml
401 |
402 |
403 |
404 |
405 |
406 | ```
407 | #### 一键生成MVP基础代码
408 | > - copy项目下的MvpActivity文件夹到Android Studio安装目录 例:C:\Android\Android Studio 3.0 release\plugins\android\lib\templates\activities文件夹下.
409 | > - MvpFragment 的路径是 C:\Android\Android Studio 3.0 release\plugins\android\lib\templates\other
410 | > - 重启Android Studio。
411 |
412 |
413 | - 重启Android Studio之后,选中包名路径
414 |
415 | 
416 | - 生成MvpActivity基础代码(MvpFragment可选中Fragment里面生成)
417 |
418 | 
419 |
420 | #### 依赖库使用
421 | > 将所有依赖的版本控制提取到根目录下的config.gradle做统一管理
422 | > - supportVersion : "26.1.0"
423 | > - retrofit : "2.2.0",
424 | > - rxjava : "2.0.1",
425 | > - rxandroid : "2.0.1",
426 | > - okhttp3 : "3.4.1",
427 | > - constraint_layout: "1.0.2",
428 | > - rxjava2_adapter : "1.0.0",
429 | > - logging : "3.4.0-RC1",
430 | > - butterknife : "8.8.1",
431 | #### 意见反馈
432 | 如果遇到问题或者好的优化建议,请反馈到:Issues、927195249@qq.com 或者LiangLuDev@gmail.com
433 |
434 | 如果觉得还行的话,右上角的星星点一下吧! 谢谢啦!
--------------------------------------------------------------------------------
/app/src/main/java/com/luliang/devmvp/mvp/bean/BookBean.java:
--------------------------------------------------------------------------------
1 | package com.luliang.devmvp.mvp.bean;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Created by LuLiang on 2018/4/4.
7 | *
8 | * @author LuLiang
9 | * @github https://github.com/LiangLuDev
10 | */
11 |
12 | public class BookBean {
13 |
14 |
15 | /**
16 | * male : [{"name":"玄幻","bookCount":514683,"monthlyCount":21366,"icon":"/icon/玄幻_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1228859%2F_1228859_441552.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F891697%2F_891697_378164.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F41584%2F_41584_123902.jpg%2F"]},{"name":"奇幻","bookCount":49774,"monthlyCount":2077,"icon":"/icon/奇幻_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1130743%2F_1130743_505316.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2230412%2F2230412_378f83347e304b10ba6c36a12b434a7b.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F713823%2F_713823_841716.jpg%2F"]},{"name":"武侠","bookCount":42693,"monthlyCount":1619,"icon":"/icon/武侠_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F682805%2F_682805_516722.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2219099%2F2219099_923da06a1a3e4d3ebd775e6264b18c59.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2194747%2F2194747_cbb7d4e028cb467e9fdd290a92e0a259.jpg%2F"]},{"name":"仙侠","bookCount":138121,"monthlyCount":7469,"icon":"/icon/仙侠_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1188355%2F_1188355_363695.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F682770%2F682770_abddc02117024aacb4ae3299cab3eb95.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2014980%2F2014980_bbbc3ba8b18646d09278e03f2a6dcaca.jpg%2F"]},{"name":"都市","bookCount":361097,"monthlyCount":14151,"icon":"/icon/都市_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F857368%2F857368_c92c5211a6504e0889fb1c09dcf4ce06.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F683354%2F_683354_716237.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2078208%2F2078208_b5931e0074c542608ef38c2ba0d961d7.jpg%2F"]},{"name":"职场","bookCount":16537,"monthlyCount":832,"icon":"/icon/职场_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2080563%2F2080563_7ff8c11c387b4517b57a311e57bd5407.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1159594%2F_1159594_169195.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1466377%2F_1466377_886541.jpg%2F"]},{"name":"历史","bookCount":72238,"monthlyCount":2851,"icon":"/icon/历史_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1314571%2F_1314571_289295.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1127342%2F_1127342_276630.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F634346%2F_634346_106373.jpg%2F"]},{"name":"军事","bookCount":15413,"monthlyCount":1291,"icon":"/icon/军事_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2194052%2F2194052_5831cda813fb4c758b90f2fc3ac20227.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1367432%2F_1367432_658946.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1164563%2F_1164563_951629.jpg%2F"]},{"name":"游戏","bookCount":82044,"monthlyCount":2383,"icon":"/icon/游戏_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2044454%2F2044454_75533bb1fdd94ea199c25abb2cd65985.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2208312%2F2208312_8e68612833784d6ca6e0b1875084dec2.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2202011%2F2202011_c9f4689365524bb1956d73fc3d9ab10c.jpg%2F"]},{"name":"竞技","bookCount":5877,"monthlyCount":361,"icon":"/icon/竞技_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1478042%2F_1478042_857319.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2096246%2F2096246_4e55a0850e6b46b385ec4b302b82b8fa.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1312764%2F_1312764_438601.jpg%2F"]},{"name":"科幻","bookCount":119885,"monthlyCount":2577,"icon":"/icon/科幻_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2185681%2F2185681_40c9ddb71b0048c394cf58df0dfca732.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2162481%2F2162481_94f413b58701406bbcb49d38bcd45e15.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1169779%2F_1169779_955701.jpg%2F"]},{"name":"灵异","bookCount":41914,"monthlyCount":4490,"icon":"/icon/灵异_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2190222%2F2190222_e20dc28831714bf8a67401e414f8d425.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2225869%2F2225869_20e952434e3d4ba2a3db22a71837d8b5.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1496497%2F_1496497_188071.jpg%2F"]},{"name":"同人","bookCount":40535,"monthlyCount":286,"icon":"/icon/同人_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1518279%2F_1518279_096405.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2213453%2F2213453_e5bfe0f131d446069e536497d896fb85.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2044717%2F2044717_87093d361a4b483896b61fd55f8a2a28.jpg%2F"]},{"name":"轻小说","bookCount":5048,"monthlyCount":335,"icon":"/icon/轻小说_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1494992%2F_1494992_119116.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2243879%2F2243879_94ff33910679471bb8060ad1c54663c6.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2206001%2F2206001_c7c857a454ec4a4b9ae4b5637f863a7e.jpg%2F"]}]
17 | * female : [{"name":"古代言情","bookCount":474997,"monthlyCount":11803,"icon":"/icon/古代言情_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2143521%2F2143521_083a5ac565cd458f9b84fcb88adf33fb.png%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1362823%2F_1362823_256513.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1505754%2F_1505754_955413.jpg%2F"]},{"name":"现代言情","bookCount":609275,"monthlyCount":17984,"icon":"/icon/现代言情_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F84550%2F84550_8767d46cd8e44064b51b4efd6ae08c2e.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2148350%2F2148350_b0ad169278c44027babf1b0aa1d8eabb.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1367041%2F_1367041_461002.jpg%2F"]},{"name":"青春校园","bookCount":116842,"monthlyCount":2874,"icon":"/icon/青春校园_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1200747%2F1200747_7f02bffa6b0b47889293ebc613d883ff.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1131279%2F_1131279_024701.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2207688%2F2207688_69a480b0c8924f16be9bf1b1a880ecc0.jpg%2F"]},{"name":"纯爱","bookCount":133668,"monthlyCount":1443,"icon":"/icon/耽美_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1174497%2F_1174497_618871.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F67324%2F_67324_158064.jpg%2F","/agent/http://ww2.sinaimg.cn/mw690/ed992597gw1ey1euf3n00j20f00k0wg9.jpg"]},{"name":"玄幻奇幻","bookCount":131234,"monthlyCount":662,"icon":"/icon/玄幻奇幻_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F42127%2F42127_765ca130f8d340558a87e2d5f1fc1301.png%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2045755%2F2045755_7a7a750f61f64703977e72cca5c8dc90.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2194067%2F2194067_c764cc59d729466e9d505fa33789b58a.jpg%2F"]},{"name":"武侠仙侠","bookCount":64772,"monthlyCount":1586,"icon":"/icon/武侠仙侠_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2143666%2F2143666_9bea767b345e4bf793060937af6a4c5f.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F44329%2F_44329_593234.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1187773%2F_1187773_659828.jpg%2F"]},{"name":"科幻","bookCount":10636,"monthlyCount":475,"icon":"/icon/科幻_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2175669%2F2175669_f7a71b481eb647d3978b8cceb1fe52e1.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2020880%2F2020880_9aa14120a38e4e34bfa1cf51920c17a1.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2207711%2F2207711_524c81ce00b74c508dcb8fa7cac18c75.jpg%2F"]},{"name":"游戏竞技","bookCount":6677,"monthlyCount":139,"icon":"/icon/游戏竞技_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F42014%2F_42014_918695.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F74250%2F74250_eb225d07b43b48a38623bf7817e0fde7.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2182694%2F2182694_610b00f6aa5b4dc888c266fee46d711b.jpg%2F"]},{"name":"悬疑灵异","bookCount":14181,"monthlyCount":714,"icon":"/icon/悬疑灵异_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1457026%2F_1457026_237840.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1267576%2F_1267576_273302.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F58330%2F58330_885b2bcace1740d18c680880dd9bbff7.jpg%2F"]},{"name":"同人","bookCount":118596,"monthlyCount":200,"icon":"/icon/同人_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2182241%2F2182241_252c8b2f0302468abe96aabde683c640.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2182242%2F2182242_418232fc41054c1f91f0a36b8aae6f2a.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2175881%2F2175881_3d3307249df5460ebf254edd6e5f3e2b.jpg%2F"]},{"name":"女尊","bookCount":20840,"monthlyCount":1080,"icon":"/icon/女尊_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F851414%2F_851414_740896.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F857217%2F857217_34eea5a4425d4437896b19d2774ac5da.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2148904%2F2148904_418eb43d34aa479087d8092720446b2b.jpg%2F"]},{"name":"莉莉","bookCount":25956,"monthlyCount":81,"icon":"/icon/百合_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2190309%2F2190309_78c7346877924b62a260fb1fc09228fd.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2190667%2F2190667_0bfcccfc6c264980aada08c1b36762b6.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2190689%2F2190689_9ba615979d174cc1995afda9afe078d4.jpg%2F"]}]
18 | * picture : [{"name":"热血","bookCount":720,"monthlyCount":114,"icon":"/icon/热血_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F194607%2F194607_72270909242745fd83336e39b251e874.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F182350%2F41eb45e4c2e740a69140be391ad7cb4a.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F187647%2F187647_6275adb20b7248e487b4162d07911a6d.jpg%2F"]},{"name":"魔幻","bookCount":525,"monthlyCount":122,"icon":"/icon/魔幻_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F168407%2F168407_d1492388cfdc4f4c974bc503939edff0.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F184162%2F184162_33ed57ff61704076bfd487393623103b.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F166465%2F166465_5af02a7135da402abd9d4138b3bfa42f.jpg%2F"]},{"name":"科幻","bookCount":76,"monthlyCount":11,"icon":"/icon/科幻_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F195759%2F195759_26346998ba4b48e38127aa7d44d96586.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F193264%2F193264_eed196c5293543ff85a1812e59772abd.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F176272%2F176272_c231f6803b0040a48dda7b21a73e7629.jpg%2F"]},{"name":"恋爱","bookCount":1340,"monthlyCount":237,"icon":"/icon/恋爱_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2021320%2F2021320_dd612b7c03794c00a385f8d95ee56a4e.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F180377%2F180377_7cc9d58141574542bace87325ceb19a6.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2191154%2F2191154_b83b6f631cb2462096d7bd4fa36188bf.jpg%2F"]},{"name":"搞笑","bookCount":1747,"monthlyCount":158,"icon":"/icon/搞笑_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2021717%2F2021717_b9c8d4bfbcdb4c649b7cce9478efbb94.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2185190%2F2185190_02b51397c05d48b1baefd51fcaaa6023.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2205236%2F2205236_7147872c63624b009128a06e481d2039.jpg%2F"]},{"name":"悬疑","bookCount":338,"monthlyCount":73,"icon":"/icon/悬疑_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F180667%2F180667_71d180052a4341558cad79e1d67d7be9.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F191033%2F191033_496b5f1507b9410e8d05e8c2edaa3b49.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F167573%2F167573_5ced5851fd144fcdb226e18274e0a430.jpg%2F"]},{"name":"少儿","bookCount":3376,"monthlyCount":1507,"icon":"/icon/少儿_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F196173%2F4feec11cc5374667b58c4d2ea4cc095a.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F189090%2F7839c7161b544d40b492627281e70492.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F177704%2F9b8c606f4c30403189731ae11660f441.jpg%2F"]}]
19 | * press : [{"name":"传记名著","bookCount":5026,"monthlyCount":1528,"icon":"/icon/传记名著_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F30771%2F_30771_973261.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F42798%2F_42798_755444.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F53598%2F_53598_122310.jpg%2F"]},{"name":"出版小说","bookCount":13273,"monthlyCount":3438,"icon":"/icon/出版小说_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2202149%2F2202149_4c108c40f4264a4089e977b1830c5a40.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F41574%2F_41574_081848.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F685582%2F_685582_433326.jpg%2F"]},{"name":"人文社科","bookCount":63312,"monthlyCount":13923,"icon":"/icon/人文社科_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2053642%2F2053642_1675460130664e3295282eeea531f0b9.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1175601%2F_1175601_339438.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2091345%2F2091345_default_cover.png%2F"]},{"name":"生活时尚","bookCount":2915,"monthlyCount":537,"icon":"/icon/生活时尚_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2063886%2F2063886_ee5c3b3bb2cc4332a319c05adea1753f.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2186830%2F2186830_52ad3a388ff14adca060f232526d4227.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1529069%2F_1529069_328412.jpg%2F"]},{"name":"经管理财","bookCount":5482,"monthlyCount":1727,"icon":"/icon/经管理财_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F19087%2F_19087_732103.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F34695%2F_34695_083305.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2111603%2F2111603_default_cover.png%2F"]},{"name":"青春言情","bookCount":12199,"monthlyCount":2063,"icon":"/icon/青春言情_.png","bookCover":["/cover/152151126559339","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1419744%2F_1419744_418690.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2144003%2F2144003_0ce9ce7d451c467990617050122914c7.jpg%2F"]},{"name":"外文原版","bookCount":1400,"monthlyCount":423,"icon":"/icon/外文原版_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2022998%2F2022998_17ff5053c0344d5db5c892fbd4d9dde6.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F42735%2F_42735_042736.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1418090%2F_1418090_647350.jpg%2F"]},{"name":"政治军事","bookCount":740,"monthlyCount":263,"icon":"/icon/政治军事_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F685458%2F_685458_619168.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F685334%2F_685334_174607.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2043686%2F2043686_f6d7f4a2769245648754943037d2e9aa.jpg%2F"]},{"name":"成功励志","bookCount":11103,"monthlyCount":2765,"icon":"/icon/成功励志_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F577424%2F_577424_901386.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1522490%2F_1522490_091877.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F858627%2F_858627_838818.jpg%2F"]},{"name":"育儿健康","bookCount":11655,"monthlyCount":2740,"icon":"/icon/育儿健康_.png","bookCover":["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2154248%2F2154248_51181588edee4bef8d794a534442fc2d.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2041720%2F2041720_e3a7cf609777415fba8cfc91b3a87e28.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1371877%2F_1371877_559378.jpg%2F"]}]
20 | * ok : true
21 | */
22 |
23 | private boolean ok;
24 | private List male;
25 | private List female;
26 | private List picture;
27 | private List press;
28 |
29 | public boolean isOk() {
30 | return ok;
31 | }
32 |
33 | public void setOk(boolean ok) {
34 | this.ok = ok;
35 | }
36 |
37 | public List getMale() {
38 | return male;
39 | }
40 |
41 | public void setMale(List male) {
42 | this.male = male;
43 | }
44 |
45 | public List getFemale() {
46 | return female;
47 | }
48 |
49 | public void setFemale(List female) {
50 | this.female = female;
51 | }
52 |
53 | public List getPicture() {
54 | return picture;
55 | }
56 |
57 | public void setPicture(List picture) {
58 | this.picture = picture;
59 | }
60 |
61 | public List getPress() {
62 | return press;
63 | }
64 |
65 | public void setPress(List press) {
66 | this.press = press;
67 | }
68 |
69 | public static class MaleBean {
70 | /**
71 | * name : 玄幻
72 | * bookCount : 514683
73 | * monthlyCount : 21366
74 | * icon : /icon/玄幻_.png
75 | * bookCover : ["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1228859%2F_1228859_441552.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F891697%2F_891697_378164.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F41584%2F_41584_123902.jpg%2F"]
76 | */
77 |
78 | private String name;
79 | private int bookCount;
80 | private int monthlyCount;
81 | private String icon;
82 | private List bookCover;
83 |
84 | public String getName() {
85 | return name;
86 | }
87 |
88 | public void setName(String name) {
89 | this.name = name;
90 | }
91 |
92 | public int getBookCount() {
93 | return bookCount;
94 | }
95 |
96 | public void setBookCount(int bookCount) {
97 | this.bookCount = bookCount;
98 | }
99 |
100 | public int getMonthlyCount() {
101 | return monthlyCount;
102 | }
103 |
104 | public void setMonthlyCount(int monthlyCount) {
105 | this.monthlyCount = monthlyCount;
106 | }
107 |
108 | public String getIcon() {
109 | return icon;
110 | }
111 |
112 | public void setIcon(String icon) {
113 | this.icon = icon;
114 | }
115 |
116 | public List getBookCover() {
117 | return bookCover;
118 | }
119 |
120 | public void setBookCover(List bookCover) {
121 | this.bookCover = bookCover;
122 | }
123 | }
124 |
125 | public static class FemaleBean {
126 | /**
127 | * name : 古代言情
128 | * bookCount : 474997
129 | * monthlyCount : 11803
130 | * icon : /icon/古代言情_.png
131 | * bookCover : ["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F2143521%2F2143521_083a5ac565cd458f9b84fcb88adf33fb.png%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1362823%2F_1362823_256513.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F1505754%2F_1505754_955413.jpg%2F"]
132 | */
133 |
134 | private String name;
135 | private int bookCount;
136 | private int monthlyCount;
137 | private String icon;
138 | private List bookCover;
139 |
140 | public String getName() {
141 | return name;
142 | }
143 |
144 | public void setName(String name) {
145 | this.name = name;
146 | }
147 |
148 | public int getBookCount() {
149 | return bookCount;
150 | }
151 |
152 | public void setBookCount(int bookCount) {
153 | this.bookCount = bookCount;
154 | }
155 |
156 | public int getMonthlyCount() {
157 | return monthlyCount;
158 | }
159 |
160 | public void setMonthlyCount(int monthlyCount) {
161 | this.monthlyCount = monthlyCount;
162 | }
163 |
164 | public String getIcon() {
165 | return icon;
166 | }
167 |
168 | public void setIcon(String icon) {
169 | this.icon = icon;
170 | }
171 |
172 | public List getBookCover() {
173 | return bookCover;
174 | }
175 |
176 | public void setBookCover(List bookCover) {
177 | this.bookCover = bookCover;
178 | }
179 | }
180 |
181 | public static class PictureBean {
182 | /**
183 | * name : 热血
184 | * bookCount : 720
185 | * monthlyCount : 114
186 | * icon : /icon/热血_.png
187 | * bookCover : ["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F194607%2F194607_72270909242745fd83336e39b251e874.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F182350%2F41eb45e4c2e740a69140be391ad7cb4a.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F187647%2F187647_6275adb20b7248e487b4162d07911a6d.jpg%2F"]
188 | */
189 |
190 | private String name;
191 | private int bookCount;
192 | private int monthlyCount;
193 | private String icon;
194 | private List bookCover;
195 |
196 | public String getName() {
197 | return name;
198 | }
199 |
200 | public void setName(String name) {
201 | this.name = name;
202 | }
203 |
204 | public int getBookCount() {
205 | return bookCount;
206 | }
207 |
208 | public void setBookCount(int bookCount) {
209 | this.bookCount = bookCount;
210 | }
211 |
212 | public int getMonthlyCount() {
213 | return monthlyCount;
214 | }
215 |
216 | public void setMonthlyCount(int monthlyCount) {
217 | this.monthlyCount = monthlyCount;
218 | }
219 |
220 | public String getIcon() {
221 | return icon;
222 | }
223 |
224 | public void setIcon(String icon) {
225 | this.icon = icon;
226 | }
227 |
228 | public List getBookCover() {
229 | return bookCover;
230 | }
231 |
232 | public void setBookCover(List bookCover) {
233 | this.bookCover = bookCover;
234 | }
235 | }
236 |
237 | public static class PressBean {
238 | /**
239 | * name : 传记名著
240 | * bookCount : 5026
241 | * monthlyCount : 1528
242 | * icon : /icon/传记名著_.png
243 | * bookCover : ["/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F30771%2F_30771_973261.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F42798%2F_42798_755444.jpg%2F","/agent/http%3A%2F%2Fimg.1391.com%2Fapi%2Fv1%2Fbookcenter%2Fcover%2F1%2F53598%2F_53598_122310.jpg%2F"]
244 | */
245 |
246 | private String name;
247 | private int bookCount;
248 | private int monthlyCount;
249 | private String icon;
250 | private List bookCover;
251 |
252 | public String getName() {
253 | return name;
254 | }
255 |
256 | public void setName(String name) {
257 | this.name = name;
258 | }
259 |
260 | public int getBookCount() {
261 | return bookCount;
262 | }
263 |
264 | public void setBookCount(int bookCount) {
265 | this.bookCount = bookCount;
266 | }
267 |
268 | public int getMonthlyCount() {
269 | return monthlyCount;
270 | }
271 |
272 | public void setMonthlyCount(int monthlyCount) {
273 | this.monthlyCount = monthlyCount;
274 | }
275 |
276 | public String getIcon() {
277 | return icon;
278 | }
279 |
280 | public void setIcon(String icon) {
281 | this.icon = icon;
282 | }
283 |
284 | public List getBookCover() {
285 | return bookCover;
286 | }
287 |
288 | public void setBookCover(List bookCover) {
289 | this.bookCover = bookCover;
290 | }
291 | }
292 | }
293 |
--------------------------------------------------------------------------------