├── .github └── workflows │ └── main.yml ├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── sunflower │ │ └── rxandroiddemo │ │ └── ApplicationTest.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── sunflower │ │ └── rxandroiddemo │ │ ├── BaseApplication.java │ │ ├── DialogLoading.java │ │ ├── activity │ │ ├── BaseActivity.java │ │ ├── GithubAPIActivity.java │ │ ├── MainActivity.java │ │ └── SplashActivity.java │ │ ├── api │ │ ├── APIService.java │ │ ├── ApiWrapper.java │ │ ├── GithubHelper.java │ │ └── GithubService.java │ │ ├── dto │ │ ├── ArticleCategory.java │ │ ├── ArticleListDTO.java │ │ ├── AuthorDTO.java │ │ ├── BindAreaAndHospitalInfo.java │ │ ├── HomeRequest.java │ │ ├── PersonalConfigs.java │ │ ├── PersonalInfo.java │ │ ├── RemindDTO.java │ │ ├── Response.java │ │ ├── VersionDto.java │ │ └── github │ │ │ ├── Repos.java │ │ │ └── User.java │ │ └── utils │ │ ├── CacheInterceptor.java │ │ ├── ClippingPicture.java │ │ ├── Constant.java │ │ ├── CropCircleTransformation.java │ │ ├── HttpLoggingInterceptor.java │ │ ├── ProgressResponseBody.java │ │ ├── RetrofitUtil.java │ │ └── SecretConstant.java │ └── res │ ├── drawable-hdpi │ └── splash.jpg │ ├── drawable │ ├── background_splash.xml │ └── loading_progress_bg.xml │ ├── layout │ ├── activity_github_api.xml │ ├── activity_main.xml │ └── dialog_loading_layout.xml │ ├── menu │ ├── menu_github_api.xml │ └── menu_main.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: First Action 2 | 3 | on: 4 | push: 5 | schedule: 6 | # * is a special character in YAML so you have to quote this string 7 | - cron: '*/1 * * * *' 8 | 9 | jobs: 10 | build: 11 | # runs-on: ubuntu-latest 12 | # steps: 13 | # - name: Send mail 14 | # uses: dawidd6/action-send-mail@master 15 | # with: 16 | # server_address: smtp.qq.com 17 | # server_port: 465 18 | # username: ${{secrets.MAIL_USERNAME}} 19 | # password: ${{secrets.MAIL_PASSWORD}} 20 | # subject: Github Actions job result 21 | # # Read file contents as body: 22 | # body: This is body. 23 | # to: 645148061@qq.com 24 | # from: GitHub Actions 25 | # # Optional content type: 26 | # content_type: text/html 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | /captures 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RxAndroidDemo 2 | RxJava+Retrofit网络请求框架Demo 3 | 4 | 详细说明见[RxJava+Retrofit框架Demo(一)](http://www.jianshu.com/p/2b0aeb6b6b61) 5 | 6 | 安全起见,将服务器地址删除了,大家可以看代码 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.sunflower.rxandroiddemo" 9 | minSdkVersion 15 10 | targetSdkVersion 22 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 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:22.2.0' 25 | compile 'io.reactivex:rxandroid:1.1.0' 26 | compile 'io.reactivex:rxjava:1.1.0' 27 | // https://github.com/square/retrofit 28 | compile 'com.squareup.retrofit2:retrofit:2.0.0-beta3' 29 | compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta3' 30 | compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta3' 31 | //filter request and response log with okHttpClient 32 | //自己重写了log拦截器 33 | // compile 'com.squareup.okhttp:logging-interceptor:2.7.0' 34 | //https://github.com/JakeWharton/butterknife 35 | compile 'com.jakewharton:butterknife:6.1.0' 36 | //https://github.com/bumptech/glide 37 | compile 'com.github.bumptech.glide:glide:3.6.1' 38 | //https://github.com/gitskarios/GithubAndroidSdk 39 | //不会用啊 40 | // compile 'com.github.alorma:github-sdk:3.1.2' 41 | } 42 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/sunflower/rxandroiddemo/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo; 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 | 15 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/BaseApplication.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo; 2 | 3 | import android.app.Application; 4 | 5 | /** 6 | * Created by Sunflower on 2016/1/19. 7 | */ 8 | public class BaseApplication extends Application { 9 | static BaseApplication mInstance; 10 | 11 | @Override 12 | public void onCreate() { 13 | super.onCreate(); 14 | mInstance = this; 15 | } 16 | 17 | public static BaseApplication getInstance() { 18 | return mInstance; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/DialogLoading.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.widget.TextView; 6 | 7 | 8 | public class DialogLoading extends Dialog { 9 | 10 | private TextView loadingLabel; 11 | 12 | public DialogLoading(Context context) { 13 | super(context, R.style.Dialog); 14 | setContentView(R.layout.dialog_loading_layout); 15 | setCanceledOnTouchOutside(false); 16 | loadingLabel = (TextView) findViewById(R.id.loading_text); 17 | } 18 | 19 | public void setDialogLabel(String label) { 20 | loadingLabel.setText(label); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/activity/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.text.TextUtils; 6 | import android.util.Log; 7 | import android.widget.Toast; 8 | 9 | import com.sunflower.rxandroiddemo.DialogLoading; 10 | import com.sunflower.rxandroiddemo.utils.RetrofitUtil; 11 | 12 | import java.net.ConnectException; 13 | import java.net.SocketTimeoutException; 14 | 15 | import butterknife.ButterKnife; 16 | import rx.Subscriber; 17 | import rx.functions.Action1; 18 | import rx.subscriptions.CompositeSubscription; 19 | 20 | /** 21 | * Created by sunflower on 2016/1/11. 22 | */ 23 | public class BaseActivity extends AppCompatActivity { 24 | 25 | protected final String TAG = "RxJava"; 26 | private DialogLoading loading; 27 | protected AppCompatActivity activity; 28 | protected Toast mToast = null; 29 | 30 | /** 31 | * 使用CompositeSubscription来持有所有的Subscriptions 32 | */ 33 | protected CompositeSubscription mCompositeSubscription; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | activity = this; 39 | mCompositeSubscription = new CompositeSubscription(); 40 | } 41 | 42 | @Override 43 | public void setContentView(int layoutResID) { 44 | super.setContentView(layoutResID); 45 | ButterKnife.inject(this); 46 | } 47 | 48 | /** 49 | * 创建观察者 50 | * 51 | * @param onNext 52 | * @param 53 | * @return 54 | */ 55 | protected Subscriber newSubscriber(final Action1 onNext) { 56 | return new Subscriber() { 57 | 58 | 59 | @Override 60 | public void onCompleted() { 61 | hideLoadingDialog(); 62 | } 63 | 64 | @Override 65 | public void onError(Throwable e) { 66 | if (e instanceof RetrofitUtil.APIException) { 67 | RetrofitUtil.APIException exception = (RetrofitUtil.APIException) e; 68 | showToast(exception.message); 69 | } else if (e instanceof SocketTimeoutException) { 70 | showToast(e.getMessage()); 71 | } else if (e instanceof ConnectException) { 72 | showToast(e.getMessage()); 73 | } 74 | Log.e(TAG, String.valueOf(e.getMessage())); 75 | // e.printStackTrace(); 76 | hideLoadingDialog(); 77 | } 78 | 79 | @Override 80 | public void onNext(T t) { 81 | if (!mCompositeSubscription.isUnsubscribed()) { 82 | onNext.call(t); 83 | } 84 | } 85 | 86 | }; 87 | } 88 | 89 | 90 | /** 91 | * 显示一个Toast信息 92 | * 93 | * @param content 94 | */ 95 | public void showToast(String content) { 96 | if (mToast == null) { 97 | mToast = Toast.makeText(this, content, Toast.LENGTH_SHORT); 98 | } else { 99 | mToast.setText(content); 100 | } 101 | mToast.show(); 102 | } 103 | 104 | protected void showLoadingDialog() { 105 | if (loading == null) { 106 | loading = new DialogLoading(this); 107 | } 108 | loading.show(); 109 | } 110 | 111 | protected void hideLoadingDialog() { 112 | if (loading != null) { 113 | loading.dismiss(); 114 | } 115 | 116 | } 117 | 118 | @Override 119 | protected void onDestroy() { 120 | super.onDestroy(); 121 | //一旦调用了 CompositeSubscription.unsubscribe(),这个CompositeSubscription对象就不可用了, 122 | // 如果还想使用CompositeSubscription,就必须在创建一个新的对象了。 123 | mCompositeSubscription.unsubscribe(); 124 | 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/activity/GithubAPIActivity.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.activity; 2 | 3 | import android.os.Bundle; 4 | import android.util.Log; 5 | import android.view.Menu; 6 | import android.view.MenuItem; 7 | 8 | import com.sunflower.rxandroiddemo.R; 9 | import com.sunflower.rxandroiddemo.api.GithubHelper; 10 | import com.sunflower.rxandroiddemo.dto.github.Repos; 11 | import com.sunflower.rxandroiddemo.dto.github.User; 12 | import com.sunflower.rxandroiddemo.utils.SecretConstant; 13 | 14 | import java.util.List; 15 | 16 | import butterknife.OnClick; 17 | import rx.functions.Action1; 18 | 19 | /** 20 | * GithubAPI测试,不会用啊 21 | */ 22 | public class GithubAPIActivity extends BaseActivity { 23 | 24 | GithubHelper helper; 25 | User user; 26 | 27 | @Override 28 | protected void onCreate(Bundle savedInstanceState) { 29 | super.onCreate(savedInstanceState); 30 | setContentView(R.layout.activity_github_api); 31 | helper = new GithubHelper(); 32 | 33 | 34 | } 35 | 36 | @OnClick(R.id.test_login_btn) 37 | void loginGithub() { 38 | showLoadingDialog(); 39 | helper.loginWithToken(SecretConstant.GITHUB_AUTH_TOKEN) 40 | .doOnNext(new Action1() { 41 | @Override 42 | public void call(User user) { 43 | GithubAPIActivity.this.user = user; 44 | } 45 | }) 46 | .subscribe(newSubscriber(new Action1() { 47 | @Override 48 | public void call(User user) { 49 | Log.i(TAG, "login--" + user.toString()); 50 | } 51 | })); 52 | } 53 | 54 | 55 | @OnClick(R.id.test_update_btn) 56 | void update() { 57 | // TODO: 2016/1/28 更新个人资料失败 58 | String location = "BeiJing"; 59 | helper.updateLocation(location) 60 | .subscribe(newSubscriber(new Action1() { 61 | @Override 62 | public void call(User user) { 63 | Log.i(TAG, "" + user.getLocation()); 64 | } 65 | })); 66 | } 67 | 68 | @OnClick(R.id.following_btn) 69 | void getFollowing() { 70 | showLoadingDialog(); 71 | final String name = "sunflower-zyb"; 72 | // helper.getFollowing(name) 73 | helper.getMyFollowing() 74 | .subscribe(newSubscriber(new Action1() { 75 | @Override 76 | public void call(Object o) { 77 | StringBuilder sb = new StringBuilder(); 78 | // for (User user : users) { 79 | // sb.append("user name is "); 80 | // sb.append(user.login); 81 | // sb.append("\n"); 82 | // } 83 | Log.i(TAG, sb.toString()); 84 | // Log.i(TAG, "getFollowing---" + users.toString()); 85 | } 86 | })); 87 | } 88 | 89 | 90 | @OnClick(R.id.repos_btn) 91 | void listMyRepositories() { 92 | showLoadingDialog(); 93 | helper.listMyRepositories() 94 | .subscribe(newSubscriber(new Action1>() { 95 | @Override 96 | public void call(List reposes) { 97 | Log.i(TAG, "listMyRepositories----" + reposes.size()); 98 | } 99 | })); 100 | } 101 | 102 | @Override 103 | public boolean onCreateOptionsMenu(Menu menu) { 104 | // Inflate the menu; this adds items to the action bar if it is present. 105 | getMenuInflater().inflate(R.menu.menu_github_api, menu); 106 | return true; 107 | } 108 | 109 | @Override 110 | public boolean onOptionsItemSelected(MenuItem item) { 111 | // Handle action bar item clicks here. The action bar will 112 | // automatically handle clicks on the Home/Up button, so long 113 | // as you specify a parent activity in AndroidManifest.xml. 114 | int id = item.getItemId(); 115 | 116 | //noinspection SimplifiableIfStatement 117 | if (id == R.id.action_settings) { 118 | return true; 119 | } 120 | 121 | return super.onOptionsItemSelected(item); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.view.Menu; 7 | import android.view.MenuItem; 8 | import android.widget.ImageView; 9 | 10 | import com.bumptech.glide.Glide; 11 | import com.sunflower.rxandroiddemo.R; 12 | import com.sunflower.rxandroiddemo.api.ApiWrapper; 13 | import com.sunflower.rxandroiddemo.dto.ArticleCategory; 14 | import com.sunflower.rxandroiddemo.dto.ArticleListDTO; 15 | import com.sunflower.rxandroiddemo.dto.HomeRequest; 16 | import com.sunflower.rxandroiddemo.dto.PersonalConfigs; 17 | import com.sunflower.rxandroiddemo.dto.PersonalInfo; 18 | import com.sunflower.rxandroiddemo.dto.RemindDTO; 19 | import com.sunflower.rxandroiddemo.dto.VersionDto; 20 | import com.sunflower.rxandroiddemo.utils.CropCircleTransformation; 21 | 22 | import java.net.SocketTimeoutException; 23 | import java.util.Arrays; 24 | import java.util.List; 25 | 26 | import butterknife.InjectView; 27 | import butterknife.OnClick; 28 | import rx.Observable; 29 | import rx.Subscriber; 30 | import rx.Subscription; 31 | import rx.functions.Action1; 32 | import rx.functions.Func1; 33 | import rx.functions.Func2; 34 | import rx.functions.Func3; 35 | 36 | public class MainActivity extends BaseActivity { 37 | 38 | 39 | @InjectView(R.id.avatar) 40 | ImageView mAvatar; 41 | 42 | 43 | @Override 44 | protected void onCreate(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | setContentView(R.layout.activity_main); 47 | } 48 | 49 | 50 | @OnClick(R.id.test_github_btn) 51 | void gotoGithubAPIActivity() { 52 | Intent intent = new Intent(this, GithubAPIActivity.class); 53 | startActivity(intent); 54 | } 55 | 56 | 57 | /** 58 | * 分类id 59 | */ 60 | long categoryId; 61 | 62 | @OnClick(R.id.get_article_btn) 63 | void getArticleList() { 64 | final ApiWrapper wrapper = new ApiWrapper(); 65 | showLoadingDialog(); 66 | Subscription subscription = wrapper.getArticleCategory() 67 | //可以在doOnNext处理数据 68 | .doOnNext(new Action1>() { 69 | @Override 70 | public void call(List articleCategories) { 71 | categoryId = articleCategories.get(0).getId(); 72 | } 73 | }) 74 | //设置请求次数 75 | .retry(new Func2() { 76 | @Override 77 | public Boolean call(Integer integer, Throwable throwable) { 78 | Log.e(TAG, "call " + integer); 79 | if (throwable instanceof SocketTimeoutException && integer < 2) 80 | return true; 81 | else 82 | return false; 83 | } 84 | }) 85 | .flatMap(new Func1, Observable>>() { 86 | @Override 87 | public Observable> call(List articleCategories) { 88 | return wrapper.getArticleList(categoryId, 1); 89 | } 90 | }) 91 | .subscribe(newSubscriber(new Action1>() { 92 | @Override 93 | public void call(List articleList) { 94 | for (ArticleListDTO article : articleList) { 95 | Log.i(TAG, article.getId() + " " + article.getTitle() + " " + article.getIntro()); 96 | } 97 | } 98 | })); 99 | mCompositeSubscription.add(subscription); 100 | 101 | } 102 | 103 | 104 | @OnClick(R.id.get_home_btn) 105 | void getHome() { 106 | //同时请求多个接口 107 | ApiWrapper wrapper = new ApiWrapper(); 108 | showLoadingDialog(); 109 | //将多个接口的返回结果结合成一个对象 110 | Subscription subscription = Observable.zip(wrapper.checkVersion(), wrapper.getPersonalInfo(), wrapper.getPersonalConfigs(), 111 | new Func3() { 112 | @Override 113 | public HomeRequest call(VersionDto versionDto, PersonalInfo personalInfo, PersonalConfigs personalConfigs) { 114 | HomeRequest request = new HomeRequest(); 115 | request.setVersionDto(versionDto); 116 | request.setPersonalInfo(personalInfo); 117 | request.setPersonalConfigs(personalConfigs); 118 | return request; 119 | } 120 | }) 121 | .subscribe(newSubscriber(new Action1() { 122 | @Override 123 | public void call(HomeRequest request) { 124 | Log.i(TAG, "versionDto--" + request.getVersionDto().toString()); 125 | Log.i(TAG, "personalInfo--" + request.getPersonalInfo().toString()); 126 | Log.i(TAG, "PersonalConfigs--" + request.getPersonalConfigs().toString()); 127 | } 128 | })); 129 | mCompositeSubscription.add(subscription); 130 | } 131 | 132 | 133 | @OnClick(R.id.upload_avatar_btn) 134 | void updatePersonalInfo() { 135 | ApiWrapper wrapper = new ApiWrapper(); 136 | showLoadingDialog(); 137 | String path = "/storage/emulated/0/Tencent/QQfile_recv/111355.60083131_1280.jpg"; 138 | Subscription subscription = wrapper.updatePersonalInfo(path) 139 | .subscribe(newSubscriber(new Action1() { 140 | @Override 141 | public void call(PersonalInfo personalInfo) { 142 | Log.i(TAG, "updatePersonalInfo---" + personalInfo.avatar); 143 | //设置圆形头像 144 | Glide.with(MainActivity.this) 145 | .load(personalInfo.avatar) 146 | .bitmapTransform(new CropCircleTransformation(MainActivity.this)) 147 | .into(mAvatar); 148 | } 149 | })); 150 | mCompositeSubscription.add(subscription); 151 | } 152 | 153 | @OnClick(R.id.comment_product_btn) 154 | void commentProduct() { 155 | ApiWrapper wrapper = new ApiWrapper(); 156 | showLoadingDialog(); 157 | long orderId = 511; 158 | long productId = 9; 159 | String content = "xixi"; 160 | List paths = Arrays.asList("/storage/emulated/0/UCDownloads/640.jpg", 161 | "/storage/emulated/0/Pictures/Screenshots/Screenshot_2016-01-11-16-34-44.jpeg"); 162 | Subscription subscription = wrapper.commentProduct(orderId, productId, content, paths) 163 | .subscribe(newSubscriber(new Action1() { 164 | @Override 165 | public void call(Object o) { 166 | // Log.i(TAG, "") 167 | } 168 | })); 169 | mCompositeSubscription.add(subscription); 170 | } 171 | 172 | 173 | @OnClick(R.id.notification_btn) 174 | void getNotification() { 175 | ApiWrapper wrapper = new ApiWrapper(); 176 | showLoadingDialog(); 177 | Subscription subscription = wrapper.getNotificationList() 178 | .doOnNext(new Action1>() { 179 | @Override 180 | public void call(List remindDTOs) { 181 | 182 | } 183 | }) 184 | .subscribe(newSubscriber(new Action1>() { 185 | @Override 186 | public void call(List remindDTOs) { 187 | Log.i(TAG, "getNotification---" + remindDTOs.toString()); 188 | } 189 | })); 190 | mCompositeSubscription.add(subscription); 191 | } 192 | 193 | @OnClick(R.id.cancel_favorite_btn) 194 | void cancelFavorite() { 195 | showLoadingDialog(); 196 | List articleId = Arrays.asList(1L, 91L); 197 | ApiWrapper wrapper = new ApiWrapper(); 198 | Subscription subscription = wrapper.cancelFavorite(articleId) 199 | .subscribe(newSubscriber(new Action1() { 200 | @Override 201 | public void call(Object o) { 202 | Log.i(TAG, "cancelFavorite-- " + "Success"); 203 | } 204 | })); 205 | mCompositeSubscription.add(subscription); 206 | } 207 | 208 | @Override 209 | public void onBackPressed() { 210 | super.onBackPressed(); 211 | mCompositeSubscription.unsubscribe(); 212 | 213 | } 214 | 215 | @Override 216 | public boolean onCreateOptionsMenu(Menu menu) { 217 | // Inflate the menu; this adds items to the action bar if it is present. 218 | getMenuInflater().inflate(R.menu.menu_main, menu); 219 | return true; 220 | } 221 | 222 | @Override 223 | public boolean onOptionsItemSelected(MenuItem item) { 224 | // Handle action bar item clicks here. The action bar will 225 | // automatically handle clicks on the Home/Up button, so long 226 | // as you specify a parent activity in AndroidManifest.xml. 227 | int id = item.getItemId(); 228 | 229 | //noinspection SimplifiableIfStatement 230 | if (id == R.id.action_settings) { 231 | return true; 232 | } else if (id == R.id.action_github) { 233 | 234 | Intent intent = new Intent(this, GithubAPIActivity.class); 235 | startActivity(intent); 236 | return true; 237 | } 238 | 239 | return super.onOptionsItemSelected(item); 240 | } 241 | 242 | 243 | } 244 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/activity/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import rx.Observable; 9 | import rx.functions.Action1; 10 | 11 | public class SplashActivity extends BaseActivity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | 17 | Observable.timer(2, TimeUnit.SECONDS) 18 | .subscribe(new Action1() { 19 | @Override 20 | public void call(Long aLong) { 21 | Intent intent = new Intent(activity, MainActivity.class); 22 | startActivity(intent); 23 | finish(); 24 | } 25 | }); 26 | 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/api/APIService.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.api; 2 | 3 | import com.sunflower.rxandroiddemo.dto.ArticleCategory; 4 | import com.sunflower.rxandroiddemo.dto.ArticleListDTO; 5 | import com.sunflower.rxandroiddemo.dto.PersonalConfigs; 6 | import com.sunflower.rxandroiddemo.dto.PersonalInfo; 7 | import com.sunflower.rxandroiddemo.dto.RemindDTO; 8 | import com.sunflower.rxandroiddemo.dto.Response; 9 | import com.sunflower.rxandroiddemo.dto.VersionDto; 10 | 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | import okhttp3.RequestBody; 15 | import retrofit2.http.Body; 16 | import retrofit2.http.Field; 17 | import retrofit2.http.FormUrlEncoded; 18 | import retrofit2.http.Headers; 19 | import retrofit2.http.Multipart; 20 | import retrofit2.http.POST; 21 | import retrofit2.http.Part; 22 | import retrofit2.http.PartMap; 23 | import retrofit2.http.Query; 24 | import rx.Observable; 25 | 26 | /** 27 | * Created by Sunflower on 2015/11/4. 28 | */ 29 | public interface APIService { 30 | 31 | /** 32 | * 获取帖子分类列表 33 | * 34 | * @return 35 | */ 36 | @POST("api/gravida/article/categories.json") 37 | Observable>> getArticleCategory(); 38 | 39 | /** 40 | * 根据分类获取帖子列表 41 | * 42 | * @param id 分类id 43 | * @param pageNumber 44 | * @param pageSize 45 | * @return 46 | */ 47 | @FormUrlEncoded 48 | @POST("api/gravida/article/list.json") 49 | Observable>> getArticleList(@Field("id") long id, 50 | @Field("pageNumber") int pageNumber, 51 | @Field("pageSize") int pageSize); 52 | 53 | /** 54 | * 检查版本 55 | * 56 | * @param version 57 | * @param type 58 | * @param device 59 | * @return 60 | */ 61 | @FormUrlEncoded 62 | @POST("api/common/version.json") 63 | Observable> checkVersion(@Field("version") String version, 64 | @Field("type") String type, 65 | @Field("device") String device); 66 | 67 | /** 68 | * 获取个人信息 69 | * 70 | * @param id 71 | * @return 72 | */ 73 | @FormUrlEncoded 74 | @POST("api/gravida/personal/info.json") 75 | Observable> getPersonalInfo(@Field("id") String id); 76 | 77 | /** 78 | * 获取个人配置信息 79 | * 80 | * @param id 81 | * @return 82 | */ 83 | @FormUrlEncoded 84 | @POST("api/gravida/personal/configs.json") 85 | Observable> getPersonalConfigs(@Field("id") String id); 86 | 87 | @Multipart 88 | @POST("api/gravida/personal/update.json") 89 | Observable> updatePersonalInfo(@Part("avatar") RequestBody avatar, 90 | @Part("id") String id); 91 | 92 | @Multipart 93 | @POST("api/gravida/personal/update.json") 94 | Observable> updatePersonalInfo(@PartMap Map params); 95 | 96 | /** 97 | * 测试用对象作为参数,失败 98 | * 99 | * @param info 100 | * @return 101 | */ 102 | @POST("api/gravida/personal/update.json") 103 | Observable> updatePersonalInfo(@Body PersonalInfo info); 104 | 105 | 106 | @Multipart 107 | @POST("api/gravida/product/comment.json") 108 | Observable> commentProduct(@PartMap Map params); 109 | 110 | 111 | @FormUrlEncoded 112 | @POST("api/gravida/remind/flow.json") 113 | Observable>> getNotificationList(@Field("id") String id); 114 | 115 | 116 | /** 117 | * 取消收藏帖子 118 | * 与{@link #cancelFavorite(String, List)}效果一致 119 | * 120 | * @param id 121 | * @param articleId 传递的为数组 122 | * @return 123 | */ 124 | @POST("api/gravida/article/unfavourite.json") 125 | Observable> cancelFavoriteWithQuery(@Query("id") String id, @Query("articleId") List articleId); 126 | 127 | 128 | @FormUrlEncoded 129 | @POST("api/gravida/article/unfavourite.json") 130 | Observable> cancelFavorite(@Field("id") String id, @Field("articleId") List articleId); 131 | 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/api/ApiWrapper.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.api; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | import com.sunflower.rxandroiddemo.BuildConfig; 6 | import com.sunflower.rxandroiddemo.dto.ArticleCategory; 7 | import com.sunflower.rxandroiddemo.dto.ArticleListDTO; 8 | import com.sunflower.rxandroiddemo.dto.PersonalConfigs; 9 | import com.sunflower.rxandroiddemo.dto.PersonalInfo; 10 | import com.sunflower.rxandroiddemo.dto.RemindDTO; 11 | import com.sunflower.rxandroiddemo.dto.Response; 12 | import com.sunflower.rxandroiddemo.dto.VersionDto; 13 | import com.sunflower.rxandroiddemo.utils.ClippingPicture; 14 | import com.sunflower.rxandroiddemo.utils.RetrofitUtil; 15 | 16 | import java.io.File; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | import okhttp3.MediaType; 22 | import okhttp3.RequestBody; 23 | import rx.Observable; 24 | import rx.android.schedulers.AndroidSchedulers; 25 | import rx.functions.Action0; 26 | import rx.functions.Func1; 27 | import rx.schedulers.Schedulers; 28 | 29 | /** 30 | * Created by Sunflower on 2016/1/11. 31 | */ 32 | public class ApiWrapper extends RetrofitUtil { 33 | 34 | private final int pageSize = 10; 35 | 36 | 37 | /** 38 | * 获取帖子分类 39 | * 40 | * @return 41 | */ 42 | public Observable> getArticleCategory() { 43 | return getService().getArticleCategory() 44 | // .subscribeOn(Schedulers.io()) 45 | // .observeOn(AndroidSchedulers.mainThread()) 46 | // .flatMap(new Func1>, Observable>>() { 47 | // @Override 48 | // public Observable> call(Response> listResponse) { 49 | // return flatResponse(listResponse); 50 | // } 51 | // }) 52 | 53 | .compose(this.>applySchedulers()) 54 | ; 55 | } 56 | 57 | 58 | /** 59 | * 根据类型id,获取文章列表 60 | * 61 | * @param id 62 | * @param pageNumber 63 | * @return 64 | */ 65 | public Observable> getArticleList(long id, int pageNumber) { 66 | return getService().getArticleList(id, pageNumber, pageSize) 67 | // .subscribeOn(Schedulers.io()) 68 | // .observeOn(AndroidSchedulers.mainThread()) 69 | // .flatMap(new Func1>, Observable>>() { 70 | // @Override 71 | // public Observable> call(Response> articleListDTOs) { 72 | // return flatResponse(articleListDTOs); 73 | // } 74 | // }) 75 | .compose(this.>applySchedulers()) 76 | ; 77 | } 78 | 79 | /** 80 | * 版本更新 81 | * 82 | * @return 83 | */ 84 | public Observable checkVersion() { 85 | return getService().checkVersion(BuildConfig.VERSION_NAME, "GRAVIDA", "ANDROID") 86 | // .subscribeOn(Schedulers.io()) 87 | // .observeOn(AndroidSchedulers.mainThread()) 88 | // .flatMap(new Func1, Observable>() { 89 | // @Override 90 | // public Observable call(Response versionDtoResponse) { 91 | // return flatResponse(versionDtoResponse); 92 | // } 93 | // }) 94 | .compose(this.applySchedulers()) 95 | ; 96 | } 97 | 98 | public Observable getPersonalInfo() { 99 | return getService().getPersonalInfo("139") 100 | // .subscribeOn(Schedulers.io()) 101 | // .observeOn(AndroidSchedulers.mainThread()) 102 | // .flatMap(new Func1, Observable>() { 103 | // @Override 104 | // public Observable call(Response personalInfoResponse) { 105 | // return flatResponse(personalInfoResponse); 106 | // } 107 | // }) 108 | .compose(this.applySchedulers()) 109 | ; 110 | } 111 | 112 | public Observable getPersonalConfigs() { 113 | return getService().getPersonalConfigs("139") 114 | // .subscribeOn(Schedulers.io()) 115 | // .observeOn(AndroidSchedulers.mainThread()) 116 | // .flatMap(new Func1, Observable>() { 117 | // @Override 118 | // public Observable call(Response personalConfigsResponse) { 119 | // return flatResponse(personalConfigsResponse); 120 | // } 121 | // }) 122 | .compose(this.applySchedulers()) 123 | ; 124 | } 125 | 126 | 127 | /** 128 | * 上传单个文件 129 | * 130 | * @param path 131 | * @return 132 | */ 133 | public Observable updatePersonalInfo(String path) { 134 | File file = new File(path); 135 | RequestBody id = RequestBody.create(MediaType.parse("text/plain"), "139"); 136 | //直接传递文件 137 | // RequestBody avatar = RequestBody.create(MediaType.parse("image/*"), file); 138 | //传递byte[] 139 | Bitmap bitmap = ClippingPicture.decodeBitmapSd(path); 140 | RequestBody avatar = RequestBody.create(MediaType.parse("image/*"), ClippingPicture.bitmapToBytes(bitmap)); 141 | Map params = new HashMap<>(); 142 | params.put("id", id); 143 | params.put("avatar\"; filename=\"" + file.getName() + "", avatar); 144 | return getService().updatePersonalInfo(params) 145 | // .subscribeOn(Schedulers.io()) 146 | // .observeOn(AndroidSchedulers.mainThread()) 147 | // .flatMap(new Func1, Observable>() { 148 | // @Override 149 | // public Observable call(Response personalInfoResponse) { 150 | // return flatResponse(personalInfoResponse); 151 | // } 152 | // }) 153 | .compose(this.applySchedulers()) 154 | ; 155 | 156 | } 157 | 158 | /** 159 | * 测试使用对象作为参数,失败 160 | * 161 | * @param info 162 | * @return 163 | */ 164 | public Observable updatePersonalInfo(PersonalInfo info) { 165 | return getService().updatePersonalInfo(info) 166 | .subscribeOn(Schedulers.io()) 167 | .observeOn(AndroidSchedulers.mainThread()) 168 | .flatMap(new Func1, Observable>() { 169 | @Override 170 | public Observable call(Response personalInfoResponse) { 171 | return flatResponse(personalInfoResponse); 172 | } 173 | }); 174 | } 175 | 176 | /** 177 | * 同时传递多个文件 178 | * 179 | * @param orderId 180 | * @param productId 181 | * @param content 182 | * @param paths 183 | * @return 184 | */ 185 | public Observable commentProduct(long orderId, long productId, String content, List paths) { 186 | RequestBody id = RequestBody.create(MediaType.parse("text/plain"), "166"); 187 | RequestBody orderIdBody = RequestBody.create(MediaType.parse("text/plain"), String.valueOf(orderId)); 188 | RequestBody productIdBody = RequestBody.create(MediaType.parse("text/plain"), String.valueOf(productId)); 189 | // RequestBody contentBody = RequestBody.create(MediaType.parse("text/plain"), content); 190 | RequestBody contentBody = createRequestBody(content); 191 | Map params = new HashMap<>(); 192 | params.put("id", id); 193 | params.put("orderId", orderIdBody); 194 | params.put("productId", productIdBody); 195 | params.put("content", contentBody); 196 | for (String image : paths) { 197 | File file = new File(image); 198 | RequestBody images = RequestBody.create(MediaType.parse("image/*"), file); 199 | //key值中为images 200 | params.put("images\"; filename=\"" + file.getName() + "", images); 201 | } 202 | return getService().commentProduct(params) 203 | // .subscribeOn(Schedulers.io()) 204 | // .observeOn(AndroidSchedulers.mainThread()) 205 | // .flatMap(new Func1, Observable>() { 206 | // @Override 207 | // public Observable call(Response objectResponse) { 208 | // return flatResponse(objectResponse); 209 | // } 210 | // }) 211 | .compose(this.applySchedulers()) 212 | ; 213 | 214 | } 215 | 216 | 217 | /* 218 | * https://github.com/square/okhttp/blob/master/samples/guide/src/main/java/okhttp3/recipes/Progress.java 219 | * http://stackoverflow.com/questions/29958881/download-progress-with-rxjava-okhttp-and-okio-in-android 220 | * 下载文件的进度 221 | * */ 222 | 223 | 224 | public Observable> getNotificationList() { 225 | return getService().getNotificationList("139") 226 | // .subscribeOn(Schedulers.io()) 227 | // .observeOn(AndroidSchedulers.mainThread()) 228 | // .flatMap(new Func1>, Observable>>() { 229 | // @Override 230 | // public Observable> call(Response> listResponse) { 231 | // return flatResponse(listResponse); 232 | // } 233 | // }) 234 | .compose(this.>applySchedulers()) 235 | ; 236 | } 237 | 238 | 239 | /** 240 | * 传递数组 241 | * 242 | * @param articleId 243 | * @return 244 | */ 245 | public Observable cancelFavorite(List articleId) { 246 | return getService().cancelFavorite("139", articleId) 247 | // .subscribeOn(Schedulers.io()) 248 | // .observeOn(AndroidSchedulers.mainThread()) 249 | // .flatMap(new Func1, Observable>() { 250 | // @Override 251 | // public Observable call(Response objectResponse) { 252 | // return flatResponse(objectResponse); 253 | // } 254 | // }) 255 | .compose(this.applySchedulers()) 256 | ; 257 | 258 | } 259 | 260 | } 261 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/api/GithubHelper.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.api; 2 | 3 | import android.util.Base64; 4 | import android.util.Log; 5 | 6 | import com.sunflower.rxandroiddemo.dto.github.Repos; 7 | import com.sunflower.rxandroiddemo.dto.github.User; 8 | import com.sunflower.rxandroiddemo.utils.SecretConstant; 9 | 10 | import java.io.IOException; 11 | import java.util.List; 12 | 13 | import okhttp3.Interceptor; 14 | import okhttp3.OkHttpClient; 15 | import okhttp3.Request; 16 | import okhttp3.Response; 17 | import retrofit2.GsonConverterFactory; 18 | import retrofit2.Retrofit; 19 | import retrofit2.RxJavaCallAdapterFactory; 20 | import rx.Observable; 21 | import rx.android.schedulers.AndroidSchedulers; 22 | import rx.schedulers.Schedulers; 23 | 24 | /** 25 | * Github API 帮助类 26 | * Created by Sunflower on 2016/1/26. 27 | */ 28 | public class GithubHelper { 29 | 30 | private final static String API_HOST = "https://api.github.com"; 31 | private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); 32 | 33 | private static Retrofit.Builder builder = 34 | new Retrofit.Builder() 35 | .baseUrl(API_HOST) 36 | .addConverterFactory(GsonConverterFactory.create()) 37 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()); 38 | 39 | /** 40 | * 通过账号密码获取{@link GithubService},有问题 41 | * 42 | * @param serviceClass 43 | * @param username 44 | * @param password 45 | * @param 46 | * @return 47 | */ 48 | protected S getService(Class serviceClass, String username, String password) { 49 | if (username != null && password != null) { 50 | // concatenate username and password with colon for authentication 51 | String credentials = username + ":" + password; 52 | // create Base64 encodet string 53 | final String basic = 54 | "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP); 55 | Log.i("RxJava", "getService " + basic); 56 | httpClient.interceptors().add(new Interceptor() { 57 | @Override 58 | public Response intercept(Chain chain) throws IOException { 59 | Request original = chain.request(); 60 | Request.Builder requestBuilder = original.newBuilder() 61 | .header("Authorization", basic) 62 | .header("Accept", "applicaton/json") 63 | .method(original.method(), original.body()); 64 | Request request = requestBuilder.build(); 65 | return chain.proceed(request); 66 | } 67 | 68 | }); 69 | } 70 | OkHttpClient client = httpClient.build(); 71 | Retrofit retrofit = builder.client(client).build(); 72 | return retrofit.create(serviceClass); 73 | } 74 | 75 | /** 76 | * 通过token获取{@link GithubService} 77 | * 78 | * @param serviceClass 79 | * @param authToken 80 | * @param 81 | * @return 82 | */ 83 | public S getService(Class serviceClass, final String authToken) { 84 | if (authToken != null) { 85 | httpClient.interceptors().add(new Interceptor() { 86 | @Override 87 | public Response intercept(Interceptor.Chain chain) throws IOException { 88 | Request original = chain.request(); 89 | 90 | // Request customization: add request headers 91 | Request.Builder requestBuilder = original.newBuilder() 92 | .header("Authorization", "token " + authToken) 93 | .method(original.method(), original.body()); 94 | 95 | Request request = requestBuilder.build(); 96 | return chain.proceed(request); 97 | } 98 | }); 99 | } 100 | 101 | OkHttpClient client = httpClient.build(); 102 | Retrofit retrofit = builder.client(client).build(); 103 | return retrofit.create(serviceClass); 104 | } 105 | 106 | public GithubService getService() { 107 | return getService(GithubService.class, null); 108 | 109 | } 110 | 111 | 112 | public Observable loginWithPwd(String username, String password) { 113 | return getService(GithubService.class, username, password) 114 | .login(username) 115 | .subscribeOn(Schedulers.io()) 116 | .observeOn(AndroidSchedulers.mainThread()); 117 | } 118 | 119 | public Observable loginWithToken(String authToken) { 120 | String username = "sunflower-zyb"; 121 | return getService(GithubService.class, authToken) 122 | .login(username) 123 | .subscribeOn(Schedulers.io()) 124 | .observeOn(AndroidSchedulers.mainThread()); 125 | } 126 | 127 | 128 | public Observable updateLocation(String location) { 129 | return getService(GithubService.class, SecretConstant.GITHUB_AUTH_TOKEN) 130 | .updateLocation(location) 131 | .subscribeOn(Schedulers.io()) 132 | .observeOn(AndroidSchedulers.mainThread()); 133 | } 134 | 135 | 136 | public Observable> getFollowing(String user) { 137 | return getService().getFollowing(user) 138 | .subscribeOn(Schedulers.io()) 139 | .observeOn(AndroidSchedulers.mainThread()); 140 | } 141 | 142 | public Observable getMyFollowing() { 143 | return getService(GithubService.class, SecretConstant.GITHUB_AUTH_TOKEN) 144 | .getMyFollowing() 145 | .subscribeOn(Schedulers.io()) 146 | .observeOn(AndroidSchedulers.mainThread()); 147 | } 148 | 149 | 150 | public Observable> listMyRepositories() { 151 | return getService(GithubService.class, SecretConstant.GITHUB_AUTH_TOKEN) 152 | .listMyRepositories() 153 | .subscribeOn(Schedulers.io()) 154 | .observeOn(AndroidSchedulers.mainThread()); 155 | } 156 | 157 | } 158 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/api/GithubService.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.api; 2 | 3 | import com.sunflower.rxandroiddemo.dto.github.Repos; 4 | import com.sunflower.rxandroiddemo.dto.github.User; 5 | 6 | import java.util.List; 7 | 8 | import retrofit2.Callback; 9 | import retrofit2.http.Field; 10 | import retrofit2.http.FormUrlEncoded; 11 | import retrofit2.http.GET; 12 | import retrofit2.http.POST; 13 | import retrofit2.http.Path; 14 | import rx.Observable; 15 | 16 | /** 17 | * Github API 18 | * Created by Sunflower on 2016/1/26. 19 | */ 20 | public interface GithubService { 21 | 22 | 23 | @GET("/users/{user}") 24 | void getUserInfo(@Path("user") String user, Callback callback); 25 | 26 | 27 | @GET("/users/{user}") 28 | Observable login(@Path("user") String user); 29 | 30 | 31 | @GET("/users/{user}") 32 | Observable getFeed(@Path("user") String user); 33 | 34 | 35 | @FormUrlEncoded 36 | @POST("/user") 37 | Observable updateLocation(@Field("location") String location); 38 | 39 | 40 | @GET("/users/{user}/following") 41 | Observable> getFollowing(@Path("user") String user); 42 | 43 | 44 | @GET("/user/following") 45 | Observable getMyFollowing(); 46 | 47 | 48 | @GET("/user/repos") 49 | Observable> listMyRepositories(); 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/dto/ArticleCategory.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.dto; 2 | 3 | /** 4 | * Created by sunflower on 2016/1/11. 5 | */ 6 | public class ArticleCategory { 7 | private long id; 8 | 9 | private String name; 10 | 11 | public long getId() { 12 | return id; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/dto/ArticleListDTO.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.dto; 2 | 3 | /** 4 | * 帖子 5 | */ 6 | public class ArticleListDTO { 7 | 8 | /** 9 | * ID 10 | */ 11 | private long id; 12 | 13 | /** 14 | * 图片 15 | */ 16 | private String image; 17 | 18 | /** 19 | * 标题 20 | */ 21 | private String title; 22 | 23 | /** 24 | * 介绍 25 | */ 26 | private String intro; 27 | 28 | /** 29 | * 发布时间 30 | */ 31 | private String createDate; 32 | 33 | /** 34 | * 评论数 35 | */ 36 | private long hits; 37 | 38 | private AuthorDTO author; 39 | 40 | /** 41 | * 是否选中 42 | * add by sunflower 43 | */ 44 | private boolean selected; 45 | 46 | public AuthorDTO getAuthor() { 47 | return author; 48 | } 49 | 50 | public long getId() { 51 | return id; 52 | } 53 | 54 | public String getImage() { 55 | return image; 56 | } 57 | 58 | public String getTitle() { 59 | return title; 60 | } 61 | 62 | public String getIntro() { 63 | return intro; 64 | } 65 | 66 | public String getCreateDate() { 67 | return createDate; 68 | } 69 | 70 | public long getHits() { 71 | 72 | return hits; 73 | } 74 | 75 | public boolean isSelected() { 76 | return selected; 77 | } 78 | 79 | public void setSelected(boolean selected) { 80 | this.selected = selected; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/dto/AuthorDTO.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.dto; 2 | 3 | /** 4 | * DTO - 作者 5 | * 6 | * @author Mounate Yan。 7 | * @version 1.0 8 | */ 9 | public class AuthorDTO { 10 | 11 | /** 12 | * 类型 13 | */ 14 | public enum AuthorType { 15 | /** 16 | * 孕妇 17 | */ 18 | GRAVIDA(0), 19 | /** 20 | * 医生 21 | */ 22 | DOCTOR(1), 23 | 24 | /** 25 | * 系统管理员 26 | */ 27 | SYSTEM(2); 28 | 29 | 30 | private int key; 31 | 32 | private AuthorType(int key) { 33 | this.key = key; 34 | } 35 | 36 | public int getKey() { 37 | return key; 38 | } 39 | 40 | public static AuthorType valueOf(int ordinal) { 41 | if (ordinal < 0 || ordinal >= values().length) { 42 | throw new IndexOutOfBoundsException("Invalid ordinal"); 43 | } 44 | return values()[ordinal]; 45 | } 46 | } 47 | 48 | /** 49 | * ID 50 | */ 51 | private long id; 52 | 53 | /** 54 | * 头像 55 | */ 56 | private String avatar; 57 | 58 | /** 59 | * 昵称 60 | */ 61 | private String nickname; 62 | 63 | /** 64 | * 类型 65 | */ 66 | private AuthorType type; 67 | 68 | public Long getId() { 69 | return id; 70 | } 71 | 72 | public String getAvatar() { 73 | return avatar; 74 | } 75 | 76 | public String getNickname() { 77 | return String.valueOf(nickname); 78 | } 79 | 80 | public AuthorType getType() { 81 | return type; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/dto/BindAreaAndHospitalInfo.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.dto; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Sunflower on 2015/11/4. 7 | */ 8 | public class BindAreaAndHospitalInfo { 9 | String hospitalName; 10 | int hospitalId; 11 | List areas; 12 | 13 | 14 | public String getHospitalName() { 15 | return hospitalName; 16 | } 17 | 18 | public int getHospitalId() { 19 | return hospitalId; 20 | } 21 | 22 | public List getAreas() { 23 | return areas; 24 | } 25 | 26 | public String getAreaId() { 27 | return areas.get(areas.size() - 1).getId(); 28 | } 29 | 30 | public String getFullName() { 31 | return areas.get(0).getName() + areas.get(1).getName() + areas.get(2).getName(); 32 | } 33 | 34 | class Area { 35 | int id; 36 | String name; 37 | 38 | public String getId() { 39 | return String.valueOf(id); 40 | } 41 | 42 | public String getName() { 43 | return name; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/dto/HomeRequest.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.dto; 2 | 3 | /** 4 | * Created by Sunflower on 2016/1/15. 5 | */ 6 | public class HomeRequest { 7 | 8 | VersionDto versionDto; 9 | PersonalInfo personalInfo; 10 | PersonalConfigs personalConfigs; 11 | 12 | public VersionDto getVersionDto() { 13 | return versionDto; 14 | } 15 | 16 | public void setVersionDto(VersionDto versionDto) { 17 | this.versionDto = versionDto; 18 | } 19 | 20 | public PersonalInfo getPersonalInfo() { 21 | return personalInfo; 22 | } 23 | 24 | public void setPersonalInfo(PersonalInfo personalInfo) { 25 | this.personalInfo = personalInfo; 26 | } 27 | 28 | public PersonalConfigs getPersonalConfigs() { 29 | return personalConfigs; 30 | } 31 | 32 | public void setPersonalConfigs(PersonalConfigs personalConfigs) { 33 | this.personalConfigs = personalConfigs; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/dto/PersonalConfigs.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.dto; 2 | 3 | /** 4 | * 个人配置信息 5 | * Created by Sunflower on 2015/10/21. 6 | */ 7 | public class PersonalConfigs { 8 | 9 | /** 10 | * 接收消息 11 | */ 12 | boolean receive; 13 | /** 14 | * 声音 15 | */ 16 | boolean voice; 17 | /** 18 | * 是否已经补充身份证资料 19 | */ 20 | boolean idcard; 21 | /** 22 | * 是否已经订购了套餐 23 | */ 24 | boolean purchased; 25 | 26 | /** 27 | * 是否已经完善个人资料 28 | */ 29 | boolean supplement; 30 | 31 | /** 32 | * 是否正在诊断 33 | */ 34 | boolean diagnosing; 35 | 36 | /** 37 | * 是否有包含需要评论医生的 38 | */ 39 | String doctor_comment_content; 40 | 41 | String bluetooth; 42 | 43 | /** 44 | * 是否购买了设备 45 | */ 46 | boolean hasDevice; 47 | 48 | /** 49 | * 购买设备订单状态1:未发货2已发货 3已收货 50 | */ 51 | int orderStatus; 52 | 53 | /** 54 | * 购买设备订单序号 55 | */ 56 | String orderSn; 57 | 58 | 59 | public boolean isReceive() { 60 | return receive; 61 | } 62 | 63 | public boolean isVoice() { 64 | return voice; 65 | } 66 | 67 | public boolean isIdcard() { 68 | return idcard; 69 | } 70 | 71 | public boolean isPurchased() { 72 | return purchased; 73 | } 74 | 75 | public boolean isSupplement() { 76 | return supplement; 77 | } 78 | 79 | 80 | public boolean isDiagnosing() { 81 | return diagnosing; 82 | } 83 | 84 | 85 | public String getBluetooth() { 86 | return String.valueOf(bluetooth); 87 | } 88 | 89 | public String getDoctorCommentContent() { 90 | return doctor_comment_content; 91 | } 92 | 93 | 94 | public boolean isHasDevice() { 95 | return hasDevice; 96 | } 97 | 98 | public int getOrderStatus() { 99 | return orderStatus; 100 | } 101 | 102 | public String getOrderSn() { 103 | return orderSn; 104 | } 105 | 106 | @Override 107 | public String toString() { 108 | return "PersonalConfigs{" + 109 | "receive=" + receive + 110 | ", voice=" + voice + 111 | ", idcard=" + idcard + 112 | ", purchased=" + purchased + 113 | ", supplement=" + supplement + 114 | ", diagnosing=" + diagnosing + 115 | ", doctor_comment_content='" + doctor_comment_content + '\'' + 116 | ", bluetooth='" + bluetooth + '\'' + 117 | ", hasDevice=" + hasDevice + 118 | ", orderStatus=" + orderStatus + 119 | ", orderSn='" + orderSn + '\'' + 120 | '}'; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/dto/PersonalInfo.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.dto; 2 | 3 | 4 | /** 5 | * Created by Sunflower on 2015/9/25. 6 | */ 7 | public class PersonalInfo { 8 | 9 | /** 10 | * ID 11 | */ 12 | public String id; 13 | 14 | /** 15 | * 昵称 16 | */ 17 | public String nickname; 18 | 19 | /** 20 | * 地址 21 | */ 22 | public String address; 23 | 24 | /** 25 | * 头像 26 | */ 27 | public String avatar; 28 | 29 | 30 | /** 31 | * 身份证号 32 | */ 33 | public String IDNO; 34 | 35 | 36 | /** 37 | * 生日 38 | */ 39 | public String birthday; 40 | 41 | /** 42 | * 预产期 43 | */ 44 | public String expected; 45 | 46 | /** 47 | * 身高 48 | */ 49 | public double stature; 50 | 51 | /** 52 | * 体重 53 | */ 54 | public double weight; 55 | 56 | /** 57 | * 亲情帐号 58 | */ 59 | public String kinship; 60 | 61 | public int age; 62 | 63 | public long areaId; 64 | 65 | 66 | public PersonalInfo(String id, String nickname, String address, String avatar, String IDNO, 67 | String birthday, String expected, double stature, double weight, String kinship, 68 | int age, long areaId) { 69 | this.id = id; 70 | this.nickname = nickname; 71 | this.address = address; 72 | this.avatar = avatar; 73 | this.IDNO = IDNO; 74 | this.birthday = birthday; 75 | this.expected = expected; 76 | this.stature = stature; 77 | this.weight = weight; 78 | this.kinship = kinship; 79 | this.age = age; 80 | this.areaId = areaId; 81 | } 82 | 83 | @Override 84 | public String toString() { 85 | return "PersonalInfo{" + 86 | "id='" + id + '\'' + 87 | ", nickname='" + nickname + '\'' + 88 | ", address='" + address + '\'' + 89 | ", avatar='" + avatar + '\'' + 90 | ", IDNO='" + IDNO + '\'' + 91 | ", birthday='" + birthday + '\'' + 92 | ", expected='" + expected + '\'' + 93 | ", stature=" + stature + 94 | ", weight=" + weight + 95 | ", kinship='" + kinship + '\'' + 96 | ", age=" + age + 97 | ", areaId=" + areaId + 98 | '}'; 99 | } 100 | 101 | public static class Builder { 102 | 103 | /** 104 | * ID 105 | */ 106 | private String id; 107 | 108 | /** 109 | * 昵称 110 | */ 111 | private String nickname; 112 | 113 | /** 114 | * 地址 115 | */ 116 | private String address; 117 | 118 | /** 119 | * 头像 120 | */ 121 | private String avatar; 122 | 123 | 124 | /** 125 | * 身份证号 126 | */ 127 | private String IDNO; 128 | 129 | 130 | /** 131 | * 生日 132 | */ 133 | private String birthday; 134 | 135 | /** 136 | * 预产期 137 | */ 138 | private String expected; 139 | 140 | /** 141 | * 身高 142 | */ 143 | private double stature; 144 | 145 | /** 146 | * 体重 147 | */ 148 | private double weight; 149 | 150 | /** 151 | * 亲情帐号 152 | */ 153 | private String kinship; 154 | 155 | private int age; 156 | public long areaId; 157 | 158 | public Builder(String id) { 159 | this.id = id; 160 | } 161 | 162 | public Builder() { 163 | // this.id = Preference.getInstance().getUserId(); 164 | } 165 | 166 | 167 | // public Builder(String id, String nickname, String address, String avatar, String IDNO, 168 | // String birthday, String expected, Double stature, Double weight, 169 | // String kinship) { 170 | // this.id = id; 171 | // this.nickname = nickname; 172 | // this.address = address; 173 | // this.avatar = avatar; 174 | // this.IDNO = IDNO; 175 | // this.birthday = birthday; 176 | // this.expected = expected; 177 | // this.stature = stature; 178 | // this.weight = weight; 179 | // this.kinship = kinship; 180 | // } 181 | 182 | public Builder setNickname(String nickname) { 183 | this.nickname = nickname; 184 | return this; 185 | } 186 | 187 | public Builder setAddress(String address) { 188 | this.address = address; 189 | return this; 190 | } 191 | 192 | public Builder setAvatar(String avatar) { 193 | this.avatar = avatar; 194 | return this; 195 | } 196 | 197 | public Builder setIDNO(String IDNO) { 198 | this.IDNO = IDNO; 199 | return this; 200 | } 201 | 202 | public Builder setBirthday(String birthday) { 203 | this.birthday = birthday; 204 | return this; 205 | } 206 | 207 | public Builder setExpected(String expected) { 208 | this.expected = expected; 209 | return this; 210 | } 211 | 212 | public Builder setStature(double stature) { 213 | this.stature = stature; 214 | return this; 215 | } 216 | 217 | public Builder setWeight(double weight) { 218 | this.weight = weight; 219 | return this; 220 | } 221 | 222 | public Builder setKinship(String kinship) { 223 | this.kinship = kinship; 224 | return this; 225 | } 226 | 227 | public Builder setAge(int age) { 228 | this.age = age; 229 | return this; 230 | } 231 | 232 | public void setAreaId(long areaId) { 233 | this.areaId = areaId; 234 | } 235 | 236 | public PersonalInfo build() { 237 | // id = builder.id; 238 | // nickname = builder.nickname; 239 | // address = builder.address; 240 | // avatar = builder.avatar; 241 | // birthday = builder.birthday; 242 | // IDNO = builder.IDNO; 243 | // expected = builder.expected; 244 | // stature = builder.stature; 245 | // weight = builder.weight; 246 | // kinship = builder.kinship; 247 | 248 | return new PersonalInfo(id, nickname, address, avatar, IDNO, birthday, expected, 249 | stature, weight, kinship, age, areaId); 250 | } 251 | 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/dto/RemindDTO.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.dto; 2 | 3 | /** 4 | * Created by Sunflower on 2015/11/26. 5 | */ 6 | public class RemindDTO implements Comparable { 7 | /** 8 | * ID 9 | */ 10 | private long id; 11 | 12 | /** 13 | * 时间 14 | */ 15 | private String remindTime; 16 | 17 | /** 18 | * 内容 19 | */ 20 | private String content; 21 | 22 | /** 23 | * 状态 24 | */ 25 | private RemindStatus status; 26 | 27 | /** 28 | * 类型 29 | */ 30 | private RemindType type; 31 | 32 | /** 33 | * 进入医院流程提醒详情页面时,需要该字段 34 | */ 35 | private long templateId; 36 | 37 | public long getId() { 38 | return id; 39 | } 40 | 41 | public String getRemindTime() { 42 | return remindTime; 43 | } 44 | 45 | public String getContent() { 46 | return content; 47 | } 48 | 49 | public RemindStatus getStatus() { 50 | return status; 51 | } 52 | 53 | public RemindType getType() { 54 | return type; 55 | } 56 | 57 | public long getTemplateId() { 58 | return templateId; 59 | } 60 | 61 | /** 62 | * Compares this object to the specified object to determine their relative 63 | * order. 64 | * 65 | * @param another the object to compare to this instance. 66 | * @return a negative integer if this instance is less than {@code another}; 67 | * a positive integer if this instance is greater than 68 | * {@code another}; 0 if this instance has the same order as 69 | * {@code another}. 70 | * @throws ClassCastException if {@code another} cannot be converted into something 71 | * comparable to {@code this} instance. 72 | */ 73 | @Override 74 | public int compareTo(RemindDTO another) { 75 | return remindTime.compareTo(another.remindTime); 76 | } 77 | 78 | 79 | /** 80 | * 提醒状态 81 | */ 82 | public enum RemindStatus { 83 | CREATE { 84 | public String label() { 85 | return "新建"; 86 | } 87 | }, 88 | DONE { 89 | public String label() { 90 | return "过时"; 91 | } 92 | }; 93 | 94 | public String label() { 95 | return this.label(); 96 | } 97 | } 98 | 99 | /** 100 | * 提醒类型 101 | */ 102 | public enum RemindType { 103 | SYSTEM { 104 | public String label() { 105 | return "医院流程"; 106 | } 107 | }, 108 | USERDEFINED { 109 | public String label() { 110 | return "自定义"; 111 | } 112 | }; 113 | 114 | public String label() { 115 | return this.label(); 116 | } 117 | } 118 | 119 | 120 | @Override 121 | public String toString() { 122 | return "RemindDTO{" + 123 | "id=" + id + 124 | ", remindTime='" + remindTime + '\'' + 125 | ", content='" + content + '\'' + 126 | ", status=" + status + 127 | ", type=" + type + 128 | ", templateId=" + templateId + 129 | '}'; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/dto/Response.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.dto; 2 | 3 | import com.sunflower.rxandroiddemo.utils.Constant; 4 | 5 | /** 6 | * Created by Sunflower on 2016/1/11. 7 | */ 8 | public class Response { 9 | 10 | public String code; 11 | public String message; 12 | public T object; 13 | 14 | 15 | public boolean isSuccess() { 16 | return code.equals(Constant.OK); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/dto/VersionDto.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.dto; 2 | 3 | /** 4 | * 版本信息 5 | * Created by Sunflower on 2015/12/3. 6 | */ 7 | public class VersionDto { 8 | 9 | 10 | /** 11 | * createDate : 1442542101000 12 | * device : ANDROID 13 | * filepath : http://www.baidu.com 14 | * id : 2 15 | * introduce : 第一个版本 16 | * isDeleted : false 17 | * modifyDate : 1442542107000 18 | * type : GRAVIDA 19 | * version : 1.0 20 | */ 21 | 22 | private String createDate; 23 | private String device; 24 | private String filepath; 25 | private int id; 26 | private String introduce; 27 | private boolean isDeleted; 28 | private String modifyDate; 29 | private String type; 30 | private String version; 31 | private boolean forced; 32 | 33 | public String getCreateDate() { 34 | return createDate; 35 | } 36 | 37 | public String getDevice() { 38 | return device; 39 | } 40 | 41 | public String getFilepath() { 42 | return filepath; 43 | } 44 | 45 | public int getId() { 46 | return id; 47 | } 48 | 49 | public String getIntroduce() { 50 | return introduce; 51 | } 52 | 53 | public boolean isDeleted() { 54 | return isDeleted; 55 | } 56 | 57 | public String getModifyDate() { 58 | return modifyDate; 59 | } 60 | 61 | public String getType() { 62 | return type; 63 | } 64 | 65 | public String getVersion() { 66 | return version; 67 | } 68 | 69 | public boolean isForced() { 70 | return forced; 71 | } 72 | 73 | 74 | @Override 75 | public String toString() { 76 | return "VersionDto{" + 77 | "createDate='" + createDate + '\'' + 78 | ", device='" + device + '\'' + 79 | ", filepath='" + filepath + '\'' + 80 | ", id=" + id + 81 | ", introduce='" + introduce + '\'' + 82 | ", isDeleted=" + isDeleted + 83 | ", modifyDate='" + modifyDate + '\'' + 84 | ", type='" + type + '\'' + 85 | ", version='" + version + '\'' + 86 | ", forced=" + forced + 87 | '}'; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/dto/github/Repos.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.dto.github; 2 | 3 | import com.google.gson.annotations.SerializedName; 4 | 5 | /** 6 | * Created by Sunflower on 2016/1/29. 7 | */ 8 | public class Repos { 9 | 10 | 11 | /** 12 | * id : 49484435 13 | * name : RxAndroidDemo 14 | * full_name : sunflower-zyb/RxAndroidDemo 15 | * owner : {"login":"sunflower-zyb","id":8893855,"avatar_url":"https://avatars.githubusercontent.com/u/8893855?v=3","gravatar_id":"","url":"https://api.github.com/users/sunflower-zyb","html_url":"https://github.com/sunflower-zyb","followers_url":"https://api.github.com/users/sunflower-zyb/followers","following_url":"https://api.github.com/users/sunflower-zyb/following{/other_user}","gists_url":"https://api.github.com/users/sunflower-zyb/gists{/gist_id}","starred_url":"https://api.github.com/users/sunflower-zyb/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sunflower-zyb/subscriptions","organizations_url":"https://api.github.com/users/sunflower-zyb/orgs","repos_url":"https://api.github.com/users/sunflower-zyb/repos","events_url":"https://api.github.com/users/sunflower-zyb/events{/privacy}","received_events_url":"https://api.github.com/users/sunflower-zyb/received_events","type":"User","site_admin":false} 16 | * private : false 17 | * html_url : https://github.com/sunflower-zyb/RxAndroidDemo 18 | * description : RxJava+Retrofit网络请求框架 19 | * fork : false 20 | * url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo 21 | * forks_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/forks 22 | * keys_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/keys{/key_id} 23 | * collaborators_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/collaborators{/collaborator} 24 | * teams_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/teams 25 | * hooks_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/hooks 26 | * issue_events_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/issues/events{/number} 27 | * events_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/events 28 | * assignees_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/assignees{/user} 29 | * branches_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/branches{/branch} 30 | * tags_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/tags 31 | * blobs_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/git/blobs{/sha} 32 | * git_tags_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/git/tags{/sha} 33 | * git_refs_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/git/refs{/sha} 34 | * trees_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/git/trees{/sha} 35 | * statuses_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/statuses/{sha} 36 | * languages_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/languages 37 | * stargazers_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/stargazers 38 | * contributors_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/contributors 39 | * subscribers_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/subscribers 40 | * subscription_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/subscription 41 | * commits_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/commits{/sha} 42 | * git_commits_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/git/commits{/sha} 43 | * comments_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/comments{/number} 44 | * issue_comment_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/issues/comments{/number} 45 | * contents_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/contents/{+path} 46 | * compare_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/compare/{base}...{head} 47 | * merges_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/merges 48 | * archive_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/{archive_format}{/ref} 49 | * downloads_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/downloads 50 | * issues_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/issues{/number} 51 | * pulls_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/pulls{/number} 52 | * milestones_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/milestones{/number} 53 | * notifications_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/notifications{?since,all,participating} 54 | * labels_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/labels{/name} 55 | * releases_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/releases{/id} 56 | * deployments_url : https://api.github.com/repos/sunflower-zyb/RxAndroidDemo/deployments 57 | * created_at : 2016-01-12T07:58:12Z 58 | * updated_at : 2016-01-27T09:37:19Z 59 | * pushed_at : 2016-01-28T09:35:35Z 60 | * git_url : git://github.com/sunflower-zyb/RxAndroidDemo.git 61 | * ssh_url : git@github.com:sunflower-zyb/RxAndroidDemo.git 62 | * clone_url : https://github.com/sunflower-zyb/RxAndroidDemo.git 63 | * svn_url : https://github.com/sunflower-zyb/RxAndroidDemo 64 | * homepage : null 65 | * size : 139 66 | * stargazers_count : 2 67 | * watchers_count : 2 68 | * language : Java 69 | * has_issues : true 70 | * has_downloads : true 71 | * has_wiki : true 72 | * has_pages : false 73 | * forks_count : 2 74 | * mirror_url : null 75 | * open_issues_count : 0 76 | * forks : 2 77 | * open_issues : 0 78 | * watchers : 2 79 | * default_branch : master 80 | * permissions : {"admin":true,"push":true,"pull":true} 81 | */ 82 | 83 | public int id; 84 | public String name; 85 | public String full_name; 86 | public OwnerEntity owner; 87 | @SerializedName("private") 88 | public boolean privateX; 89 | public String html_url; 90 | public String description; 91 | public boolean fork; 92 | public String url; 93 | public String forks_url; 94 | public String keys_url; 95 | public String collaborators_url; 96 | public String teams_url; 97 | public String hooks_url; 98 | public String issue_events_url; 99 | public String events_url; 100 | public String assignees_url; 101 | public String branches_url; 102 | public String tags_url; 103 | public String blobs_url; 104 | public String git_tags_url; 105 | public String git_refs_url; 106 | public String trees_url; 107 | public String statuses_url; 108 | public String languages_url; 109 | public String stargazers_url; 110 | public String contributors_url; 111 | public String subscribers_url; 112 | public String subscription_url; 113 | public String commits_url; 114 | public String git_commits_url; 115 | public String comments_url; 116 | public String issue_comment_url; 117 | public String contents_url; 118 | public String compare_url; 119 | public String merges_url; 120 | public String archive_url; 121 | public String downloads_url; 122 | public String issues_url; 123 | public String pulls_url; 124 | public String milestones_url; 125 | public String notifications_url; 126 | public String labels_url; 127 | public String releases_url; 128 | public String deployments_url; 129 | public String created_at; 130 | public String updated_at; 131 | public String pushed_at; 132 | public String git_url; 133 | public String ssh_url; 134 | public String clone_url; 135 | public String svn_url; 136 | public Object homepage; 137 | public int size; 138 | public int stargazers_count; 139 | public int watchers_count; 140 | public String language; 141 | public boolean has_issues; 142 | public boolean has_downloads; 143 | public boolean has_wiki; 144 | public boolean has_pages; 145 | public int forks_count; 146 | public Object mirror_url; 147 | public int open_issues_count; 148 | public int forks; 149 | public int open_issues; 150 | public int watchers; 151 | public String default_branch; 152 | public PermissionsEntity permissions; 153 | 154 | public static class OwnerEntity { 155 | /** 156 | * login : sunflower-zyb 157 | * id : 8893855 158 | * avatar_url : https://avatars.githubusercontent.com/u/8893855?v=3 159 | * gravatar_id : 160 | * url : https://api.github.com/users/sunflower-zyb 161 | * html_url : https://github.com/sunflower-zyb 162 | * followers_url : https://api.github.com/users/sunflower-zyb/followers 163 | * following_url : https://api.github.com/users/sunflower-zyb/following{/other_user} 164 | * gists_url : https://api.github.com/users/sunflower-zyb/gists{/gist_id} 165 | * starred_url : https://api.github.com/users/sunflower-zyb/starred{/owner}{/repo} 166 | * subscriptions_url : https://api.github.com/users/sunflower-zyb/subscriptions 167 | * organizations_url : https://api.github.com/users/sunflower-zyb/orgs 168 | * repos_url : https://api.github.com/users/sunflower-zyb/repos 169 | * events_url : https://api.github.com/users/sunflower-zyb/events{/privacy} 170 | * received_events_url : https://api.github.com/users/sunflower-zyb/received_events 171 | * type : User 172 | * site_admin : false 173 | */ 174 | 175 | public String login; 176 | public int id; 177 | public String avatar_url; 178 | public String gravatar_id; 179 | public String url; 180 | public String html_url; 181 | public String followers_url; 182 | public String following_url; 183 | public String gists_url; 184 | public String starred_url; 185 | public String subscriptions_url; 186 | public String organizations_url; 187 | public String repos_url; 188 | public String events_url; 189 | public String received_events_url; 190 | public String type; 191 | public boolean site_admin; 192 | } 193 | 194 | public static class PermissionsEntity { 195 | /** 196 | * admin : true 197 | * push : true 198 | * pull : true 199 | */ 200 | 201 | public boolean admin; 202 | public boolean push; 203 | public boolean pull; 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/dto/github/User.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.dto.github; 2 | 3 | /** 4 | * Created by Sunflower on 2016/1/26. 5 | */ 6 | public class User { 7 | 8 | 9 | /** 10 | * login : sunflower-zyb 11 | * id : 8893855 12 | * avatar_url : https://avatars.githubusercontent.com/u/8893855?v=3 13 | * gravatar_id : 14 | * url : https://api.github.com/users/sunflower-zyb 15 | * html_url : https://github.com/sunflower-zyb 16 | * followers_url : https://api.github.com/users/sunflower-zyb/followers 17 | * following_url : https://api.github.com/users/sunflower-zyb/following{/other_user} 18 | * gists_url : https://api.github.com/users/sunflower-zyb/gists{/gist_id} 19 | * starred_url : https://api.github.com/users/sunflower-zyb/starred{/owner}{/repo} 20 | * subscriptions_url : https://api.github.com/users/sunflower-zyb/subscriptions 21 | * organizations_url : https://api.github.com/users/sunflower-zyb/orgs 22 | * repos_url : https://api.github.com/users/sunflower-zyb/repos 23 | * events_url : https://api.github.com/users/sunflower-zyb/events{/privacy} 24 | * received_events_url : https://api.github.com/users/sunflower-zyb/received_events 25 | * type : User 26 | * site_admin : false 27 | * name : null 28 | * company : null 29 | * blog : null 30 | * location : null 31 | * email : null 32 | * hireable : null 33 | * bio : null 34 | * public_repos : 3 35 | * public_gists : 0 36 | * followers : 1 37 | * following : 10 38 | * created_at : 2014-09-24T05:16:55Z 39 | * updated_at : 2016-01-13T08:29:15Z 40 | */ 41 | 42 | public String login; 43 | public int id; 44 | public String avatar_url; 45 | public String gravatar_id; 46 | public String url; 47 | public String html_url; 48 | public String followers_url; 49 | public String following_url; 50 | public String gists_url; 51 | public String starred_url; 52 | public String subscriptions_url; 53 | public String organizations_url; 54 | public String repos_url; 55 | public String events_url; 56 | public String received_events_url; 57 | public String type; 58 | public boolean site_admin; 59 | public Object name; 60 | public Object company; 61 | public Object blog; 62 | public String location; 63 | public Object email; 64 | public Object hireable; 65 | public Object bio; 66 | public int public_repos; 67 | public int public_gists; 68 | public int followers; 69 | public int following; 70 | public String created_at; 71 | public String updated_at; 72 | 73 | public String getLogin() { 74 | return login; 75 | } 76 | 77 | public int getId() { 78 | return id; 79 | } 80 | 81 | public String getAvatar_url() { 82 | return avatar_url; 83 | } 84 | 85 | public String getGravatar_id() { 86 | return gravatar_id; 87 | } 88 | 89 | public String getUrl() { 90 | return url; 91 | } 92 | 93 | public String getHtml_url() { 94 | return html_url; 95 | } 96 | 97 | public String getFollowers_url() { 98 | return followers_url; 99 | } 100 | 101 | public String getFollowing_url() { 102 | return following_url; 103 | } 104 | 105 | public String getGists_url() { 106 | return gists_url; 107 | } 108 | 109 | public String getStarred_url() { 110 | return starred_url; 111 | } 112 | 113 | public String getSubscriptions_url() { 114 | return subscriptions_url; 115 | } 116 | 117 | public String getOrganizations_url() { 118 | return organizations_url; 119 | } 120 | 121 | public String getRepos_url() { 122 | return repos_url; 123 | } 124 | 125 | public String getEvents_url() { 126 | return events_url; 127 | } 128 | 129 | public String getReceived_events_url() { 130 | return received_events_url; 131 | } 132 | 133 | public String getType() { 134 | return type; 135 | } 136 | 137 | public boolean isSite_admin() { 138 | return site_admin; 139 | } 140 | 141 | public Object getName() { 142 | return name; 143 | } 144 | 145 | public Object getCompany() { 146 | return company; 147 | } 148 | 149 | public Object getBlog() { 150 | return blog; 151 | } 152 | 153 | public String getLocation() { 154 | return String.valueOf(location); 155 | } 156 | 157 | public Object getEmail() { 158 | return email; 159 | } 160 | 161 | public Object getHireable() { 162 | return hireable; 163 | } 164 | 165 | public Object getBio() { 166 | return bio; 167 | } 168 | 169 | public int getPublic_repos() { 170 | return public_repos; 171 | } 172 | 173 | public int getPublic_gists() { 174 | return public_gists; 175 | } 176 | 177 | public int getFollowers() { 178 | return followers; 179 | } 180 | 181 | public int getFollowing() { 182 | return following; 183 | } 184 | 185 | public String getCreated_at() { 186 | return created_at; 187 | } 188 | 189 | public String getUpdated_at() { 190 | return updated_at; 191 | } 192 | 193 | 194 | @Override 195 | public String toString() { 196 | return "User{" + 197 | "login='" + login + '\'' + 198 | ", id=" + id + 199 | ", avatar_url='" + avatar_url + '\'' + 200 | ", gravatar_id='" + gravatar_id + '\'' + 201 | ", url='" + url + '\'' + 202 | ", html_url='" + html_url + '\'' + 203 | ", followers_url='" + followers_url + '\'' + 204 | ", following_url='" + following_url + '\'' + 205 | ", gists_url='" + gists_url + '\'' + 206 | ", starred_url='" + starred_url + '\'' + 207 | ", subscriptions_url='" + subscriptions_url + '\'' + 208 | ", organizations_url='" + organizations_url + '\'' + 209 | ", repos_url='" + repos_url + '\'' + 210 | ", events_url='" + events_url + '\'' + 211 | ", received_events_url='" + received_events_url + '\'' + 212 | ", type='" + type + '\'' + 213 | ", site_admin=" + site_admin + 214 | ", name=" + name + 215 | ", company=" + company + 216 | ", blog=" + blog + 217 | ", location=" + location + 218 | ", email=" + email + 219 | ", hireable=" + hireable + 220 | ", bio=" + bio + 221 | ", public_repos=" + public_repos + 222 | ", public_gists=" + public_gists + 223 | ", followers=" + followers + 224 | ", following=" + following + 225 | ", created_at='" + created_at + '\'' + 226 | ", updated_at='" + updated_at + '\'' + 227 | '}'; 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/utils/CacheInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.utils; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | import android.text.TextUtils; 7 | 8 | import java.io.IOException; 9 | 10 | import okhttp3.Interceptor; 11 | import okhttp3.Request; 12 | import okhttp3.Response; 13 | 14 | /** 15 | * Created by Sunflower on 2016/1/19. 16 | */ 17 | public class CacheInterceptor implements Interceptor { 18 | @Override 19 | public Response intercept(Chain chain) throws IOException { 20 | // Request request = chain.request(); 21 | // if (!isNetworkReachable(BaseApplication.getInstance())) { 22 | // request = request.newBuilder() 23 | // .cacheControl(CacheControl.FORCE_CACHE) 24 | // .build(); 25 | // } 26 | // 27 | // Response response = chain.proceed(request); 28 | // if (isNetworkReachable(BaseApplication.getInstance())) { 29 | // int maxAge = 60; // read from cache for 1 minute 30 | // response.newBuilder() 31 | // .removeHeader("Pragma") 32 | //// .removeHeader("Cache-Control") 33 | // .header("Cache-Control", "public, max-age=" + maxAge) 34 | // .build(); 35 | // } else { 36 | // int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks stale 37 | // response.newBuilder() 38 | // .removeHeader("Pragma") 39 | //// .removeHeader("Cache-Control") 40 | // .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale) 41 | // .build(); 42 | // } 43 | // return response; 44 | Response originalResponse = chain.proceed(chain.request()); 45 | Request request = chain.request(); 46 | String cacheControl = request.cacheControl().toString(); 47 | if (TextUtils.isEmpty(cacheControl)) { 48 | cacheControl = "no-cache"; 49 | } 50 | return originalResponse.newBuilder() 51 | .header("Cache-Control", cacheControl) 52 | .removeHeader("Pragma").build(); 53 | 54 | } 55 | 56 | /** 57 | * 判断网络是否可用 58 | * 59 | * @param context Context对象 60 | */ 61 | public Boolean isNetworkReachable(Context context) { 62 | ConnectivityManager cm = (ConnectivityManager) context 63 | .getSystemService(Context.CONNECTIVITY_SERVICE); 64 | NetworkInfo current = cm.getActiveNetworkInfo(); 65 | if (current == null) { 66 | return false; 67 | } 68 | return (current.isAvailable()); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/utils/ClippingPicture.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.utils; 2 | 3 | import android.content.Context; 4 | import android.content.res.AssetManager; 5 | import android.content.res.Resources; 6 | import android.graphics.Bitmap; 7 | import android.graphics.Bitmap.Config; 8 | import android.graphics.BitmapFactory; 9 | import android.graphics.Canvas; 10 | import android.graphics.Matrix; 11 | import android.graphics.Paint; 12 | import android.graphics.PorterDuff.Mode; 13 | import android.graphics.PorterDuffXfermode; 14 | import android.graphics.Rect; 15 | import android.graphics.RectF; 16 | import android.graphics.drawable.Drawable; 17 | import android.media.ExifInterface; 18 | import android.util.Base64; 19 | import android.util.Log; 20 | import android.view.View; 21 | import android.view.View.MeasureSpec; 22 | 23 | import java.io.BufferedOutputStream; 24 | import java.io.ByteArrayOutputStream; 25 | import java.io.File; 26 | import java.io.FileDescriptor; 27 | import java.io.FileInputStream; 28 | import java.io.FileNotFoundException; 29 | import java.io.FileOutputStream; 30 | import java.io.IOException; 31 | import java.io.InputStream; 32 | 33 | /** 34 | * 图片剪切 35 | * 36 | * @author zhangyb@ifenguo.com 37 | * @createDate 2015年3月10日 38 | */ 39 | public class ClippingPicture { 40 | 41 | /** 42 | * 保存图片到文�? 43 | * 44 | * @param path 45 | * @param data 46 | */ 47 | public static void savePicture(String path, byte[] data) { 48 | if (data == null) { 49 | return; 50 | } 51 | Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length); 52 | File f = new File(path); 53 | BufferedOutputStream bos; 54 | try { 55 | bos = new BufferedOutputStream(new FileOutputStream(f)); 56 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos); 57 | bos.flush(); 58 | bos.close(); 59 | } catch (Exception e) { 60 | e.printStackTrace(); 61 | } 62 | } 63 | 64 | /** 65 | * 保存图片到文�? 66 | * 67 | * @param path 68 | * @param bitmap 69 | */ 70 | public static void savePicture(String path, Bitmap bitmap) { 71 | if (bitmap == null) { 72 | return; 73 | } 74 | File f = new File(path); 75 | BufferedOutputStream bos; 76 | try { 77 | bos = new BufferedOutputStream(new FileOutputStream(f)); 78 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos); 79 | bos.flush(); 80 | bos.close(); 81 | } catch (Exception e) { 82 | e.printStackTrace(); 83 | } 84 | } 85 | 86 | /** 87 | * 从asset目录读取图片 88 | * 89 | * @param context 90 | * @param fileName 91 | * @return 92 | */ 93 | public static Bitmap getImageFromAssetsDef(Context context, String fileName) { 94 | return getImageFromAssetsDef(context.getResources(), fileName); 95 | } 96 | 97 | public static Bitmap getImageFromAssetsDef(Resources resource, String fileName) { 98 | if (fileName == null) { 99 | return null; 100 | } 101 | Bitmap image = null; 102 | AssetManager am = resource.getAssets(); 103 | try { 104 | BitmapFactory.Options options = new BitmapFactory.Options(); 105 | InputStream is = am.open(fileName); 106 | options.inPurgeable = true; 107 | options.inInputShareable = true; 108 | options.inPreferredConfig = Config.RGB_565; 109 | image = BitmapFactory.decodeStream(is, null, options); 110 | is.close(); 111 | } catch (IOException e) { 112 | e.printStackTrace(); 113 | } 114 | return image; 115 | } 116 | 117 | /** 118 | * 图片读取 119 | * 120 | * @param desc 121 | * @return 122 | */ 123 | public static Bitmap decodeBitmap(FileDescriptor desc) { 124 | BitmapFactory.Options opts = new BitmapFactory.Options(); 125 | opts.inSampleSize = 1; 126 | try { 127 | opts.inPurgeable = true; 128 | opts.inInputShareable = true; 129 | opts.inPreferredConfig = Config.RGB_565; 130 | Bitmap bmp = BitmapFactory.decodeFileDescriptor(desc, null, opts); 131 | return bmp; 132 | } catch (Exception e) { 133 | e.printStackTrace(); 134 | } 135 | return null; 136 | } 137 | 138 | /** 139 | * 根据路径从sd卡读取图�? 140 | * 141 | * @param filePath 142 | * @return 143 | */ 144 | public static Bitmap decodeBitmapSd(String filePath) { 145 | File file = new File(filePath); 146 | if (!file.exists()) { 147 | return null; 148 | } 149 | Bitmap bitmap = null; 150 | try { 151 | FileInputStream inputStream = new FileInputStream(file); 152 | FileDescriptor fileDescriptor = inputStream.getFD(); 153 | bitmap = decodeBitmap(fileDescriptor); 154 | if (inputStream != null) { 155 | inputStream.close(); 156 | } 157 | } catch (FileNotFoundException e) { 158 | Log.e("FileNotFound", filePath + "not found"); 159 | } catch (IOException e) { 160 | Log.e("IOException", filePath + "read error"); 161 | } 162 | return bitmap; 163 | } 164 | 165 | /** 166 | * 按照指定的宽高成比例的读取缩小的图片 167 | * 168 | * @param filePath 169 | * @param width 170 | * @param height 171 | * @return 172 | */ 173 | public static Bitmap decodeResizeBitmapSd(String filePath, int width, int height) { 174 | File file = new File(filePath); 175 | if (!file.exists()) { 176 | return null; 177 | } 178 | Bitmap bitmap = null; 179 | try { 180 | FileInputStream inputStream = new FileInputStream(file); 181 | FileDescriptor fileDescriptor = inputStream.getFD(); 182 | BitmapFactory.Options opts = new BitmapFactory.Options(); 183 | opts.inSampleSize = 1; 184 | opts.inPurgeable = true; 185 | opts.inInputShareable = true; 186 | opts.inJustDecodeBounds = true; 187 | opts.inPreferredConfig = Config.RGB_565; 188 | BitmapFactory.decodeFileDescriptor(fileDescriptor, null, opts); 189 | // 计算缩放�? 190 | int simpleSize = calculateInSampleSize(opts, width, height); 191 | opts.inJustDecodeBounds = false; 192 | opts.inSampleSize = simpleSize; 193 | // 正式读取图片 194 | bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, opts); 195 | if (inputStream != null) { 196 | inputStream.close(); 197 | } 198 | } catch (FileNotFoundException e) { 199 | Log.e("FileNotFound", filePath + "not found"); 200 | } catch (IOException e) { 201 | Log.e("IOException", filePath + "read error"); 202 | } 203 | return bitmap; 204 | } 205 | 206 | /** 207 | * 精确缩放图片到某个尺�? 208 | * 209 | * @param path 210 | * @param width 211 | * @param height 212 | * @return 213 | */ 214 | public static Bitmap resizeBitmap(String path, int width, int height) { 215 | Bitmap bitmap = decodeResizeBitmapSd(path, width, height); 216 | int bitmapWidth = bitmap.getWidth(); 217 | float scale = width / (bitmapWidth * 1.0f); 218 | if (scale > 1) { 219 | return bitmap; 220 | } 221 | // 取得想要缩放的matrix参数 222 | Matrix matrix = new Matrix(); 223 | matrix.postScale(scale, scale); 224 | // 得到新的图片 225 | Bitmap newbm = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true); 226 | if (bitmap != newbm) { 227 | bitmap.recycle(); 228 | } 229 | return newbm; 230 | } 231 | 232 | /** 233 | * 修改图片为圆�? 234 | * 235 | * @param bitmap 236 | * @return 237 | */ 238 | public static Bitmap toCircleCorner(Bitmap bitmap) { 239 | if (bitmap == null) { 240 | return null; 241 | } 242 | Bitmap output = Bitmap 243 | .createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); 244 | Canvas canvas = new Canvas(output); 245 | 246 | final int color = 0xff424242; 247 | final Paint paint = new Paint(); 248 | final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); 249 | final RectF rectF = new RectF(rect); 250 | final float roundPx = bitmap.getWidth() / 2; 251 | 252 | paint.setAntiAlias(true); 253 | canvas.drawARGB(0, 0, 0, 0); 254 | paint.setColor(color); 255 | canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 256 | 257 | paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 258 | canvas.drawBitmap(bitmap, rect, rect, paint); 259 | if (output != bitmap) { 260 | bitmap.recycle(); 261 | } 262 | return output; 263 | } 264 | 265 | /** 266 | * 裁剪图片为圆�? 267 | * 268 | * @param bitmap 269 | * @param pixels 270 | * @return 271 | */ 272 | public static Bitmap toRoundCorner(Bitmap bitmap, int pixels) { 273 | if (bitmap == null) { 274 | return null; 275 | } 276 | Bitmap output = Bitmap 277 | .createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888); 278 | Canvas canvas = new Canvas(output); 279 | 280 | final int color = 0xff424242; 281 | final Paint paint = new Paint(); 282 | final Rect rect = new Rect(0, 0, bitmap.getHeight(), bitmap.getHeight()); 283 | final RectF rectF = new RectF(rect); 284 | final float roundPx = pixels * bitmap.getWidth() / 128; 285 | 286 | paint.setAntiAlias(true); 287 | canvas.drawARGB(0, 0, 0, 0); 288 | paint.setColor(color); 289 | canvas.drawRoundRect(rectF, roundPx, roundPx, paint); 290 | 291 | paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 292 | canvas.drawBitmap(bitmap, rect, rect, paint); 293 | if (output != bitmap) { 294 | bitmap.recycle(); 295 | } 296 | return output; 297 | } 298 | 299 | /** 300 | * 从resource目录读取图片 301 | * 302 | * @param context 303 | * @param resId 304 | * @return 305 | */ 306 | public static Drawable getDrawableFromResource(Context context, int resId) { 307 | return context.getResources().getDrawable(resId); 308 | } 309 | 310 | /** 311 | * 根据宽高计算缩放�? 312 | * 313 | * @param options 314 | * @param reqWidth 315 | * @param reqHeight 316 | * @return 317 | */ 318 | public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, 319 | int reqHeight) { 320 | final int height = options.outHeight; 321 | final int width = options.outWidth; 322 | int inSampleSize = 1; 323 | if (height > reqHeight || width > reqWidth) { 324 | final int heightRatio = Math.round((float) height / (float) reqHeight); 325 | final int widthRatio = Math.round((float) width / (float) reqWidth); 326 | inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; 327 | final float totalPixels = width * height; 328 | final float totalReqPixelsCap = reqWidth * reqHeight * 2; 329 | while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { 330 | inSampleSize++; 331 | } 332 | } 333 | return inSampleSize; 334 | } 335 | 336 | /** 337 | * bitmap转为byte[] 338 | * 339 | * @param bitmap 340 | * @return 341 | */ 342 | public static byte[] bitmapToBytes(Bitmap bitmap) { 343 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 344 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); 345 | try { 346 | baos.flush(); 347 | baos.close(); 348 | } catch (IOException e) { 349 | e.printStackTrace(); 350 | } 351 | return baos.toByteArray(); 352 | } 353 | 354 | // public static String bitmapToBase64(String file) { 355 | // byte[] iconByte = FileUtil.readFile(file); 356 | // String total = Base64.encodeToString(iconByte, Base64.DEFAULT); 357 | // return total; 358 | // } 359 | 360 | public static String bitmapToBase64(Bitmap bitmap) { 361 | 362 | String result = null; 363 | ByteArrayOutputStream baos = null; 364 | try { 365 | if (bitmap != null) { 366 | baos = new ByteArrayOutputStream(); 367 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); 368 | 369 | baos.flush(); 370 | baos.close(); 371 | 372 | byte[] bitmapBytes = baos.toByteArray(); 373 | result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT); 374 | } 375 | } catch (IOException e) { 376 | e.printStackTrace(); 377 | } finally { 378 | try { 379 | if (baos != null) { 380 | baos.flush(); 381 | baos.close(); 382 | } 383 | } catch (IOException e) { 384 | e.printStackTrace(); 385 | } 386 | } 387 | return result; 388 | } 389 | 390 | public static Bitmap decodeBitmapStream(InputStream input, int width, int height) { 391 | BitmapFactory.Options opts = new BitmapFactory.Options(); 392 | opts.inSampleSize = 1; 393 | opts.inPurgeable = true; 394 | opts.inInputShareable = true; 395 | opts.inJustDecodeBounds = true; 396 | opts.inPreferredConfig = Config.RGB_565; 397 | // BitmapFactory.decodeStream(input, null, opts); 398 | // 计算缩放�? 399 | int simpleSize = calculateInSampleSize(opts, width, height); 400 | opts.inJustDecodeBounds = false; 401 | opts.inSampleSize = simpleSize; 402 | Bitmap bitmap = BitmapFactory.decodeStream(input, null, opts); 403 | if (input != null) { 404 | try { 405 | input.close(); 406 | } catch (IOException e) { 407 | e.printStackTrace(); 408 | } 409 | } 410 | return bitmap; 411 | } 412 | 413 | public static Bitmap decodeBitmapResourse(Context context, int resourceId) { 414 | Resources resource = context.getResources(); 415 | return BitmapFactory.decodeResource(resource, resourceId); 416 | } 417 | 418 | /** 419 | * 读取图片属性:旋转的角度 三星手机特别注意 420 | * 421 | * @param path 图片绝对路径 422 | * @return degree旋转的角度 423 | */ 424 | public static int readPictureDegree(String path) { 425 | int degree = 0; 426 | try { 427 | ExifInterface exifInterface = new ExifInterface(path); 428 | int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, 429 | ExifInterface.ORIENTATION_NORMAL); 430 | switch (orientation) { 431 | case ExifInterface.ORIENTATION_ROTATE_90: 432 | degree = 90; 433 | break; 434 | case ExifInterface.ORIENTATION_ROTATE_180: 435 | degree = 180; 436 | break; 437 | case ExifInterface.ORIENTATION_ROTATE_270: 438 | degree = 270; 439 | break; 440 | } 441 | } catch (IOException e) { 442 | e.printStackTrace(); 443 | } 444 | return degree; 445 | } 446 | 447 | /** 448 | * 旋转图片,使图片保持正确的方向。 449 | * 450 | * @param bitmap 原始图片 451 | * @param degrees 原始图片的角度 452 | * @return Bitmap 旋转后的图片 453 | */ 454 | public static Bitmap rotateBitmap(Bitmap bitmap, int degrees) { 455 | if (degrees == 0 || null == bitmap) { 456 | return bitmap; 457 | } 458 | Matrix matrix = new Matrix(); 459 | matrix.setRotate(degrees, bitmap.getWidth() / 2, bitmap.getHeight() / 2); 460 | Bitmap bmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), 461 | matrix, true); 462 | if (null != bitmap) { 463 | bitmap.recycle(); 464 | } 465 | return bmp; 466 | } 467 | 468 | /** 469 | * @param @param view 470 | * @param @return 设定文件 471 | * @return Bitmap 返回类型 472 | * @throws 473 | * @Title: convertViewToBitmap 474 | * @Description: View转换为Bitmap 475 | */ 476 | public static Bitmap convertViewToBitmap(View view) { 477 | view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 478 | MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 479 | view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); 480 | view.buildDrawingCache(); 481 | Bitmap bitmap = view.getDrawingCache(); 482 | return bitmap; 483 | } 484 | 485 | public static byte[] convertViewToByte(View view) { 486 | view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 487 | MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 488 | view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight()); 489 | view.buildDrawingCache(); 490 | Bitmap bitmap = view.getDrawingCache(); 491 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 492 | bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); 493 | try { 494 | baos.flush(); 495 | baos.close(); 496 | } catch (IOException e) { 497 | e.printStackTrace(); 498 | } 499 | view.destroyDrawingCache(); 500 | return baos.toByteArray(); 501 | } 502 | } 503 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/utils/Constant.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.utils; 2 | 3 | /** 4 | * Created by Sunflower on 2016/1/11. 5 | */ 6 | public class Constant { 7 | /** 8 | * 成功 9 | */ 10 | public static final String OK = "1"; 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/utils/CropCircleTransformation.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.utils; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | *

6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | *

10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | *

12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.content.Context; 20 | import android.graphics.Bitmap; 21 | import android.graphics.BitmapShader; 22 | import android.graphics.Canvas; 23 | import android.graphics.Matrix; 24 | import android.graphics.Paint; 25 | 26 | import com.bumptech.glide.Glide; 27 | import com.bumptech.glide.load.Transformation; 28 | import com.bumptech.glide.load.engine.Resource; 29 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; 30 | import com.bumptech.glide.load.resource.bitmap.BitmapResource; 31 | 32 | /** 33 | * https://github.com/wasabeef/glide-transformations 34 | * 设置圆形图片 35 | * Glide.with(context) 36 | * .load(url) 37 | * .bitmapTransform(new CropCircleTransformation(context)) 38 | * .into(imageview); 39 | */ 40 | public class CropCircleTransformation implements Transformation { 41 | 42 | private BitmapPool mBitmapPool; 43 | 44 | public CropCircleTransformation(Context context) { 45 | this(Glide.get(context).getBitmapPool()); 46 | } 47 | 48 | public CropCircleTransformation(BitmapPool pool) { 49 | this.mBitmapPool = pool; 50 | } 51 | 52 | @Override 53 | public Resource transform(Resource resource, int outWidth, int outHeight) { 54 | Bitmap source = resource.get(); 55 | int size = Math.min(source.getWidth(), source.getHeight()); 56 | 57 | int width = (source.getWidth() - size) / 2; 58 | int height = (source.getHeight() - size) / 2; 59 | 60 | Bitmap bitmap = mBitmapPool.get(size, size, Bitmap.Config.ARGB_8888); 61 | if (bitmap == null) { 62 | bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); 63 | } 64 | 65 | Canvas canvas = new Canvas(bitmap); 66 | Paint paint = new Paint(); 67 | BitmapShader shader = 68 | new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP); 69 | if (width != 0 || height != 0) { 70 | // source isn't square, move viewport to center 71 | Matrix matrix = new Matrix(); 72 | matrix.setTranslate(-width, -height); 73 | shader.setLocalMatrix(matrix); 74 | } 75 | paint.setShader(shader); 76 | paint.setAntiAlias(true); 77 | 78 | float r = size / 2f; 79 | canvas.drawCircle(r, r, r, paint); 80 | 81 | return BitmapResource.obtain(bitmap, mBitmapPool); 82 | } 83 | 84 | @Override 85 | public String getId() { 86 | return "CropCircleTransformation()"; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/utils/HttpLoggingInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.utils; 2 | 3 | 4 | import java.io.IOException; 5 | import java.nio.charset.Charset; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import okhttp3.Headers; 9 | import okhttp3.Interceptor; 10 | import okhttp3.MediaType; 11 | import okhttp3.MultipartBody; 12 | import okhttp3.Protocol; 13 | import okhttp3.Request; 14 | import okhttp3.RequestBody; 15 | import okhttp3.Response; 16 | import okhttp3.internal.Platform; 17 | import okio.Buffer; 18 | 19 | /** 20 | * Created by Sunflower on 2016/1/12. 21 | */ 22 | public class HttpLoggingInterceptor implements Interceptor { 23 | private static final Charset UTF8 = Charset.forName("UTF-8"); 24 | 25 | public enum Level { 26 | /** 27 | * No logs. 28 | */ 29 | NONE, 30 | /** 31 | * Logs request and response lines. 32 | *

33 | * Example: 34 | *

{@code
 35 |          * --> POST /greeting HTTP/1.1 (3-byte body)
 36 |          * 

37 | * <-- HTTP/1.1 200 OK (22ms, 6-byte body) 38 | * }

39 | */ 40 | BASIC, 41 | /** 42 | * Logs request and response lines and their respective headers. 43 | *

44 | * Example: 45 | *

{@code
 46 |          * --> POST /greeting HTTP/1.1
 47 |          * Host: example.com
 48 |          * Content-Type: plain/text
 49 |          * Content-Length: 3
 50 |          * --> END POST
 51 |          * 

52 | * <-- HTTP/1.1 200 OK (22ms) 53 | * Content-Type: plain/text 54 | * Content-Length: 6 55 | * <-- END HTTP 56 | * }

57 | */ 58 | HEADERS, 59 | /** 60 | * Logs request and response lines and their respective headers and bodies (if present). 61 | *

62 | * Example: 63 | *

{@code
 64 |          * --> POST /greeting HTTP/1.1
 65 |          * Host: example.com
 66 |          * Content-Type: plain/text
 67 |          * Content-Length: 3
 68 |          * 

69 | * Hi? 70 | * --> END GET 71 | *

72 | * <-- HTTP/1.1 200 OK (22ms) 73 | * Content-Type: plain/text 74 | * Content-Length: 6 75 | *

76 | * Hello! 77 | * <-- END HTTP 78 | * }

79 | */ 80 | BODY 81 | } 82 | 83 | public interface Logger { 84 | void log(String message); 85 | 86 | /** 87 | * A {@link Logger} defaults output appropriate for the current platform. 88 | */ 89 | Logger DEFAULT = new Logger() { 90 | @Override 91 | public void log(String message) { 92 | Platform.get().log(message); 93 | } 94 | }; 95 | } 96 | 97 | public HttpLoggingInterceptor() { 98 | this(Logger.DEFAULT); 99 | } 100 | 101 | public HttpLoggingInterceptor(Logger logger) { 102 | this.logger = logger; 103 | } 104 | 105 | private final Logger logger; 106 | 107 | private volatile Level level = Level.BODY; 108 | 109 | /** 110 | * Change the level at which this interceptor logs. 111 | */ 112 | public HttpLoggingInterceptor setLevel(Level level) { 113 | if (level == null) throw new NullPointerException("level == null. Use Level.NONE instead."); 114 | this.level = level; 115 | return this; 116 | } 117 | 118 | @Override 119 | public Response intercept(Interceptor.Chain chain) throws IOException { 120 | Level level = this.level; 121 | 122 | Request request = chain.request(); 123 | if (level == Level.NONE) { 124 | return chain.proceed(request); 125 | } 126 | 127 | boolean logBody = level == Level.BODY; 128 | boolean logHeaders = logBody || level == Level.HEADERS; 129 | 130 | RequestBody requestBody = request.body(); 131 | boolean hasRequestBody = requestBody != null; 132 | 133 | String requestStartMessage = request.method() + ' ' + request.url(); 134 | if (!logHeaders && hasRequestBody) { 135 | requestStartMessage += " (" + requestBody.contentLength() + "-byte body)"; 136 | } 137 | logger.log(requestStartMessage); 138 | 139 | if (logHeaders) { 140 | 141 | if (!logBody || !hasRequestBody) { 142 | logger.log("--> END " + request.method()); 143 | } else if (bodyEncoded(request.headers())) { 144 | logger.log("--> END " + request.method() + " (encoded body omitted)"); 145 | } else if (request.body() instanceof MultipartBody) { 146 | //如果是MultipartBody,会log出一大推乱码的东东 147 | } else { 148 | Buffer buffer = new Buffer(); 149 | requestBody.writeTo(buffer); 150 | 151 | Charset charset = UTF8; 152 | MediaType contentType = requestBody.contentType(); 153 | if (contentType != null) { 154 | contentType.charset(UTF8); 155 | } 156 | 157 | logger.log(buffer.readString(charset)); 158 | 159 | // logger.log(request.method() + " (" + requestBody.contentLength() + "-byte body)"); 160 | } 161 | } 162 | 163 | long startNs = System.nanoTime(); 164 | Response response = chain.proceed(request); 165 | long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs); 166 | logger.log(response.code() + ' ' + response.message() + " (" + tookMs + "ms" + ')'); 167 | 168 | return response; 169 | } 170 | 171 | private boolean bodyEncoded(Headers headers) { 172 | String contentEncoding = headers.get("Content-Encoding"); 173 | return contentEncoding != null && !contentEncoding.equalsIgnoreCase("identity"); 174 | } 175 | 176 | private static String protocol(Protocol protocol) { 177 | return protocol == Protocol.HTTP_1_0 ? "HTTP/1.0" : "HTTP/1.1"; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/utils/ProgressResponseBody.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.utils; 2 | 3 | import java.io.IOException; 4 | 5 | import okhttp3.MediaType; 6 | import okhttp3.ResponseBody; 7 | import okio.Buffer; 8 | import okio.BufferedSource; 9 | import okio.ForwardingSource; 10 | import okio.Okio; 11 | import okio.Source; 12 | 13 | /** 14 | * Created by Sunflower on 2016/1/15. 15 | */ 16 | public class ProgressResponseBody extends ResponseBody { 17 | private final ResponseBody responseBody; 18 | private BufferedSource bufferedSource; 19 | 20 | public ProgressResponseBody(ResponseBody responseBody) { 21 | this.responseBody = responseBody; 22 | // this.progressListener = progressListener; 23 | } 24 | 25 | @Override 26 | public MediaType contentType() { 27 | return responseBody.contentType(); 28 | } 29 | 30 | @Override 31 | public long contentLength() { 32 | return responseBody.contentLength(); 33 | } 34 | 35 | @Override 36 | public BufferedSource source() { 37 | if (bufferedSource == null) { 38 | bufferedSource = Okio.buffer(source(responseBody.source())); 39 | } 40 | return bufferedSource; 41 | } 42 | 43 | private Source source(Source source) { 44 | return new ForwardingSource(source) { 45 | long totalBytesRead = 0L; 46 | 47 | @Override 48 | public long read(Buffer sink, long byteCount) throws IOException { 49 | long bytesRead = super.read(sink, byteCount); 50 | // read() returns the number of bytes read, or -1 if this source is exhausted. 51 | totalBytesRead += bytesRead != -1 ? bytesRead : 0; 52 | // progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1); 53 | return bytesRead; 54 | } 55 | }; 56 | } 57 | } -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/utils/RetrofitUtil.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.utils; 2 | 3 | import android.graphics.Bitmap; 4 | import android.util.Log; 5 | 6 | import com.sunflower.rxandroiddemo.api.APIService; 7 | import com.sunflower.rxandroiddemo.dto.Response; 8 | 9 | import java.io.File; 10 | 11 | import okhttp3.MediaType; 12 | import okhttp3.OkHttpClient; 13 | import okhttp3.RequestBody; 14 | import retrofit2.GsonConverterFactory; 15 | import retrofit2.Retrofit; 16 | import retrofit2.RxJavaCallAdapterFactory; 17 | import rx.Observable; 18 | import rx.Subscriber; 19 | import rx.android.schedulers.AndroidSchedulers; 20 | import rx.functions.Func1; 21 | import rx.schedulers.Schedulers; 22 | 23 | /** 24 | * Created by Sunflower on 2015/11/4. 25 | */ 26 | public class RetrofitUtil { 27 | 28 | /** 29 | * 服务器地址 30 | */ 31 | private static final String API_HOST = SecretConstant.API_HOST; 32 | 33 | private static APIService service; 34 | private static Retrofit retrofit; 35 | 36 | public static APIService getService() { 37 | if (service == null) { 38 | service = getRetrofit().create(APIService.class); 39 | } 40 | return service; 41 | } 42 | 43 | private static Retrofit getRetrofit() { 44 | if (retrofit == null) { 45 | HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { 46 | @Override 47 | public void log(String message) { 48 | Log.i("RxJava", message); 49 | } 50 | }); 51 | //网络缓存路径文件 52 | // File httpCacheDirectory = new File(BaseApplication.getInstance().getExternalCacheDir(), "responses"); 53 | //通过拦截器设置缓存,暂未实现 54 | //CacheInterceptor cacheInterceptor = new CacheInterceptor(); 55 | 56 | OkHttpClient client = new OkHttpClient.Builder() 57 | //设置缓存 58 | // .cache(new Cache(httpCacheDirectory, 10 * 1024 * 1024)) 59 | //log请求参数 60 | .addInterceptor(interceptor) 61 | //网络请求缓存,未实现 62 | // .addInterceptor(cacheInterceptor) 63 | .build(); 64 | retrofit = new Retrofit.Builder() 65 | .client(client) 66 | .baseUrl(API_HOST) 67 | .addConverterFactory(GsonConverterFactory.create()) 68 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 69 | .build(); 70 | } 71 | return retrofit; 72 | } 73 | 74 | /** 75 | * 对网络接口返回的Response进行分割操作 76 | * 77 | * @param response 78 | * @param 79 | * @return 80 | */ 81 | public Observable flatResponse(final Response response) { 82 | return Observable.create(new Observable.OnSubscribe() { 83 | 84 | @Override 85 | public void call(Subscriber subscriber) { 86 | if (response.isSuccess()) { 87 | if (!subscriber.isUnsubscribed()) { 88 | subscriber.onNext(response.object); 89 | } 90 | } else { 91 | if (!subscriber.isUnsubscribed()) { 92 | subscriber.onError(new APIException(response.code, response.message)); 93 | } 94 | return; 95 | } 96 | 97 | if (!subscriber.isUnsubscribed()) { 98 | subscriber.onCompleted(); 99 | } 100 | 101 | } 102 | }); 103 | } 104 | 105 | 106 | /** 107 | * 自定义异常,当接口返回的{@link Response#code}不为{@link Constant#OK}时,需要跑出此异常 108 | * eg:登陆时验证码错误;参数为传递等 109 | */ 110 | public static class APIException extends Exception { 111 | public String code; 112 | public String message; 113 | 114 | public APIException(String code, String message) { 115 | this.code = code; 116 | this.message = message; 117 | } 118 | 119 | @Override 120 | public String getMessage() { 121 | return message; 122 | } 123 | } 124 | 125 | 126 | /** 127 | * http://www.jianshu.com/p/e9e03194199e 128 | *

129 | * Transformer实际上就是一个Func1, Observable>, 130 | * 换言之就是:可以通过它将一种类型的Observable转换成另一种类型的Observable, 131 | * 和调用一系列的内联操作符是一模一样的。 132 | * 133 | * @param 134 | * @return 135 | */ 136 | // protected Observable.Transformer applySchedulers() { 137 | //// return new Observable.Transformer() { 138 | //// @Override 139 | //// public Observable call(Observable observable) { 140 | //// return observable.subscribeOn(Schedulers.io()) 141 | //// .observeOn(AndroidSchedulers.mainThread()); 142 | //// } 143 | //// }; 144 | // 145 | // return (Observable.Transformer) schedulersTransformer; 146 | // } 147 | // 148 | // final Observable.Transformer schedulersTransformer = new Observable.Transformer() { 149 | // @Override 150 | // public Object call(Object observable) { 151 | // return ((Observable) observable).subscribeOn(Schedulers.io()) 152 | // .observeOn(AndroidSchedulers.mainThread()) 153 | // ; 154 | // } 155 | // }; 156 | 157 | protected Observable.Transformer, T> applySchedulers() { 158 | // return new Observable.Transformer, T>() { 159 | // @Override 160 | // public Observable call(Observable> responseObservable) { 161 | // return responseObservable.subscribeOn(Schedulers.io()) 162 | // .observeOn(AndroidSchedulers.mainThread()) 163 | // .flatMap(new Func1, Observable>() { 164 | // @Override 165 | // public Observable call(Response tResponse) { 166 | // return flatResponse(tResponse); 167 | // } 168 | // }) 169 | // ; 170 | // } 171 | // }; 172 | return (Observable.Transformer, T>) transformer; 173 | } 174 | 175 | final Observable.Transformer transformer = new Observable.Transformer() { 176 | @Override 177 | public Object call(Object observable) { 178 | return ((Observable) observable).subscribeOn(Schedulers.io()) 179 | .observeOn(AndroidSchedulers.mainThread()) 180 | .flatMap(new Func1() { 181 | @Override 182 | public Object call(Object response) { 183 | return flatResponse((Response)response); 184 | } 185 | }) 186 | ; 187 | } 188 | }; 189 | 190 | 191 | /** 192 | * 当{@link APIService}中接口的注解为{@link retrofit2.http.Multipart}时,参数为{@link RequestBody} 193 | * 生成对应的RequestBody 194 | * 195 | * @param param 196 | * @return 197 | */ 198 | protected RequestBody createRequestBody(int param) { 199 | return RequestBody.create(MediaType.parse("text/plain"), String.valueOf(param)); 200 | } 201 | 202 | protected RequestBody createRequestBody(long param) { 203 | return RequestBody.create(MediaType.parse("text/plain"), String.valueOf(param)); 204 | } 205 | 206 | protected RequestBody createRequestBody(String param) { 207 | return RequestBody.create(MediaType.parse("text/plain"), param); 208 | } 209 | 210 | protected RequestBody createRequestBody(File param) { 211 | return RequestBody.create(MediaType.parse("image/*"), param); 212 | } 213 | 214 | /** 215 | * 已二进制传递图片文件,对图片文件进行了压缩 216 | * 217 | * @param path 文件路径 218 | * @return 219 | */ 220 | protected RequestBody createPictureRequestBody(String path) { 221 | Bitmap bitmap = ClippingPicture.decodeResizeBitmapSd(path, 400, 800); 222 | return RequestBody.create(MediaType.parse("image/*"), ClippingPicture.bitmapToBytes(bitmap)); 223 | } 224 | 225 | 226 | } 227 | -------------------------------------------------------------------------------- /app/src/main/java/com/sunflower/rxandroiddemo/utils/SecretConstant.java: -------------------------------------------------------------------------------- 1 | package com.sunflower.rxandroiddemo.utils; 2 | 3 | /** 4 | * 保存一些私密数据 5 | * Created by Sunflower on 2016/1/13. 6 | */ 7 | public class SecretConstant { 8 | /** 9 | * 三瑞测试服务器地址 10 | */ 11 | public final static String API_HOST = ""; 12 | 13 | /** 14 | * github上的token 15 | */ 16 | public final static String GITHUB_AUTH_TOKEN = ""; 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/splash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sunflower-zyb/RxAndroidDemo/54023566e752c48cb71d68c6fde1443cef2ba079/app/src/main/res/drawable-hdpi/splash.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/background_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/loading_progress_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_github_api.xml: -------------------------------------------------------------------------------- 1 | 11 | 12 |