├── .gitignore ├── .idea ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── example │ │ └── sunddenfix │ │ └── retrofit │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── sunddenfix │ │ │ └── retrofit │ │ │ ├── App.java │ │ │ ├── base │ │ │ ├── BaseActivity.java │ │ │ ├── BaseAdapter.java │ │ │ ├── BasePrensenter.java │ │ │ ├── BaseViewHolder.java │ │ │ ├── IPresenter.java │ │ │ └── IView.java │ │ │ ├── bean │ │ │ └── CountryModel.java │ │ │ ├── business │ │ │ ├── MainReq.java │ │ │ └── api │ │ │ │ └── IMainService.java │ │ │ ├── config │ │ │ ├── ActionResult.java │ │ │ ├── ConfigServer.kt │ │ │ └── Constant.kt │ │ │ ├── presenter │ │ │ └── MainPresenter.java │ │ │ ├── ui │ │ │ ├── MainActivity.java │ │ │ └── adapter │ │ │ │ └── CountryAdapter.java │ │ │ ├── utils │ │ │ ├── TimeUtils.kt │ │ │ ├── UncheckedUtil.java │ │ │ ├── bus │ │ │ │ ├── BusUtil.kt │ │ │ │ └── EventBusModel.kt │ │ │ ├── glide │ │ │ │ ├── GlideUtil.kt │ │ │ │ └── OkHttpGlideModule.kt │ │ │ ├── request │ │ │ │ └── BaseApi.kt │ │ │ └── rx │ │ │ │ ├── RxSubscriber.java │ │ │ │ └── SchedulersHelper.java │ │ │ └── viewIm │ │ │ └── MainView.java │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ └── item_country.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ ├── bg_default_img.png │ │ ├── bg_default_square.png │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── example │ └── sunddenfix │ └── retrofit │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .idea/ 10 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 24 | 41 | 42 | 43 | 44 | 45 | 46 | 48 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 项目说明: 2 | 上线说明: 3 | 1:注意切换环境 测试 予发布 线上 ConfigServer API_INDEX( 0 测试 1予发布 2 线上) 4 | 2:记得修改版办号(gradle.properties 文件中) 5 | 3:AndroidManifest.xml 关闭log开关 is_debug:(release-false debug-true) 6 | 7 | 整个项目使用java 语言编写 8 | 1:整体架构设计 9 | MVP+Rx+Retrofit 这是一套完整的架构设计,用MVP这种设计模式,结合Rx这种响应式的方式降低耦合度,网络框架使用了okhttp的封装框架Retrofit 10 | 该框架也支持Rx这种响应式。 11 | 12 | 2.使用到的三方库: 13 | 目前图片加载框架使用的是Glide(自己包装了一层,在util包下的glide包下,方便后期如果更换,只需要在包装类中做修改)。通知还是使用的EventBus。 14 | 网络请求框架Retrofit,异步处理Rxjava RxAndroid。线程切换工具类SchedulersHelper。 15 | 16 | 例外:DisposableSubscriber对这个类进行了包装,方便以后所有的请求处理都在RxSubscriber中的onNext方法处理,比如后期需要增加不同的状态做不同的事情,只需要在这里增加即可 17 | 不需要再所有请求的地方去添加。针对请求结果处理,自己实现_onSuccess方法,结合泛型,该方法拿到的就是自己需要的数据模型。 18 | 19 | 3.项目包说明: 20 | base: 21 | 该包下存放的都是基类,以及顶层的父类以及接口。命名规则:基类以Base开头,顶层接口以I开头 22 | bean: 23 | 该包下存放的是所有的数据model,命名规则:功能名称+bean 比如UserBean 用户的数据model 24 | config: 25 | 该包下存放的都是常量管理类,ActionResult 接口返回的统一标准;configServer接口相关的,比如接口名称,域名,等常量管理类; 26 | Constant 其他常量。 27 | exception: 28 | 自定义的异常处理类 29 | listener: 30 | 自定义的Listener类 31 | presenter: 32 | presenter管理类,所有的逻辑处理presenter都在包下统一管理, 命名规则:功能+pre(名字太长的可缩写成pre) 比如:LoginPre 33 | req: 34 | 请求管理类。 35 | 该包下的api包:所有页面的接口请求定义的Service,命名规则:I+功能+service 比如:ILoginService 登陆相关的请求定义接口 36 | 该包下的http:关于http相关的工具 和 封装的Retrofit管理类。后面如需定义接口返回的statusCode 也放在这里 37 | 所有的请求处理类,命名规则:功能+Req,表示某个页面的请求处理类。比如首页: MainReq 登陆 LoginReq 38 | 39 | ui: 40 | //分包 待商榷,有2种方式,1:四大组件方式,2功能模块方式,商榷后确定即可 41 | 所有界面相关的类。没有完全的按照功能分包,因为像presenter 以及 req 这些没必要每个功能包下都建一个,可以放在一个包统一进行管理,出于这个考虑所以没有完全按照功能分,可以说是按照 42 | 逻辑处理,以及界面显示将两者分开 这样的思想分的包。在ui包下,可以建各个二级包表示某个功能的页面,比如:login包下 就是login相关的界面显示(activity,fragment)。 43 | adapter包由于也是驱动页面显示 所以也放在了该包下,所有的adapter都放在该包下,命名规则:功能+adapter 比如 CouponAdapter 优惠券列表的adapter 44 | 45 | util: 46 | 该包下都是可以直接使用的一些工具类,工具类都放这里。 47 | bus:通知的工具类 48 | glide:glide的工具类 49 | rx:rx相关的工具封装类 50 | viewImpl:所有MVP模式需要的界面显示方法接口定义的接口view 命名规则:功能+view 比如:LoginView 51 | 52 | widget: 53 | 存放所有自定义View的包。 54 | 55 | 56 | 4:整个项目的规则 57 | 58 | 1:所有的string都需要定义在values/strings下,不可直接写在代码中 59 | 2:所有的color都需要定义在values/colors下,特殊情况除外 60 | 3:布局xml中的dp sp 都需要定义在values/dimens下。dp_10 sp_12 61 | 62 | 4:所有代码中的命名规则均以驼峰命名:比如: 变量:userInfo 类:LoginActivity 成员变量m开头 如mCountry 63 | 64 | 5:控件id命名规则: 65 | 控件缩写+功能 缩写即是所有单词首字母组合 66 | 比如: 67 | TextView 缩写 tv 68 | Button 缩写 btn 69 | ImageView 缩写 iv 70 | RelativeLayout 缩写 rl 71 | 比如:mBtnLogin 表示 登陆按钮 (xml 中下划线 btn_login)kotlin 中可以直接在xml 声明控件的成员变量 mBtnLogin 72 | 73 | 6:Activity和Fragment命名规则: 74 | 所有的Activiy命名都以 功能+Activity 方式,layout xml 对应的 activity_功能名称 75 | 比如:LoginActivity 对应xml activity_login 76 | 同理Fragment: LoginFragment 对应xml fragment_login 77 | 78 | 类似:列表Adapter中的xml 以item+功能 比如:item_coupon 优惠券列表 79 | 自定义view中xml 以 view_功能 比如:view_refresh_footer 自定义的刷新footer 80 | 81 | 7:drawable命名: 82 | shape 以 shape开头 83 | selector以selector开头 84 | 8:资源图片只放一套:(.9除外) 85 | 如果高保真是1080 资源图片放到 mipmap-xxhdpi 86 | 如果高保真是750 资源图片放到 mipmap-xhdpi 87 | 88 | 9:注释: 89 | 所有的类需加上类说明的注释 表示该类的功能和作用 90 | 比如:LoginActivity 91 | 92 | /** 93 | * @Author wangchengm 94 | * @desc 登陆页面 95 | */ 96 | 成员变量尽量规范命名,看名知用的效果,可以增加代码的可读性,比较复杂的逻辑 尽量对成员变量以及,方法加上说明注释,甚至对每一行代码加上注释。 -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | 3 | .idea/ -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | defaultConfig { 6 | applicationId rootProject.ext.applicationId 7 | minSdkVersion rootProject.ext.minSdkVersion 8 | targetSdkVersion rootProject.ext.targetSdkVersion 9 | multiDexEnabled true 10 | versionCode rootProject.ext.versionCode 11 | versionName rootProject.ext.versionName 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | flavorDimensions "versionCode" 14 | 15 | manifestPlaceholders = [ 16 | //需要在清单文件中配置的 三方id,所有三方用到的ID 都配置到gradle.properties文件中统一管理 包括版本号,这些 17 | WX_APP_ID : rootProject.ext.WXAppId, 18 | UMENG_APP_KEY: rootProject.ext.UmengAppKey 19 | ] 20 | 21 | compileOptions { 22 | sourceCompatibility = JavaVersion.VERSION_1_8 23 | targetCompatibility = JavaVersion.VERSION_1_8 24 | } 25 | 26 | ndk { 27 | abiFilters "armeabi-v7a" 28 | //, "arm64-v8a"//"armeabi",// "x86", "x86_64" 国内通常只需要armeabi-v7a即可 29 | } 30 | resConfigs "zh" 31 | javaCompileOptions { 32 | annotationProcessorOptions { 33 | includeCompileClasspath = true 34 | } 35 | } 36 | } 37 | 38 | //签名设置 39 | // signingConfigs { 40 | // debug { 41 | // storeFile file(rootProject.ext.AppSignNameFile) 42 | // storePassword rootProject.ext.AppSignPassword 43 | // keyAlias rootProject.ext.AppSignKeyAlias 44 | // keyPassword rootProject.ext.AppSignPassword 45 | // } 46 | // release { 47 | // storeFile file(rootProject.ext.AppSignNameFile) 48 | // storePassword rootProject.ext.AppSignPassword 49 | // keyAlias rootProject.ext.AppSignKeyAlias 50 | // keyPassword rootProject.ext.AppSignPassword 51 | // } 52 | // } 53 | 54 | buildTypes { 55 | release { 56 | minifyEnabled false 57 | zipAlignEnabled true 58 | shrinkResources false 59 | multiDexEnabled true 60 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 61 | } 62 | 63 | debug { 64 | minifyEnabled false 65 | zipAlignEnabled true 66 | shrinkResources false 67 | multiDexEnabled true 68 | renderscriptDebuggable true 69 | } 70 | } 71 | } 72 | 73 | dependencies { 74 | implementation fileTree(dir: 'libs', include: ['*.jar']) 75 | implementation 'androidx.appcompat:appcompat:1.1.0' 76 | implementation 'androidx.core:core-ktx:1.2.0' 77 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 78 | testImplementation 'junit:junit:4.12' 79 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 80 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 81 | implementation "androidx.recyclerview:recyclerview:1.1.0" 82 | implementation "com.google.android.material:material:1.1.0" 83 | 84 | //rx retrofit 85 | implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' 86 | implementation 'com.squareup.retrofit2:retrofit:2.4.0' 87 | implementation 'com.squareup.retrofit2:converter-gson:2.4.0' 88 | implementation 'com.squareup.okhttp3:okhttp:3.10.0' 89 | implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' 90 | implementation 'com.squareup.retrofit2:converter-scalars:2.4.0' 91 | implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' 92 | implementation 'com.google.code.gson:gson:2.8.5' 93 | implementation 'com.jakewharton.rxbinding2:rxbinding:2.0.0' 94 | //分包 95 | implementation 'com.android.support:multidex:1.0.3' 96 | //eventBus 97 | implementation 'org.greenrobot:eventbus:3.1.1' 98 | 99 | //glide 100 | implementation 'com.github.bumptech.glide:glide:4.9.0' 101 | annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0' 102 | implementation('me.imid.swipebacklayout.lib:library:1.1.0') { 103 | exclude group: 'com.android.support' 104 | } 105 | 106 | implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.2' //1.0.5及以前版本的老用户升级需谨慎,API改动过大 107 | // implementation 'com.scwang.smartrefresh:SmartRefreshHeader:1.1.2' //没有使用特殊Header,可以不加这行 108 | 109 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in E:\studioSDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/example/sunddenfix/retrofit/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/App.java: -------------------------------------------------------------------------------- 1 | // (c)2016 Flipboard Inc, All Rights Reserved. 2 | 3 | package com.example.sunddenfix.retrofit; 4 | 5 | import android.app.Application; 6 | 7 | public class App extends Application { 8 | private static App INSTANCE; 9 | 10 | public static App getInstance() { 11 | return INSTANCE; 12 | } 13 | 14 | @Override 15 | public void onCreate() { 16 | super.onCreate(); 17 | INSTANCE = this; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.base; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.annotation.Nullable; 6 | import androidx.appcompat.app.AppCompatActivity; 7 | 8 | /** 9 | * @author wangchengmeng 10 | * @desc 11 | * @更新时间 12 | */ 13 | public abstract class BaseActivity extends AppCompatActivity { 14 | 15 | protected T mIPresenter; 16 | 17 | @Override 18 | protected void onCreate(@Nullable Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | if (0 != getResourceId()) { 21 | setContentView(getResourceId()); 22 | } 23 | 24 | mIPresenter = getPresenter(); 25 | } 26 | 27 | protected abstract T getPresenter(); 28 | 29 | protected abstract int getResourceId(); 30 | 31 | @Override 32 | protected void onDestroy() { 33 | super.onDestroy(); 34 | //取消订阅 35 | mIPresenter.detachView(); 36 | mIPresenter = null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/base/BaseAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.base; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import androidx.annotation.NonNull; 9 | import androidx.recyclerview.widget.RecyclerView; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * @Author wangchengm 15 | * RecyclerView Adapter 的基类 增强了 可以自由添加header 和 footer功能 16 | */ 17 | public abstract class BaseAdapter extends RecyclerView.Adapter { 18 | protected static final String TAG = BaseAdapter.class.getSimpleName(); 19 | 20 | private OnItemClickListener mOnItemClickListener; 21 | 22 | private enum ITEM_TYPE { 23 | HEADER, //头部 24 | FOOTER, //尾部 25 | NORMAL, //中间 26 | } 27 | 28 | private int mLayoutId;//item的布局id 29 | private Context mContext; 30 | private List mDatas; //数据载体 31 | 32 | private View mHeaderView; 33 | private View mFooterView; 34 | 35 | /** 36 | * 添加尾部 37 | * 38 | * @param footerView 尾部的View 39 | */ 40 | public void addFooter(View footerView) { 41 | if (!hasFooter()) { 42 | mFooterView = footerView; 43 | } 44 | } 45 | 46 | /** 47 | * 移除尾部 48 | */ 49 | public void removeFooter() { 50 | if (hasFooter()) { 51 | mFooterView = null; 52 | } 53 | } 54 | 55 | public List getAllData() { 56 | return mDatas; 57 | } 58 | 59 | /** 60 | * 添加头部 61 | * 62 | * @param headerView 头部的View 63 | */ 64 | public void addHeader(View headerView) { 65 | mHeaderView = headerView; 66 | } 67 | 68 | public boolean hasHeader() { 69 | return null != mHeaderView; 70 | } 71 | 72 | public boolean hasFooter() { 73 | return null != mFooterView; 74 | } 75 | 76 | 77 | @Override 78 | public int getItemViewType(int position) { 79 | int count = mDatas.size();//获取除 中间部分的数据条数 80 | if (hasHeader()) { 81 | count++; //如anjue 果带了header 那就+1 82 | } 83 | if (hasHeader() && position == 0) { 84 | return BaseAdapter.ITEM_TYPE.HEADER.ordinal(); //返回header类型 85 | } else if (hasFooter() && position == count) { 86 | return BaseAdapter.ITEM_TYPE.FOOTER.ordinal(); //返回footer类型 87 | } else { 88 | return BaseAdapter.ITEM_TYPE.NORMAL.ordinal(); //返回normal类型 89 | } 90 | } 91 | 92 | protected BaseAdapter(Context context, int layoutId, @NonNull List datas) { 93 | this.mContext = context; 94 | this.mLayoutId = layoutId; 95 | this.mDatas = datas; 96 | } 97 | 98 | public void setList(List data) { 99 | this.mDatas = data; 100 | notifyDataSetChanged(); 101 | } 102 | 103 | /** 104 | * 如果没有更多数据了 添加没有更多的footer 105 | * 106 | * @param hasMore true 有更多 false 没有更多 107 | */ 108 | public void hasMoreData(boolean hasMore) { 109 | if (hasMore) { 110 | removeFooter(); 111 | } else { 112 | // addFooter(new VRefreshFooterView(mContext, false)); 113 | } 114 | } 115 | 116 | @Override 117 | public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 118 | //根绝不同的类型处理对应的ViewHolder 119 | if (viewType == BaseAdapter.ITEM_TYPE.HEADER.ordinal()) { 120 | return new BaseViewHolder(mContext, mHeaderView); 121 | } else if (viewType == BaseAdapter.ITEM_TYPE.FOOTER.ordinal()) { 122 | return new BaseViewHolder(mContext, mFooterView); 123 | } else { 124 | //使用子类的ViewHolder(为了方便在子类ViewHolder里面做适配测量) 125 | VH viewHolder = getViewHolder(LayoutInflater.from(mContext).inflate(mLayoutId, parent, false)); 126 | setListener(viewHolder.getContentView(), viewHolder); 127 | return viewHolder; 128 | } 129 | } 130 | 131 | protected abstract VH getViewHolder(View itemView); 132 | 133 | protected void setListener(final View contentView, BaseViewHolder viewHolder) { 134 | contentView.setOnClickListener(v -> { 135 | if (null != mOnItemClickListener) { 136 | mOnItemClickListener.onItemClick(v, viewHolder, viewHolder.getAdapterPosition()); 137 | } 138 | }); 139 | 140 | contentView.setOnLongClickListener(v -> { 141 | if (null != mOnItemClickListener) { 142 | return mOnItemClickListener.onItemLongClick(v, viewHolder, viewHolder.getAdapterPosition()); 143 | } 144 | return false; 145 | }); 146 | } 147 | 148 | @Override 149 | public void onBindViewHolder(@NonNull BaseViewHolder holder, int position) { 150 | if (hasHeader() && position == 0) { 151 | //header的逻辑分离开来,在外部处理 152 | return; 153 | } 154 | int count = mDatas.size(); 155 | if (hasHeader()) { 156 | count++; 157 | } 158 | if (hasFooter()) { 159 | count++; 160 | } 161 | if (hasFooter() && position == count - 1) { 162 | //footer的逻辑分离开来,在外部处理 163 | return; 164 | } 165 | //normal的逻辑 交给实现类去处理 166 | if (hasHeader()) { 167 | onChildBindViewHolder(holder, getData(position - 1), position); 168 | } else { 169 | onChildBindViewHolder(holder, getData(position), position); 170 | } 171 | } 172 | 173 | @Override 174 | public int getItemCount() { 175 | int count = 0; 176 | if (null != mDatas) { 177 | count = mDatas.size(); 178 | if (hasHeader()) { 179 | count++; 180 | } 181 | if (hasFooter()) { 182 | count++; 183 | } 184 | } 185 | return count; //获取数据的数目,要加上对应的带header和footer的条数 186 | } 187 | 188 | /** 189 | * 获取数据对象 190 | * 191 | * @param position 列表中的位置 192 | * @return 返回列表中位置对应的数据 193 | */ 194 | public T getData(int position) { 195 | if (null != mDatas && position < mDatas.size()) { 196 | return mDatas.get(position); 197 | } 198 | return null; 199 | } 200 | 201 | /** 202 | * 返回数据的条目数量 203 | * 204 | * @return 数目 205 | */ 206 | public int getDataCount() { 207 | if (null != mDatas) { 208 | return mDatas.size(); 209 | } 210 | return 0; 211 | } 212 | 213 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 214 | this.mOnItemClickListener = onItemClickListener; 215 | } 216 | 217 | public interface OnItemClickListener { 218 | void onItemClick(View view, RecyclerView.ViewHolder holder, int position); 219 | 220 | boolean onItemLongClick(View view, RecyclerView.ViewHolder holder, int position); 221 | } 222 | 223 | /** 224 | * 子类必须实现的方法,在该方法中进行数据处理以及显示 225 | * 226 | * @param holder holder对象 227 | * @param data 数据 228 | */ 229 | protected abstract void onChildBindViewHolder(BaseViewHolder holder, T data, int position); 230 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/base/BasePrensenter.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.base; 2 | 3 | import android.app.Activity; 4 | 5 | import io.reactivex.disposables.CompositeDisposable; 6 | import io.reactivex.disposables.Disposable; 7 | 8 | /** 9 | * @author wangchengmeng 10 | */ 11 | public class BasePrensenter implements IPresenter { 12 | 13 | protected T mIView; 14 | protected Activity mActivity; 15 | 16 | //2.0之后的 取消订阅 17 | protected CompositeDisposable mCompositeDisposable; 18 | 19 | public BasePrensenter(Activity activity, T view) { 20 | this.mActivity = activity; 21 | this.mIView = view; 22 | } 23 | 24 | //取消所有的订阅 25 | protected void unSubscribe() { 26 | if (mCompositeDisposable != null) { 27 | mCompositeDisposable.dispose(); 28 | } 29 | } 30 | 31 | //将创建的subscriber添加到这个集合中,方便在Activity销毁的时候取消订阅 32 | protected void addSubscribe(Disposable disposable) { 33 | if (mCompositeDisposable == null) { 34 | mCompositeDisposable = new CompositeDisposable(); 35 | } 36 | mCompositeDisposable.add(disposable); 37 | } 38 | 39 | @Override 40 | public void detachView() { 41 | this.mIView = null; 42 | unSubscribe(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/base/BaseViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.base; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.text.Html; 6 | import android.util.SparseArray; 7 | import android.view.View; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import androidx.annotation.ColorRes; 12 | import androidx.annotation.DrawableRes; 13 | import androidx.annotation.IdRes; 14 | import androidx.annotation.StringRes; 15 | import androidx.core.content.ContextCompat; 16 | import androidx.recyclerview.widget.RecyclerView; 17 | 18 | import com.example.sunddenfix.retrofit.utils.UncheckedUtil; 19 | 20 | 21 | /** 22 | * @Author wangchengm 23 | * @desc Adapter 的BaseHolder 24 | */ 25 | public class BaseViewHolder extends RecyclerView.ViewHolder { 26 | 27 | private SparseArray mCacheView;//缓存pool 28 | private Context mContext;//上下文对象 29 | private View mContentView;//列表中的itemView 30 | 31 | public BaseViewHolder(Context context, View itemView) { 32 | super(itemView); 33 | this.mContext = context; 34 | this.mContentView = itemView; 35 | this.mCacheView = new SparseArray<>(); 36 | } 37 | 38 | public View getContentView() { 39 | return mContentView; 40 | } 41 | 42 | /** 43 | * 获取id对应的View 44 | * 45 | * @param viewId View的id 46 | * @param 泛型 47 | * @return 返回该id对应的View 48 | */ 49 | public T retrieveView(@IdRes int viewId) { 50 | View view = mCacheView.get(viewId); 51 | if (null == view) { 52 | //pool中还没有该id对应的View对象,添加进去 53 | view = mContentView.findViewById(viewId); 54 | mCacheView.put(viewId, view); 55 | } 56 | //如果pool中存在该id对应的View了 就不用去find了 57 | return UncheckedUtil.cast(view); 58 | } 59 | 60 | /** 61 | * 设置文本数据 62 | * 63 | * @param viewID viewID 64 | * @param value 设置的文本值 65 | */ 66 | public void setText(@IdRes int viewID, String value) { 67 | TextView textView = retrieveView(viewID); 68 | if (null != textView) { 69 | textView.setText(value); 70 | } 71 | } 72 | 73 | /** 74 | * html 5设置TextView的值 75 | * 76 | * @param viewId 77 | * @param source 78 | * @return 79 | */ 80 | public BaseViewHolder setHtmlText(int viewId, String source) { 81 | TextView tv = retrieveView(viewId); 82 | 83 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { 84 | tv.setText(Html.fromHtml(source, Html.FROM_HTML_MODE_LEGACY)); 85 | } else { 86 | tv.setText(Html.fromHtml(source)); 87 | } 88 | return this; 89 | } 90 | 91 | /** 92 | * 设置文本数据 93 | * 94 | * @param viewID View的id 95 | * @param resID 字符串资源的id 96 | */ 97 | public void setText(@IdRes int viewID, @StringRes int resID) { 98 | TextView textView = retrieveView(viewID); 99 | textView.setText(resID); 100 | } 101 | 102 | /** 103 | * 设置View的显示和隐藏 104 | * 105 | * @param viewID viewID 106 | * @param visible 是否隐藏 true 显示-VISIBLE false 隐藏-GONE 107 | */ 108 | public void setVisible(@IdRes int viewID, boolean visible) { 109 | View view = retrieveView(viewID); 110 | view.setVisibility(visible ? View.VISIBLE : View.GONE); 111 | } 112 | 113 | /** 114 | * 设置图片 115 | * 116 | * @param viewID View的id 117 | * @param resID 图片资源的id 118 | */ 119 | public void setImageRes(@IdRes int viewID, @DrawableRes int resID) { 120 | ImageView imageView = retrieveView(viewID); 121 | imageView.setImageResource(resID); 122 | } 123 | 124 | /** 125 | * 设置图片 126 | * 127 | * @param viewID View的id 128 | * @param bitmap 设置的bitmap 129 | */ 130 | public void setImageBitmap(@IdRes int viewID, Bitmap bitmap) { 131 | ImageView imageView = retrieveView(viewID); 132 | imageView.setImageBitmap(bitmap); 133 | } 134 | 135 | /** 136 | * 设置背景颜色 137 | * 138 | * @param viewID ViewID 139 | * @param color 颜色资源id 140 | */ 141 | public void setBackgroundColor(@IdRes int viewID, @ColorRes int color) { 142 | View view = retrieveView(viewID); 143 | view.setBackgroundColor(mContext.getResources().getColor(color)); 144 | } 145 | 146 | /** 147 | * 设置背景 148 | * 149 | * @param viewID View的id 150 | * @param resID 资源的id 151 | */ 152 | public void setBackgroundRes(@IdRes int viewID, @DrawableRes int resID) { 153 | View view = retrieveView(viewID); 154 | view.setBackgroundResource(resID); 155 | } 156 | 157 | /** 158 | * 设置字体的颜色 159 | * 160 | * @param viewID View的id 161 | * @param color 颜色资源id 162 | */ 163 | public void setTextColor(@IdRes int viewID, @ColorRes int color) { 164 | TextView textView = retrieveView(viewID); 165 | textView.setTextColor(ContextCompat.getColor(mContext, color)); 166 | } 167 | 168 | /** 169 | * 设置点击事件 170 | * 171 | * @param viewID View的id 172 | * @param listener 点击事件 173 | */ 174 | public void setOnClickListener(@IdRes int viewID, View.OnClickListener listener) { 175 | View view = retrieveView(viewID); 176 | view.setOnClickListener(listener); 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/base/IPresenter.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.base; 2 | 3 | /** 4 | * @author wangchengmeng 5 | */ 6 | public interface IPresenter { 7 | void detachView(); 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/base/IView.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.base; 2 | 3 | /** 4 | * @author wangchengmeng 5 | */ 6 | public interface IView { 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/bean/CountryModel.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.bean; 2 | 3 | /** 4 | * @author wangchengmeng 5 | */ 6 | public class CountryModel { 7 | private String area; 8 | private String area_id; 9 | private String city; 10 | private String city_id; 11 | private String country; 12 | private String country_id; 13 | private String county; 14 | private String county_id; 15 | private String ip; 16 | private String isp; 17 | private String isp_id; 18 | private String region; 19 | private String region_id; 20 | 21 | public String getArea() { 22 | return area; 23 | } 24 | 25 | public void setArea(String area) { 26 | this.area = area; 27 | } 28 | 29 | public String getArea_id() { 30 | return area_id; 31 | } 32 | 33 | public void setArea_id(String area_id) { 34 | this.area_id = area_id; 35 | } 36 | 37 | public String getCity() { 38 | return city; 39 | } 40 | 41 | public void setCity(String city) { 42 | this.city = city; 43 | } 44 | 45 | public String getCity_id() { 46 | return city_id; 47 | } 48 | 49 | public void setCity_id(String city_id) { 50 | this.city_id = city_id; 51 | } 52 | 53 | public String getCountry() { 54 | return country; 55 | } 56 | 57 | public void setCountry(String country) { 58 | this.country = country; 59 | } 60 | 61 | public String getCountry_id() { 62 | return country_id; 63 | } 64 | 65 | public void setCountry_id(String country_id) { 66 | this.country_id = country_id; 67 | } 68 | 69 | public String getCounty() { 70 | return county; 71 | } 72 | 73 | public void setCounty(String county) { 74 | this.county = county; 75 | } 76 | 77 | public String getCounty_id() { 78 | return county_id; 79 | } 80 | 81 | public void setCounty_id(String county_id) { 82 | this.county_id = county_id; 83 | } 84 | 85 | public String getIp() { 86 | return ip; 87 | } 88 | 89 | public void setIp(String ip) { 90 | this.ip = ip; 91 | } 92 | 93 | public String getIsp() { 94 | return isp; 95 | } 96 | 97 | public void setIsp(String isp) { 98 | this.isp = isp; 99 | } 100 | 101 | public String getIsp_id() { 102 | return isp_id; 103 | } 104 | 105 | public void setIsp_id(String isp_id) { 106 | this.isp_id = isp_id; 107 | } 108 | 109 | public String getRegion() { 110 | return region; 111 | } 112 | 113 | public void setRegion(String region) { 114 | this.region = region; 115 | } 116 | 117 | public String getRegion_id() { 118 | return region_id; 119 | } 120 | 121 | public void setRegion_id(String region_id) { 122 | this.region_id = region_id; 123 | } 124 | 125 | @Override 126 | public String toString() { 127 | return "CountryModel{" + 128 | "area='" + area + '\'' + 129 | ", area_id='" + area_id + '\'' + 130 | ", city='" + city + '\'' + 131 | ", city_id='" + city_id + '\'' + 132 | ", country='" + country + '\'' + 133 | ", country_id='" + country_id + '\'' + 134 | ", county='" + county + '\'' + 135 | ", county_id='" + county_id + '\'' + 136 | ", ip='" + ip + '\'' + 137 | ", isp='" + isp + '\'' + 138 | ", isp_id='" + isp_id + '\'' + 139 | ", region='" + region + '\'' + 140 | ", region_id='" + region_id + '\'' + 141 | '}'; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/business/MainReq.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.business; 2 | 3 | import com.example.sunddenfix.retrofit.business.api.IMainService; 4 | import com.example.sunddenfix.retrofit.config.ActionResult; 5 | import com.example.sunddenfix.retrofit.bean.CountryModel; 6 | import com.example.sunddenfix.retrofit.utils.request.BaseApi; 7 | import com.example.sunddenfix.retrofit.utils.rx.SchedulersHelper; 8 | 9 | import java.util.List; 10 | 11 | import io.reactivex.subscribers.DisposableSubscriber; 12 | import retrofit2.Retrofit; 13 | 14 | /** 15 | * @author wangchengmeng 16 | * @desc 首页业务逻辑管理类 17 | */ 18 | 19 | public class MainReq { 20 | 21 | private static MainReq INSTANCE; 22 | private IMainService mMainService; 23 | 24 | public static MainReq getInstance() { 25 | if (null == INSTANCE) { 26 | INSTANCE = new MainReq(); 27 | } 28 | return INSTANCE; 29 | } 30 | 31 | /** 32 | * 在实例化请求类的时候 就获取到IMainService对象 33 | */ 34 | private MainReq() { 35 | Retrofit retrofit = BaseApi.Companion.getInstance(); 36 | mMainService = retrofit.create(IMainService.class); 37 | } 38 | 39 | /** 40 | * @param consumer 处理结果的 订阅者 41 | * @param ip 请求参数 42 | * return 返回Disposable 方便在销毁的时候取消订阅 43 | */ 44 | public void getCountry(DisposableSubscriber>> consumer, String ip) { 45 | mMainService.getCountry(ip) 46 | .compose(SchedulersHelper.io2MainFlowable()) 47 | .subscribe(consumer); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/business/api/IMainService.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.business.api; 2 | 3 | import com.example.sunddenfix.retrofit.config.ActionResult; 4 | import com.example.sunddenfix.retrofit.config.ConfigServer; 5 | import com.example.sunddenfix.retrofit.bean.CountryModel; 6 | 7 | import java.util.List; 8 | 9 | import io.reactivex.Flowable; 10 | import retrofit2.http.GET; 11 | import retrofit2.http.Query; 12 | 13 | /** 14 | * @author wangchengmeng 15 | */ 16 | public interface IMainService { 17 | 18 | //使用Flowable 返回列表的案例 19 | @GET(ConfigServer.API_ACTIVE_DEVICE) 20 | Flowable>> getCountry(@Query("ip") String ip); 21 | 22 | // @GET("getIpInfo.php") 返回对象的案例 23 | // Flowable> getCountry(@Query("ip") String ip); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/config/ActionResult.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.config; 2 | 3 | /** 4 | * @author wangchengmeng 5 | */ 6 | public class ActionResult { 7 | 8 | /** 9 | * 接口正常 10 | */ 11 | public static final String RESULT_CODE_SUCCESS = "0"; 12 | /** 13 | * 网络异常 14 | */ 15 | public static final String RESULT_CODE_NET_ERROR = "111"; 16 | /** 17 | * 未授权 18 | */ 19 | public static final String RESULT_CODE_NO_AUTH = "401"; 20 | /** 21 | * token过期状态 22 | */ 23 | public static final String RESULT_CODE_NO_LOGIN = "403"; 24 | /** 25 | * 页面未发现 26 | */ 27 | public static final String RESULT_CODE_NO_FOUND = "404"; 28 | 29 | /** 30 | * 一般返回数据格式: 31 | * code:200 32 | * data:{} 或者[] 33 | * message:返回信息 34 | */ 35 | private String code; 36 | private String message; 37 | private T data; 38 | 39 | public String getCode() { 40 | return code; 41 | } 42 | 43 | public void setCode(String code) { 44 | this.code = code; 45 | } 46 | 47 | public String getMessage() { 48 | return message; 49 | } 50 | 51 | public void setMessage(String message) { 52 | this.message = message; 53 | } 54 | 55 | public T getData() { 56 | return data; 57 | } 58 | 59 | public void setData(T data) { 60 | this.data = data; 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return "ActionResult{" + 66 | "code='" + code + '\'' + 67 | ", message='" + message + '\'' + 68 | ", Object=" + data + 69 | '}'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/config/ConfigServer.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("ConfigServer") 2 | package com.example.sunddenfix.retrofit.config 3 | 4 | /** 5 | * @author wangchengm 6 | * @desc 接口url 的管理类 7 | */ 8 | class ConfigServer { 9 | companion object { 10 | //TODO 发布切换环境 -1 本地dev调试 0 测试 1予发布 2 线上 11 | var API_INDEX = 0 12 | 13 | // 线上地址 2 14 | private const val API_BASE_URL: String = "https://sapi.xiaonianyu.com/" 15 | 16 | //线上的 api key 17 | private const val API_KEY: String = "ec480296721a1f549391fb616a0ca37f" 18 | 19 | //线上的api secret 20 | private const val API_SECRET: String = "71795f013d49ba0674fab783e32f8155" 21 | 22 | //预生产 1 23 | private const val API_RELEASE_BASE_URL: String = "https://pre-release.xiaonianyu.com/" 24 | 25 | //预生产 api key 26 | private const val API_KEY_RELEASE: String = "268472588ecd0907af3888289794b246" 27 | 28 | //预生产 secret 29 | private const val API_SECRET_RELEASE: String = "bf3e127a4a79a13e9cf07f3a270ca76d" 30 | 31 | //测试地址 0 32 | private const val API_TEST_DEVELOP_BASE_URL: String = "https://test-app.xiaonianyu.com/" 33 | 34 | //本地调试地址 -1 35 | private const val API_DEV_DEVELOP_BASE_URL: String = " https://dev-app.xiaonianyu.com/" 36 | 37 | // 测试的 api key 38 | private const val API_KEY_DEVELOP: String = "8a60f57f9d3bc3698e09abf4e7e1c217" 39 | 40 | //测试api secret 41 | private const val API_SECRET_DEVELOP: String = "b1800bc0171564850ea674087172aa7c" 42 | 43 | // 神策 数据接收地址 测试 44 | private const val SA_DEVELOP_SERVER_URL: String = 45 | "http://action-log-test.xiaonianyu.com/sa.php?project=xiaonianyu" 46 | 47 | // 神策 数据接收地址 正式 48 | private const val SA_RELEASE_SERVER_URL: String = 49 | "https://action-log.xiaonianyu.com/sa.php?project=xiaonianyu" 50 | 51 | /** 52 | * 获取app的 BaseUrl index : 0 测试 1 予发布 2 正式 53 | */ 54 | fun getAppBaseUrl(index: Int): String = when (index) { 55 | -1 -> { 56 | API_DEV_DEVELOP_BASE_URL 57 | } 58 | 0 -> { 59 | API_TEST_DEVELOP_BASE_URL 60 | } 61 | 1 -> { 62 | API_RELEASE_BASE_URL 63 | } 64 | else -> { 65 | API_BASE_URL 66 | } 67 | } 68 | 69 | /** 70 | * 获取app的 BaseUrl index : 0 测试 1 予发布 2 正式 71 | */ 72 | fun getApiKey(index: Int): String = when (index) { 73 | 0, -1 -> { 74 | API_KEY_DEVELOP 75 | } 76 | 1 -> { 77 | API_KEY_RELEASE 78 | } 79 | else -> { 80 | API_KEY 81 | } 82 | } 83 | 84 | /** 85 | * 获取app的 BaseUrl index : 0 测试 1 予发布 2 正式 86 | */ 87 | fun getApiSecret(index: Int): String = when (index) { 88 | 0, -1 -> { 89 | API_SECRET_DEVELOP 90 | } 91 | 1 -> { 92 | API_SECRET_RELEASE 93 | } 94 | else -> { 95 | API_SECRET 96 | } 97 | } 98 | 99 | //首页 100 | const val API_APP_MAIN_BANNER: String = "app/v6/api_banner" 101 | const val API_APP_MAIN_PORCELAIN: String = "app/v6/api_porcelain" 102 | const val API_APP_MAIN_SPECIAL_OFFER: String = "app/v6/api_index_category_info" 103 | const val API_APP_MAIN_NEW_EXCLUSIVE: String = "api/v1.0/goods/new_user" 104 | const val API_APP_MAIN_TOPIC: String = "app/v6/api_topic" 105 | const val API_APP_MAIN_LIMIT_SECOND: String = "app/v7/api_limit_goods_index" 106 | const val API_APP_MAIN_GOODS_TODAY: String = "app/v6/api_active" 107 | const val API_APP_MAIN_GET_NEW_COUPON: String = "app/v6/api_new_people_coupon_get" 108 | const val API_APP_MAIN_GET_RED_PACKAGE_STATUS: String = "app/v7/api_get_redpackage_status" 109 | const val API_APP_GET_APP_UPDATE_INFO: String = "app/v6/api_update" 110 | const val API_APP_GET_LIMIT_GOODS_LIST: String = "app/v7/api_limit_goods" 111 | const val API_APP_GET_MAIN_ACTIVE_LIST: String = "app/v6/api_spec_active" 112 | const val API_APP_GET_SEARCH_GOODS_LIST: String = "api/v1.0/search/goods" 113 | const val API_APP_GET_SEARCH_GOODS_NAME: String = "api/v1.0/search/suggest" 114 | const val API_APP_GET_SEARCH_HOTOWRD: String = "api/v1.0/search/hotword" 115 | const val API_APP_GET_SEARCH_DEFAULT_HOTOWRD_HINT: String = "api/v1.0/search/default" 116 | const val API_APP_GET_API_TOPIC_DETAIL: String = "app/v6/api_topic_detail" 117 | const val API_APP_GET_BRAND_GOODS_LIST: String = "app/v6/api_brand_goods_list" 118 | const val API_APP_DELETE_CAR_ITEM: String = "app/v6/api_cart" 119 | const val API_APP_GET_ORDER_STATUS: String = "app/v6/api_order_count" 120 | const val API_APP_GET_ORDER_LIST: String = "app/v6/api_order" 121 | const val API_APP_GET_RECOMMEND_GOODS: String = "app/v6/api_suggest_goods_list" 122 | const val API_APP_GET_ORDER_DETAIL: String = "app/v6/api_order/1" 123 | const val API_APP_GET_ORDER_LOGISTICS: String = "app/v6/api_first_express" 124 | const val API_APP_GET_ALTER_ORDER_STATUS: String = "app/v6/api_order/{orderId}" 125 | const val API_APP_GET_DELETE_ORDER: String = "app/v6/api_order_del" 126 | const val API_APP_GET_COLLECT_LIST: String = "app/v6/api_collect" 127 | const val API_APP_CENCEL_COLLECT: String = "app/v6/api_collect_cancel" 128 | const val API_APP_GET_COUPON_LIST: String = "app/v7/api_coupon_list" 129 | const val API_APP_GET_LOGISTICS_INFO: String = "app/v6/api_express" 130 | const val API_APP_GET_RETURN_LOGISTICS_INFO: String = "app/v6/api_change_return_express" 131 | const val API_APP_GET_COMMNET_GOODS: String = "app/v6/api_order_comment_get" 132 | const val API_APP_COMMON_UPLOAD_FILES: String = "app/v6/api_common_upload_files" 133 | const val API_APP_COMMON_SUBMIT: String = "app/v6/api_order_comment_submit" 134 | const val API_APP_GET_REFUND_DETAIL: String = "app/v6/api_change_datail" 135 | const val API_APP_GET_CANCEL_REFUND: String = "app/v6/api_change_cancel" 136 | const val API_APP_GET_EXPRESS_LIST: String = "app/v6/api_expresslist" 137 | const val API_APP_GET_CHANGE_EXPRESS_LIST: String = "app/v6/api_change_express_submit" 138 | const val API_APP_GET_PROMULGATE_STATUS: String = "app/v6/api_promulgate_status" 139 | const val API_APP_GET_ADVICE_TYPE: String = "app/v6/api_suggest_type" 140 | const val API_APP_UPLOAD_ADVICE: String = "app/v6/api_suggest_submit" 141 | const val API_APP_GET_SHOP_GOODS: String = "app/v6/api_supplier_goods" 142 | const val API_APP_GET_GOODS_DETAIL: String = "app/v7/api_goods_detail" 143 | const val API_APP_GET_GOODS_COUPON: String = "app/v8/api_goods_coupon" 144 | const val API_APP_GET_GOODS_COUPON_SPOT_PRICE: String = "app/v8/api_goods_price" 145 | const val API_APP_GET_COUPONE_COUPON: String = "app/v6/api_order_coupon" 146 | const val API_APP_GET_COMMENT_COLLECT: String = "app/v6/api_goods_comment_collect" 147 | const val API_APP_COLLECT: String = "app/v6/api_collect_save" 148 | const val API_APP_CANCEL_COLLECT: String = "app/v6/api_collect_cancel" 149 | const val API_APP_HIGH_COMMENT_LIST: String = "app/v6/api_goods_comment_high_list" 150 | const val API_APP_COMMENT_LIST: String = "app/v6/api_goods_comment_list" 151 | const val API_APP_ADD_SHOP_CAR: String = "app/v6/api_cart_save" 152 | const val API_APP_SERVICE_GUARANTE: String = "app/v6/api_goods_service_guarantee" 153 | const val API_APP_ORDER_GOODS: String = "app/v6/api_order_goods" 154 | const val API_APP_USER_ADDRESS: String = "app/v6/api_user_address_list" 155 | const val API_APP_ALTER_USER_ADDRESS: String = "app/v6/api_user_address_edit" 156 | const val API_APP_ADD_USER_ADDRESS: String = "app/v6/api_user_address_add" 157 | const val API_APP_DELETE_USER_ADDRESS: String = "app/v6/api_user_address_del" 158 | const val API_APP_USER_ADDRESS_INFO: String = "app/v6/api_user_address_info" 159 | const val API_APP_API_LOGIC_OPEN_DAY: String = "app/v6/api_logic_open_day" 160 | 161 | const val API_APP_COMMNET_PRISE: String = "app/v6/api_goods_comment_give_star" 162 | const val API_APP_COMMNET_CANCEL_PRISE: String = "app/v6/api_goods_comment_canal_star" 163 | const val API_APP_COMMNET_NUM: String = "/app/v6/api_goods_comment_nums" 164 | const val API_APP_CREATE_ORDER: String = "app/v8/api_order" 165 | const val API_APP_GET_WX_PAY: String = "app/v8/api_pay" 166 | const val API_APP_GET_AY_TYPE: String = "app/v8/app_payment/index" 167 | const val API_APP_GET_ALI_PAY: String = "app/v8/app_ali_pay/ali_pay" 168 | const val API_APP_GET_COMPANY_LIST: String = "app/v6/api_expresslist" 169 | const val API_APP_ALTER_CART_AMOUNT: String = "app/v6/api_cart_amount" 170 | const val API_APP_PLAQUE_ADVERTISEMENT: String = "api/v1.0/plaque" 171 | const val API_APP_LOGIN_OUT: String = "api/v1.0/user/logout" 172 | const val API_APP_ACTIVE_GIFT: String = "api/v1.0/gift" 173 | const val API_OUT_REFRESH_TOKEN: String = "api/v1.0/user/token" 174 | const val API_ACTIVE_DEVICE: String = "api/v1.0/device/active" 175 | const val API_NEW_CUSTOMER_CATE: String = "api/v1.0/goods/new_user/cat" 176 | const val API_GET_HOME_STATUE: String = "api/v1.0/activity/app/state" 177 | const val API_GET_DOUBLE_11_INFO: String = "api/v1.0/activity/app/info" 178 | const val API_GET_OPEN_SCREEN: String = "api/v1.0/open_screen" 179 | const val API_GET_LOTTERY_STATE: String = "api/v1.0/lottery/prize_state" 180 | const val API_GET_GOODS_NEW_CAT: String = "api/v1.0/goods/new/cat" 181 | const val API_GET_GOODS_NEW_HOT: String = "api/v1.0/goods/new" 182 | const val API_GET_SUBSIDY_GOODS: String = "api/v1.0/activity/subsidy/goods" 183 | const val API_GET_SUBSIDY_COUPON: String = "api/v1.0/activity/subsidy/coupon" 184 | const val API_GET_SUBSIDY_PRICE_DAY: String = "api/v1.0/activity/subsidy/price_day" 185 | const val API_REMIND_LIMIT: String = "api/v1.0/limit/alarm" 186 | const val API_GET_SUBSIDY_WINDOW: String = "api/v1.0/activity/subsidy/window" 187 | const val API_CLOSE_SUBSIDY_WINDOW: String = "api/v1.0/activity/subsidy/window" 188 | const val API_GET_HOME_NEW_GOODS: String = "api/v1.0/app/home" 189 | const val API_GET_HOME_NEW_GOODS_HOT: String = "api/v1.0/goods/hot_new" 190 | const val API_GET_HOME_WISH_LIST: String = "api/v1.0/activity/wish/window" 191 | const val API_GET_BASE_INFO: String = "app/v8/config/base" 192 | 193 | 194 | } 195 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/config/Constant.kt: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.config 2 | 3 | 4 | /** 5 | * @author : wangchengm 6 | * @date : 2020-05-1910:55 7 | * @desc : 常量管理类 8 | */ 9 | class Constant { 10 | companion object { 11 | 12 | //全局保存配置的文件名 13 | const val GLOBAL_FLAG_FILE_NAME = "GLOBAL_FLAG_FILE_NAME" 14 | 15 | //保存关闭新人红包弹窗的状态 的key 16 | const val FLAG_CLOSE_RED_PACKAGE = "FLAG_CLOSE_RED_PACKAGE" 17 | const val FLAG_DEVICE = "FLAG_DEVICE" 18 | const val FLAG_ACTIVE_DEVICE = "FLAG_ACTIVE_DEVICE" 19 | const val GIF_END_WITH = ".gif" 20 | 21 | 22 | //下拉刷新 23 | const val PULL_DOWN_FRESH = 0 24 | 25 | //上拉加载 26 | const val PULL_UP_LOAD = 1 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/presenter/MainPresenter.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.presenter; 2 | 3 | import android.app.Activity; 4 | import android.util.Log; 5 | 6 | import com.example.sunddenfix.retrofit.base.BasePrensenter; 7 | import com.example.sunddenfix.retrofit.business.MainReq; 8 | import com.example.sunddenfix.retrofit.config.ActionResult; 9 | import com.example.sunddenfix.retrofit.config.Constant; 10 | import com.example.sunddenfix.retrofit.bean.CountryModel; 11 | import com.example.sunddenfix.retrofit.utils.rx.RxSubscriber; 12 | import com.example.sunddenfix.retrofit.viewIm.MainView; 13 | 14 | import java.util.List; 15 | 16 | import io.reactivex.subscribers.DisposableSubscriber; 17 | 18 | /** 19 | * @author wangchengmeng 20 | */ 21 | public class MainPresenter extends BasePrensenter { 22 | private int mCurrentPage = 1; 23 | 24 | public MainPresenter(Activity activity, MainView view) { 25 | super(activity, view); 26 | } 27 | 28 | /** 29 | * 一般返回数据格式: 30 | * code:200 31 | * data:{} 或者[] 32 | * message:返回信息 33 | */ 34 | public void getCountry(String ip, int status) { 35 | if (status == Constant.PULL_UP_LOAD && mCurrentPage == 1) { 36 | mIView.refreshOrDisLayout(status); 37 | return; 38 | } 39 | if (status == Constant.PULL_DOWN_FRESH) { 40 | mCurrentPage = 1; 41 | } 42 | DisposableSubscriber>> consumer = new RxSubscriber>() { 43 | @Override 44 | public void _onSuccess(List countryModel) { 45 | //请求成功 更新ui 46 | mIView.getCountrySuccess(countryModel, status); 47 | 48 | mCurrentPage++; 49 | mIView.refreshOrDisLayout(status); 50 | 51 | //分页处理根据接口 来 如果可以判断最后一页 直接调用 52 | // mIView.loadNorMoreData(); 53 | } 54 | 55 | @Override 56 | public void _onError(String error) { 57 | //请求失败 58 | mIView.refreshOrDisLayout(status); 59 | Log.d("aaa", "_onError" + error); 60 | } 61 | }; 62 | MainReq.getInstance().getCountry(consumer, ip); 63 | addSubscribe(consumer);//添加订阅者,内部实现在页面关闭的时候取消订阅防止内存泄漏 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/ui/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.ui; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.recyclerview.widget.LinearLayoutManager; 7 | import androidx.recyclerview.widget.RecyclerView; 8 | 9 | import com.example.sunddenfix.retrofit.R; 10 | import com.example.sunddenfix.retrofit.base.BaseActivity; 11 | import com.example.sunddenfix.retrofit.config.Constant; 12 | import com.example.sunddenfix.retrofit.bean.CountryModel; 13 | import com.example.sunddenfix.retrofit.presenter.MainPresenter; 14 | import com.example.sunddenfix.retrofit.ui.adapter.CountryAdapter; 15 | import com.example.sunddenfix.retrofit.viewIm.MainView; 16 | import com.scwang.smartrefresh.layout.SmartRefreshLayout; 17 | import com.scwang.smartrefresh.layout.api.RefreshLayout; 18 | import com.scwang.smartrefresh.layout.listener.OnLoadMoreListener; 19 | import com.scwang.smartrefresh.layout.listener.OnRefreshListener; 20 | 21 | import java.util.List; 22 | 23 | public class MainActivity extends BaseActivity implements MainView { 24 | 25 | private List mCountryList; 26 | private CountryAdapter mCountryAdapter; 27 | private RecyclerView mRvCommonList; 28 | private SmartRefreshLayout mSmartRefreshLayout; 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | mCountryAdapter = new CountryAdapter(this, mCountryList); 34 | mRvCommonList = findViewById(R.id.rv_commonList); 35 | mSmartRefreshLayout = findViewById(R.id.srl_freshList); 36 | mRvCommonList.setLayoutManager(new LinearLayoutManager(this)); 37 | mRvCommonList.setAdapter(mCountryAdapter); 38 | 39 | mSmartRefreshLayout.autoRefresh(); 40 | mSmartRefreshLayout.setOnRefreshListener(new OnRefreshListener() { 41 | @Override 42 | public void onRefresh(@NonNull RefreshLayout refreshLayout) { 43 | mIPresenter.getCountry("21.22.11.33", Constant.PULL_DOWN_FRESH); 44 | } 45 | }); 46 | 47 | mSmartRefreshLayout.setOnLoadMoreListener(new OnLoadMoreListener() { 48 | @Override 49 | public void onLoadMore(@NonNull RefreshLayout refreshLayout) { 50 | mIPresenter.getCountry("21.22.11.33", Constant.PULL_UP_LOAD); 51 | } 52 | }); 53 | } 54 | 55 | @Override 56 | protected MainPresenter getPresenter() { 57 | return new MainPresenter(this, this); 58 | } 59 | 60 | @Override 61 | protected int getResourceId() { 62 | return R.layout.activity_main; 63 | } 64 | 65 | @Override 66 | public void getCountrySuccess(List model, int status) { 67 | //请求成功 更新ui 68 | if (status == Constant.PULL_DOWN_FRESH) { 69 | mCountryList.clear(); 70 | } 71 | mCountryList.addAll(model); 72 | if (status == Constant.PULL_DOWN_FRESH) { 73 | mCountryAdapter.notifyDataSetChanged(); 74 | } else { 75 | mCountryAdapter.notifyItemInserted(mCountryList.size() - 1); 76 | } 77 | } 78 | 79 | @Override 80 | public void refreshOrDisLayout(int status) { 81 | if (status == Constant.PULL_DOWN_FRESH) { 82 | //下拉刷新 83 | mSmartRefreshLayout.finishRefresh(); 84 | } else { 85 | //上拉加载 86 | mSmartRefreshLayout.finishLoadMore(); 87 | } 88 | } 89 | 90 | @Override 91 | public void loadNorMoreData() { 92 | mSmartRefreshLayout.finishLoadMoreWithNoMoreData(); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/ui/adapter/CountryAdapter.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | 6 | import androidx.annotation.NonNull; 7 | 8 | import com.example.sunddenfix.retrofit.R; 9 | import com.example.sunddenfix.retrofit.base.BaseAdapter; 10 | import com.example.sunddenfix.retrofit.base.BaseViewHolder; 11 | import com.example.sunddenfix.retrofit.bean.CountryModel; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * @author : wangchengm 17 | * @date : 2021/1/55:32 PM 18 | * @desc : 19 | */ 20 | public class CountryAdapter extends BaseAdapter { 21 | 22 | private Context mContext; 23 | 24 | public CountryAdapter(Context context, @NonNull List datas) { 25 | super(context, R.layout.item_country, datas); 26 | mContext = context; 27 | } 28 | 29 | @Override 30 | protected BaseViewHolder getViewHolder(View itemView) { 31 | return new BaseViewHolder(mContext, itemView); 32 | } 33 | 34 | @Override 35 | protected void onChildBindViewHolder(BaseViewHolder holder, CountryModel data, int position) { 36 | holder.setText(R.id.tv_result, data.getArea()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/utils/TimeUtils.kt: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.utils 2 | 3 | import android.content.Context 4 | import android.net.ConnectivityManager 5 | 6 | 7 | /** 8 | * @author : wangchengm 9 | * @date : 2020-05-2215:20 10 | * @desc : 11 | */ 12 | object TimeUtils { 13 | 14 | /*** 15 | * 检查网络 16 | * @return 17 | */ 18 | fun checkNet(context: Context): Boolean { 19 | try { 20 | val connectivity = context 21 | .getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager 22 | if (connectivity != null) { 23 | // 获取网络连接管理的对像 24 | val info = connectivity.activeNetworkInfo 25 | return !(info == null || !info.isAvailable) 26 | } 27 | } catch (e: Exception) { 28 | e.printStackTrace() 29 | } 30 | return false 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/utils/UncheckedUtil.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.utils; 2 | 3 | public class UncheckedUtil { 4 | 5 | @SuppressWarnings("unchecked") 6 | public static T cast(Object obj) { 7 | return (T) obj; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/utils/bus/BusUtil.kt: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.utils.bus 2 | 3 | 4 | import org.greenrobot.eventbus.EventBus 5 | 6 | 7 | /** 8 | * @author wangchengm 9 | * @desc EventBus的封装类 10 | */ 11 | object BusUtil { 12 | 13 | private const val TAG = "BusUtil" 14 | 15 | fun register(any: Any) { 16 | if (!EventBus.getDefault().isRegistered(any)) { 17 | EventBus.getDefault().register(any) 18 | } 19 | } 20 | 21 | fun unregister(any: Any) { 22 | if (EventBus.getDefault().isRegistered(any)) { 23 | EventBus.getDefault().unregister(any) 24 | } 25 | } 26 | 27 | fun post(model: EventBusModel?) { 28 | if (null == model) { 29 | return 30 | } 31 | EventBus.getDefault().post(model) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/utils/bus/EventBusModel.kt: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.utils.bus 2 | 3 | import java.io.Serializable 4 | 5 | /** 6 | * EventBus传递数据的model 7 | * 8 | * @author wangchengm 9 | */ 10 | data class EventBusModel(val eventBusAction: String, val eventBusObject: Any?) : Serializable -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/utils/glide/GlideUtil.kt: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.utils.glide 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.net.Uri 6 | import android.widget.ImageView 7 | import com.bumptech.glide.load.engine.DiskCacheStrategy 8 | import com.bumptech.glide.load.resource.bitmap.CircleCrop 9 | import com.bumptech.glide.request.RequestOptions 10 | import com.example.sunddenfix.retrofit.R 11 | import com.example.sunddenfix.retrofit.config.Constant 12 | 13 | /** 14 | * @Author wangchengm 15 | * @desc Glide加载网络图片 16 | */ 17 | class GlideUtil { 18 | 19 | companion object { 20 | 21 | fun showGif(context: Context, url: String, imageView: ImageView) { 22 | GlideApp.with(context) 23 | .asGif() 24 | .load(url) 25 | .placeholder(R.mipmap.bg_default_img) 26 | .error(R.mipmap.bg_default_img) 27 | .diskCacheStrategy(DiskCacheStrategy.RESOURCE) 28 | .fitCenter() 29 | .skipMemoryCache(true) 30 | .into(imageView) 31 | } 32 | 33 | fun showGif(context: Context, url: Int, imageView: ImageView) { 34 | GlideApp.with(context) 35 | .asGif() 36 | .load(url) 37 | .placeholder(R.mipmap.bg_default_img) 38 | .error(R.mipmap.bg_default_img) 39 | .diskCacheStrategy(DiskCacheStrategy.RESOURCE) 40 | .fitCenter() 41 | .skipMemoryCache(true) 42 | .into(imageView) 43 | } 44 | 45 | /** 46 | * 显示网络图片 47 | * 48 | * @param context 可以是 Activity FragmentActivity 49 | * @param url 网络图片链接 50 | * @param placeResId 占位图片资源id 51 | * @param errorId 加再错误的图片资源id 52 | */ 53 | @JvmOverloads 54 | fun showNetImage( 55 | context: Context, 56 | url: Uri, 57 | imageView: ImageView, 58 | isSquare: Boolean = false 59 | ) { 60 | val placeResId = if (isSquare) R.mipmap.bg_default_square else R.mipmap.bg_default_img 61 | GlideApp.with(context) 62 | .load(url) 63 | .apply(getRequestOps(placeResId, placeResId)) 64 | .into(imageView) 65 | } 66 | 67 | /** 68 | * 显示网络图片 支持gif 69 | * 70 | * @param context 可以是 Activity FragmentActivity 71 | * @param url 网络图片链接 72 | * @param placeResId 占位图片资源id 73 | * @param errorId 加再错误的图片资源id 74 | * @param isPlaceholder 是否需要加载占位图 图片列表需要 75 | */ 76 | @JvmOverloads 77 | fun showNetImage( 78 | context: Context, 79 | url: String, 80 | imageView: ImageView, 81 | isSquare: Boolean = false, 82 | isPlaceholder: Boolean = false 83 | ) { 84 | val placeResId = if (isSquare) R.mipmap.bg_default_square else R.mipmap.bg_default_img 85 | val uri = Uri.parse(url) 86 | if (url.endsWith(Constant.GIF_END_WITH, true)) { 87 | showGif(context, url, imageView) 88 | } else { 89 | GlideApp.with(context) 90 | .load(uri) 91 | .apply(getRequestOps(placeResId, placeResId, isPlaceholder)) 92 | .into(imageView) 93 | } 94 | } 95 | 96 | /** 97 | * 显示圆形网络图片 98 | * 99 | * @param context 可以是 Activity FragmentActivity 100 | * @param url 网络图片链接 101 | * @param placeResId 占位图片资源id 102 | * @param errorId 加再错误的图片资源id 103 | */ 104 | @JvmOverloads 105 | fun showCircleNetImage( 106 | context: Context, 107 | url: String, 108 | imageView: ImageView 109 | ) { 110 | val uri = Uri.parse(url) 111 | GlideApp.with(context) 112 | .load(uri) 113 | .apply(RequestOptions.bitmapTransform(CircleCrop())) 114 | .into(imageView) 115 | } 116 | 117 | /** 118 | * 显示网络图片 固定宽高 119 | * 120 | * @param context 可以是 Activity FragmentActivity 121 | * @param url 网络图片链接 122 | * @param width 图片宽 123 | * @param height 图片高 124 | */ 125 | fun showFixNetImage( 126 | context: Context, 127 | url: String, 128 | imageView: ImageView, 129 | width: Int, 130 | height: Int 131 | ) { 132 | GlideApp.with(context) 133 | .load(url) 134 | .apply(getFixRequestOps(width, height)) 135 | .into(imageView) 136 | } 137 | 138 | /** 139 | * 显示网络图片 固定宽高 140 | * 141 | * @param context 可以是 Activity FragmentActivity 142 | * @param url 网络图片链接 143 | * @param width 图片宽 144 | * @param height 图片高 145 | */ 146 | fun showFixNetImage( 147 | context: Context, 148 | url: Uri, 149 | imageView: ImageView, 150 | width: Int, 151 | height: Int 152 | ) { 153 | GlideApp.with(context) 154 | .load(url) 155 | .apply(getFixRequestOps(width, height)) 156 | .into(imageView) 157 | } 158 | 159 | /** 160 | * 显示本地图片 161 | * 162 | * @param context 可以是 Activity FragmentActivity 163 | * @param resId 图片资源id 164 | */ 165 | fun showNetImage(context: Context, resId: Int, imageView: ImageView) { 166 | GlideApp.with(context) 167 | .load(resId) 168 | .into(imageView) 169 | } 170 | 171 | @SuppressLint("CheckResult") 172 | private fun getRequestOps( 173 | placeResId: Int, errorId: Int, 174 | isPlaceholder: Boolean = false 175 | ): RequestOptions { 176 | val requestOptions = RequestOptions() 177 | if (isPlaceholder) { 178 | requestOptions 179 | .placeholder(placeResId) 180 | } 181 | return requestOptions 182 | .error(errorId) 183 | .dontAnimate() 184 | .fitCenter() 185 | .diskCacheStrategy(DiskCacheStrategy.ALL)//缓存各个尺寸的图片 加载更快 只是需要更大的磁盘空间 186 | .skipMemoryCache(true)//跳过内存缓存 187 | } 188 | 189 | @SuppressLint("CheckResult") 190 | private fun getFixRequestOps(width: Int, height: Int): RequestOptions { 191 | val requestOptions = RequestOptions() 192 | return requestOptions 193 | // .placeholder(placeResId) 194 | // .error(errorId) 195 | .dontAnimate() 196 | .override(width, height) 197 | .diskCacheStrategy(DiskCacheStrategy.ALL)//缓存各个尺寸的图片 加载更快 只是需要更大的磁盘空间 198 | .skipMemoryCache(true)//跳过内存缓存 199 | } 200 | } 201 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/utils/glide/OkHttpGlideModule.kt: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.utils.glide 2 | 3 | import android.content.Context 4 | import com.bumptech.glide.Glide 5 | import com.bumptech.glide.GlideBuilder 6 | import com.bumptech.glide.Registry 7 | import com.bumptech.glide.annotation.GlideModule 8 | import com.bumptech.glide.module.AppGlideModule 9 | 10 | @GlideModule 11 | class OkHttpGlideModule : AppGlideModule() { 12 | override fun applyOptions(context: Context, builder: GlideBuilder) { 13 | 14 | } 15 | 16 | override fun isManifestParsingEnabled(): Boolean { 17 | return false 18 | } 19 | 20 | override fun registerComponents(context: Context, glide: Glide, registry: Registry) { 21 | // val httpClient = OkHttpClient().newBuilder() 22 | // .sslSocketFactory(HtcHostnameVerifier.getSSLSocketFactory()) 23 | // .hostnameVerifier(HtcHostnameVerifier.getHostnameVerifier()) 24 | // .build() 25 | // registry.replace( 26 | // GlideUrl::class.java, 27 | // InputStream::class.java, 28 | // OkHttpUrlLoader.Factory(httpClient) 29 | // ) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/utils/request/BaseApi.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("BaseApi") 2 | package com.example.sunddenfix.retrofit.utils.request 3 | 4 | 5 | import android.util.Log 6 | import com.example.sunddenfix.retrofit.App 7 | import com.example.sunddenfix.retrofit.config.ConfigServer 8 | import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory 9 | import okhttp3.* 10 | import okhttp3.CacheControl.FORCE_CACHE 11 | import okhttp3.logging.HttpLoggingInterceptor 12 | import retrofit2.Retrofit 13 | import retrofit2.converter.gson.GsonConverterFactory 14 | import java.io.File 15 | import java.util.concurrent.TimeUnit 16 | 17 | 18 | public class BaseApi private constructor() { 19 | companion object { 20 | private const val TAG: String = "okHttpClient" 21 | private const val DEFAULT_TIMEOUT: Long = 15//链接超时时间 22 | private var mRetrofit: Retrofit? = null 23 | 24 | fun getInstance() = getRetrofit(ConfigServer.getAppBaseUrl(ConfigServer.API_INDEX)) 25 | 26 | private fun getRetrofit(url: String): Retrofit { 27 | if (null == mRetrofit || url != mRetrofit?.baseUrl().toString()) { 28 | val builder: OkHttpClient.Builder = OkHttpClient.Builder() 29 | .addInterceptor(interceptor) 30 | .addInterceptor(cacheInterceptor) 31 | .addNetworkInterceptor(cacheInterceptor) 32 | .addInterceptor(loggingInterceptor) 33 | .retryOnConnectionFailure(true) 34 | .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) 35 | .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) 36 | .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) 37 | .cache( 38 | Cache( 39 | //网络数据缓存文件 40 | File(App.getInstance().cacheDir, "net_data_cache"), 41 | 10 * 1024 * 1024 42 | ) 43 | ) 44 | .connectionSpecs( 45 | listOf( 46 | ConnectionSpec.MODERN_TLS, 47 | ConnectionSpec.COMPATIBLE_TLS 48 | ) 49 | ) 50 | 51 | val okHttpClient = builder.build() 52 | 53 | mRetrofit = Retrofit.Builder() 54 | .baseUrl(url) 55 | .addConverterFactory(GsonConverterFactory.create())//添加gson 56 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create())//添加rx 57 | .client(okHttpClient) 58 | .build() 59 | } 60 | return mRetrofit!! 61 | } 62 | 63 | /** 64 | * 网络请求头 拦截器 65 | */ 66 | private val interceptor: Interceptor = Interceptor { 67 | val newRequest = it.request().newBuilder() 68 | val build = newRequest 69 | .addHeader("x-os", "Android") 70 | .build() 71 | it.proceed(build) 72 | } 73 | 74 | /** 75 | * 网络请求 日志打印拦截器 76 | */ 77 | private val loggingInterceptor: HttpLoggingInterceptor = 78 | HttpLoggingInterceptor(HttpLoggingInterceptor.Logger { 79 | Log.d(TAG, it) 80 | }).setLevel(HttpLoggingInterceptor.Level.BODY) 81 | 82 | 83 | //网络数据缓存 84 | private var cacheInterceptor = Interceptor { chain -> 85 | var request = chain.request() 86 | if (com.example.sunddenfix.retrofit.utils.TimeUtils.checkNet(App.getInstance())) { 87 | //有网时 88 | val response = chain.proceed(request) 89 | val cacheControl = request.cacheControl().toString() 90 | Log.e("yjbo-cache", "在线缓存在1分钟内可读取$cacheControl") 91 | val netGet = 0 92 | when (netGet) { 93 | //总获取实时信息 94 | 0 -> return@Interceptor response.newBuilder() 95 | .removeHeader("Pragma") 96 | .removeHeader("Cache-Control") 97 | .header("Cache-Control", "public, max-age=" + 0) 98 | .build() 99 | //t(s)之后获取实时信息--此处是 100 | 1 -> return@Interceptor response.newBuilder() 101 | .removeHeader("Pragma") 102 | .removeHeader("Cache-Control") 103 | .header("Cache-Control", "public, max-age=${60}") 104 | .build() 105 | } 106 | null 107 | } else { //无网时 108 | val nonetGet = 0 109 | when (nonetGet) { 110 | //此处不设置过期时间 111 | 0 -> request = request.newBuilder() 112 | .cacheControl(FORCE_CACHE) 113 | .build() 114 | //此处设置了t秒---修改了系统方法 115 | 1 -> request = request.newBuilder() 116 | .cacheControl(FORCE_CACHE1) 117 | .build() 118 | } 119 | val response = chain.proceed(request) 120 | //下面注释的部分设置也没有效果,因为在上面已经设置了 121 | response.newBuilder() 122 | .header("Cache-Control", "public, only-if-cached") 123 | .removeHeader("Pragma") 124 | .build() 125 | } 126 | } 127 | 128 | //这是设置在多长时间范围内获取缓存里面 129 | var FORCE_CACHE1 = CacheControl.Builder() 130 | .onlyIfCached() 131 | .maxStale( 132 | 60, 133 | TimeUnit.SECONDS 134 | ) //CacheControl.FORCE_CACHE--是int型最大值 135 | .build() 136 | } 137 | 138 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/utils/rx/RxSubscriber.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.utils.rx; 2 | 3 | import android.text.TextUtils; 4 | import android.util.Log; 5 | 6 | import com.example.sunddenfix.retrofit.config.ActionResult; 7 | 8 | import io.reactivex.subscribers.DisposableSubscriber; 9 | 10 | /** 11 | * @author wangchengmeng 12 | * @desc Subscriber的重新封装 13 | * 网络请求的统一处理,具体实现交给需要实现的方法 14 | */ 15 | public class RxSubscriber extends DisposableSubscriber> { 16 | private static final String TAG = "RxSubscriber"; 17 | 18 | @Override 19 | public void onError(Throwable e) { 20 | //该方法在出错的时候一定会调用 21 | Log.d(TAG, e.toString()); 22 | _onError("网络链接出错"); 23 | } 24 | 25 | @Override 26 | public void onComplete() { 27 | //订阅处理完成 自定义处理 28 | } 29 | 30 | @Override 31 | public void onNext(ActionResult tActionResult) { 32 | //在这里可以根据返回的不同code 做不同的事情 类似403这类型的错误code便可以统一处理 33 | Log.d(TAG, tActionResult.toString()); 34 | switch (tActionResult.getCode()) { 35 | case ActionResult.RESULT_CODE_NO_LOGIN: 36 | //返回403 token失效 37 | break; 38 | case ActionResult.RESULT_CODE_NO_FOUND: 39 | //返回404 页面未找到 40 | break; 41 | case ActionResult.RESULT_CODE_SUCCESS: 42 | //返回200 请求成功 43 | _onSuccess(tActionResult.getData()); 44 | break; 45 | default: 46 | if (!TextUtils.isEmpty(tActionResult.getMessage())) { 47 | //如果有返回的message 48 | _onError(tActionResult.getMessage()); 49 | } else { 50 | _onError("网络链接出错"); 51 | } 52 | } 53 | } 54 | 55 | //该方法在实例化的时候留给自己去实现 56 | public void _onSuccess(T t) { 57 | 58 | } 59 | 60 | //该方法在实例化的时候留给自己去实现 61 | public void _onError(String error) { 62 | 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/utils/rx/SchedulersHelper.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.utils.rx; 2 | 3 | import org.reactivestreams.Publisher; 4 | 5 | import io.reactivex.Flowable; 6 | import io.reactivex.FlowableTransformer; 7 | import io.reactivex.Observable; 8 | import io.reactivex.ObservableSource; 9 | import io.reactivex.ObservableTransformer; 10 | import io.reactivex.android.schedulers.AndroidSchedulers; 11 | import io.reactivex.schedulers.Schedulers; 12 | 13 | /** 14 | * Created by wangchengm 15 | * Rx2.0实现线程切换封装的工具 16 | */ 17 | 18 | public class SchedulersHelper { 19 | 20 | //使用2.0ObservableTransformer 实现 当被观察者 是Observable的时候使用 21 | public static ObservableTransformer io2MainObservable() { 22 | return new ObservableTransformer() { 23 | @Override 24 | public ObservableSource apply(Observable upstream) { 25 | return upstream.subscribeOn(Schedulers.io()) 26 | .unsubscribeOn(AndroidSchedulers.mainThread()) 27 | .observeOn(AndroidSchedulers.mainThread()); 28 | } 29 | }; 30 | } 31 | 32 | //当被观察者 是FLowable的时候使用 33 | public static FlowableTransformer io2MainFlowable() { 34 | return new FlowableTransformer() { 35 | @Override 36 | public Publisher apply(Flowable upstream) { 37 | return upstream.subscribeOn(Schedulers.io()) 38 | .unsubscribeOn(AndroidSchedulers.mainThread()) 39 | .observeOn(AndroidSchedulers.mainThread()); 40 | } 41 | }; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/sunddenfix/retrofit/viewIm/MainView.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit.viewIm; 2 | 3 | import com.example.sunddenfix.retrofit.base.IView; 4 | import com.example.sunddenfix.retrofit.bean.CountryModel; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * @author wangchengmeng 10 | */ 11 | public interface MainView extends IView { 12 | void getCountrySuccess(List models, int status); 13 | 14 | void refreshOrDisLayout(int status); 15 | 16 | void loadNorMoreData(); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_country.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangchengmeng/Retrofit-MVP-RxJava/3c0d87e92143f2ae5b58ecd474a0bc30bb8d2491/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangchengmeng/Retrofit-MVP-RxJava/3c0d87e92143f2ae5b58ecd474a0bc30bb8d2491/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangchengmeng/Retrofit-MVP-RxJava/3c0d87e92143f2ae5b58ecd474a0bc30bb8d2491/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/bg_default_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangchengmeng/Retrofit-MVP-RxJava/3c0d87e92143f2ae5b58ecd474a0bc30bb8d2491/app/src/main/res/mipmap-xxhdpi/bg_default_img.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/bg_default_square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangchengmeng/Retrofit-MVP-RxJava/3c0d87e92143f2ae5b58ecd474a0bc30bb8d2491/app/src/main/res/mipmap-xxhdpi/bg_default_square.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangchengmeng/Retrofit-MVP-RxJava/3c0d87e92143f2ae5b58ecd474a0bc30bb8d2491/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangchengmeng/Retrofit-MVP-RxJava/3c0d87e92143f2ae5b58ecd474a0bc30bb8d2491/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Retrofit 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/test/java/com/example/sunddenfix/retrofit/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.example.sunddenfix.retrofit; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.kotlin_version = '1.3.50' 5 | repositories { 6 | jcenter() 7 | google() 8 | } 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.5.3' 11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 12 | 13 | // NOTE: Do not place your application dependencies here; they belong 14 | // in the individual module build.gradle files 15 | } 16 | } 17 | 18 | allprojects { 19 | repositories { 20 | jcenter() 21 | google() 22 | } 23 | } 24 | 25 | task clean(type: Delete) { 26 | delete rootProject.buildDir 27 | } 28 | 29 | project.ext { 30 | applicationId = "${ANDROID_APPLICATION_ID}" 31 | versionCode = ANDROID_VERSION_CODE.toInteger() 32 | versionName = "${ANDROID_VERSION_NAME}" 33 | WXAppId = "${WX_APP_ID}" 34 | UmengAppKey = "${UMENG_APP_KEY}" 35 | 36 | //SDK版本信息 37 | //编译版本 38 | compileSdkVersion = "${COMPILE_SDK_VERSION}" 39 | //最小SDK版本 40 | minSdkVersion = "${MIN_SDK_VERSION}" 41 | //目标版本 42 | targetSdkVersion = "${TARGET_SDK_VERSION}" 43 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | android.useDeprecatedNdk=true 21 | # Kotlin code style for this project: "official" or "obsolete": 22 | kotlin.code.style=official 23 | #####xiaonianyu 配置文件####### 24 | ANDROID_APPLICATION_ID=com.example.app 25 | #app 版本 200-2 000-.0 000-.0 code - name 2.0.0 26 | ANDROID_VERSION_CODE=200200300 27 | ANDROID_VERSION_NAME=2.2.3 28 | #微信appId 29 | WX_APP_ID=wx138caa47e153820a 30 | #xiaomi 31 | XIAOMI_APPKEY=MI-5721813649446 32 | XIAOMI_APPID=MI-2882303761518136446 33 | #umeng appkey 34 | UMENG_APP_KEY=5d663e21570df3eb9a0003ef 35 | #sdk 版本 36 | COMPILE_SDK_VERSION=29 37 | MIN_SDK_VERSION=24 38 | TARGET_SDK_VERSION=29 39 | #####xiaonianyu 配置文件####### 40 | 41 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangchengmeng/Retrofit-MVP-RxJava/3c0d87e92143f2ae5b58ecd474a0bc30bb8d2491/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Jan 05 16:32:25 CST 2021 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------