├── .gitignore ├── .idea ├── .name ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ ├── BaiduLBS_Android.jar │ ├── arm64-v8a │ │ ├── libBaiduMapSDK_base_v4_0_0.so │ │ ├── libBaiduMapSDK_cloud_v4_0_0.so │ │ ├── libBaiduMapSDK_map_v4_0_0.so │ │ ├── libBaiduMapSDK_radar_v4_0_0.so │ │ ├── libBaiduMapSDK_search_v4_0_0.so │ │ ├── libBaiduMapSDK_util_v4_0_0.so │ │ └── liblocSDK6a.so │ ├── armeabi-v7a │ │ ├── libBaiduMapSDK_base_v4_0_0.so │ │ ├── libBaiduMapSDK_cloud_v4_0_0.so │ │ ├── libBaiduMapSDK_map_v4_0_0.so │ │ ├── libBaiduMapSDK_radar_v4_0_0.so │ │ ├── libBaiduMapSDK_search_v4_0_0.so │ │ ├── libBaiduMapSDK_util_v4_0_0.so │ │ └── liblocSDK6a.so │ ├── armeabi │ │ ├── libBaiduMapSDK_base_v4_0_0.so │ │ ├── libBaiduMapSDK_cloud_v4_0_0.so │ │ ├── libBaiduMapSDK_map_v4_0_0.so │ │ ├── libBaiduMapSDK_radar_v4_0_0.so │ │ ├── libBaiduMapSDK_search_v4_0_0.so │ │ ├── libBaiduMapSDK_util_v4_0_0.so │ │ └── liblocSDK6a.so │ ├── x86 │ │ ├── libBaiduMapSDK_base_v4_0_0.so │ │ ├── libBaiduMapSDK_cloud_v4_0_0.so │ │ ├── libBaiduMapSDK_map_v4_0_0.so │ │ ├── libBaiduMapSDK_radar_v4_0_0.so │ │ ├── libBaiduMapSDK_search_v4_0_0.so │ │ ├── libBaiduMapSDK_util_v4_0_0.so │ │ └── liblocSDK6a.so │ └── x86_64 │ │ ├── libBaiduMapSDK_base_v4_0_0.so │ │ ├── libBaiduMapSDK_cloud_v4_0_0.so │ │ ├── libBaiduMapSDK_map_v4_0_0.so │ │ ├── libBaiduMapSDK_radar_v4_0_0.so │ │ ├── libBaiduMapSDK_search_v4_0_0.so │ │ ├── libBaiduMapSDK_util_v4_0_0.so │ │ └── liblocSDK6a.so ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── happyheng │ │ └── sport_android │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── happyheng │ │ │ └── sport_android │ │ │ ├── App.java │ │ │ ├── activity │ │ │ ├── ActivityMain.java │ │ │ ├── ActivitySportList.java │ │ │ ├── ActivitySportMessage.java │ │ │ ├── ArticleActivity.java │ │ │ ├── BaseActivity.java │ │ │ ├── LoginActivity.java │ │ │ ├── MapActivity.java │ │ │ └── RegisterActivity.java │ │ │ ├── fragment │ │ │ ├── FragmentMine.java │ │ │ ├── FragmentNews.java │ │ │ ├── FragmentSport.java │ │ │ └── recycler │ │ │ │ ├── FragmentBaseRecycler.java │ │ │ │ └── FragmentLoadRecycler.java │ │ │ ├── model │ │ │ ├── IdEntity.java │ │ │ ├── News.java │ │ │ ├── User.java │ │ │ ├── entity │ │ │ │ ├── BaseResult.java │ │ │ │ ├── Location.java │ │ │ │ ├── NewsResult.java │ │ │ │ ├── PostRequestBody.java │ │ │ │ ├── SportListResult.java │ │ │ │ └── SportMessageResult.java │ │ │ ├── event │ │ │ │ └── LocationEvent.java │ │ │ ├── network │ │ │ │ ├── HttpClient.java │ │ │ │ ├── HttpClientRequestHelper.java │ │ │ │ └── listener │ │ │ │ │ └── OnRequestListener.java │ │ │ └── request │ │ │ │ ├── BaseRequest.java │ │ │ │ ├── LoginRequest.java │ │ │ │ ├── NewsRequest.java │ │ │ │ ├── RecordSportMessageRequest.java │ │ │ │ ├── RegisterRequest.java │ │ │ │ ├── SportIdRequest.java │ │ │ │ ├── SportListRequest.java │ │ │ │ └── SportMessageRequest.java │ │ │ ├── service │ │ │ └── LocationService.java │ │ │ ├── servicecode │ │ │ ├── RecordService.java │ │ │ └── impl │ │ │ │ └── RecordServiceImpl.java │ │ │ ├── utils │ │ │ ├── AESUtils.java │ │ │ ├── DensityUtils.java │ │ │ ├── HexUtils.java │ │ │ ├── NetUtils.java │ │ │ ├── SPUtils.java │ │ │ ├── ScreenUtils.java │ │ │ ├── SimpleStartActivityUtils.java │ │ │ ├── ThreadUtils.java │ │ │ └── ToastUtils.java │ │ │ └── view │ │ │ ├── MainBottomView.java │ │ │ ├── NewsItemView.java │ │ │ └── TabSportBackView.java │ └── res │ │ ├── drawable │ │ ├── bg_oval.xml │ │ ├── bg_tab_information.xml │ │ ├── bg_tab_mine.xml │ │ ├── bg_tab_sport.xml │ │ ├── bg_tab_sport_button.xml │ │ ├── bg_tab_sport_button_press.xml │ │ └── bg_tab_sport_normal.xml │ │ ├── layout │ │ ├── activity_article.xml │ │ ├── activity_login.xml │ │ ├── activity_main.xml │ │ ├── activity_map.xml │ │ ├── activity_register.xml │ │ ├── activity_sport_list.xml │ │ ├── activity_sport_message.xml │ │ ├── fragment_base_recycler.xml │ │ ├── fragment_information.xml │ │ ├── fragment_mine.xml │ │ ├── fragment_sport.xml │ │ ├── item_load_more.xml │ │ ├── item_news.xml │ │ ├── item_sport_list.xml │ │ └── view_main_bottom.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── tab_information_selected.png │ │ ├── tab_information_unselected.png │ │ ├── tab_me_selected.png │ │ ├── tab_me_unselected.png │ │ ├── tab_sport_selected.png │ │ └── tab_sport_unselected.png │ │ ├── mipmap-xxhdpi │ │ ├── tab_me_selected.png │ │ ├── tab_me_unselected.png │ │ ├── tab_sport_selected.png │ │ ├── tab_sport_unselected.png │ │ └── user_icon.jpg │ │ ├── mipmap-xxxhdpi │ │ └── icon.jpg │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── happyheng │ └── sport_android │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshot ├── 1.png ├── 2.png ├── 3.png ├── 4.png └── 5.png └── 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/.name: -------------------------------------------------------------------------------- 1 | Sport_Android -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | Android 39 | 40 | 41 | Android > Lint > Correctness 42 | 43 | 44 | Java 45 | 46 | 47 | Java language level migration aidsJava 48 | 49 | 50 | 51 | 52 | Android 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 74 | 75 | 76 | 77 | 78 | 1.8 79 | 80 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 描述 2 | 一个Android版的运动APP。其实现了登陆、注册、资讯详情、运动记录等功能。 3 | 4 | #技术栈 5 | [okhttp](https://github.com/square/okhttp) 为项目的网络请求库 6 | 7 | [fastjson](https://github.com/alibaba/fastjson) 为项目中的json解析库 8 | 9 | [eventbus](https://github.com/greenrobot/EventBus) 为项目中的发布/订阅事件总线 10 | 11 | [glide](https://github.com/bumptech/glide) 为项目中的图片加载框架 12 | # 如何使用 13 | 此APP需与相应的服务端源码配合使用,当然,服务端源码也是开源的,链接为: [服务器端源码](https://github.com/happyheng/Sport_Service) 14 | 15 | 需要注意的是,在clone了服务器端代码进行使用时,需要找到自己电脑的ip地址,然后把Android中BaseRequest的IP变量换成自己电脑的ip地址,否则访问会失败。 16 | 17 | #程序截图 18 | 截图1 19 | 截图2 20 | 截图3 21 | 截图4 22 | 截图5 23 | 24 | # 更多 25 | 关于此APP的设计我会在博客中做出更多的介绍,欢迎大家参观我的博客: [博客](http://blog.csdn.net/happyheng) 26 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | applicationId "com.happyheng.sport_android" 9 | minSdkVersion 14 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | sourceSets { 22 | main() { 23 | jniLibs.srcDirs = ['libs'] 24 | } 25 | } 26 | } 27 | 28 | dependencies { 29 | compile fileTree(dir: 'libs', include: ['*.jar']) 30 | testCompile 'junit:junit:4.12' 31 | compile 'com.android.support:appcompat-v7:23.1.1' 32 | compile 'com.android.support:recyclerview-v7:+' 33 | 34 | compile 'com.squareup.okhttp3:okhttp:3.3.1' 35 | compile 'com.github.orhanobut:logger:1.12' 36 | compile 'com.alibaba:fastjson:1.1.46.android' 37 | compile 'org.greenrobot:eventbus:3.0.0' 38 | compile files('libs/BaiduLBS_Android.jar') 39 | compile 'com.github.bumptech.glide:glide:3.7.0' 40 | } 41 | -------------------------------------------------------------------------------- /app/libs/BaiduLBS_Android.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/BaiduLBS_Android.jar -------------------------------------------------------------------------------- /app/libs/arm64-v8a/libBaiduMapSDK_base_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/arm64-v8a/libBaiduMapSDK_base_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/arm64-v8a/libBaiduMapSDK_cloud_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/arm64-v8a/libBaiduMapSDK_cloud_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/arm64-v8a/libBaiduMapSDK_map_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/arm64-v8a/libBaiduMapSDK_map_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/arm64-v8a/libBaiduMapSDK_radar_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/arm64-v8a/libBaiduMapSDK_radar_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/arm64-v8a/libBaiduMapSDK_search_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/arm64-v8a/libBaiduMapSDK_search_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/arm64-v8a/libBaiduMapSDK_util_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/arm64-v8a/libBaiduMapSDK_util_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/arm64-v8a/liblocSDK6a.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/arm64-v8a/liblocSDK6a.so -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/libBaiduMapSDK_base_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi-v7a/libBaiduMapSDK_base_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/libBaiduMapSDK_cloud_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi-v7a/libBaiduMapSDK_cloud_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/libBaiduMapSDK_map_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi-v7a/libBaiduMapSDK_map_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/libBaiduMapSDK_radar_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi-v7a/libBaiduMapSDK_radar_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/libBaiduMapSDK_search_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi-v7a/libBaiduMapSDK_search_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/libBaiduMapSDK_util_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi-v7a/libBaiduMapSDK_util_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/armeabi-v7a/liblocSDK6a.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi-v7a/liblocSDK6a.so -------------------------------------------------------------------------------- /app/libs/armeabi/libBaiduMapSDK_base_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi/libBaiduMapSDK_base_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/armeabi/libBaiduMapSDK_cloud_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi/libBaiduMapSDK_cloud_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/armeabi/libBaiduMapSDK_map_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi/libBaiduMapSDK_map_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/armeabi/libBaiduMapSDK_radar_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi/libBaiduMapSDK_radar_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/armeabi/libBaiduMapSDK_search_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi/libBaiduMapSDK_search_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/armeabi/libBaiduMapSDK_util_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi/libBaiduMapSDK_util_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/armeabi/liblocSDK6a.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/armeabi/liblocSDK6a.so -------------------------------------------------------------------------------- /app/libs/x86/libBaiduMapSDK_base_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86/libBaiduMapSDK_base_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/x86/libBaiduMapSDK_cloud_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86/libBaiduMapSDK_cloud_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/x86/libBaiduMapSDK_map_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86/libBaiduMapSDK_map_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/x86/libBaiduMapSDK_radar_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86/libBaiduMapSDK_radar_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/x86/libBaiduMapSDK_search_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86/libBaiduMapSDK_search_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/x86/libBaiduMapSDK_util_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86/libBaiduMapSDK_util_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/x86/liblocSDK6a.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86/liblocSDK6a.so -------------------------------------------------------------------------------- /app/libs/x86_64/libBaiduMapSDK_base_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86_64/libBaiduMapSDK_base_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/x86_64/libBaiduMapSDK_cloud_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86_64/libBaiduMapSDK_cloud_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/x86_64/libBaiduMapSDK_map_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86_64/libBaiduMapSDK_map_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/x86_64/libBaiduMapSDK_radar_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86_64/libBaiduMapSDK_radar_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/x86_64/libBaiduMapSDK_search_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86_64/libBaiduMapSDK_search_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/x86_64/libBaiduMapSDK_util_v4_0_0.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86_64/libBaiduMapSDK_util_v4_0_0.so -------------------------------------------------------------------------------- /app/libs/x86_64/liblocSDK6a.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/happyheng/Sport_Android/599b7e75fc8b00085e19285b8765c596e45daa1c/app/libs/x86_64/liblocSDK6a.so -------------------------------------------------------------------------------- /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 /Users/liuheng/Desktop/Android/sdk/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/happyheng/sport_android/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android; 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 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 42 | 43 | 44 | 47 | 48 | 49 | 50 | 51 | 52 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 65 | 66 | 67 | 68 | 71 | 72 | 73 | 74 | 77 | 78 | 79 | 80 | 82 | 83 | 84 | 85 | 87 | 88 | 89 | 90 | 92 | 93 | 94 | 95 | 96 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/App.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android; 2 | 3 | import android.app.Application; 4 | 5 | import com.baidu.mapapi.SDKInitializer; 6 | import com.happyheng.sport_android.model.User; 7 | import com.happyheng.sport_android.model.network.HttpClient; 8 | import com.orhanobut.logger.Logger; 9 | 10 | /** 11 | * 程序的Application对象 12 | * Created by liuheng on 16/6/7. 13 | */ 14 | public class App extends Application{ 15 | 16 | private static final String TAG_NAME = "MY_TAG"; 17 | 18 | @Override 19 | public void onCreate() { 20 | super.onCreate(); 21 | 22 | //可以在Application对象中初始化一些类库 23 | 24 | Logger.init(TAG_NAME); 25 | HttpClient.init(this); 26 | 27 | User.init(getApplicationContext()); 28 | 29 | SDKInitializer.initialize(getApplicationContext()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/activity/ActivityMain.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | 6 | import com.happyheng.sport_android.R; 7 | import com.happyheng.sport_android.fragment.FragmentNews; 8 | import com.happyheng.sport_android.fragment.FragmentMine; 9 | import com.happyheng.sport_android.fragment.FragmentSport; 10 | import com.happyheng.sport_android.view.MainBottomView; 11 | import com.orhanobut.logger.Logger; 12 | 13 | /** 14 | * 主页面 15 | * Created by liuheng on 16/7/12. 16 | */ 17 | public class ActivityMain extends BaseActivity { 18 | 19 | private static final String FRAGMENT_BASE_TAG = "base_fragment"; 20 | 21 | private MainBottomView mBottomView; 22 | 23 | private int mSelectPosition = 0; 24 | 25 | private MainBottomView.OnBottomChooseListener mBottomChooseListener = new BottomChooseListener(); 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_main); 31 | 32 | initView(); 33 | 34 | selectPositionFragment(mSelectPosition); 35 | } 36 | 37 | private void initView() { 38 | mBottomView = (MainBottomView) findViewById(R.id.main_bottom_tab); 39 | mBottomView.setBottomCLickListener(mBottomChooseListener); 40 | } 41 | 42 | //初始化一个Fragment,并将其添加到指定位置 43 | private void initFragment(int position){ 44 | 45 | Fragment fragment; 46 | switch (position){ 47 | 48 | case 0: 49 | fragment = new FragmentNews(); 50 | break; 51 | 52 | case 1: 53 | fragment = new FragmentSport(); 54 | break; 55 | 56 | default: 57 | fragment = new FragmentMine(); 58 | break; 59 | } 60 | getSupportFragmentManager().beginTransaction().add(R.id.main_content_ll,fragment,getFragmentTagByPosition(position)).commit(); 61 | } 62 | 63 | //得到指定Tag的Fragment 64 | private Fragment getFragmentByTag(int position){ 65 | return getSupportFragmentManager().findFragmentByTag(getFragmentTagByPosition(position)); 66 | } 67 | 68 | //得到每个Fragment对应的tag 69 | private String getFragmentTagByPosition(int position){ 70 | return FRAGMENT_BASE_TAG + position; 71 | } 72 | 73 | private void selectPositionFragment(int position){ 74 | Fragment selectFragment = getFragmentByTag(position); 75 | 76 | if (selectFragment == null){ 77 | initFragment(position); 78 | } else { 79 | getSupportFragmentManager().beginTransaction().show(selectFragment).commit(); 80 | } 81 | } 82 | 83 | 84 | private class BottomChooseListener implements MainBottomView.OnBottomChooseListener { 85 | 86 | @Override 87 | public void onClick(int oldPosition, int selectPosition) { 88 | 89 | Fragment nowFragment = getFragmentByTag(oldPosition); 90 | getSupportFragmentManager().beginTransaction().hide(nowFragment).commit(); 91 | selectPositionFragment(selectPosition); 92 | 93 | mSelectPosition = selectPosition; 94 | } 95 | } 96 | 97 | 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/activity/ActivitySportList.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.AdapterView; 10 | import android.widget.BaseAdapter; 11 | import android.widget.ListView; 12 | import android.widget.TextView; 13 | 14 | import com.happyheng.sport_android.R; 15 | import com.happyheng.sport_android.model.User; 16 | import com.happyheng.sport_android.model.request.SportListRequest; 17 | import com.orhanobut.logger.Logger; 18 | 19 | import java.util.ArrayList; 20 | import java.util.List; 21 | 22 | /** 23 | * 显示所有运动记录的Activity 24 | * Created by liuheng on 16/8/15. 25 | */ 26 | public class ActivitySportList extends BaseActivity implements SportListRequest.ListListener,ListView.OnItemClickListener{ 27 | 28 | private ListView mSportList; 29 | private SportListAdapter mAdapter; 30 | private List mListData = new ArrayList<>(); 31 | 32 | @Override 33 | protected void onCreate(@Nullable Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_sport_list); 36 | 37 | initView(); 38 | initData(); 39 | } 40 | 41 | private void initView() { 42 | mSportList = (ListView) findViewById(R.id.sport_list_lv); 43 | mAdapter = new SportListAdapter(); 44 | mSportList.setAdapter(mAdapter); 45 | mSportList.setOnItemClickListener(this); 46 | } 47 | 48 | private void initData() { 49 | SportListRequest request = new SportListRequest(User.getUser().getUserToken()); 50 | request.setListListener(this); 51 | request.doRequest(); 52 | } 53 | 54 | @Override 55 | public void onSuccess(List list) { 56 | mListData.addAll(list); 57 | mAdapter.notifyDataSetChanged(); 58 | } 59 | 60 | @Override 61 | public void onFail() { 62 | Logger.d("获取失败"); 63 | } 64 | 65 | @Override 66 | public void onItemClick(AdapterView parent, View view, int position, long id) { 67 | int sportId = mListData.get(position); 68 | Logger.d("得到的sportId为"+sportId); 69 | 70 | Intent intent = new Intent(this,ActivitySportMessage.class); 71 | intent.putExtra(ActivitySportMessage.TAG_SPORT_ID,sportId); 72 | startActivity(intent); 73 | } 74 | 75 | private class SportListAdapter extends BaseAdapter{ 76 | 77 | @Override 78 | public int getCount() { 79 | return mListData.size(); 80 | } 81 | 82 | @Override 83 | public Object getItem(int position) { 84 | return null; 85 | } 86 | 87 | @Override 88 | public long getItemId(int position) { 89 | return 0; 90 | } 91 | 92 | @Override 93 | public View getView(int position, View convertView, ViewGroup parent) { 94 | 95 | if (convertView == null){ 96 | convertView = LayoutInflater.from(ActivitySportList.this).inflate(R.layout.item_sport_list,null); 97 | } 98 | TextView textView = (TextView) convertView.findViewById(R.id.item_sport_list_tv); 99 | textView.setText("运动轨迹"+(position+1)); 100 | 101 | return convertView; 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/activity/ActivitySportMessage.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | 6 | import com.baidu.mapapi.map.BaiduMap; 7 | import com.baidu.mapapi.map.DotOptions; 8 | import com.baidu.mapapi.map.MapStatus; 9 | import com.baidu.mapapi.map.MapStatusUpdateFactory; 10 | import com.baidu.mapapi.map.MapView; 11 | import com.baidu.mapapi.map.MyLocationConfiguration; 12 | import com.baidu.mapapi.map.MyLocationData; 13 | import com.baidu.mapapi.map.OverlayOptions; 14 | import com.baidu.mapapi.map.PolygonOptions; 15 | import com.baidu.mapapi.map.PolylineOptions; 16 | import com.baidu.mapapi.model.LatLng; 17 | import com.happyheng.sport_android.R; 18 | import com.happyheng.sport_android.model.User; 19 | import com.happyheng.sport_android.model.entity.Location; 20 | import com.happyheng.sport_android.model.request.BaseRequest; 21 | import com.happyheng.sport_android.model.request.SportMessageRequest; 22 | import com.orhanobut.logger.Logger; 23 | 24 | import java.util.ArrayList; 25 | import java.util.List; 26 | 27 | /** 28 | * 显示运动轨迹的Activity 29 | * Created by liuheng on 16/8/16. 30 | */ 31 | public class ActivitySportMessage extends BaseActivity implements SportMessageRequest.OnSportMessageListener{ 32 | 33 | public static final String TAG_SPORT_ID = "sport_id"; 34 | 35 | //显示的百度MapView 36 | private MapView mMapView = null; 37 | private BaiduMap mMap = null; 38 | 39 | private int mSportId; 40 | private SportMessageRequest request; 41 | 42 | @Override 43 | protected void onCreate(@Nullable Bundle savedInstanceState) { 44 | super.onCreate(savedInstanceState); 45 | setContentView(R.layout.activity_sport_message); 46 | 47 | initView(); 48 | getData(); 49 | } 50 | 51 | private void initView() { 52 | //获取地图控件引用 53 | mMapView = (MapView) findViewById(R.id.bmapView); 54 | mMap = mMapView.getMap(); 55 | } 56 | 57 | private void getData(){ 58 | mSportId = getIntent().getIntExtra(TAG_SPORT_ID,0); 59 | request = new SportMessageRequest(User.getUser().getUserToken(),String.valueOf(mSportId)); 60 | request.setMessageListener(this); 61 | request.doRequest(); 62 | } 63 | 64 | @Override 65 | public void onSuccess(List data) { 66 | 67 | if (!data.isEmpty()){ 68 | Location firstLocation = data.get(0); 69 | 70 | //1、定位至第一个点,然后缩小地图范围 71 | //此为设置缩放比例为15级 72 | mMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder().zoom(18).build())); 73 | LatLng firstLatLng = new LatLng(firstLocation.getPosy(),firstLocation.getPosx()); 74 | location(firstLatLng); 75 | 76 | //2、绘制运动信息 77 | List latLngList = new ArrayList<>(); 78 | List optionsList = new ArrayList<>(); 79 | for (Location location : data){ 80 | LatLng latLng = new LatLng(location.getPosy(),location.getPosx()); 81 | latLngList.add(latLng); 82 | 83 | OverlayOptions options = new DotOptions().center(latLng); 84 | optionsList.add(options); 85 | } 86 | 87 | //画点 88 | mMap.addOverlays(optionsList); 89 | 90 | //画折线 91 | if(latLngList.size() != 1){ 92 | OverlayOptions lineOptions = new PolylineOptions().points(latLngList); 93 | mMap.addOverlay(lineOptions); 94 | } 95 | } 96 | } 97 | 98 | 99 | //根据定位信息进行定位,即移动地图至当前点 100 | private void location(LatLng bdLocation) { 101 | 102 | //可以用下面的方法对在得到经纬度信息后在百度地图中进行显示 103 | BaiduMap mMap = mMapView.getMap(); 104 | 105 | // 开启定位图层 106 | mMap.setMyLocationEnabled(true); 107 | // 构造定位数据 108 | MyLocationData locData = new MyLocationData.Builder() 109 | // 此处设置开发者获取到的方向信息,顺时针0-360 110 | .direction(100) 111 | .latitude(bdLocation.latitude) 112 | .longitude(bdLocation.longitude) 113 | .build(); 114 | 115 | //设置定位的配置信息 116 | MyLocationConfiguration configuration = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.FOLLOWING, true, null); 117 | mMap.setMyLocationConfigeration(configuration); 118 | // 设置定位数据 119 | mMap.setMyLocationData(locData); 120 | } 121 | 122 | @Override 123 | public void onFail() { 124 | Logger.d("请求失败"); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/activity/ArticleActivity.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.View; 6 | import android.webkit.WebSettings; 7 | import android.webkit.WebView; 8 | 9 | import com.happyheng.sport_android.R; 10 | import com.orhanobut.logger.Logger; 11 | 12 | /** 13 | * 文章详情界面 14 | * Created by liuheng on 16/7/27. 15 | */ 16 | public class ArticleActivity extends BaseActivity { 17 | 18 | public static final String BUNDLE_URL = "url"; 19 | //private static final String TEST_URL = "http://192.168.0.104:8080/Sport/NewsDetail?id=3"; 20 | 21 | private WebView mWebView; 22 | 23 | //文章的url 24 | private String mArticleUrl; 25 | 26 | 27 | @Override 28 | protected void onCreate(@Nullable Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_article); 31 | mWebView = (WebView) findViewById(R.id.article_wv); 32 | 33 | initWebView(); 34 | 35 | mArticleUrl = getIntent().getStringExtra(BUNDLE_URL); 36 | 37 | mWebView.loadUrl(mArticleUrl); 38 | } 39 | 40 | private void initWebView() { 41 | WebSettings settings = mWebView.getSettings(); 42 | 43 | settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN); 44 | settings.setUseWideViewPort(true); 45 | settings.setLoadWithOverviewMode(true); 46 | mWebView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/activity/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.activity; 2 | 3 | import android.app.Activity; 4 | import android.support.v4.app.FragmentActivity; 5 | import android.widget.Toast; 6 | 7 | /** 8 | * 项目中所有Activity的基类 9 | * Created by liuheng on 16/6/26. 10 | */ 11 | public class BaseActivity extends FragmentActivity{ 12 | 13 | protected void showToast(String toast){ 14 | Toast.makeText(this,toast,Toast.LENGTH_LONG).show(); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/activity/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.activity; 2 | 3 | import android.animation.ObjectAnimator; 4 | import android.animation.PropertyValuesHolder; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.text.TextUtils; 8 | import android.view.View; 9 | import android.widget.Button; 10 | import android.widget.EditText; 11 | import android.widget.ImageView; 12 | 13 | import com.happyheng.sport_android.R; 14 | import com.happyheng.sport_android.model.request.BaseRequest; 15 | import com.happyheng.sport_android.model.request.LoginRequest; 16 | import com.happyheng.sport_android.model.User; 17 | import com.happyheng.sport_android.utils.DensityUtils; 18 | import com.happyheng.sport_android.utils.ScreenUtils; 19 | import com.happyheng.sport_android.utils.SimpleStartActivityUtils; 20 | import com.happyheng.sport_android.utils.ToastUtils; 21 | import com.orhanobut.logger.Logger; 22 | 23 | /** 24 | * "登陆"的Activity 25 | * Created by liuheng on 16/6/6. 26 | */ 27 | public class LoginActivity extends BaseActivity { 28 | 29 | //动画的时长 30 | private static final int ANIMATION_TIME = 1000; 31 | //底部Button距中间线的高度 32 | private static final int BOTTOM_MARGIN = 50; 33 | 34 | private View.OnClickListener mLoginBtClickListener = new OnLoginBtClickListener(); 35 | private LoginRequest.OnLoginListener mLoginListener = new OnLoginListener(); 36 | 37 | private ImageView mIconIv; 38 | private EditText mUserNameEt, mPassWordEt; 39 | private Button mLoginBt, mRegisterBt; 40 | 41 | private View mTopLl, mBottomLl; 42 | 43 | 44 | @Override 45 | protected void onCreate(Bundle savedInstanceState) { 46 | super.onCreate(savedInstanceState); 47 | setContentView(R.layout.activity_login); 48 | 49 | initView(); 50 | 51 | beginAnimation(); 52 | } 53 | 54 | 55 | /** 56 | * 初始化所有的View 57 | */ 58 | private void initView() { 59 | mIconIv = (ImageView) findViewById(R.id.icon_iv); 60 | mUserNameEt = (EditText) findViewById(R.id.username_et); 61 | mPassWordEt = (EditText) findViewById(R.id.password_et); 62 | mLoginBt = (Button) findViewById(R.id.login_bt); 63 | mRegisterBt = (Button) findViewById(R.id.register_bt); 64 | 65 | mTopLl = findViewById(R.id.top_ll); 66 | mBottomLl = findViewById(R.id.bottom_ll); 67 | 68 | mLoginBt.setOnClickListener(mLoginBtClickListener); 69 | 70 | mRegisterBt.setOnClickListener(new View.OnClickListener() { 71 | @Override 72 | public void onClick(View v) { 73 | //点击注册,跳转到注册的界面 74 | SimpleStartActivityUtils.startActivity(LoginActivity.this, RegisterActivity.class); 75 | } 76 | }); 77 | } 78 | 79 | private class OnLoginBtClickListener implements View.OnClickListener { 80 | 81 | @Override 82 | public void onClick(View v) { 83 | String userNameString = mUserNameEt.getText().toString(); 84 | String passWordString = mPassWordEt.getText().toString(); 85 | //1、先判断是否为空 86 | if (TextUtils.isEmpty(userNameString) || TextUtils.isEmpty(passWordString)) { 87 | ToastUtils.showToast(LoginActivity.this, getResources().getString(R.string.user_pass_empty)); 88 | } 89 | //2、判断是否为用户名为字母+数字 90 | 91 | 92 | //3、调用相关接口 93 | BaseRequest request = new LoginRequest(userNameString, passWordString, mLoginListener); 94 | request.doRequest(); 95 | } 96 | } 97 | 98 | private class OnLoginListener implements LoginRequest.OnLoginListener{ 99 | 100 | @Override 101 | public void onSuccess(String token) { 102 | 103 | User.getUser().setUserToken(token); 104 | 105 | Intent intent = new Intent(LoginActivity.this, ActivityMain.class); 106 | startActivity(intent); 107 | } 108 | 109 | 110 | @Override 111 | public void onFail(int code) { 112 | Logger.d("失败的code为" + code); 113 | 114 | switch (code) { 115 | 116 | case LoginRequest.REQUEST_WRONG_USERNAME: 117 | ToastUtils.showToast(LoginActivity.this, getResources().getString(R.string.wrong_username)); 118 | 119 | break; 120 | 121 | case LoginRequest.REQUEST_WRONG_PASSWORD: 122 | ToastUtils.showToast(LoginActivity.this, getResources().getString(R.string.wrong_password)); 123 | 124 | break; 125 | 126 | default: 127 | ToastUtils.showToast(LoginActivity.this, getResources().getString(R.string.wrong_request)); 128 | 129 | break; 130 | } 131 | } 132 | } 133 | 134 | /** 135 | * 开始动画 136 | */ 137 | private void beginAnimation() { 138 | 139 | final int screenHeight = ScreenUtils.getScreenHeight(this); 140 | 141 | mTopLl.post(new Runnable() { 142 | @Override 143 | public void run() { 144 | int topLlHeight = mTopLl.getMeasuredHeight(); 145 | int animationHeight = screenHeight / 2 - topLlHeight; 146 | 147 | PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("translationY", animationHeight); 148 | PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("alpha", 0.3f, 1.0f); 149 | 150 | ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mTopLl, holder1, holder2); 151 | animator.setDuration(ANIMATION_TIME); 152 | animator.start(); 153 | } 154 | }); 155 | 156 | mBottomLl.post(new Runnable() { 157 | @Override 158 | public void run() { 159 | int animationHeight = screenHeight / 2 + DensityUtils.dp2px(LoginActivity.this, BOTTOM_MARGIN) - mBottomLl.getTop(); 160 | 161 | PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("translationY", animationHeight); 162 | PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("alpha", 0.3f, 1.0f); 163 | 164 | ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mBottomLl, holder1, holder2); 165 | animator.setDuration(ANIMATION_TIME); 166 | animator.start(); 167 | } 168 | }); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/activity/MapActivity.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | 6 | import com.baidu.location.BDLocation; 7 | import com.baidu.location.BDLocationListener; 8 | import com.baidu.location.LocationClient; 9 | import com.baidu.location.LocationClientOption; 10 | import com.baidu.mapapi.map.BaiduMap; 11 | import com.baidu.mapapi.map.DotOptions; 12 | import com.baidu.mapapi.map.MapStatus; 13 | import com.baidu.mapapi.map.MapStatusUpdateFactory; 14 | import com.baidu.mapapi.map.MapView; 15 | import com.baidu.mapapi.map.MyLocationConfiguration; 16 | import com.baidu.mapapi.map.MyLocationData; 17 | import com.baidu.mapapi.map.OverlayOptions; 18 | import com.baidu.mapapi.map.PolylineOptions; 19 | import com.baidu.mapapi.model.LatLng; 20 | import com.happyheng.sport_android.R; 21 | import com.happyheng.sport_android.model.event.LocationEvent; 22 | import com.happyheng.sport_android.service.LocationService; 23 | import com.happyheng.sport_android.servicecode.RecordService; 24 | import com.happyheng.sport_android.servicecode.impl.RecordServiceImpl; 25 | import com.orhanobut.logger.Logger; 26 | 27 | import org.greenrobot.eventbus.EventBus; 28 | import org.greenrobot.eventbus.Subscribe; 29 | 30 | import java.util.ArrayList; 31 | import java.util.LinkedList; 32 | import java.util.List; 33 | 34 | /** 35 | * 地图的Activity 36 | * Created by liuheng on 16/6/26. 37 | */ 38 | public class MapActivity extends BaseActivity { 39 | 40 | //显示的百度MapView 41 | private MapView mMapView = null; 42 | private BaiduMap mMap = null; 43 | 44 | private LatLng mBeforeLocation = null; 45 | 46 | @Override 47 | protected void onCreate(Bundle savedInstanceState) { 48 | super.onCreate(savedInstanceState); 49 | setContentView(R.layout.activity_map); 50 | 51 | //获取地图控件引用 52 | mMapView = (MapView) findViewById(R.id.bmapView); 53 | mMap = mMapView.getMap(); 54 | 55 | startLocationService(); 56 | 57 | EventBus.getDefault().register(this); 58 | } 59 | 60 | //启动定位的Service 61 | private void startLocationService(){ 62 | Intent intent = new Intent(this, LocationService.class); 63 | startService(intent); 64 | } 65 | 66 | //获取经纬度后回调的方法 67 | @Subscribe 68 | public void onEvent(LocationEvent bdLocation) { 69 | //先暂时获得经纬度信息,并将其记录在List中 70 | //进行定位 71 | location(bdLocation.getLocation()); 72 | 73 | //绘制位置 74 | drawLocation(bdLocation.getLocation()); 75 | } 76 | 77 | //根据定位信息进行定位,即移动地图至当前点 78 | private void location(LatLng bdLocation) { 79 | 80 | //将map缩放至18级 81 | mMap.setMapStatus(MapStatusUpdateFactory.newMapStatus(new MapStatus.Builder().zoom(18).build())); 82 | 83 | //可以用下面的方法对在得到经纬度信息后在百度地图中进行显示 84 | BaiduMap mMap = mMapView.getMap(); 85 | 86 | // 开启定位图层 87 | mMap.setMyLocationEnabled(true); 88 | // 构造定位数据 89 | MyLocationData locData = new MyLocationData.Builder() 90 | // 此处设置开发者获取到的方向信息,顺时针0-360 91 | .direction(100) 92 | .latitude(bdLocation.latitude) 93 | .longitude(bdLocation.longitude) 94 | .build(); 95 | 96 | //设置定位的配置信息 97 | MyLocationConfiguration configuration = new MyLocationConfiguration(MyLocationConfiguration.LocationMode.FOLLOWING, true, null); 98 | mMap.setMyLocationConfigeration(configuration); 99 | // 设置定位数据 100 | mMap.setMyLocationData(locData); 101 | } 102 | 103 | //根据当前的坐标画出点数和直线 104 | private void drawLocation(LatLng nowLatLng) { 105 | 106 | //1、画出当前的点数 107 | OverlayOptions dotOptions = new DotOptions().center(nowLatLng); 108 | mMap.addOverlay(dotOptions); 109 | 110 | //2、如果不为1,那么还要画一个指向之前的横线 111 | if (mBeforeLocation != null){ 112 | List linePoints = new ArrayList<>(); 113 | linePoints.add(mBeforeLocation); 114 | linePoints.add(nowLatLng); 115 | OverlayOptions lineOptions = new PolylineOptions().points(linePoints); 116 | mMap.addOverlay(lineOptions); 117 | } 118 | mBeforeLocation = nowLatLng; 119 | } 120 | 121 | @Override 122 | protected void onResume() { 123 | super.onResume(); 124 | //在activity执行onResume时执行mMapView. onResume (),实现地图生命周期管理 125 | mMapView.onResume(); 126 | } 127 | 128 | @Override 129 | protected void onPause() { 130 | super.onPause(); 131 | //在activity执行onPause时执行mMapView. onPause (),实现地图生命周期管理 132 | mMapView.onPause(); 133 | } 134 | 135 | 136 | @Override 137 | protected void onDestroy() { 138 | super.onDestroy(); 139 | //在activity执行onDestroy时执行mMapView.onDestroy(),实现地图生命周期管理 140 | mMapView.onDestroy(); 141 | 142 | //将定位Service关闭掉 143 | Intent intent = new Intent(this, LocationService.class); 144 | stopService(intent); 145 | } 146 | 147 | 148 | } 149 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/activity/RegisterActivity.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.activity; 2 | 3 | import android.os.Bundle; 4 | import android.text.TextUtils; 5 | import android.view.View; 6 | import android.widget.Button; 7 | import android.widget.EditText; 8 | 9 | import com.happyheng.sport_android.R; 10 | import com.happyheng.sport_android.model.request.BaseRequest; 11 | import com.happyheng.sport_android.model.request.RegisterRequest; 12 | 13 | /** 14 | * "注册"的Activity 15 | * Created by liuheng on 16/6/7. 16 | */ 17 | public class RegisterActivity extends BaseActivity { 18 | 19 | private EditText mUserNameEt, mPassWordEt, mPassWordConfirmEt, mNickNameEt; 20 | private Button mRegisterBt; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_register); 26 | 27 | initView(); 28 | } 29 | 30 | private void initView() { 31 | mUserNameEt = (EditText) findViewById(R.id.username_et); 32 | mPassWordEt = (EditText) findViewById(R.id.password_et); 33 | mPassWordConfirmEt = (EditText) findViewById(R.id.password_confirm_et); 34 | mNickNameEt = (EditText) findViewById(R.id.nickname_et); 35 | 36 | mRegisterBt = (Button) findViewById(R.id.register_bt); 37 | mRegisterBt.setOnClickListener(new View.OnClickListener() { 38 | @Override 39 | public void onClick(View v) { 40 | 41 | String userName = mUserNameEt.getText().toString(); 42 | String passWord = mPassWordEt.getText().toString(); 43 | String passWordConfirm = mPassWordConfirmEt.getText().toString(); 44 | String nickName = mNickNameEt.getText().toString(); 45 | 46 | //进行判断,如果为空则弹出提示 47 | if (TextUtils.isEmpty(userName)) { 48 | showToast(getString(R.string.user_empty)); 49 | } else if (TextUtils.isEmpty(passWord) || TextUtils.isEmpty(passWordConfirm)) { 50 | showToast(getString(R.string.pass_empty)); 51 | } else if (!passWord.equals(passWordConfirm)) { 52 | showToast(getString(R.string.pass_wrong_confirm)); 53 | } else if (TextUtils.isEmpty(nickName)) { 54 | showToast(getString(R.string.nick_empty)); 55 | } 56 | 57 | BaseRequest request = new RegisterRequest(userName, passWord, nickName, new RegisterRequest.onRegisterListener() { 58 | @Override 59 | public void onSuccess() { 60 | showToast(getString(R.string.register_success)); 61 | finish(); 62 | } 63 | 64 | @Override 65 | public void onRepeatUserName() { 66 | showToast(getString(R.string.repeat_user_name)); 67 | } 68 | 69 | @Override 70 | public void onRepeatNickName() { 71 | showToast(getString(R.string.repeat_nick)); 72 | } 73 | 74 | @Override 75 | public void onFail() { 76 | showToast(getString(R.string.wrong_request)); 77 | } 78 | }); 79 | request.doRequest(); 80 | } 81 | }); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/fragment/FragmentMine.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.fragment; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.TextView; 11 | 12 | import com.happyheng.sport_android.R; 13 | import com.happyheng.sport_android.activity.ActivitySportList; 14 | 15 | /** 16 | * 主页面---我的 17 | * Created by liuheng on 16/7/14. 18 | */ 19 | public class FragmentMine extends Fragment { 20 | 21 | private TextView mSportMessageTv; 22 | 23 | @Nullable 24 | @Override 25 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 26 | return inflater.inflate(R.layout.fragment_mine,container,false); 27 | } 28 | 29 | @Override 30 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 31 | super.onViewCreated(view, savedInstanceState); 32 | 33 | mSportMessageTv = (TextView) view.findViewById(R.id.mine_sport_message_tv); 34 | mSportMessageTv.setOnClickListener(new View.OnClickListener() { 35 | @Override 36 | public void onClick(View v) { 37 | Intent intent = new Intent(getActivity(), ActivitySportList.class); 38 | startActivity(intent); 39 | } 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/fragment/FragmentNews.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.fragment; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Rect; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.happyheng.sport_android.activity.ArticleActivity; 10 | import com.happyheng.sport_android.fragment.recycler.FragmentLoadRecycler; 11 | import com.happyheng.sport_android.model.News; 12 | import com.happyheng.sport_android.model.request.NewsRequest; 13 | import com.happyheng.sport_android.view.NewsItemView; 14 | import com.orhanobut.logger.Logger; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | /** 20 | * 主页面---展示信息的Fragment 21 | * Created by liuheng on 16/7/14. 22 | */ 23 | public class FragmentNews extends FragmentLoadRecycler { 24 | 25 | private List mNewsList = new ArrayList<>(); 26 | 27 | private void OnItemClick(int position) { 28 | News news = mNewsList.get(position); 29 | String articleUrl = news.getUrl(); 30 | 31 | Intent intent = new Intent(getActivity(), ArticleActivity.class); 32 | intent.putExtra(ArticleActivity.BUNDLE_URL, articleUrl); 33 | startActivity(intent); 34 | } 35 | 36 | @Override 37 | protected RequestResult requestDataInBackground(boolean isRefresh) { 38 | 39 | int begin; 40 | if (isRefresh) { 41 | begin = 0; 42 | } else { 43 | begin = mNewsList.size(); 44 | } 45 | 46 | NewsRequest request = new NewsRequest(); 47 | request.setBeginCount(begin, DEFAULT_REQUEST_COUNT); 48 | List resultList = request.getNewsItem(); 49 | 50 | RequestResult result = new RequestResult(); 51 | if (resultList != null) { 52 | mNewsList.addAll(resultList); 53 | 54 | result.ret = RequestResult.RET_SUCCESS; 55 | result.addCount = resultList.size(); 56 | } else { 57 | result.ret = RequestResult.RET_FAILED; 58 | } 59 | return result; 60 | } 61 | 62 | @Override 63 | protected int getItemSize() { 64 | return mNewsList.size(); 65 | } 66 | 67 | @Override 68 | protected void setItemOffset(Rect outRect, int position) { 69 | outRect.set(0, mDefaultTopDecoration, 0, 0); 70 | } 71 | 72 | @Override 73 | protected RecyclerView.ViewHolder getViewHolder(ViewGroup parent) { 74 | NewsItemView view = new NewsItemView(getContext(), null); 75 | return getBaseViewHolder(view); 76 | } 77 | 78 | @Override 79 | protected void bindingViewHolder(RecyclerView.ViewHolder holder, final int position) { 80 | NewsItemView itemView = (NewsItemView) holder.itemView; 81 | News news = mNewsList.get(position); 82 | 83 | itemView.setThumbnailSource(news.getThumbnail()); 84 | itemView.setTitleString(news.getName()); 85 | itemView.setContentString(news.getSimplecontent()); 86 | itemView.setOnClickListener(new View.OnClickListener() { 87 | @Override 88 | public void onClick(View v) { 89 | OnItemClick(position); 90 | } 91 | }); 92 | } 93 | 94 | } 95 | 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/fragment/FragmentSport.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.fragment; 2 | 3 | 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 | import android.widget.Button; 12 | 13 | import com.happyheng.sport_android.R; 14 | import com.happyheng.sport_android.activity.MapActivity; 15 | 16 | /** 17 | * 主页面---运动的Fragment 18 | * Created by liuheng on 16/7/14. 19 | */ 20 | public class FragmentSport extends Fragment implements View.OnClickListener{ 21 | 22 | private Button mSportStartButton; 23 | 24 | @Nullable 25 | @Override 26 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 27 | return inflater.inflate(R.layout.fragment_sport,container,false); 28 | } 29 | 30 | 31 | @Override 32 | public void onViewCreated(View view, Bundle savedInstanceState) { 33 | mSportStartButton = (Button) view.findViewById(R.id.tab_sport_start_bt); 34 | 35 | mSportStartButton.setOnClickListener(this); 36 | } 37 | 38 | @Override 39 | public void onClick(View v) { 40 | switch (v.getId()){ 41 | 42 | //如果是开始运动的按钮 43 | case R.id.tab_sport_start_bt: 44 | 45 | Intent intent = new Intent(getActivity(), MapActivity.class); 46 | startActivity(intent); 47 | break; 48 | 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/fragment/recycler/FragmentBaseRecycler.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.fragment.recycler; 2 | 3 | import android.os.AsyncTask; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v4.app.Fragment; 7 | import android.support.v4.widget.SwipeRefreshLayout; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import com.happyheng.sport_android.R; 14 | 15 | 16 | /** 17 | * 下拉刷新使用的RecyclerView的父类 18 | */ 19 | public abstract class FragmentBaseRecycler 20 | extends Fragment 21 | { 22 | //默认还有多少item到底部时需要加载更多 23 | private static final int DEFAULT_RESET_ITEM_COUNT = 3; 24 | 25 | private View mContentView; 26 | private SwipeRefreshLayout mRefreshLayout; 27 | protected RecyclerView mRecyclerView; 28 | 29 | private RecyclerView.OnScrollListener mScrollListener = new ScrollListener(); 30 | private SwipeRefreshLayout.OnRefreshListener mRefreshListener = new RefreshListener(); 31 | 32 | protected boolean mIsInit = true; 33 | //是否正在请求的标志位 34 | private boolean mIsLoad = false; 35 | //是否有更多的标志位 36 | protected boolean mShouldLoad = true; 37 | 38 | @Nullable 39 | @Override 40 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle 41 | savedInstanceState) 42 | { 43 | if (mContentView == null) 44 | { 45 | mContentView = inflater.inflate(R.layout.fragment_base_recycler, container, false); 46 | mRefreshLayout = (SwipeRefreshLayout) mContentView.findViewById(R.id.refresh_layout); 47 | mRecyclerView = (RecyclerView) mContentView.findViewById(R.id.recycler_view); 48 | 49 | //设置是否下拉刷新 50 | mRefreshLayout.setEnabled(isRefreshEnable()); 51 | if (isRefreshEnable()) 52 | { 53 | mRefreshLayout.setRefreshing(true); 54 | } 55 | mRefreshLayout.setOnRefreshListener(mRefreshListener); 56 | mRecyclerView.addOnScrollListener(mScrollListener); 57 | 58 | //刚开始进入时,要进行刷新操作 59 | load(true); 60 | } 61 | else 62 | { 63 | mIsInit = false; 64 | } 65 | return mContentView; 66 | } 67 | 68 | 69 | //进行刷新的方法 70 | protected void refresh(boolean isShowSwipeRefreshView){ 71 | if (isShowSwipeRefreshView){ 72 | mRefreshLayout.setRefreshing(true); 73 | } 74 | load(true); 75 | } 76 | 77 | //从开始加载,或者从后面进行加载的方法 78 | protected void load(boolean isRefresh) 79 | { 80 | if (!mIsLoad) 81 | { 82 | LoadAsyncTask loadTask = new LoadAsyncTask(isRefresh); 83 | loadTask.execute(); 84 | } 85 | } 86 | 87 | 88 | //SwipeRefreshLayout刷新的实现类 89 | private class RefreshListener 90 | implements SwipeRefreshLayout.OnRefreshListener 91 | { 92 | 93 | @Override 94 | public void onRefresh() 95 | { 96 | if (mIsLoad) 97 | { 98 | mRefreshLayout.setRefreshing(false); 99 | } 100 | else 101 | { 102 | load(true); 103 | } 104 | 105 | } 106 | } 107 | 108 | //RecyclerView滑动时回调的实现类 109 | private class ScrollListener 110 | extends RecyclerView.OnScrollListener 111 | { 112 | @Override 113 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) 114 | { 115 | int lastVisibleItem = findLastVisibleItemPosition(); 116 | int totalItemCount = recyclerView.getLayoutManager().getItemCount(); 117 | //当距离底部小于约定数且有下一页时,才会进行刷新 118 | if (totalItemCount - lastVisibleItem <= DEFAULT_RESET_ITEM_COUNT && mShouldLoad) 119 | { 120 | load(false); 121 | } 122 | } 123 | 124 | @Override 125 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) 126 | { 127 | 128 | } 129 | } 130 | 131 | /** 132 | * 设置SwipeRefreshLayout下拉刷新时结束的位置 133 | */ 134 | protected void setSwipeRefreshEnd(int end){ 135 | setSwipeRefreshStartAndEnd(0,end); 136 | } 137 | 138 | /** 139 | * 设置SwipeRefreshLayout下拉刷新时开始的位置和结束的位置 140 | */ 141 | protected void setSwipeRefreshStartAndEnd(int start,int end){ 142 | mRefreshLayout.setProgressViewOffset(false,start,end); 143 | } 144 | 145 | //每次都进行加载的AsyncTask 146 | protected class LoadAsyncTask 147 | extends AsyncTask 148 | { 149 | 150 | private boolean mIsRefresh; 151 | 152 | public LoadAsyncTask(boolean isRefresh) 153 | { 154 | this.mIsRefresh = isRefresh; 155 | } 156 | 157 | 158 | @Override 159 | protected RequestResult doInBackground(Void... params) 160 | { 161 | mIsLoad = true; 162 | return requestDataInBackground(mIsRefresh); 163 | } 164 | 165 | @Override 166 | protected void onPostExecute(RequestResult requestResult) 167 | { 168 | 169 | mIsLoad = false; 170 | 171 | //将mRefreshLayout消失  172 | mRefreshLayout.setRefreshing(false); 173 | 174 | if (requestResult != null && requestResult.ret == RequestResult.RET_SUCCESS && requestResult.addCount != 0) 175 | { 176 | mShouldLoad = true; 177 | } 178 | else 179 | { 180 | mShouldLoad = false; 181 | } 182 | 183 | //这个应该子类去实现 184 | onPostRequest(requestResult, mIsRefresh); 185 | } 186 | } 187 | 188 | public class RequestResult 189 | { 190 | public static final int RET_SUCCESS = 0; 191 | public static final int RET_FAILED = -1; 192 | public static final int ADD_COUNT_EMPTY = 0; 193 | 194 | public int ret = RET_FAILED; 195 | public int addCount = ADD_COUNT_EMPTY; 196 | } 197 | 198 | 199 | //子类需要实现的方法 200 | protected abstract RequestResult requestDataInBackground(boolean isRefresh); 201 | 202 | protected abstract void onPostRequest(RequestResult data, boolean refresh); 203 | 204 | protected abstract int findLastVisibleItemPosition(); 205 | 206 | 207 | //子类来控制父类行为的方法 208 | // 是否可以下拉刷新 209 | protected boolean isRefreshEnable() 210 | { 211 | return true; 212 | } 213 | 214 | } 215 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/fragment/recycler/FragmentLoadRecycler.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.fragment.recycler; 2 | 3 | import android.graphics.Canvas; 4 | import android.graphics.Rect; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import com.happyheng.sport_android.R; 14 | 15 | 16 | /** 17 | * 继承自FragmentBaseRecycler,此类负责显示Load的判断以及LoadView的显示 18 | * 也对Adapter和ItemDecoration做出了简化,子类不在需要自定义Adapter,而是实现此类定义好的方法即可 19 | */ 20 | public abstract class FragmentLoadRecycler 21 | extends FragmentBaseRecycler { 22 | 23 | //默认请求的数量 24 | protected static final int DEFAULT_REQUEST_COUNT = 10; 25 | 26 | protected LinearLayoutManager mLayoutManager; 27 | private RecyclerItemDecoration mDecoration; 28 | protected RecyclerView.Adapter mAdapter; 29 | //第一种为空View的类型,第二种为item的类型,第三种为footer的类型 30 | protected static final int TYPE_EMPTY = 0, TYPE_ITEM = 1, TYPE_FOOTER = 2; 31 | //默认的距离顶部的间距 32 | protected int mDefaultTopDecoration; 33 | 34 | //是否显示空View,使用此标志位的原因是使其刚开始加载的时候不显示空View,当首次加载成功后,以后才会显示 35 | protected boolean mIsShowEmptyView = false; 36 | //是否有默认的背景颜色,使用标志位的原因是子类可以选择不设置默认背景颜色来方式出现的过度绘制的问题 37 | private boolean mIsHadDefaultBack = true; 38 | 39 | @Override 40 | public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 41 | super.onViewCreated(view, savedInstanceState); 42 | 43 | if (mIsInit) { 44 | //1、设置分割线 45 | mDecoration = new RecyclerItemDecoration(); 46 | mRecyclerView.addItemDecoration(mDecoration); 47 | 48 | //2、设置LayoutManager 49 | mLayoutManager = new LinearLayoutManager(getActivity()); 50 | mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); 51 | mRecyclerView.setLayoutManager(mLayoutManager); 52 | 53 | //3、设置Adapter(子类可以复写这个Adapter) 54 | mAdapter = new RecyclerAdapter(); 55 | mRecyclerView.setAdapter(mAdapter); 56 | 57 | //得到默认距离顶部的间距 58 | mDefaultTopDecoration = getResources().getDimensionPixelSize(R.dimen.recycler_default_decoration_height); 59 | //设置背景颜色 60 | if (mIsHadDefaultBack) { 61 | mRecyclerView.setBackgroundColor(getResources().getColor(R.color.recycler_default_bg)); 62 | } 63 | } 64 | 65 | } 66 | 67 | protected class RecyclerItemDecoration 68 | extends RecyclerView.ItemDecoration { 69 | @Override 70 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { 71 | super.getItemOffsets(outRect, view, parent, state); 72 | 73 | int position = parent.getChildAdapterPosition(view); 74 | setItemOffset(outRect, position); 75 | } 76 | 77 | 78 | @Override 79 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { 80 | super.onDraw(c, parent, state); 81 | } 82 | } 83 | 84 | @Override 85 | protected void onPostRequest(RequestResult data, boolean refresh) { 86 | mIsShowEmptyView = true; 87 | 88 | notifyDataSetChanged(); 89 | } 90 | 91 | /** 92 | * 更新RecyclerView的方法 93 | */ 94 | protected void notifyDataSetChanged() { 95 | if (mAdapter != null) { 96 | mAdapter.notifyDataSetChanged(); 97 | } 98 | } 99 | 100 | protected RecyclerView.ViewHolder getBaseViewHolder(View itemView) { 101 | return new RecyclerView.ViewHolder(itemView) { 102 | }; 103 | } 104 | 105 | public class RecyclerAdapter 106 | extends RecyclerView.Adapter { 107 | 108 | @Override 109 | public int getItemCount() { 110 | int num = getItemSize(); 111 | 112 | //如果没有数据,那么应该显示EmptyView 113 | if (num == 0 && mIsShowEmptyView) { 114 | return 1; 115 | } 116 | 117 | if (mShouldLoad) { 118 | return num + 1; 119 | } else { 120 | return num; 121 | } 122 | } 123 | 124 | @Override 125 | public int getItemViewType(int position) { 126 | 127 | int num = getItemSize(); 128 | if (num == 0) { 129 | return TYPE_EMPTY; 130 | } 131 | 132 | if (position == num) { 133 | return TYPE_FOOTER; 134 | } else { 135 | return TYPE_ITEM; 136 | } 137 | } 138 | 139 | @Override 140 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 141 | 142 | RecyclerView.ViewHolder holder; 143 | 144 | if (viewType == TYPE_EMPTY) { 145 | 146 | View mEmptyView = getEmptyView(parent); 147 | if (mEmptyView == null) { 148 | mEmptyView = getDefaultEmptyView(parent); 149 | } 150 | 151 | holder = getBaseViewHolder(mEmptyView); 152 | holder.itemView.setTag(TYPE_EMPTY); 153 | } else if (viewType == TYPE_ITEM) { 154 | //从子类中获取对应的Holder 155 | holder = getViewHolder(parent); 156 | RecyclerView.LayoutParams params = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 157 | ViewGroup.LayoutParams.WRAP_CONTENT); 158 | holder.itemView.setLayoutParams(params); 159 | holder.itemView.setTag(TYPE_ITEM); 160 | } else { 161 | View footerView = LayoutInflater.from(getActivity()).inflate(R.layout.item_load_more, parent, 162 | false); 163 | footerView.setTag(TYPE_FOOTER); 164 | holder = getBaseViewHolder(footerView); 165 | } 166 | return holder; 167 | } 168 | 169 | @Override 170 | public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { 171 | if (holder.itemView.getTag() != null && (int) holder.itemView.getTag() == TYPE_ITEM) { 172 | //让子类去绑定数据源 173 | bindingViewHolder(holder, position); 174 | } 175 | } 176 | 177 | } 178 | 179 | /** 180 | * 得到默认的EmptyView的方法 181 | * 182 | * @param parent 183 | * @return 184 | */ 185 | protected View getDefaultEmptyView(ViewGroup parent) { 186 | return new View(getActivity()); 187 | } 188 | 189 | @Override 190 | protected int findLastVisibleItemPosition() { 191 | return mLayoutManager.findLastVisibleItemPosition(); 192 | } 193 | 194 | protected RecyclerView.LayoutManager getLayoutManager() { 195 | return mLayoutManager; 196 | } 197 | 198 | 199 | //子类进行配置的方法 200 | //1、是否画默认的背景 201 | protected void hadDefaultBackColor(boolean hadDefaultBack) { 202 | this.mIsHadDefaultBack = hadDefaultBack; 203 | } 204 | 205 | 206 | // 子类必须要实现的方法 207 | // 1、得到要显示的item的大小(而不是得到数据源的大小,因为有的界面一个item会对应好几个数据源) 208 | protected abstract int getItemSize(); 209 | 210 | // 2、得到item之间的间距 211 | protected abstract void setItemOffset(Rect outRect, int position); 212 | 213 | // 3、得到子类所对应的Item的ViewHolder 214 | protected abstract RecyclerView.ViewHolder getViewHolder(ViewGroup parent); 215 | 216 | // 4、设置子类所对应的Item的ViewHolder 217 | protected abstract void bindingViewHolder(RecyclerView.ViewHolder holder, int position); 218 | 219 | //得到空View,如果想换成其他的空View,子类可以复写这个方法 220 | public View getEmptyView(ViewGroup parent) { 221 | return null; 222 | } 223 | 224 | } 225 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/IdEntity.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model; 2 | 3 | public abstract class IdEntity { 4 | protected Long id; 5 | 6 | public Long getId() { 7 | return id; 8 | } 9 | 10 | public void setId(Long id) { 11 | this.id = id; 12 | } 13 | 14 | } -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/News.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model; 2 | 3 | public class News extends IdEntity { 4 | private String name; 5 | private String simplecontent; 6 | private String thumbnail; 7 | private String url; 8 | public String getName() { 9 | return name; 10 | } 11 | public void setName(String name) { 12 | this.name = name; 13 | } 14 | public String getSimplecontent() { 15 | return simplecontent; 16 | } 17 | public void setSimplecontent(String simplecontent) { 18 | this.simplecontent = simplecontent; 19 | } 20 | public String getThumbnail() { 21 | return thumbnail; 22 | } 23 | public void setThumbnail(String thumbnail) { 24 | this.thumbnail = thumbnail; 25 | } 26 | public String getUrl() { 27 | return url; 28 | } 29 | public void setUrl(String url) { 30 | this.url = url; 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "News{" + 36 | "name='" + name + '\'' + 37 | ", simplecontent='" + simplecontent + '\'' + 38 | ", thumbnail='" + thumbnail + '\'' + 39 | ", url='" + url + '\'' + 40 | '}'; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/User.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model; 2 | 3 | import android.content.Context; 4 | import android.text.TextUtils; 5 | 6 | import com.happyheng.sport_android.utils.SPUtils; 7 | 8 | /** 9 | * User类封装了用户操作的一系列信息 10 | * Created by liuheng on 16/6/13. 11 | */ 12 | public class User { 13 | 14 | //储存用户token的key 15 | private static final String TOKEN_KEY = "token"; 16 | private static User defaultUser; 17 | 18 | private Context mContext; 19 | 20 | /** 21 | * 初始化单例User对象 22 | * @param context 23 | */ 24 | public static void init(Context context){ 25 | if (defaultUser == null){ 26 | defaultUser = new User(context); 27 | } 28 | } 29 | 30 | /** 31 | * 得到单例对象 32 | * @return 33 | */ 34 | public static User getUser(){ 35 | return defaultUser; 36 | } 37 | 38 | 39 | private User(Context context){ 40 | this.mContext = context; 41 | } 42 | 43 | /** 44 | * 得到用户是否登录的方法 45 | * @return 46 | */ 47 | public boolean isUserLogin(){ 48 | String token = getUserToken(); 49 | return !TextUtils.isEmpty(token); 50 | } 51 | 52 | 53 | /** 54 | * 设置User的Token 55 | * 56 | * @param token 57 | */ 58 | public void setUserToken(String token) { 59 | SPUtils.put(mContext, TOKEN_KEY, token); 60 | } 61 | 62 | 63 | /** 64 | * 得到User的Token 65 | * @return 66 | */ 67 | public String getUserToken(){ 68 | return (String) SPUtils.get(mContext,TOKEN_KEY,""); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/entity/BaseResult.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.entity; 2 | 3 | /** 4 | * 所有返回的数据的基类 5 | * Created by liuheng on 16/7/7. 6 | */ 7 | public class BaseResult { 8 | private int result; 9 | 10 | public int getResult() { 11 | return result; 12 | } 13 | 14 | public void setResult(int result) { 15 | this.result = result; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/entity/Location.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.entity; 2 | 3 | public class Location { 4 | 5 | private double posx; 6 | private double posy; 7 | 8 | public double getPosx() { 9 | return posx; 10 | } 11 | 12 | public void setPosx(double posx) { 13 | this.posx = posx; 14 | } 15 | 16 | public double getPosy() { 17 | return posy; 18 | } 19 | 20 | public void setPosy(double posy) { 21 | this.posy = posy; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/entity/NewsResult.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.entity; 2 | 3 | 4 | import com.happyheng.sport_android.model.News; 5 | 6 | import java.util.List; 7 | 8 | public class NewsResult { 9 | private int code; 10 | private List data; 11 | 12 | 13 | public int getCode() { 14 | return code; 15 | } 16 | public void setCode(int code) { 17 | this.code = code; 18 | } 19 | public List getData() { 20 | return data; 21 | } 22 | public void setData(List data) { 23 | this.data = data; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/entity/PostRequestBody.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.entity; 2 | 3 | /** 4 | * 在Post请求中的将key-value封装的类 5 | * Created by liuheng on 16/6/11. 6 | */ 7 | public class PostRequestBody { 8 | public String name; 9 | public String value; 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/entity/SportListResult.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.entity; 2 | 3 | import java.util.List; 4 | 5 | 6 | public class SportListResult { 7 | private int result; 8 | private List data; 9 | 10 | 11 | public int getResult() { 12 | return result; 13 | } 14 | public void setResult(int result) { 15 | this.result = result; 16 | } 17 | public List getData() { 18 | return data; 19 | } 20 | public void setData(List data) { 21 | this.data = data; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/entity/SportMessageResult.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.entity; 2 | 3 | import java.util.List; 4 | 5 | 6 | public class SportMessageResult { 7 | 8 | private int result; 9 | private List data; 10 | 11 | public int getResult() { 12 | return result; 13 | } 14 | public void setResult(int result) { 15 | this.result = result; 16 | } 17 | public List getData() { 18 | return data; 19 | } 20 | public void setData(List data) { 21 | this.data = data; 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/event/LocationEvent.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.event; 2 | 3 | import com.baidu.mapapi.model.LatLng; 4 | 5 | /** 6 | * 定位的Event 7 | * Created by liuheng on 16/7/24. 8 | */ 9 | public class LocationEvent { 10 | 11 | private LatLng location; 12 | 13 | public LocationEvent(LatLng location) { 14 | this.location = location; 15 | } 16 | 17 | public LatLng getLocation() { 18 | return location; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/network/HttpClient.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.network; 2 | 3 | import android.content.Context; 4 | 5 | import com.happyheng.sport_android.model.entity.PostRequestBody; 6 | import com.happyheng.sport_android.model.network.listener.OnRequestListener; 7 | import com.happyheng.sport_android.utils.ThreadUtils; 8 | import com.orhanobut.logger.Logger; 9 | 10 | import java.io.IOException; 11 | import java.io.UnsupportedEncodingException; 12 | 13 | import okhttp3.Cache; 14 | import okhttp3.Call; 15 | import okhttp3.Callback; 16 | import okhttp3.OkHttpClient; 17 | import okhttp3.Request; 18 | import okhttp3.Response; 19 | 20 | /** 21 | * 基于"Okhttp"的网络访问工具类 22 | * 注意在所有的请求中,都会有请求对应的路径名,和对应的键值对,需要把键值对序列化成json,然后请求时让s对应此json。这样是为了 23 | * 将数据加密 24 | * Created by liuheng on 2016/6/7. 25 | */ 26 | public class HttpClient { 27 | 28 | private static final int CacheSize = 50 * 1024 * 1024; // 缓存的大小,默认为50 MiB 29 | private static final String DEFAULT_NULL_RESULT = ""; //默认的空返回值 30 | 31 | 32 | private static OkHttpClient mOkHttpClient = null; 33 | 34 | 35 | public enum CacheControl { 36 | //先从缓存中取,如果没有,在从网络上去取 37 | CacheElseNetwork, 38 | //只从网络中去取 39 | Network 40 | } 41 | 42 | /** 43 | * 初始化请求工具类的方法 44 | */ 45 | public static void init(Context context) { 46 | //写到缓存下的子目录下,方便统一管理 47 | Cache cache = new Cache(context.getExternalCacheDir(), CacheSize); 48 | if (mOkHttpClient == null) { 49 | mOkHttpClient = new OkHttpClient.Builder() 50 | .cache(cache) 51 | .build(); 52 | } 53 | 54 | } 55 | 56 | 57 | /** 58 | * 同步从网络上获取数据 59 | * 60 | * @param url 请求的url 61 | * @param bodys 此为请求的键值对数组 62 | * @return 返回请求的json字符串,如果失败,返回"" 63 | */ 64 | public static String doSyncPost(String url, PostRequestBody[] bodys) { 65 | 66 | Request request; 67 | try { 68 | request = HttpClientRequestHelper.getRequest(url, bodys, okhttp3.CacheControl.FORCE_NETWORK); 69 | Response response = mOkHttpClient.newCall(request).execute(); 70 | 71 | if (response.isSuccessful()) { 72 | 73 | return response.body().string(); 74 | } else { 75 | Logger.d("请求失败"); 76 | } 77 | } catch (Exception e) { 78 | e.printStackTrace(); 79 | } 80 | 81 | return DEFAULT_NULL_RESULT; 82 | } 83 | 84 | 85 | /** 86 | * 异步去网络上请求数据的方法 87 | * 88 | * @param url 请求的url 89 | * @param bodys 此为请求的键值对数组 90 | * @param requestListener 请求回调的接口 两种情况: 91 | * 请求完全成功后,才会调用onSuccess()方法,其它调用onFail()方法 92 | */ 93 | public static void doAsyncPost(String url, PostRequestBody[] bodys, final OnRequestListener requestListener) { 94 | final Request request; 95 | try { 96 | request = HttpClientRequestHelper.getRequest(url, bodys, okhttp3.CacheControl.FORCE_NETWORK); 97 | 98 | mOkHttpClient.newCall(request).enqueue(new Callback() { 99 | 100 | @Override 101 | public void onResponse(Call call, final Response response) throws IOException { 102 | 103 | 104 | try { 105 | if (response.isSuccessful()) { 106 | 107 | final String result = response.body().string(); 108 | ThreadUtils.runOnMainThread(new Runnable() { 109 | @Override 110 | public void run() { 111 | requestListener.onSuccess(result); 112 | } 113 | }); 114 | 115 | } 116 | //在这里失败,即为返回的code不在200-300之间,意思即为服务器出现的错误,这种情况很少出现,但视为网络错误 117 | else { 118 | ThreadUtils.runOnMainThread(new Runnable() { 119 | @Override 120 | public void run() { 121 | requestListener.onFail(); 122 | } 123 | }); 124 | } 125 | 126 | } catch (IOException e) { 127 | e.printStackTrace(); 128 | ThreadUtils.runOnMainThread(new Runnable() { 129 | @Override 130 | public void run() { 131 | requestListener.onFail(); 132 | } 133 | }); 134 | } 135 | } 136 | 137 | //一般来说,如果是失败的话,一般都为网络异常,比如手机未联网等 138 | @Override 139 | public void onFailure(Call call, IOException e) { 140 | ThreadUtils.runOnMainThread(new Runnable() { 141 | @Override 142 | public void run() { 143 | requestListener.onFail(); 144 | } 145 | }); 146 | } 147 | }); 148 | } catch (UnsupportedEncodingException e) { 149 | e.printStackTrace(); 150 | requestListener.onFail(); 151 | } 152 | 153 | } 154 | 155 | 156 | /** 157 | * 提供"缓存"的异步方法,具体的缓存方法为: 158 | * 159 | * 1、先从本地去取缓存,取到缓存后,先回调成功接口,然后走下一步,如果没有取到缓存,直接走下一步 160 | * 2、不管取没取到,都会从网络取新的数据,如果失败,回调失败接口。如果成功,回调成功接口。 161 | */ 162 | 163 | 164 | /** 165 | * 根据请求的数据等来获取Okhttp中的Request请求对象 166 | */ 167 | // private static Request getRequest(String path, String requestString, okhttp3.CacheControl cacheControl) throws UnsupportedEncodingException { 168 | // 169 | // String encoderRequestString = URLEncoder.encode(requestString, "UTF8"); 170 | // 171 | // RequestBody requestBody = new FormBody.Builder() 172 | // .add("s", encoderRequestString) 173 | // .build(); 174 | // 175 | // return new Request.Builder() 176 | // .url(BASE_URL + path) 177 | // .post(requestBody) 178 | // .cacheControl(cacheControl) 179 | // .build(); 180 | // } 181 | 182 | 183 | } 184 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/network/HttpClientRequestHelper.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.network; 2 | 3 | import com.happyheng.sport_android.model.entity.PostRequestBody; 4 | 5 | import java.io.UnsupportedEncodingException; 6 | import java.net.URLEncoder; 7 | 8 | import okhttp3.FormBody; 9 | import okhttp3.Request; 10 | import okhttp3.RequestBody; 11 | 12 | /** 13 | * 获取HttpClient中Request请求对象的帮助类 14 | * Created by liuheng on 16/6/11. 15 | */ 16 | public class HttpClientRequestHelper { 17 | 18 | public static Request getRequest(String url, PostRequestBody[] bodys, okhttp3.CacheControl cacheControl) throws UnsupportedEncodingException { 19 | 20 | FormBody.Builder builder = new FormBody.Builder(); 21 | for (PostRequestBody body : bodys) { 22 | //请求的value要经过编码 23 | //String encoderRequestString = URLEncoder.encode(body.value, "UTF8"); 24 | builder.add(body.name, body.value); 25 | } 26 | 27 | RequestBody requestBody = builder.build(); 28 | 29 | return new Request.Builder() 30 | .url(url) 31 | .post(requestBody) 32 | .cacheControl(cacheControl) 33 | .build(); 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/network/listener/OnRequestListener.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.network.listener; 2 | 3 | /** 4 | * 异步请求的接口 5 | * Created by liuheng on 2016/6/7. 6 | */ 7 | public interface OnRequestListener{ 8 | void onSuccess(T t); 9 | void onFail(); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/request/BaseRequest.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.request; 2 | 3 | import com.happyheng.sport_android.model.entity.PostRequestBody; 4 | import com.happyheng.sport_android.model.network.HttpClient; 5 | import com.happyheng.sport_android.model.network.listener.OnRequestListener; 6 | import com.happyheng.sport_android.utils.AESUtils; 7 | import com.happyheng.sport_android.utils.HexUtils; 8 | 9 | 10 | /** 11 | * Request请求的基类,封装了错误码,网络访问的方法 12 | * 子类需要实现HttpClient请求的回调,即获取到返回值,并根据不同的请求作出处理,在写出相应请求的回调。 13 | * Created by liuheng on 16/6/11. 14 | */ 15 | public abstract class BaseRequest { 16 | 17 | private static final String HEX_KEY = "5de7e29919fad4d5a17f97a3b6215a68"; 18 | private static final byte[] key = HexUtils.hexStringToBytes(HEX_KEY); 19 | 20 | //private static final String DOMAIN_NAME = "www.happyheng.top"; 21 | private static final String DOMAIN_NAME = "192.168.1.4"; 22 | private static final String BASE_URL = "http://"+ DOMAIN_NAME +":8080/Sport/"; 23 | private static final String REQUEST_BASE_KEY = "s"; 24 | protected static final String RESULT_KEY = "result"; 25 | 26 | public static final int REQUEST_SUCCESS = 0; //成功 27 | public static final int REQUEST_OTHER_EXCEPTION = 100; //服务器错误,请求错误等等非逻辑错误,都是这个 28 | 29 | public void doRequest(){ 30 | String path = BASE_URL+getRequestPath(); 31 | 32 | PostRequestBody body = new PostRequestBody(); 33 | body.name = REQUEST_BASE_KEY; 34 | body.value = AESUtils.encrypt(key,getRequestJsonString()); 35 | 36 | HttpClient.doAsyncPost(path,new PostRequestBody[]{body}, getRequestListener()); 37 | } 38 | 39 | public String doSyncPost(){ 40 | String path = BASE_URL+getRequestPath(); 41 | 42 | PostRequestBody body = new PostRequestBody(); 43 | body.name = REQUEST_BASE_KEY; 44 | body.value = AESUtils.encrypt(key,getRequestJsonString()); 45 | 46 | return HttpClient.doSyncPost(path,new PostRequestBody[]{body}); 47 | } 48 | 49 | 50 | /** 51 | * 得到HttpClient请求的回调接口 52 | * @return 请求回调 53 | */ 54 | protected abstract OnRequestListener getRequestListener(); 55 | 56 | /** 57 | * 得到请求的path 58 | * @return 59 | */ 60 | protected abstract String getRequestPath(); 61 | 62 | /** 63 | * 得到封装的请求json数据 64 | * @return 65 | */ 66 | protected abstract String getRequestJsonString(); 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/request/LoginRequest.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.request; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.happyheng.sport_android.model.network.listener.OnRequestListener; 6 | 7 | /** 8 | * 登陆请求的类 9 | * Created by liuheng on 16/6/8. 10 | */ 11 | public class LoginRequest extends BaseRequest{ 12 | 13 | public static final int REQUEST_WRONG_USERNAME = 1; //没有相应用户名 14 | public static final int REQUEST_WRONG_PASSWORD = 2; //密码错误 15 | 16 | public static final String REQUEST_PATH = "Login"; 17 | 18 | //登陆的用户名和密码 19 | private String userName,password; 20 | private OnLoginListener listener; 21 | 22 | public LoginRequest(String userName, String password, OnLoginListener listener) { 23 | this.userName = userName; 24 | this.password = password; 25 | this.listener = listener; 26 | } 27 | 28 | @Override 29 | protected String getRequestPath() { 30 | return REQUEST_PATH; 31 | } 32 | 33 | @Override 34 | protected String getRequestJsonString() { 35 | JSONObject jsonObject = new JSONObject(); 36 | jsonObject.put("uname", userName); 37 | jsonObject.put("upwd", password); 38 | return jsonObject.toString(); 39 | } 40 | 41 | @Override 42 | protected OnRequestListener getRequestListener() { 43 | return new OnRequestListener() { 44 | @Override 45 | public void onSuccess(String s) { 46 | 47 | if (listener != null){ 48 | JSONObject resultJson = JSON.parseObject(s); 49 | int code = resultJson.getInteger(RESULT_KEY); 50 | if (code == REQUEST_SUCCESS) { 51 | String token = resultJson.getJSONObject("data").getString("token"); 52 | listener.onSuccess(token); 53 | } else { 54 | listener.onFail(code); 55 | } 56 | } 57 | 58 | } 59 | 60 | @Override 61 | public void onFail() { 62 | if (listener!=null){ 63 | listener.onFail(REQUEST_OTHER_EXCEPTION); 64 | } 65 | } 66 | }; 67 | } 68 | 69 | public interface OnLoginListener { 70 | void onSuccess(String token); 71 | 72 | void onFail(int code); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/request/NewsRequest.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.request; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.alibaba.fastjson.JSON; 6 | import com.alibaba.fastjson.JSONObject; 7 | import com.happyheng.sport_android.model.News; 8 | import com.happyheng.sport_android.model.entity.NewsResult; 9 | import com.happyheng.sport_android.model.network.listener.OnRequestListener; 10 | import com.orhanobut.logger.Logger; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * '发现频道'的请求类 16 | * Created by liuheng on 16/7/20. 17 | */ 18 | public class NewsRequest extends BaseRequest { 19 | 20 | public static final String REQUEST_PATH = "News"; 21 | public static final int DEFAULT_VALUE = -1; 22 | 23 | private int mBeginPosition = DEFAULT_VALUE, mId = DEFAULT_VALUE, mCount; 24 | 25 | public void setBeginCount(int beginPosition, int count) { 26 | this.mBeginPosition = beginPosition; 27 | this.mCount = count; 28 | } 29 | 30 | public void setIdCount(int id, int count) { 31 | this.mId = id; 32 | this.mCount = count; 33 | } 34 | 35 | 36 | /** 37 | * 通过获取新闻数据源的方法 38 | * @return 39 | */ 40 | public List getNewsItem() { 41 | 42 | //进行同步请求 43 | String resultJson = doSyncPost(); 44 | 45 | if (!TextUtils.isEmpty(resultJson)){ 46 | NewsResult result = JSON.parseObject(resultJson, NewsResult.class); 47 | if (result != null && result.getCode() == REQUEST_SUCCESS) { 48 | return result.getData(); 49 | } else { 50 | return null; 51 | } 52 | } else { 53 | return null; 54 | } 55 | 56 | } 57 | 58 | @Override 59 | protected OnRequestListener getRequestListener() { 60 | return new OnRequestListener() { 61 | @Override 62 | public void onSuccess(String s) { 63 | 64 | if (mNewsListener != null) { 65 | NewsResult result = JSON.parseObject(s, NewsResult.class); 66 | 67 | if (result != null && result.getCode() == REQUEST_SUCCESS) { 68 | mNewsListener.onSuccess(result.getData()); 69 | } else { 70 | mNewsListener.onFail(); 71 | } 72 | } 73 | 74 | } 75 | 76 | @Override 77 | public void onFail() { 78 | if (mNewsListener != null) { 79 | mNewsListener.onFail(); 80 | } 81 | } 82 | }; 83 | } 84 | 85 | 86 | @Override 87 | protected String getRequestPath() { 88 | return REQUEST_PATH; 89 | } 90 | 91 | @Override 92 | protected String getRequestJsonString() { 93 | 94 | JSONObject jsonObject = new JSONObject(); 95 | if (mId == DEFAULT_VALUE) { 96 | jsonObject.put("begin", mBeginPosition); 97 | } else { 98 | jsonObject.put("id", mId); 99 | } 100 | jsonObject.put("count", mCount); 101 | 102 | return jsonObject.toString(); 103 | } 104 | 105 | public interface OnNewsListener { 106 | void onSuccess(List list); 107 | 108 | void onFail(); 109 | } 110 | 111 | private OnNewsListener mNewsListener; 112 | 113 | public void setNewsListener(OnNewsListener newsListener) { 114 | this.mNewsListener = newsListener; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/request/RecordSportMessageRequest.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.request; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.happyheng.sport_android.model.entity.BaseResult; 6 | import com.happyheng.sport_android.model.network.listener.OnRequestListener; 7 | 8 | /** 9 | * 上传用户运动信息的Request 10 | * Created by liuheng on 16/7/7. 11 | */ 12 | public class RecordSportMessageRequest extends BaseRequest{ 13 | 14 | public static final String REQUEST_PATH = "Record"; 15 | //需要上传的运动信息 16 | public SportMessage mMessage; 17 | 18 | public void setMessage(SportMessage message){ 19 | this.mMessage = message; 20 | } 21 | 22 | @Override 23 | protected OnRequestListener getRequestListener() { 24 | return new OnRequestListener() { 25 | @Override 26 | public void onSuccess(String s) { 27 | if (mRecordListener != null){ 28 | BaseResult result = JSONObject.parseObject(s,BaseResult.class); 29 | if (result.getResult() == REQUEST_SUCCESS){ 30 | mRecordListener.onSuccess(); 31 | } else { 32 | mRecordListener.onFail(); 33 | } 34 | } 35 | } 36 | 37 | @Override 38 | public void onFail() { 39 | if (mRecordListener != null){ 40 | mRecordListener.onFail(); 41 | } 42 | } 43 | }; 44 | } 45 | 46 | @Override 47 | protected String getRequestPath() { 48 | return REQUEST_PATH; 49 | } 50 | 51 | @Override 52 | protected String getRequestJsonString() { 53 | if (mMessage!=null){ 54 | return JSON.toJSONString(mMessage); 55 | } else { 56 | return null; 57 | } 58 | } 59 | 60 | /** 61 | * 封装了上传至服务器运动信息的类 62 | */ 63 | public static class SportMessage{ 64 | public int id; 65 | public double posx; 66 | public double posy; 67 | public String location; 68 | 69 | public SportMessage(){} 70 | 71 | public SportMessage(int id, double posx, double posy, String location) { 72 | this.id = id; 73 | this.posx = posx; 74 | this.posy = posy; 75 | this.location = location; 76 | } 77 | 78 | public int getId() { 79 | return id; 80 | } 81 | 82 | public void setId(int id) { 83 | this.id = id; 84 | } 85 | 86 | public double getPosx() { 87 | return posx; 88 | } 89 | 90 | public void setPosx(double posx) { 91 | this.posx = posx; 92 | } 93 | 94 | public double getPosy() { 95 | return posy; 96 | } 97 | 98 | public void setPosy(double posy) { 99 | this.posy = posy; 100 | } 101 | 102 | public String getLocation() { 103 | return location; 104 | } 105 | 106 | public void setLocation(String location) { 107 | this.location = location; 108 | } 109 | } 110 | 111 | public interface OnRecordListener{ 112 | void onSuccess(); 113 | void onFail(); 114 | } 115 | 116 | private OnRecordListener mRecordListener; 117 | 118 | public void setRecordListener(OnRecordListener listener){ 119 | this.mRecordListener = listener; 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/request/RegisterRequest.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.request; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.happyheng.sport_android.model.network.listener.OnRequestListener; 6 | 7 | /** 8 | * 注册请求的类 9 | * Created by liuheng on 16/6/25. 10 | */ 11 | public class RegisterRequest extends BaseRequest { 12 | 13 | private String mUserName, mPassWord, mNickName; 14 | private onRegisterListener mListener; 15 | 16 | public static final String REQUEST_PATH = "Register"; 17 | 18 | //重复用户名 19 | public static final int REQUEST_REPEAT_USERNAME = 1; 20 | //重复昵称 21 | public static final int REQUEST_REPEAT_NICKNAME = 2; 22 | 23 | public RegisterRequest(String userName, String passWord, String nickName, onRegisterListener listener) { 24 | this.mUserName = userName; 25 | this.mPassWord = passWord; 26 | this.mNickName = nickName; 27 | this.mListener = listener; 28 | } 29 | 30 | @Override 31 | protected OnRequestListener getRequestListener() { 32 | return new OnRequestListener() { 33 | @Override 34 | public void onSuccess(String s) { 35 | JSONObject resultJson = JSON.parseObject(s); 36 | int code = resultJson.getInteger(RESULT_KEY); 37 | 38 | //根据不同的code,回调不同的接口的方法 39 | if (code == REQUEST_SUCCESS) { 40 | mListener.onSuccess(); 41 | } else if (code == REQUEST_REPEAT_USERNAME) { 42 | mListener.onRepeatUserName(); 43 | } else if (code == REQUEST_REPEAT_NICKNAME) { 44 | mListener.onRepeatNickName(); 45 | } else { 46 | mListener.onFail(); 47 | } 48 | } 49 | 50 | @Override 51 | public void onFail() { 52 | mListener.onFail(); 53 | } 54 | }; 55 | } 56 | 57 | @Override 58 | protected String getRequestPath() { 59 | return REQUEST_PATH; 60 | } 61 | 62 | @Override 63 | protected String getRequestJsonString() { 64 | JSONObject jsonObject = new JSONObject(); 65 | jsonObject.put("uname", mUserName); 66 | jsonObject.put("upwd", mPassWord); 67 | jsonObject.put("nkname", mNickName); 68 | return jsonObject.toJSONString(); 69 | } 70 | 71 | public interface onRegisterListener { 72 | void onSuccess(); 73 | 74 | void onRepeatUserName(); 75 | 76 | void onRepeatNickName(); 77 | 78 | void onFail(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/request/SportIdRequest.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.request; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.happyheng.sport_android.model.User; 6 | import com.happyheng.sport_android.model.network.listener.OnRequestListener; 7 | 8 | /** 9 | * 得到运动id的Request 10 | * Created by liuheng on 16/7/5. 11 | */ 12 | public class SportIdRequest extends BaseRequest{ 13 | 14 | 15 | private OnSportIdListener mSportIdListener; 16 | 17 | public SportIdRequest(OnSportIdListener sportIdListener){ 18 | this.mSportIdListener = sportIdListener; 19 | } 20 | 21 | 22 | @Override 23 | protected OnRequestListener getRequestListener() { 24 | return new OnRequestListener() { 25 | @Override 26 | public void onSuccess(String s) { 27 | if (mSportIdListener != null) { 28 | JSONObject resultJson = JSON.parseObject(s); 29 | int code = resultJson.getIntValue(RESULT_KEY); 30 | 31 | if (code == REQUEST_SUCCESS) { 32 | mSportIdListener.onSuccess(resultJson.getIntValue("id")); 33 | }else { 34 | mSportIdListener.onFail(); 35 | } 36 | } 37 | } 38 | 39 | @Override 40 | public void onFail() { 41 | if (mSportIdListener != null) { 42 | mSportIdListener.onFail(); 43 | } 44 | } 45 | }; 46 | } 47 | 48 | @Override 49 | protected String getRequestPath() { 50 | return "SportId"; 51 | } 52 | 53 | @Override 54 | protected String getRequestJsonString() { 55 | JSONObject jsonObject = new JSONObject(); 56 | jsonObject.put("ukey", User.getUser().getUserToken()); 57 | return jsonObject.toString(); 58 | } 59 | 60 | public interface OnSportIdListener { 61 | void onSuccess(int sportId); 62 | void onFail(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/request/SportListRequest.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.request; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.happyheng.sport_android.model.entity.SportListResult; 6 | import com.happyheng.sport_android.model.network.listener.OnRequestListener; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 请求Sport信息的Request 12 | * Created by liuheng on 16/8/15. 13 | */ 14 | public class SportListRequest extends BaseRequest { 15 | 16 | private String mUserKey; 17 | 18 | public SportListRequest(String userKey) { 19 | this.mUserKey = userKey; 20 | } 21 | 22 | @Override 23 | protected OnRequestListener getRequestListener() { 24 | return new OnRequestListener() { 25 | @Override 26 | public void onSuccess(String s) { 27 | if (listener!=null){ 28 | SportListResult result = JSON.parseObject(s,SportListResult.class); 29 | 30 | if (result != null && result.getResult() != REQUEST_OTHER_EXCEPTION){ 31 | listener.onSuccess(result.getData()); 32 | } else { 33 | listener.onFail(); 34 | } 35 | } 36 | } 37 | 38 | @Override 39 | public void onFail() { 40 | if (listener!=null){ 41 | listener.onFail(); 42 | } 43 | } 44 | }; 45 | } 46 | 47 | @Override 48 | protected String getRequestPath() { 49 | return "SportList"; 50 | } 51 | 52 | @Override 53 | protected String getRequestJsonString() { 54 | 55 | JSONObject jsonObject = new JSONObject(); 56 | jsonObject.put("userkey", mUserKey); 57 | return jsonObject.toString(); 58 | } 59 | 60 | public interface ListListener{ 61 | void onSuccess(List list); 62 | void onFail(); 63 | } 64 | 65 | private ListListener listener; 66 | 67 | public void setListListener(ListListener listener){ 68 | this.listener = listener; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/model/request/SportMessageRequest.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.model.request; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.happyheng.sport_android.model.entity.Location; 6 | import com.happyheng.sport_android.model.entity.SportMessageResult; 7 | import com.happyheng.sport_android.model.network.listener.OnRequestListener; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * 请求详细运动数据的Request 13 | * Created by liuheng on 16/8/16. 14 | */ 15 | public class SportMessageRequest extends BaseRequest { 16 | 17 | 18 | private String userKey, sportId; 19 | 20 | public SportMessageRequest(String userKey, String sportId) { 21 | this.userKey = userKey; 22 | this.sportId = sportId; 23 | } 24 | 25 | @Override 26 | protected OnRequestListener getRequestListener() { 27 | return new OnRequestListener() { 28 | @Override 29 | public void onSuccess(String s) { 30 | 31 | if (messageListener != null) { 32 | 33 | SportMessageResult result = JSON.parseObject(s, SportMessageResult.class); 34 | if (result != null && result.getResult() != REQUEST_OTHER_EXCEPTION) { 35 | messageListener.onSuccess(result.getData()); 36 | } else { 37 | messageListener.onFail(); 38 | } 39 | } 40 | 41 | } 42 | 43 | @Override 44 | public void onFail() { 45 | if (messageListener != null) { 46 | messageListener.onFail(); 47 | } 48 | } 49 | }; 50 | } 51 | 52 | public interface OnSportMessageListener { 53 | void onSuccess(List data); 54 | 55 | void onFail(); 56 | } 57 | 58 | private OnSportMessageListener messageListener; 59 | 60 | public void setMessageListener(OnSportMessageListener listener) { 61 | this.messageListener = listener; 62 | } 63 | 64 | @Override 65 | protected String getRequestPath() { 66 | return "SportMessage"; 67 | } 68 | 69 | @Override 70 | protected String getRequestJsonString() { 71 | JSONObject jsonObject = new JSONObject(); 72 | jsonObject.put("userkey", userKey); 73 | jsonObject.put("sportId", sportId); 74 | return jsonObject.toString(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/service/LocationService.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.service; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.os.IBinder; 6 | import android.support.annotation.Nullable; 7 | 8 | import com.baidu.location.BDLocation; 9 | import com.baidu.location.BDLocationListener; 10 | import com.baidu.location.LocationClient; 11 | import com.baidu.location.LocationClientOption; 12 | import com.baidu.mapapi.model.LatLng; 13 | import com.happyheng.sport_android.model.event.LocationEvent; 14 | import com.happyheng.sport_android.servicecode.RecordService; 15 | import com.happyheng.sport_android.servicecode.impl.RecordServiceImpl; 16 | import com.orhanobut.logger.Logger; 17 | 18 | import org.greenrobot.eventbus.EventBus; 19 | 20 | import java.util.LinkedList; 21 | import java.util.List; 22 | 23 | /** 24 | * 定位的Service类,用户在运动时此服务会在后台进行定位。 25 | * Created by liuheng on 16/7/24. 26 | */ 27 | public class LocationService extends Service implements BDLocationListener { 28 | 29 | //定位的时间间隔,单位是毫秒 30 | private static final int LOCATION_SPAN = 10 * 1000; 31 | 32 | //百度地图中定位的类 33 | public LocationClient mLocationClient = null; 34 | //记录着运动中移动的坐标位置 35 | private List mSportLatLngs = new LinkedList<>(); 36 | 37 | //记录运动信息的Service 38 | private RecordService mRecordService = null; 39 | 40 | @Override 41 | public void onCreate() { 42 | 43 | //声明LocationClient类 44 | mLocationClient = new LocationClient(getApplicationContext()); 45 | //给定位类加入自定义的配置 46 | initLocationOption(); 47 | //注册监听函数 48 | mLocationClient.registerLocationListener(this); 49 | 50 | //初始化信息记录类 51 | mRecordService = new RecordServiceImpl(this); 52 | 53 | //开始监听 54 | mLocationClient.start(); 55 | } 56 | 57 | //初始化定位的配置 58 | private void initLocationOption() { 59 | LocationClientOption option = new LocationClientOption(); 60 | option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy 61 | );//可选,默认高精度,设置定位模式,高精度,低功耗,仅设备 62 | option.setCoorType("bd09ll");//可选,默认gcj02,设置返回的定位结果坐标系 63 | option.setScanSpan(LOCATION_SPAN);//可选,默认0,即仅定位一次,设置发起定位请求的间隔需要大于等于1000ms才是有效的 64 | option.setIsNeedAddress(true);//可选,设置是否需要地址信息,默认不需要 65 | option.setOpenGps(true);//可选,默认false,设置是否使用gps 66 | option.setLocationNotify(false);//可选,默认false,设置是否当gps有效时按照1S1次频率输出GPS结果 67 | option.setIsNeedLocationDescribe(true);//可选,默认false,设置是否需要位置语义化结果,可以在BDLocation.getLocationDescribe里得到,结果类似于“在北京天安门附近” 68 | option.setIsNeedLocationPoiList(true);//可选,默认false,设置是否需要POI结果,可以在BDLocation.getPoiList里得到 69 | option.setIgnoreKillProcess(true);//可选,默认true,定位SDK内部是一个SERVICE,并放到了独立进程,设置是否在stop的时候杀死这个进程,默认不杀死 70 | option.SetIgnoreCacheException(false);//可选,默认false,设置是否收集CRASH信息,默认收集 71 | option.setEnableSimulateGps(false);//可选,默认false,设置是否需要过滤gps仿真结果,默认需要 72 | mLocationClient.setLocOption(option); 73 | } 74 | 75 | //获取经纬度后回调的方法 76 | @Override 77 | public void onReceiveLocation(BDLocation bdLocation) { 78 | //先暂时获得经纬度信息,并将其记录在List中 79 | Logger.d("纬度信息为" + bdLocation.getLatitude()+"\n经度信息为" + bdLocation.getLongitude()); 80 | LatLng locationValue = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude()); 81 | mSportLatLngs.add(locationValue); 82 | 83 | //将运动信息上传至服务器 84 | recordLocation(locationValue,bdLocation.getLocationDescribe()); 85 | 86 | //定位成功,发送定位Event通知 87 | EventBus.getDefault().post(new LocationEvent(locationValue)); 88 | } 89 | 90 | 91 | private void recordLocation(LatLng latLng, String location) { 92 | if (mRecordService != null) { 93 | mRecordService.recordSport(latLng, location); 94 | } 95 | } 96 | 97 | @Nullable 98 | @Override 99 | public IBinder onBind(Intent intent) { 100 | return null; 101 | } 102 | 103 | @Override 104 | public void onDestroy() { 105 | super.onDestroy(); 106 | mLocationClient.stop(); 107 | mLocationClient.unRegisterLocationListener(this); 108 | Logger.d("onDestroy"); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/servicecode/RecordService.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.servicecode; 2 | 3 | import com.baidu.mapapi.model.LatLng; 4 | 5 | /** 6 | * 上传跑步信息的Service接口 7 | * Created by liuheng on 16/7/3. 8 | */ 9 | public interface RecordService { 10 | 11 | //记录运动坐标和大概描述信息 12 | void recordSport(LatLng latLng,String location); 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/servicecode/impl/RecordServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.servicecode.impl; 2 | 3 | import android.content.Context; 4 | 5 | import com.baidu.mapapi.model.LatLng; 6 | import com.happyheng.sport_android.model.request.RecordSportMessageRequest; 7 | import com.happyheng.sport_android.model.request.SportIdRequest; 8 | import com.happyheng.sport_android.servicecode.RecordService; 9 | import com.orhanobut.logger.Logger; 10 | 11 | /** 12 | * 记录运动信息的实现类 13 | * Created by liuheng on 16/7/5. 14 | */ 15 | public class RecordServiceImpl implements RecordService { 16 | 17 | private static final int SPORT_DEFAULT_ID = -1; 18 | 19 | private Context mContext; 20 | private int mSportId = SPORT_DEFAULT_ID; 21 | //分别是记录SportId的Request,和记录Sport信息的Request 22 | private SportIdRequest mSportIdRequest; 23 | private RecordSportMessageRequest mSportMessageRecordRequest; 24 | 25 | //获取SportId的回调 26 | private SportIdRequest.OnSportIdListener mGetSportIdListener = new SportIdListener(); 27 | 28 | public RecordServiceImpl(Context context) { 29 | this.mContext = context; 30 | mSportIdRequest = new SportIdRequest(mGetSportIdListener); 31 | mSportMessageRecordRequest = new RecordSportMessageRequest(); 32 | } 33 | 34 | @Override 35 | public void recordSport(LatLng latLng, String location) { 36 | //如果sportId尚未获取的话,那么就继续获取 37 | if (mSportId == SPORT_DEFAULT_ID) { 38 | mSportIdRequest.doRequest(); 39 | } 40 | else { 41 | //如果获取成功,那么 42 | RecordSportMessageRequest.SportMessage message = new RecordSportMessageRequest.SportMessage(mSportId,latLng.longitude,latLng.latitude,location); 43 | mSportMessageRecordRequest.setMessage(message); 44 | mSportMessageRecordRequest.doRequest(); 45 | } 46 | } 47 | 48 | private class SportIdListener implements SportIdRequest.OnSportIdListener{ 49 | 50 | @Override 51 | public void onSuccess(int sportId) { 52 | Logger.d("获取的sportId为"+sportId); 53 | mSportId = sportId; 54 | } 55 | 56 | @Override 57 | public void onFail() { 58 | 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/utils/AESUtils.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.utils; 2 | 3 | import java.security.Key; 4 | 5 | import javax.crypto.Cipher; 6 | import javax.crypto.spec.SecretKeySpec; 7 | 8 | /** 9 | * AES进行加解密的工具类 10 | * @author liuheng 11 | * 12 | */ 13 | public class AESUtils { 14 | 15 | /** 16 | * AES加密的方法 17 | * @param byteskey AES的key 18 | * @param text 待加密的字符串 19 | * @return 返回转换成16进制的加密字符串,如果加密失败,返回null 20 | */ 21 | public static String encrypt(byte[] byteskey,String text) { 22 | try { 23 | //转换key 24 | Key convertSecretKey = new SecretKeySpec(byteskey, "AES"); 25 | //加密 26 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 27 | 28 | cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey); 29 | byte[] encryptResult = cipher.doFinal(text.getBytes()); 30 | String encryptString = HexUtils.bytesToHexString(encryptResult); 31 | 32 | System.out.println("jdk des encrypt:" + encryptString); 33 | return encryptString; 34 | 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | return null; 38 | } 39 | } 40 | 41 | /** 42 | * AES解密的方法 43 | * @param byteskey AES的key 44 | * @param encryptString 加密并转换成16进制的字符串 45 | * @return 返回解密的字符串,如果失败,返回null 46 | */ 47 | public static String decrypt(byte[] byteskey,String encryptString) { 48 | try { 49 | //转换key 50 | Key convertSecretKey = new SecretKeySpec(byteskey, "AES"); 51 | // 解密 52 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 53 | cipher.init(Cipher.DECRYPT_MODE, convertSecretKey); 54 | byte[] decryptResult = cipher.doFinal(HexUtils.hexStringToBytes(encryptString)); 55 | String decryptString = new String(decryptResult); 56 | System.out.println("jdk des decrypt:" + decryptString); 57 | return decryptString; 58 | 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | return null; 62 | } 63 | } 64 | 65 | 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/utils/DensityUtils.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.utils; 2 | 3 | import android.content.Context; 4 | import android.util.TypedValue; 5 | 6 | /** 7 | * 单位转换的工具类 8 | * Created by liuheng on 16/4/24. 9 | */ 10 | public class DensityUtils { 11 | private DensityUtils() 12 | { 13 | /** cannot be instantiated **/ 14 | throw new UnsupportedOperationException("cannot be instantiated"); 15 | } 16 | 17 | /** 18 | * dp转px 19 | * 20 | * @param context 21 | * @return 22 | */ 23 | public static int dp2px(Context context, float dpVal) 24 | { 25 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 26 | dpVal, context.getResources().getDisplayMetrics()); 27 | } 28 | 29 | /** 30 | * sp转px 31 | * 32 | * @param context 33 | * @return 34 | */ 35 | public static int sp2px(Context context, float spVal) 36 | { 37 | return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 38 | spVal, context.getResources().getDisplayMetrics()); 39 | } 40 | 41 | /** 42 | * px转dp 43 | * 44 | * @param context 45 | * @param pxVal 46 | * @return 47 | */ 48 | public static float px2dp(Context context, float pxVal) 49 | { 50 | final float scale = context.getResources().getDisplayMetrics().density; 51 | return (pxVal / scale); 52 | } 53 | /** 54 | * px转sp 55 | * 56 | * @param pxVal 57 | * @return 58 | */ 59 | public static float px2sp(Context context, float pxVal) 60 | { 61 | return (pxVal / context.getResources().getDisplayMetrics().scaledDensity); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/utils/HexUtils.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.utils; 2 | 3 | public class HexUtils { 4 | public static String bytesToHexString(byte[] src){ 5 | StringBuilder stringBuilder = new StringBuilder(""); 6 | if (src == null || src.length <= 0) { 7 | return null; 8 | } 9 | for (int i = 0; i < src.length; i++) { 10 | int v = src[i] & 0xFF; 11 | String hv = Integer.toHexString(v); 12 | if (hv.length() < 2) { 13 | stringBuilder.append(0); 14 | } 15 | stringBuilder.append(hv); 16 | } 17 | return stringBuilder.toString(); 18 | } 19 | /** 20 | * Convert hex string to byte[] 21 | * @param hexString the hex string 22 | * @return byte[] 23 | */ 24 | public static byte[] hexStringToBytes(String hexString) { 25 | if (hexString == null || hexString.equals("")) { 26 | return null; 27 | } 28 | hexString = hexString.toUpperCase(); 29 | int length = hexString.length() / 2; 30 | char[] hexChars = hexString.toCharArray(); 31 | byte[] d = new byte[length]; 32 | for (int i = 0; i < length; i++) { 33 | int pos = i * 2; 34 | d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); 35 | } 36 | return d; 37 | } 38 | /** 39 | * Convert char to byte 40 | * @param c char 41 | * @return byte 42 | */ 43 | private static byte charToByte(char c) { 44 | return (byte) "0123456789ABCDEF".indexOf(c); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/utils/NetUtils.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.ComponentName; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.net.ConnectivityManager; 8 | import android.net.NetworkInfo; 9 | 10 | /** 11 | * 网络判断方面的辅助类 12 | * Created by liuheng on 16/4/24. 13 | */ 14 | public class NetUtils { 15 | 16 | private NetUtils() 17 | { 18 | /** cannot be instantiated **/ 19 | throw new UnsupportedOperationException("cannot be instantiated"); 20 | } 21 | 22 | /** 23 | * 判断网络是否连接 24 | * 25 | * @param context 26 | * @return 27 | */ 28 | public static boolean isConnected(Context context) 29 | { 30 | 31 | ConnectivityManager connectivity = (ConnectivityManager) context 32 | .getSystemService(Context.CONNECTIVITY_SERVICE); 33 | 34 | if (null != connectivity) 35 | { 36 | 37 | NetworkInfo info = connectivity.getActiveNetworkInfo(); 38 | if (null != info && info.isConnected()) 39 | { 40 | if (info.getState() == NetworkInfo.State.CONNECTED) 41 | { 42 | return true; 43 | } 44 | } 45 | } 46 | return false; 47 | } 48 | 49 | /** 50 | * 判断是否是wifi连接 51 | */ 52 | public static boolean isWifi(Context context) 53 | { 54 | ConnectivityManager cm = (ConnectivityManager) context 55 | .getSystemService(Context.CONNECTIVITY_SERVICE); 56 | 57 | if (cm == null) 58 | return false; 59 | return cm.getActiveNetworkInfo().getType() == ConnectivityManager.TYPE_WIFI; 60 | 61 | } 62 | 63 | /** 64 | * 打开网络设置界面 65 | */ 66 | public static void openSetting(Activity activity) 67 | { 68 | Intent intent = new Intent("/"); 69 | ComponentName cm = new ComponentName("com.android.settings", 70 | "com.android.settings.WirelessSettings"); 71 | intent.setComponent(cm); 72 | intent.setAction("android.intent.action.VIEW"); 73 | activity.startActivityForResult(intent, 0); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/utils/SPUtils.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | import java.util.Map; 9 | 10 | /** 11 | * SharedPreferences工具类 12 | * Created by liuheng on 16/4/24. 13 | */ 14 | public class SPUtils { 15 | 16 | /** 17 | * 保存在手机里面的文件名 18 | */ 19 | public static final String FILE_NAME = "share_data"; 20 | 21 | /** 22 | * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法 23 | * 24 | * @param context 25 | * @param key 26 | * @param object 27 | */ 28 | public static void put(Context context, String key, Object object) 29 | { 30 | 31 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, 32 | Context.MODE_PRIVATE); 33 | SharedPreferences.Editor editor = sp.edit(); 34 | 35 | if (object instanceof String) 36 | { 37 | editor.putString(key, (String) object); 38 | } else if (object instanceof Integer) 39 | { 40 | editor.putInt(key, (Integer) object); 41 | } else if (object instanceof Boolean) 42 | { 43 | editor.putBoolean(key, (Boolean) object); 44 | } else if (object instanceof Float) 45 | { 46 | editor.putFloat(key, (Float) object); 47 | } else if (object instanceof Long) 48 | { 49 | editor.putLong(key, (Long) object); 50 | } else 51 | { 52 | editor.putString(key, object.toString()); 53 | } 54 | 55 | SharedPreferencesCompat.apply(editor); 56 | } 57 | /** 58 | * 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值 59 | * 60 | * @param context 61 | * @param key 62 | * @param defaultObject 63 | * @return 64 | */ 65 | public static Object get(Context context, String key, Object defaultObject) 66 | { 67 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, 68 | Context.MODE_PRIVATE); 69 | 70 | if (defaultObject instanceof String) 71 | { 72 | return sp.getString(key, (String) defaultObject); 73 | } else if (defaultObject instanceof Integer) 74 | { 75 | return sp.getInt(key, (Integer) defaultObject); 76 | } else if (defaultObject instanceof Boolean) 77 | { 78 | return sp.getBoolean(key, (Boolean) defaultObject); 79 | } else if (defaultObject instanceof Float) 80 | { 81 | return sp.getFloat(key, (Float) defaultObject); 82 | } else if (defaultObject instanceof Long) 83 | { 84 | return sp.getLong(key, (Long) defaultObject); 85 | } 86 | 87 | return null; 88 | } 89 | /** 90 | * 移除某个key值已经对应的值 91 | * @param context 92 | * @param key 93 | */ 94 | public static void remove(Context context, String key) 95 | { 96 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, 97 | Context.MODE_PRIVATE); 98 | SharedPreferences.Editor editor = sp.edit(); 99 | editor.remove(key); 100 | SharedPreferencesCompat.apply(editor); 101 | } 102 | 103 | /** 104 | * 清除所有数据 105 | * @param context 106 | */ 107 | public static void clear(Context context) 108 | { 109 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, 110 | Context.MODE_PRIVATE); 111 | SharedPreferences.Editor editor = sp.edit(); 112 | editor.clear(); 113 | SharedPreferencesCompat.apply(editor); 114 | } 115 | 116 | /** 117 | * 查询某个key是否已经存在 118 | * @param context 119 | * @param key 120 | * @return 121 | */ 122 | public static boolean contains(Context context, String key) 123 | { 124 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, 125 | Context.MODE_PRIVATE); 126 | return sp.contains(key); 127 | } 128 | /** 129 | * 返回所有的键值对 130 | * 131 | * @param context 132 | * @return 133 | */ 134 | public static Map getAll(Context context) 135 | { 136 | SharedPreferences sp = context.getSharedPreferences(FILE_NAME, 137 | Context.MODE_PRIVATE); 138 | return sp.getAll(); 139 | } 140 | 141 | /** 142 | * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类 143 | * 144 | * @author zhy 145 | * 146 | */ 147 | private static class SharedPreferencesCompat 148 | { 149 | private static final Method sApplyMethod = findApplyMethod(); 150 | 151 | /** 152 | * 反射查找apply的方法 153 | * 154 | * @return 155 | */ 156 | @SuppressWarnings({ "unchecked", "rawtypes" }) 157 | private static Method findApplyMethod() 158 | { 159 | try 160 | { 161 | Class clz = SharedPreferences.Editor.class; 162 | return clz.getMethod("apply"); 163 | } catch (NoSuchMethodException e) 164 | { 165 | } 166 | 167 | return null; 168 | } 169 | /** 170 | * 如果找到则使用apply执行,否则使用commit 171 | * 172 | * @param editor 173 | */ 174 | public static void apply(SharedPreferences.Editor editor) 175 | { 176 | try 177 | { 178 | if (sApplyMethod != null) 179 | { 180 | sApplyMethod.invoke(editor); 181 | return; 182 | } 183 | } catch (IllegalArgumentException e) 184 | { 185 | } catch (IllegalAccessException e) 186 | { 187 | } catch (InvocationTargetException e) 188 | { 189 | } 190 | editor.commit(); 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/utils/ScreenUtils.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Rect; 7 | import android.util.DisplayMetrics; 8 | import android.view.View; 9 | import android.view.WindowManager; 10 | 11 | /** 12 | * 屏幕宽高、状态栏高度、获取截图的辅助类 13 | * Created by liuheng on 16/4/24. 14 | */ 15 | public class ScreenUtils { 16 | private ScreenUtils() 17 | { 18 | /** cannot be instantiated **/ 19 | throw new UnsupportedOperationException("cannot be instantiated"); 20 | } 21 | 22 | /** 23 | * 获得屏幕高度 24 | * 25 | * @param context 26 | * @return 27 | */ 28 | public static int getScreenWidth(Context context) 29 | { 30 | WindowManager wm = (WindowManager) context 31 | .getSystemService(Context.WINDOW_SERVICE); 32 | DisplayMetrics outMetrics = new DisplayMetrics(); 33 | wm.getDefaultDisplay().getMetrics(outMetrics); 34 | return outMetrics.widthPixels; 35 | } 36 | 37 | /** 38 | * 获得屏幕宽度 39 | * 40 | * @param context 41 | * @return 42 | */ 43 | public static int getScreenHeight(Context context) 44 | { 45 | WindowManager wm = (WindowManager) context 46 | .getSystemService(Context.WINDOW_SERVICE); 47 | DisplayMetrics outMetrics = new DisplayMetrics(); 48 | wm.getDefaultDisplay().getMetrics(outMetrics); 49 | return outMetrics.heightPixels; 50 | } 51 | 52 | /** 53 | * 获得状态栏的高度 54 | * 55 | * @param context 56 | * @return 57 | */ 58 | public static int getStatusHeight(Context context) 59 | { 60 | 61 | int statusHeight = -1; 62 | try 63 | { 64 | Class clazz = Class.forName("com.android.internal.R$dimen"); 65 | Object object = clazz.newInstance(); 66 | int height = Integer.parseInt(clazz.getField("status_bar_height") 67 | .get(object).toString()); 68 | statusHeight = context.getResources().getDimensionPixelSize(height); 69 | } catch (Exception e) 70 | { 71 | e.printStackTrace(); 72 | } 73 | return statusHeight; 74 | } 75 | 76 | /** 77 | * 获取当前屏幕截图,包含状态栏 78 | * 79 | * @param activity 80 | * @return 81 | */ 82 | public static Bitmap snapShotWithStatusBar(Activity activity) 83 | { 84 | View view = activity.getWindow().getDecorView(); 85 | view.setDrawingCacheEnabled(true); 86 | view.buildDrawingCache(); 87 | Bitmap bmp = view.getDrawingCache(); 88 | int width = getScreenWidth(activity); 89 | int height = getScreenHeight(activity); 90 | Bitmap bp = null; 91 | bp = Bitmap.createBitmap(bmp, 0, 0, width, height); 92 | view.destroyDrawingCache(); 93 | return bp; 94 | 95 | } 96 | 97 | /** 98 | * 获取当前屏幕截图,不包含状态栏 99 | * 100 | * @param activity 101 | * @return 102 | */ 103 | public static Bitmap snapShotWithoutStatusBar(Activity activity) 104 | { 105 | View view = activity.getWindow().getDecorView(); 106 | view.setDrawingCacheEnabled(true); 107 | view.buildDrawingCache(); 108 | Bitmap bmp = view.getDrawingCache(); 109 | Rect frame = new Rect(); 110 | activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame); 111 | int statusBarHeight = frame.top; 112 | 113 | int width = getScreenWidth(activity); 114 | int height = getScreenHeight(activity); 115 | Bitmap bp = null; 116 | bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height 117 | - statusBarHeight); 118 | view.destroyDrawingCache(); 119 | return bp; 120 | 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/utils/SimpleStartActivityUtils.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.utils; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | 6 | /** 7 | * 简单的跳转Activity的工具类 8 | * Created by liuheng on 16/6/7. 9 | */ 10 | public class SimpleStartActivityUtils { 11 | public static void startActivity(Context context, Class cls) { 12 | Intent intent = new Intent(context, cls); 13 | context.startActivity(intent); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/utils/ThreadUtils.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.utils; 2 | 3 | import android.os.Handler; 4 | import android.os.Looper; 5 | 6 | /** 7 | * 线程的工具类 8 | * Created by liuheng on 16/6/9. 9 | */ 10 | public class ThreadUtils { 11 | 12 | /** 13 | * 在子线程中执行 14 | * @param runnable 15 | */ 16 | public static void runOnNewThread(Runnable runnable){ 17 | new Thread(runnable).start(); 18 | } 19 | 20 | /** 21 | * 在主线程中执行 22 | * @param runnable 23 | */ 24 | public static void runOnMainThread(Runnable runnable){ 25 | Handler handler = new Handler(Looper.getMainLooper()); 26 | handler.post(runnable); 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/utils/ToastUtils.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.utils; 2 | 3 | import android.content.Context; 4 | import android.widget.Toast; 5 | 6 | /** 7 | * 吐司的辅助类 8 | * Created by liuheng on 16/6/8. 9 | */ 10 | public class ToastUtils { 11 | 12 | public static void showToast(Context context, String content) { 13 | showToast(context, content, false); 14 | } 15 | 16 | public static void showToast(Context context, String content, boolean isLongToast) { 17 | int length; 18 | if (isLongToast) { 19 | length = Toast.LENGTH_LONG; 20 | } else { 21 | length = Toast.LENGTH_SHORT; 22 | } 23 | 24 | Toast.makeText(context, content, length).show(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/view/MainBottomView.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.widget.ImageView; 8 | import android.widget.LinearLayout; 9 | 10 | import com.happyheng.sport_android.R; 11 | 12 | /** 13 | * 主页顶部的View 14 | * Created by liuheng on 16/7/12. 15 | */ 16 | public class MainBottomView extends LinearLayout { 17 | 18 | //默认选择的位置 19 | private static final int DEFAULT_POSITION = 0; 20 | private static final int TAB_NUM = 3; 21 | 22 | private final int[] UNSELECTED_IMAGE_BG = new int[]{R.mipmap.tab_information_unselected,R.mipmap.tab_sport_unselected,R.mipmap.tab_me_unselected}; 23 | private final int[] SELECTED_IMAGE_BG = new int[]{R.mipmap.tab_information_selected,R.mipmap.tab_sport_selected,R.mipmap.tab_me_selected}; 24 | 25 | private View mInformationTab, mSportTab, mMineTab; 26 | private ImageView mInformationIv,mSportIv,mMineIv; 27 | private ImageView[] mImages = new ImageView[TAB_NUM]; 28 | 29 | private View.OnClickListener mClickListener = new ClickListener(); 30 | 31 | private int mSelectIndex = DEFAULT_POSITION; 32 | 33 | public MainBottomView(Context context, AttributeSet attrs) { 34 | super(context, attrs); 35 | 36 | setOrientation(HORIZONTAL); 37 | LayoutInflater.from(context).inflate(R.layout.view_main_bottom, this, true); 38 | 39 | mInformationTab = findViewById(R.id.tab_information); 40 | mSportTab = findViewById(R.id.tab_sport); 41 | mMineTab = findViewById(R.id.tab_mine); 42 | 43 | 44 | mInformationIv = (ImageView) findViewById(R.id.information_iv); 45 | mSportIv = (ImageView) findViewById(R.id.sport_iv); 46 | mMineIv = (ImageView) findViewById(R.id.mine_iv); 47 | mImages[0] = mInformationIv; 48 | mImages[1] = mSportIv; 49 | mImages[2] = mMineIv; 50 | 51 | setImageState(mSelectIndex,true); 52 | 53 | mInformationTab.setOnClickListener(mClickListener); 54 | mSportTab.setOnClickListener(mClickListener); 55 | mMineTab.setOnClickListener(mClickListener); 56 | } 57 | 58 | private class ClickListener implements View.OnClickListener { 59 | 60 | @Override 61 | public void onClick(View v) { 62 | 63 | if (mBottomClickListener != null) { 64 | 65 | int newSelect; 66 | switch (v.getId()) { 67 | case R.id.tab_information: 68 | newSelect = 0; 69 | break; 70 | 71 | case R.id.tab_sport: 72 | newSelect = 1; 73 | break; 74 | 75 | default: 76 | newSelect = 2; 77 | break; 78 | } 79 | 80 | if (mSelectIndex != newSelect){ 81 | setImageState(mSelectIndex,false); 82 | setImageState(newSelect,true); 83 | 84 | mBottomClickListener.onClick(mSelectIndex, newSelect); 85 | mSelectIndex = newSelect; 86 | } 87 | 88 | } 89 | 90 | } 91 | } 92 | 93 | private void setImageState(int position,boolean isSelected){ 94 | if (isSelected){ 95 | mImages[position].setBackgroundDrawable(getResources().getDrawable(SELECTED_IMAGE_BG[position])); 96 | } else { 97 | mImages[position].setBackgroundDrawable(getResources().getDrawable(UNSELECTED_IMAGE_BG[position])); 98 | } 99 | } 100 | 101 | 102 | public interface OnBottomChooseListener { 103 | void onClick(int oldPositon,int position); 104 | } 105 | 106 | private OnBottomChooseListener mBottomClickListener; 107 | 108 | public void setBottomCLickListener(OnBottomChooseListener bottomCLickListener) { 109 | this.mBottomClickListener = bottomCLickListener; 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/view/NewsItemView.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.view; 2 | 3 | import android.content.Context; 4 | import android.util.AttributeSet; 5 | import android.view.LayoutInflater; 6 | import android.widget.ImageView; 7 | import android.widget.LinearLayout; 8 | import android.widget.TextView; 9 | 10 | import com.bumptech.glide.Glide; 11 | import com.happyheng.sport_android.R; 12 | import com.orhanobut.logger.Logger; 13 | 14 | /** 15 | * 16 | * Created by liuheng on 16/7/24. 17 | */ 18 | public class NewsItemView extends LinearLayout { 19 | 20 | //顶部的缩略图 21 | private ImageView mThumbnailIv; 22 | private TextView mTitleTv, mContentTv; 23 | 24 | public NewsItemView(Context context, AttributeSet attrs) { 25 | super(context, attrs); 26 | LayoutInflater.from(context).inflate(R.layout.item_news, this, true); 27 | 28 | mThumbnailIv = (ImageView) findViewById(R.id.item_thumbnail_iv); 29 | mTitleTv = (TextView) findViewById(R.id.title_tv); 30 | mContentTv = (TextView) findViewById(R.id.content_tv); 31 | } 32 | 33 | public void setThumbnailSource(String url) { 34 | Glide.with(getContext()).load(url).into(mThumbnailIv); 35 | } 36 | 37 | public void setTitleString(String title) { 38 | mTitleTv.setText(title); 39 | } 40 | 41 | public void setContentString(String content) { 42 | mContentTv.setText(content); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/com/happyheng/sport_android/view/TabSportBackView.java: -------------------------------------------------------------------------------- 1 | package com.happyheng.sport_android.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.Path; 7 | import android.util.AttributeSet; 8 | import android.view.View; 9 | 10 | import com.happyheng.sport_android.R; 11 | 12 | /** 13 | * 运动界面的背景View 14 | * Created by liuheng on 16/7/16. 15 | */ 16 | public class TabSportBackView extends View { 17 | 18 | private Paint mPaint; 19 | private int mBackHeight,mBackBottomHeight; 20 | private Path mBottomPath; 21 | 22 | public TabSportBackView(Context context, AttributeSet attrs) { 23 | super(context, attrs); 24 | 25 | int backColor = context.getResources().getColor(R.color.sport_bg); 26 | mPaint = new Paint(); 27 | mPaint.setColor(backColor); 28 | mPaint.setStyle(Paint.Style.FILL); 29 | 30 | mBottomPath =new Path(); 31 | 32 | mBackHeight = getResources().getDimensionPixelSize(R.dimen.tab_sport_top_height); 33 | mBackBottomHeight = getResources().getDimensionPixelSize(R.dimen.tab_sport_oval_half_height); 34 | } 35 | 36 | @Override 37 | protected void onDraw(Canvas canvas) { 38 | super.onDraw(canvas); 39 | 40 | canvas.drawRect(0, 0, getMeasuredWidth(), mBackHeight, mPaint); 41 | 42 | mBottomPath.moveTo(0, mBackHeight); 43 | mBottomPath.lineTo(getMeasuredWidth()/2, mBackHeight + mBackBottomHeight); 44 | mBottomPath.lineTo(getMeasuredWidth(), mBackHeight); 45 | mBottomPath.close(); 46 | canvas.drawPath(mBottomPath,mPaint); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_oval.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tab_information.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tab_mine.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tab_sport.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tab_sport_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tab_sport_button_press.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_tab_sport_normal.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_article.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 14 | 15 | 20 | 21 | 28 | 29 | 37 | 38 | 39 | 40 | 41 | 42 | 49 | 50 |