提交 c655af94 编写于 作者: J jessyan

fix httpResponseHandle bug

上级 fee0900a
......@@ -10,6 +10,7 @@
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/arms" />
<option value="$PROJECT_DIR$/rxerrorhandler" />
</set>
</option>
<option name="myModules">
......@@ -17,6 +18,7 @@
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/arms" />
<option value="$PROJECT_DIR$/rxerrorhandler" />
</set>
</option>
</GradleProjectSettings>
......
<component name="libraryTable">
<library name="animated-vector-drawable-23.3.0">
<library name="animated-vector-drawable-23.4.0">
<CLASSES>
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/animated-vector-drawable/23.3.0/jars/classes.jar!/" />
<root url="file://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/animated-vector-drawable/23.3.0/res" />
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/animated-vector-drawable/23.4.0/jars/classes.jar!/" />
<root url="file://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/animated-vector-drawable/23.4.0/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/animated-vector-drawable/23.3.0/animated-vector-drawable-23.3.0-sources.jar!/" />
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/animated-vector-drawable/23.4.0/animated-vector-drawable-23.4.0-sources.jar!/" />
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/animated-vector-drawable/23.4.0/animated-vector-drawable-23.4.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="appcompat-v7-23.3.0">
<library name="appcompat-v7-23.4.0">
<ANNOTATIONS>
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.3.0/annotations.zip!/" />
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.4.0/annotations.zip!/" />
<root url="jar://$PROJECT_DIR$/app/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.4.0/annotations.zip!/" />
</ANNOTATIONS>
<CLASSES>
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.3.0/jars/classes.jar!/" />
<root url="file://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.3.0/res" />
<root url="file://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.4.0/res" />
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.4.0/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/appcompat-v7/23.3.0/appcompat-v7-23.3.0-sources.jar!/" />
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/appcompat-v7/23.4.0/appcompat-v7-23.4.0-sources.jar!/" />
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/appcompat-v7/23.4.0/appcompat-v7-23.4.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="paginate-0.5.1">
<CLASSES>
<root url="file://$PROJECT_DIR$/app/build/intermediates/exploded-aar/com.github.markomilos/paginate/0.5.1/res" />
<root url="jar://$PROJECT_DIR$/app/build/intermediates/exploded-aar/com.github.markomilos/paginate/0.5.1/jars/classes.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.github.markomilos/paginate/0.5.1/dd9381fc81126552196752c9529b67abee425d5a/paginate-0.5.1-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="recyclerview-v7-23.3.0">
<ANNOTATIONS>
<root url="jar://$PROJECT_DIR$/app/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.3.0/annotations.zip!/" />
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.3.0/annotations.zip!/" />
</ANNOTATIONS>
<CLASSES>
<root url="file://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.3.0/res" />
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.3.0/jars/classes.jar!/" />
<root url="jar://$PROJECT_DIR$/app/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.3.0/jars/classes.jar!/" />
<root url="file://$PROJECT_DIR$/app/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.3.0/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/recyclerview-v7/23.3.0/recyclerview-v7-23.3.0-sources.jar!/" />
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/recyclerview-v7/23.3.0/recyclerview-v7-23.3.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="rxjava-1.1.5">
<CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.reactivex/rxjava/1.1.5/ece7b5d0870e66d8226dab6dcf47a2b12afff061/rxjava-1.1.5.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.reactivex/rxjava/1.1.5/6d674958ad6810d86349fa54ebf0e95a626f106d/rxjava-1.1.5-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="support-annotations-23.3.0">
<library name="support-annotations-23.4.0">
<CLASSES>
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/support-annotations/23.3.0/support-annotations-23.3.0.jar!/" />
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/support-annotations/23.4.0/support-annotations-23.4.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/support-annotations/23.3.0/support-annotations-23.3.0-sources.jar!/" />
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/support-annotations/23.4.0/support-annotations-23.4.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="support-v4-23.3.0">
<ANNOTATIONS>
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/support-v4/23.3.0/annotations.zip!/" />
</ANNOTATIONS>
<CLASSES>
<root url="file://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/support-v4/23.3.0/res" />
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/support-v4/23.3.0/jars/classes.jar!/" />
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/support-v4/23.3.0/jars/libs/internal_impl-23.3.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/support-v4/23.3.0/support-v4-23.3.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="support-v4-23.4.0">
<ANNOTATIONS>
<root url="jar://$PROJECT_DIR$/app/build/intermediates/exploded-aar/com.android.support/support-v4/23.4.0/annotations.zip!/" />
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/support-v4/23.4.0/annotations.zip!/" />
<root url="jar://$PROJECT_DIR$/app/build/intermediates/exploded-aar/com.android.support/support-v4/23.4.0/annotations.zip!/" />
</ANNOTATIONS>
<CLASSES>
<root url="jar://$PROJECT_DIR$/app/build/intermediates/exploded-aar/com.android.support/support-v4/23.4.0/jars/classes.jar!/" />
<root url="file://$PROJECT_DIR$/app/build/intermediates/exploded-aar/com.android.support/support-v4/23.4.0/res" />
<root url="jar://$PROJECT_DIR$/app/build/intermediates/exploded-aar/com.android.support/support-v4/23.4.0/jars/libs/internal_impl-23.4.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/support-v4/23.4.0/support-v4-23.4.0-sources.jar!/" />
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/support-v4/23.4.0/support-v4-23.4.0-sources.jar!/" />
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/support-v4/23.4.0/support-v4-23.4.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
<component name="libraryTable">
<library name="support-vector-drawable-23.3.0">
<library name="support-vector-drawable-23.4.0">
<CLASSES>
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/support-vector-drawable/23.3.0/jars/classes.jar!/" />
<root url="file://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/support-vector-drawable/23.3.0/res" />
<root url="jar://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/support-vector-drawable/23.4.0/jars/classes.jar!/" />
<root url="file://$PROJECT_DIR$/arms/build/intermediates/exploded-aar/com.android.support/support-vector-drawable/23.4.0/res" />
</CLASSES>
<JAVADOC />
<SOURCES>
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/support-vector-drawable/23.3.0/support-vector-drawable-23.3.0-sources.jar!/" />
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/support-vector-drawable/23.4.0/support-vector-drawable-23.4.0-sources.jar!/" />
<root url="jar://$USER_HOME$/Library/Android/sdk/extras/android/m2repository/com/android/support/support-vector-drawable/23.4.0/support-vector-drawable-23.4.0-sources.jar!/" />
</SOURCES>
</library>
</component>
\ No newline at end of file
......@@ -5,6 +5,7 @@
<module fileurl="file://$PROJECT_DIR$/MVPArms.iml" filepath="$PROJECT_DIR$/MVPArms.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/arms/arms.iml" filepath="$PROJECT_DIR$/arms/arms.iml" />
<module fileurl="file://$PROJECT_DIR$/rxerrorhandler/rxerrorhandler.iml" filepath="$PROJECT_DIR$/rxerrorhandler/rxerrorhandler.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Statistic">
<option name="excludedDirectories">
<list>
<option value="$PROJECT_DIR$/build" />
<option value="$PROJECT_DIR$/gradle" />
<option value="$PROJECT_DIR$/arms/build" />
<option value="$PROJECT_DIR$/arms/libs" />
<option value="$PROJECT_DIR$/arms/src/androidTest" />
<option value="$PROJECT_DIR$/arms/src/main/res" />
<option value="$PROJECT_DIR$/arms/src/test" />
<option value="$PROJECT_DIR$/app/build" />
<option value="$PROJECT_DIR$/app/libs" />
<option value="$PROJECT_DIR$/app/src/androidTest" />
<option value="$PROJECT_DIR$/app/src/test" />
<option value="$PROJECT_DIR$/app/src/main/res" />
</list>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
......@@ -41,11 +41,10 @@ buildscript {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile rootProject.ext.dependencies["junit"]
apt rootProject.ext.dependencies["dagger2-apt-compiler"]
compile rootProject.ext.dependencies["cardview-v7"]
provided rootProject.ext.dependencies["javax.annotation"]
compile project(':arms')
compile rootProject.ext.dependencies["paginate"]
}
......@@ -18,7 +18,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".mvp.ui.activity.MainActivity">
<activity android:name=".mvp.ui.activity.UserActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
......
package me.jessyan.mvparms.demo.app;
import android.content.Context;
import com.jess.arms.base.BaseApplication;
import com.jess.arms.http.GlobeHttpResultHandler;
import com.jess.arms.utils.UiUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import me.jessyan.mvparms.demo.di.component.AppComponent;
import me.jessyan.mvparms.demo.di.component.DaggerAppComponent;
import me.jessyan.mvparms.demo.di.module.CacheModule;
import me.jessyan.mvparms.demo.di.module.ServiceModule;
import me.jessyan.mvparms.demo.mvp.model.api.Api;
import me.jessyan.rxerrorhandler.handler.listener.ResponseErroListener;
import okhttp3.Interceptor;
import okhttp3.Response;
import timber.log.Timber;
/**
......@@ -51,8 +61,42 @@ public class WEApplication extends BaseApplication {
public GlobeHttpResultHandler getHttpResultHandler() {
return new GlobeHttpResultHandler() {
@Override
public void onHttpResultResponse(String httpResult) {
Timber.tag(TAG).w("GlobeHttpResultHandler------>" + httpResult);
public Response onHttpResultResponse(String httpResult, Interceptor.Chain chain, Response response) {
//这里可以先客户端一步拿到每一次http请求的结果,可以解析成json,做一些操作,如检测到token过期后
//重新请求token,并重新执行请求
try {
JSONArray array = new JSONArray(httpResult);
JSONObject object = (JSONObject) array.get(0);
String login = object.getString("login");
String avatar_url = object.getString("avatar_url");
Timber.tag(TAG).w("result ------>" + login + " || avatar_url------>" + avatar_url);
} catch (JSONException e) {
e.printStackTrace();
}
//这里如果发现token过期,可以先请求最新的token,然后在拿新的token去重新请求之前的http请求
// create a new request and modify it accordingly using the new token
// Request newRequest = chain.request().newBuilder().header("token", newToken)
// .build();
//
// // retry the request
//
// originalResponse.body().close();
// return chain.proceed(newRequest);
//如果需要返回新的结果,则直接把response参数返回出去
return response;
}
};
}
@Override
protected ResponseErroListener getResponseErroListener() {
return new ResponseErroListener() {
@Override
public void handleResponseError(Context context, Exception e) {
Timber.tag(TAG).w("------------>" + e.getMessage());
UiUtils.SnackbarText("net error");
}
};
}
......
......@@ -2,6 +2,7 @@ package me.jessyan.mvparms.demo.di.component;
import android.app.Application;
import com.google.gson.Gson;
import com.jess.arms.di.module.AppModule;
import com.jess.arms.di.module.ClientModule;
import com.jess.arms.di.module.ImageModule;
......@@ -14,6 +15,7 @@ import me.jessyan.mvparms.demo.di.module.CacheModule;
import me.jessyan.mvparms.demo.di.module.ServiceModule;
import me.jessyan.mvparms.demo.mvp.model.api.cache.CacheManager;
import me.jessyan.mvparms.demo.mvp.model.api.service.ServiceManager;
import me.jessyan.rxerrorhandler.core.RxErrorHandler;
import okhttp3.OkHttpClient;
/**
......@@ -30,8 +32,14 @@ public interface AppComponent {
//缓存管理器
CacheManager cacheManager();
//Rxjava错误处理管理类
RxErrorHandler rxErrorHandler();
OkHttpClient okHttpClient();
//图片管理器
//图片管理器,用于加载图片的管理类,默认使用glide,使用策略模式,可替换框架
ImageLoader imageLoader();
//gson
Gson gson();
}
package me.jessyan.mvparms.demo.di.component;
import com.jess.arms.di.scope.ActivityScope;
import dagger.Component;
import me.jessyan.mvparms.demo.di.module.UserModule;
import me.jessyan.mvparms.demo.mvp.ui.activity.UserActivity;
/**
* Created by jess on 9/4/16 11:17
* Contact with jess.yan.effort@gmail.com
*/
@ActivityScope
@Component(modules = UserModule.class,dependencies = AppComponent.class)
public interface UserComponent {
void inject(UserActivity activity);
}
package me.jessyan.mvparms.demo.di.module;
import com.jess.arms.di.scope.ActivityScope;
import dagger.Module;
import dagger.Provides;
import me.jessyan.mvparms.demo.mvp.contract.UserContract;
import me.jessyan.mvparms.demo.mvp.model.UserModel;
import me.jessyan.mvparms.demo.mvp.model.api.cache.CacheManager;
import me.jessyan.mvparms.demo.mvp.model.api.service.ServiceManager;
/**
* Created by jess on 9/4/16 11:10
* Contact with jess.yan.effort@gmail.com
*/
@Module
public class UserModule {
private UserContract.View view;
public UserModule(UserContract.View view) {
this.view = view;
}
@ActivityScope
@Provides
UserContract.View provideUserView(){
return this.view;
}
@ActivityScope
@Provides
UserContract.Model provideUserModel(ServiceManager serviceManager, CacheManager cacheManager){
return new UserModel(serviceManager,cacheManager);
}
}
package me.jessyan.mvparms.demo.mvp.contract;
import com.jess.arms.base.DefaultAdapter;
import com.jess.arms.mvp.BaseView;
import java.util.List;
import me.jessyan.mvparms.demo.mvp.model.entity.User;
import rx.Observable;
/**
* Created by jess on 9/4/16 10:47
* Contact with jess.yan.effort@gmail.com
*/
public interface UserContract {
interface View extends BaseView {
void setAdapter(DefaultAdapter adapter);
void startLoadMore();
void endLoadMore();
}
interface Model {
Observable<List<User>> getUsers(int lastIdQueried, boolean update);
}
}
package me.jessyan.mvparms.demo.mvp.model;
import com.jess.arms.mvp.BaseModel;
import java.util.List;
import io.rx_cache.DynamicKey;
import io.rx_cache.EvictDynamicKey;
import io.rx_cache.Reply;
import me.jessyan.mvparms.demo.mvp.contract.UserContract;
import me.jessyan.mvparms.demo.mvp.model.api.cache.CacheManager;
import me.jessyan.mvparms.demo.mvp.model.api.cache.CommonCache;
import me.jessyan.mvparms.demo.mvp.model.api.service.CommonService;
import me.jessyan.mvparms.demo.mvp.model.api.service.ServiceManager;
import me.jessyan.mvparms.demo.mvp.model.entity.User;
import rx.Observable;
import rx.functions.Func1;
/**
* Created by jess on 9/4/16 10:56
* Contact with jess.yan.effort@gmail.com
*/
public class UserModel extends BaseModel<ServiceManager,CacheManager> implements UserContract.Model{
public static final int USERS_PER_PAGE = 10;
private CommonService mCommonService;
private CommonCache mCommonCache;
public UserModel(ServiceManager serviceManager, CacheManager cacheManager) {
super(serviceManager, cacheManager);
this.mCommonService = mServiceManager.getCommonService();
this.mCommonCache = mCacheManager.getCommonCache();
}
@Override
public Observable<List<User>> getUsers(int lastIdQueried, boolean update) {
Observable<List<User>> users = mCommonService
.getUsers(lastIdQueried, USERS_PER_PAGE);
//使用rxcache缓存,上拉刷新则不读取缓存,加载更多读取缓存
return mCommonCache
.getUsers(users
,new DynamicKey(lastIdQueried)
,new EvictDynamicKey(update))
.flatMap(new Func1<Reply<List<User>>, Observable<List<User>>>() {
@Override
public Observable<List<User>> call(Reply<List<User>> listReply) {
return Observable.just(listReply.getData());
}
});
}
}
......@@ -5,5 +5,5 @@ package me.jessyan.mvparms.demo.mvp.model.api;
* contact with jess.yan.effort@gmail.com
*/
public interface Api {
public static final String APP_DOMAIN = "http://baobab.wandoujia.com";
public static final String APP_DOMAIN = "https://api.github.com";
}
package me.jessyan.mvparms.demo.mvp.model.api.cache;
import java.util.List;
import java.util.concurrent.TimeUnit;
import io.rx_cache.DynamicKey;
import io.rx_cache.EvictProvider;
import io.rx_cache.LifeCache;
import io.rx_cache.Reply;
import me.jessyan.mvparms.demo.mvp.model.entity.FindDetailEntity;
import me.jessyan.mvparms.demo.mvp.model.entity.FindMoreEntity;
import me.jessyan.mvparms.demo.mvp.model.entity.HomePicEntity;
import me.jessyan.mvparms.demo.mvp.model.entity.HotStrategyEntity;
import me.jessyan.mvparms.demo.mvp.model.entity.User;
import rx.Observable;
/**
......@@ -18,17 +16,22 @@ import rx.Observable;
*/
public interface CommonCache {
@LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)
Observable<Reply<HomePicEntity>> getDailyList(Observable<HomePicEntity> service, DynamicKey publishTime, EvictProvider provider);
@LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)
Observable<Reply<FindMoreEntity>> getFindMore(Observable<FindMoreEntity> service, DynamicKey id, EvictProvider provider);
@LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)
Observable<Reply<HotStrategyEntity>> getHotStrategy(Observable<HotStrategyEntity> service, DynamicKey id, EvictProvider provider);
@LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)
Observable<Reply<FindDetailEntity>> getFindDetail(Observable<FindDetailEntity> service, DynamicKey id, EvictProvider provider);
Observable<Reply<List<User>>> getUsers(Observable<List<User>> oUsers, DynamicKey idLastUserQueried, EvictProvider evictProvider);
// @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)
// Observable<Reply<HomePicEntity>> getDailyList(Observable<HomePicEntity> service, DynamicKey publishTime, EvictProvider provider);
//
// @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)
// Observable<Reply<FindMoreEntity>> getFindMore(Observable<FindMoreEntity> service, DynamicKey id, EvictProvider provider);
//
//
// @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)
// Observable<Reply<HotStrategyEntity>> getHotStrategy(Observable<HotStrategyEntity> service, DynamicKey id, EvictProvider provider);
//
//
// @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)
// Observable<Reply<FindDetailEntity>> getFindDetail(Observable<FindDetailEntity> service, DynamicKey id, EvictProvider provider);
}
package me.jessyan.mvparms.demo.mvp.model.api.service;
import me.jessyan.mvparms.demo.mvp.model.entity.FindDetailEntity;
import me.jessyan.mvparms.demo.mvp.model.entity.FindMoreEntity;
import me.jessyan.mvparms.demo.mvp.model.entity.HomePicEntity;
import me.jessyan.mvparms.demo.mvp.model.entity.HotStrategyEntity;
import java.util.List;
import me.jessyan.mvparms.demo.mvp.model.entity.User;
import retrofit2.http.GET;
import retrofit2.http.Headers;
import retrofit2.http.Query;
import rx.Observable;
/**
......@@ -13,15 +14,22 @@ import rx.Observable;
*/
public interface CommonService {
@GET("/api/v2/feed?num=2&udid=26868b32e808498db32fd51fb422d00175e179df&vc=83")
Observable<HomePicEntity> getDailyList();
String HEADER_API_VERSION = "Accept: application/vnd.github.v3+json";
@GET("/api/v2/categories?udid=26868b32e808498db32fd51fb422d00175e179df&vc=83")
Observable<FindMoreEntity> getFindMore();
@Headers({HEADER_API_VERSION})
@GET("/users")
Observable<List<User>> getUsers(@Query("since") int lastIdQueried, @Query("per_page") int perPage);
@GET("/api/v3/ranklist?num=10&strategy=%s&udid=26868b32e808498db32fd51fb422d00175e179df&vc=83")
Observable<HotStrategyEntity> getHotStrategy();
@GET("/api/v3/videos?categoryName=%s&strategy=%s&udid=26868b32e808498db32fd51fb422d00175e179df&vc=83")
Observable<FindDetailEntity> getFindDetail();
// @GET("/api/v2/feed?num=2&udid=26868b32e808498db32fd51fb422d00175e179df&vc=83")
// Observable<HomePicEntity> getDailyList();
//
// @GET("/api/v2/categories?udid=26868b32e808498db32fd51fb422d00175e179df&vc=83")
// Observable<FindMoreEntity> getFindMore();
//
// @GET("/api/v3/ranklist?num=10&strategy=%s&udid=26868b32e808498db32fd51fb422d00175e179df&vc=83")
// Observable<HotStrategyEntity> getHotStrategy();
//
// @GET("/api/v3/videos?categoryName=%s&strategy=%s&udid=26868b32e808498db32fd51fb422d00175e179df&vc=83")
// Observable<FindDetailEntity> getFindDetail();
}
package me.jessyan.mvparms.demo.mvp.model.entity;
/**
* Created by xhb on 2016/3/2.
* 发现更多实体类
*/
public class FindMoreEntity {
/**
* id : 2
* name : 创意
* alias : null
* bgPicture : http://img.wdjimg.com/image/video/e8f7e96c58348e4dd6daede64721d02d_0_0.jpeg
* bgColor :
*/
private int id;
private String name;
private Object alias;
private String bgPicture;
private String bgColor;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAlias(Object alias) {
this.alias = alias;
}
public void setBgPicture(String bgPicture) {
this.bgPicture = bgPicture;
}
public void setBgColor(String bgColor) {
this.bgColor = bgColor;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public Object getAlias() {
return alias;
}
public String getBgPicture() {
return bgPicture;
}
public String getBgColor() {
return bgColor;
}
}
package me.jessyan.mvparms.demo.mvp.model.entity;
public class User {
private final int id;
private final String login;
private final String avatar_url;
public User(int id, String login, String avatar_url) {
this.id = id;
this.login = login;
this.avatar_url = avatar_url;
}
public String getAvatarUrl() {
if (avatar_url.isEmpty()) return avatar_url;
return avatar_url.split("\\?")[0];
}
public int getId() {
return id;
}
public String getLogin() {
return login;
}
@Override public String toString() {
return "id -> " + id + " login -> " + login;
}
}
package me.jessyan.mvparms.demo.mvp.presenter;
import com.jess.arms.base.BaseActivity;
import com.jess.arms.base.DefaultAdapter;
import com.jess.arms.di.scope.ActivityScope;
import com.jess.arms.mvp.BasePresenter;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import me.jessyan.mvparms.demo.mvp.contract.UserContract;
import me.jessyan.mvparms.demo.mvp.model.entity.User;
import me.jessyan.mvparms.demo.mvp.ui.adapter.UserAdapter;
import me.jessyan.rxerrorhandler.core.RxErrorHandler;
import me.jessyan.rxerrorhandler.handler.ErrorHandleSubscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action0;
import rx.schedulers.Schedulers;
/**
* Created by jess on 9/4/16 10:59
* Contact with jess.yan.effort@gmail.com
*/
@ActivityScope
public class UserPresenter extends BasePresenter<UserContract.Model, UserContract.View> {
private RxErrorHandler mErrorHandler;
private List<User> mUsers = new ArrayList<>();
private DefaultAdapter mAdapter;
private int lastUserId = 1;
@Inject
public UserPresenter(UserContract.Model model, UserContract.View rootView, RxErrorHandler handler) {
super(model, rootView);
this.mErrorHandler = handler;
mAdapter = new UserAdapter(mUsers);
mRootView.setAdapter(mAdapter);//设置Adapter
}
public void requestUsers(final boolean pullToRefresh) {
if (pullToRefresh) lastUserId = 1;
mModel.getUsers(lastUserId, pullToRefresh)
.subscribeOn(Schedulers.io())
.doOnSubscribe(new Action0() {
@Override
public void call() {
if (pullToRefresh)
mRootView.showLoading();//显示上拉刷新的进度条
else
mRootView.startLoadMore();
}
}).subscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread())
.doAfterTerminate(new Action0() {
@Override
public void call() {
if (pullToRefresh)
mRootView.hideLoading();//隐藏上拉刷新的进度条
else
mRootView.endLoadMore();
}
})
.compose(((BaseActivity)mRootView).<List<User>>bindToLifecycle())//使用RXlifecycle,使subscription和activity一起销毁
.subscribe(new ErrorHandleSubscriber<List<User>>(mErrorHandler) {
@Override
public void onNext(List<User> users) {
lastUserId = users.get(users.size() - 1).getId();//记录最后一个id,用于下一次请求
if (pullToRefresh) mUsers.clear();//如果是上拉刷新则晴空列表
for (User user : users) {
mUsers.add(user);
}
mAdapter.notifyDataSetChanged();//通知更新数据
}
});
}
}
package me.jessyan.mvparms.demo.mvp.ui.activity;
import android.view.LayoutInflater;
import android.view.View;
import com.jess.arms.utils.UiUtils;
import io.rx_cache.DynamicKey;
import io.rx_cache.EvictDynamicKey;
import io.rx_cache.Reply;
import me.jessyan.mvparms.demo.R;
import me.jessyan.mvparms.demo.di.component.AppComponent;
import me.jessyan.mvparms.demo.mvp.model.entity.HomePicEntity;
import me.jessyan.mvparms.demo.mvp.ui.common.WEActivity;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
import timber.log.Timber;
public class MainActivity extends WEActivity {
@Override
protected void setupActivityComponent(AppComponent appComponent) {
appComponent
.cacheManager()
.getCommonCache()
.getDailyList(appComponent
.serviceManager()
.getCommonService()
.getDailyList(),new DynamicKey("15"),new EvictDynamicKey(true))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(this.<Reply<HomePicEntity>>bindToLifecycle())
.subscribe(new Action1<Reply<HomePicEntity>>() {
@Override
public void call(Reply<HomePicEntity> homePicEntityReply) {
UiUtils.makeText(homePicEntityReply.getData().getIssueList().get(0).getPublishTime()+"/"+homePicEntityReply.getSource().name());
Timber.tag(TAG).w(homePicEntityReply.getData().getIssueList().get(0).getPublishTime()+"");
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
}
});
}
@Override
protected View initView() {
return LayoutInflater.from(this).inflate(R.layout.activity_main,null,false);
}
@Override
protected void initData() {
}
}
package me.jessyan.mvparms.demo.mvp.ui.activity;
import android.content.Intent;
import android.support.annotation.Nullable;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import com.jess.arms.base.DefaultAdapter;
import com.jess.arms.utils.UiUtils;
import com.paginate.Paginate;
import butterknife.Bind;
import me.jessyan.mvparms.demo.R;
import me.jessyan.mvparms.demo.di.component.AppComponent;
import me.jessyan.mvparms.demo.di.component.DaggerUserComponent;
import me.jessyan.mvparms.demo.di.module.UserModule;
import me.jessyan.mvparms.demo.mvp.contract.UserContract;
import me.jessyan.mvparms.demo.mvp.presenter.UserPresenter;
import me.jessyan.mvparms.demo.mvp.ui.common.WEActivity;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import timber.log.Timber;
public class UserActivity extends WEActivity<UserPresenter> implements UserContract.View, SwipeRefreshLayout.OnRefreshListener {
@Nullable
@Bind(R.id.recyclerView)
RecyclerView mRecyclerView;
@Nullable
@Bind(R.id.SwipeRefreshLayout)
SwipeRefreshLayout mSwipeRefreshLayout;
private Paginate mPaginate;
private boolean isLoadingMore;
@Override
protected void setupActivityComponent(AppComponent appComponent) {
DaggerUserComponent
.builder()
.appComponent(appComponent)
.userModule(new UserModule(this))
.build()
.inject(this);
}
@Override
protected View initView() {
return LayoutInflater.from(this).inflate(R.layout.activity_user, null, false);
}
@Override
protected void initData() {
mPresenter.requestUsers(true);//打开app时自动加载列表
}
@Override
public void onRefresh() {
mPresenter.requestUsers(true);
}
/**
* 初始化RecycleView
*/
private void initRecycleView() {
mSwipeRefreshLayout.setOnRefreshListener(this);
configRecycleView(mRecyclerView, new GridLayoutManager(this, 2));
}
/**
* 配置recycleview
*
* @param recyclerView
* @param layoutManager
*/
private void configRecycleView(RecyclerView recyclerView
, RecyclerView.LayoutManager layoutManager
) {
recyclerView.setLayoutManager(layoutManager);
//如果可以确定每个item的高度是固定的,设置这个选项可以提高性能
recyclerView.setHasFixedSize(true);
recyclerView.setItemAnimator(new DefaultItemAnimator());
}
@Override
public void showLoading() {
Timber.tag(TAG).w("showLoading");
Observable.just(1)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
mSwipeRefreshLayout.setRefreshing(true);
}
});
}
@Override
public void hideLoading() {
Timber.tag(TAG).w("hideLoading");
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void showMessage(String message) {
UiUtils.SnackbarText(message);
}
@Override
public void launchActivity(Intent intent) {
}
@Override
public void killMyself() {
}
@Override
public void setAdapter(DefaultAdapter adapter) {
mRecyclerView.setAdapter(adapter);
initRecycleView();
initPaginate();
}
/**
* 开始加载更多
*/
@Override
public void startLoadMore() {
isLoadingMore = true;
}
/**
* 介绍加载更多
*/
@Override
public void endLoadMore() {
isLoadingMore = false;
}
/**
* 初始化Paginate,用于加载更多
*/
private void initPaginate() {
if (mPaginate == null) {
Paginate.Callbacks callbacks = new Paginate.Callbacks() {
@Override
public void onLoadMore() {
mPresenter.requestUsers(false);
}
@Override
public boolean isLoading() {
return isLoadingMore;
}
@Override
public boolean hasLoadedAllItems() {
return false;
}
};
mPaginate = Paginate.with(mRecyclerView, callbacks)
.setLoadingTriggerThreshold(0)
.build();
mPaginate.setHasMoreDataToLoad(false);
}
}
}
package me.jessyan.mvparms.demo.mvp.ui.adapter;
import android.view.View;
import com.jess.arms.base.BaseHolder;
import com.jess.arms.base.DefaultAdapter;
import java.util.List;
import me.jessyan.mvparms.demo.R;
import me.jessyan.mvparms.demo.mvp.model.entity.User;
import me.jessyan.mvparms.demo.mvp.ui.holder.UserItemHolder;
/**
* Created by jess on 9/4/16 12:57
* Contact with jess.yan.effort@gmail.com
*/
public class UserAdapter extends DefaultAdapter<User> {
public UserAdapter(List<User> infos) {
super(infos);
}
@Override
public BaseHolder<User> getHolder(View v) {
return new UserItemHolder(v);
}
@Override
public int getLayoutId() {
return R.layout.recycle_list;
}
}
package me.jessyan.mvparms.demo.mvp.ui.holder;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.jakewharton.rxbinding.widget.RxTextView;
import com.jess.arms.base.BaseHolder;
import com.jess.arms.widget.imageloader.ImageLoader;
import com.jess.arms.widget.imageloader.glide.GlideImageConfig;
import butterknife.Bind;
import me.jessyan.mvparms.demo.R;
import me.jessyan.mvparms.demo.app.WEApplication;
import me.jessyan.mvparms.demo.mvp.model.entity.User;
import rx.Observable;
/**
* Created by jess on 9/4/16 12:56
* Contact with jess.yan.effort@gmail.com
*/
public class UserItemHolder extends BaseHolder<User> {
@Nullable
@Bind(R.id.iv_avatar)
ImageView mAvater;
@Nullable
@Bind(R.id.tv_name)
TextView mName;
private ImageLoader mImageLoader;//用于加载图片的管理类,默认使用glide,使用策略模式,可替换框架
private final WEApplication mApplication;
public UserItemHolder(View itemView) {
super(itemView);
mApplication = (WEApplication) itemView.getContext().getApplicationContext();
mImageLoader = mApplication.getAppComponent().imageLoader();
}
@Override
public void setData(User data) {
Observable.just(data.getLogin())
.subscribe(RxTextView.text(mName));
mImageLoader.loadImage(mApplication, GlideImageConfig
.builder()
.url(data.getAvatarUrl())
.imagerView(mAvater)
.build());
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="me.jessyan.mvparms.demo.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/SwipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="15px"
android:paddingLeft="15px"
>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
tools:listitem="@layout/recycle_list"
/>
</android.support.v4.widget.SwipeRefreshLayout>
<?xml version="1.0" encoding="utf-8"?>
<com.jess.arms.widget.autolayout.AutoCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="550px"
android:layout_marginRight="15px"
android:layout_marginBottom="15px"
>
<ImageView
android:id="@+id/iv_avatar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
tools:src="#000000" />
<TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="10px"
android:textColor="@color/white"
android:textSize="40px"
tools:text="ss" />
</com.jess.arms.widget.autolayout.AutoCardView>
\ No newline at end of file
......@@ -3,4 +3,5 @@
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="white">#FFFFFF</color>
</resources>
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
......
apply plugin: 'com.android.library'
apply plugin: 'com.neenbedankt.android-apt'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
compileSdkVersion rootProject.ext.android["compileSdkVersion"]
buildToolsVersion rootProject.ext.android["buildToolsVersion"]
useLibrary 'org.apache.http.legacy'
defaultConfig {
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
minSdkVersion rootProject.ext.android["minSdkVersion"]
targetSdkVersion rootProject.ext.android["targetSdkVersion"]
versionCode rootProject.ext.android["versionCode"]
versionName rootProject.ext.android["versionName"]
}
buildTypes {
release {
......@@ -36,6 +37,7 @@ dependencies {
compile rootProject.ext.dependencies["support-v4"]
compile rootProject.ext.dependencies["gson"]
compile rootProject.ext.dependencies["appcompat-v7"]
compile rootProject.ext.dependencies["cardview-v7"]
compile rootProject.ext.dependencies["autolayout"]
compile rootProject.ext.dependencies["butterknife"]
compile rootProject.ext.dependencies["androideventbus"]
......@@ -60,4 +62,5 @@ dependencies {
releaseCompile rootProject.ext.dependencies["canary-release"]
testCompile rootProject.ext.dependencies["canary-release"]
apt rootProject.ext.dependencies["dagger2-apt-compiler"]
compile project(':rxerrorhandler')
}
......@@ -12,6 +12,7 @@ import com.squareup.leakcanary.LeakCanary;
import java.util.LinkedList;
import me.jessyan.rxerrorhandler.handler.listener.ResponseErroListener;
import okhttp3.Interceptor;
import timber.log.Timber;
......@@ -41,7 +42,8 @@ public abstract class BaseApplication extends Application {
.buidler()
.baseurl(getBaseUrl())
.globeHttpResultHandler(getHttpResultHandler())
.Interceptors(getInterceptors())
.interceptors(getInterceptors())
.responseErroListener(getResponseErroListener())
.build();
this.mAppModule = new AppModule(this);//提供application
this.mImagerModule = new ImageModule();//图片加载框架默认使用glide
......@@ -56,11 +58,17 @@ public abstract class BaseApplication extends Application {
/**
* 提供基础url给retrofit
*
* @return
*/
protected abstract String getBaseUrl();
/**
* 返回一个存储所有存在的activity的列表
*
* @return
*/
public LinkedList<BaseActivity> getActivityList() {
if (mActivityList == null) {
mActivityList = new LinkedList<BaseActivity>();
......@@ -95,6 +103,7 @@ public abstract class BaseApplication extends Application {
/**
* 用来提供interceptor,如果要提供额外的interceptor可以让子application实现此方法
*
* @return
*/
protected Interceptor[] getInterceptors() {
......@@ -102,6 +111,21 @@ public abstract class BaseApplication extends Application {
}
/**
* 用来提供处理所有错误的监听
* 如果要使用ErrorHandleSubscriber(默认实现Subscriber的onError方法)
* 则让子application重写此方法
* @return
*/
protected ResponseErroListener getResponseErroListener() {
return new ResponseErroListener() {
@Override
public void handleResponseError(Context context, Exception e) {
}
};
}
/**
* 返回上下文
*
......
......@@ -2,6 +2,8 @@ package com.jess.arms.di.module;
import android.app.Application;
import com.google.gson.Gson;
import javax.inject.Singleton;
import dagger.Module;
......@@ -23,4 +25,8 @@ public class AppModule {
public Application provideApplication() {
return mApplication;
}
@Singleton
@Provides
public Gson provideGson(){return new Gson();}
}
......@@ -15,6 +15,8 @@ import dagger.Module;
import dagger.Provides;
import io.rx_cache.internal.RxCache;
import io.victoralbertos.jolyglot.GsonSpeaker;
import me.jessyan.rxerrorhandler.core.RxErrorHandler;
import me.jessyan.rxerrorhandler.handler.listener.ResponseErroListener;
import okhttp3.Cache;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
......@@ -34,6 +36,7 @@ public class ClientModule {
private HttpUrl mApiUrl;
private GlobeHttpResultHandler mHandler;
private Interceptor[] mInterceptors;
private ResponseErroListener mErroListener;
/**
* @author: jess
......@@ -44,6 +47,7 @@ public class ClientModule {
this.mApiUrl = buidler.apiUrl;
this.mHandler = buidler.handler;
this.mInterceptors = buidler.interceptors;
this.mErroListener = buidler.responseErroListener;
}
public static Buidler buidler() {
......@@ -124,6 +128,22 @@ public class ClientModule {
.persistence(cacheDir, new GsonSpeaker());
}
/**
* 提供处理Rxjava处理的管理器
*
* @return
*/
@Singleton
@Provides
RxErrorHandler proRxErrorHandler(Application application) {
return RxErrorHandler
.builder()
.with(application)
.responseErroListener(mErroListener)
.build();
}
/**
* @param builder
* @param client
......@@ -175,6 +195,7 @@ public class ClientModule {
private HttpUrl apiUrl = HttpUrl.parse("https://api.github.com/");
private GlobeHttpResultHandler handler;
private Interceptor[] interceptors;
private ResponseErroListener responseErroListener;
private Buidler() {
}
......@@ -189,11 +210,16 @@ public class ClientModule {
return this;
}
public Buidler Interceptors(Interceptor[] interceptors) {//动态添加任意个interceptor
public Buidler interceptors(Interceptor[] interceptors) {//动态添加任意个interceptor
this.interceptors = interceptors;
return this;
}
public Buidler responseErroListener(ResponseErroListener listener) {//处理所有Rxjava的onError逻辑
this.responseErroListener = listener;
return this;
}
public ClientModule build() {
if (apiUrl == null) {
......
package com.jess.arms.http;
import okhttp3.Interceptor;
import okhttp3.Response;
/**
* Created by jess on 8/30/16 17:47
* Contact with jess.yan.effort@gmail.com
*/
public interface GlobeHttpResultHandler {
void onHttpResultResponse(String httpResult);
Response onHttpResultResponse(String httpResult, Interceptor.Chain chain, Response response);
}
package com.jess.arms.http;
import com.jess.arms.utils.ZipHelper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
......@@ -50,17 +53,42 @@ public class RequestIntercept implements Interceptor {
BufferedSource source = responseBody.source();
source.request(Long.MAX_VALUE); // Buffer the entire body.
Buffer buffer = source.buffer();
Charset charset = Charset.forName("UTF-8");
MediaType contentType = responseBody.contentType();
if (contentType != null) {
charset = contentType.charset(charset);
//获取content的压缩类型
String encoding = originalResponse
.headers()
.get("Content-Encoding");
Buffer clone = buffer.clone();
String bodyString;
//解析response content
if (encoding != null && encoding.equalsIgnoreCase("gzip")) {//content使用gzip压缩
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
clone.writeTo(outputStream);
byte[] bytes = outputStream.toByteArray();
bodyString = ZipHelper.decompressForGzip(bytes);//解压
outputStream.close();
} else if (encoding != null && encoding.equalsIgnoreCase("zlib")) {//content使用zlib压缩
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
clone.writeTo(outputStream);
byte[] bytes = outputStream.toByteArray();
bodyString = ZipHelper.decompressToStringForZlib(bytes);//解压
outputStream.close();
} else {//content没有被压缩
Charset charset = Charset.forName("UTF-8");
MediaType contentType = responseBody.contentType();
if (contentType != null) {
charset = contentType.charset(charset);
}
bodyString = clone.readString(charset);
}
String bodyString = buffer.clone().readString(charset);
Timber.tag("Response").w("Body------>" + bodyString);
if (mHandler!=null)//这里可以比客户端提前一步拿到服务器返回的结果,可以做一些操作,比如token超时,重新获取
mHandler.onHttpResultResponse(bodyString);
Timber.tag("Result").w("Body------>" + bodyString);
if (mHandler != null)//这里可以比客户端提前一步拿到服务器返回的结果,可以做一些操作,比如token超时,重新获取
return mHandler.onHttpResultResponse(bodyString,chain,originalResponse);
return originalResponse;
}
......
......@@ -8,7 +8,7 @@ import rx.subscriptions.CompositeSubscription;
/**
* Created by jess on 16/4/28.
*/
public class BasePresenter<M extends BaseModel, V extends BaseView> implements presenter {
public class BasePresenter<M, V extends BaseView> implements presenter {
protected final String TAG = this.getClass().getSimpleName();
protected CompositeSubscription mCompositeSubscription;
......@@ -41,7 +41,6 @@ public class BasePresenter<M extends BaseModel, V extends BaseView> implements p
public void onDestroy() {
EventBus.getDefault().unregister(this);//解除注册eventbus
unSubscribe();//解除订阅
mModel.onDestory();//释放资源
this.mModel = null;
this.mRootView = null;
}
......
package com.jess.arms.utils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import java.util.zip.Inflater;
/**
* Created by jess on 16/5/10.
*/
public class ZipHelper {
/**
* zlib decompress 2 String
*
* @param bytesToDecompress
* @return
*/
public static String decompressToStringForZlib(byte[] bytesToDecompress) {
byte[] bytesDecompressed = decompressForZlib
(
bytesToDecompress
);
String returnValue = null;
try {
returnValue = new String
(
bytesDecompressed,
0,
bytesDecompressed.length,
"UTF-8"
);
} catch (UnsupportedEncodingException uee) {
uee.printStackTrace();
}
return returnValue;
}
/**
* zlib decompress 2 byte
*
* @param bytesToDecompress
* @return
*/
public static byte[] decompressForZlib(byte[] bytesToDecompress) {
byte[] returnValues = null;
Inflater inflater = new Inflater();
int numberOfBytesToDecompress = bytesToDecompress.length;
inflater.setInput
(
bytesToDecompress,
0,
numberOfBytesToDecompress
);
int bufferSizeInBytes = numberOfBytesToDecompress;
int numberOfBytesDecompressedSoFar = 0;
List<Byte> bytesDecompressedSoFar = new ArrayList<Byte>();
try {
while (inflater.needsInput() == false) {
byte[] bytesDecompressedBuffer = new byte[bufferSizeInBytes];
int numberOfBytesDecompressedThisTime = inflater.inflate
(
bytesDecompressedBuffer
);
numberOfBytesDecompressedSoFar += numberOfBytesDecompressedThisTime;
for (int b = 0; b < numberOfBytesDecompressedThisTime; b++) {
bytesDecompressedSoFar.add(bytesDecompressedBuffer[b]);
}
}
returnValues = new byte[bytesDecompressedSoFar.size()];
for (int b = 0; b < returnValues.length; b++) {
returnValues[b] = (byte) (bytesDecompressedSoFar.get(b));
}
} catch (DataFormatException dfe) {
dfe.printStackTrace();
}
inflater.end();
return returnValues;
}
/**
* zlib compress 2 byte
*
* @param bytesToCompress
* @return
*/
public static byte[] compressForZlib(byte[] bytesToCompress) {
Deflater deflater = new Deflater();
deflater.setInput(bytesToCompress);
deflater.finish();
byte[] bytesCompressed = new byte[Short.MAX_VALUE];
int numberOfBytesAfterCompression = deflater.deflate(bytesCompressed);
byte[] returnValues = new byte[numberOfBytesAfterCompression];
System.arraycopy
(
bytesCompressed,
0,
returnValues,
0,
numberOfBytesAfterCompression
);
return returnValues;
}
/**
* zlib compress 2 byte
*
* @param stringToCompress
* @return
*/
public static byte[] compressForZlib(String stringToCompress) {
byte[] returnValues = null;
try {
returnValues = compressForZlib
(
stringToCompress.getBytes("UTF-8")
);
} catch (UnsupportedEncodingException uee) {
uee.printStackTrace();
}
return returnValues;
}
/**
* gzip compress 2 byte
*
* @param string
* @return
* @throws IOException
*/
public static byte[] compressForGzip(String string) {
ByteArrayOutputStream os = null;
GZIPOutputStream gos = null;
try {
os = new ByteArrayOutputStream(string.length());
gos = new GZIPOutputStream(os);
gos.write(string.getBytes("UTF-8"));
byte[] compressed = os.toByteArray();
return compressed;
} catch (IOException e) {
e.printStackTrace();
} finally {
okhttp3.internal.Util.closeQuietly(gos);
okhttp3.internal.Util.closeQuietly(os);
}
return null;
}
/**
* gzip decompress 2 string
*
* @param compressed
* @return
* @throws IOException
*/
public static String decompressForGzip(byte[] compressed) {
final int BUFFER_SIZE = compressed.length;
GZIPInputStream gis = null;
ByteArrayInputStream is = null;
try {
is = new ByteArrayInputStream(compressed);
gis = new GZIPInputStream(is, BUFFER_SIZE);
StringBuilder string = new StringBuilder();
byte[] data = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = gis.read(data)) != -1) {
string.append(new String(data, 0, bytesRead, "UTF-8"));
}
return string.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
okhttp3.internal.Util.closeQuietly(gis);
okhttp3.internal.Util.closeQuietly(is);
}
return null;
}
}
package com.jess.arms.widget;
import android.content.Context;
import android.support.design.widget.TabLayout;
import android.util.AttributeSet;
import android.view.ViewGroup;
import com.zhy.autolayout.AutoLayoutInfo;
import com.zhy.autolayout.utils.AutoLayoutHelper;
/**
* Created by jess on 16/4/14.
*/
public class AutoTabLayout extends TabLayout {
private AutoLayoutHelper mHelper = new AutoLayoutHelper(this);
public AutoTabLayout(Context context) {
super(context);
}
public AutoTabLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (!isInEditMode())
mHelper.adjustChildren();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
super.onLayout(changed, l, t, r, b);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new AutoTabLayout.LayoutParams(getContext(), attrs);
}
public static class LayoutParams extends TabLayout.LayoutParams
implements AutoLayoutHelper.AutoLayoutParams
{
private AutoLayoutInfo mAutoLayoutInfo;
public LayoutParams(Context c, AttributeSet attrs)
{
super(c, attrs);
mAutoLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs);
}
@Override
public AutoLayoutInfo getAutoLayoutInfo()
{
return mAutoLayoutInfo;
}
public LayoutParams(int width, int height)
{
super(width, height);
}
public LayoutParams(ViewGroup.LayoutParams source)
{
super(source);
}
public LayoutParams(MarginLayoutParams source)
{
super(source);
}
}
}
package com.jess.arms.widget;
package com.jess.arms.widget.autolayout;
import android.content.Context;
import android.support.design.widget.AppBarLayout;
......
package com.jess.arms.widget.autolayout;
import android.content.Context;
import android.support.v7.widget.CardView;
import android.util.AttributeSet;
import com.zhy.autolayout.AutoFrameLayout;
import com.zhy.autolayout.utils.AutoLayoutHelper;
/**
* Created by jess on 9/3/16 21:40
* Contact with jess.yan.effort@gmail.com
*/
public class AutoCardView extends CardView
{
private final AutoLayoutHelper mHelper = new AutoLayoutHelper(this);
public AutoCardView(Context context)
{
super(context);
}
public AutoCardView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public AutoCardView(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
}
@Override
public AutoFrameLayout.LayoutParams generateLayoutParams(AttributeSet attrs)
{
return new AutoFrameLayout.LayoutParams(getContext(), attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (!isInEditMode())
{
mHelper.adjustChildren();
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
\ No newline at end of file
package com.jess.arms.widget;
package com.jess.arms.widget.autolayout;
import android.content.Context;
import android.support.design.widget.CollapsingToolbarLayout;
......
package com.jess.arms.widget.autolayout;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.design.widget.TabLayout;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.widget.TextView;
import com.jess.arms.R;
import com.zhy.autolayout.utils.AutoUtils;
import com.zhy.autolayout.utils.DimenUtils;
/**
* Created by jess on 16/4/14.
*/
public class AutoTabLayout extends TabLayout
{
private static final int NO_VALID = -1;
private int mTextSize;
private boolean mTextSizeBaseWidth = false;
public AutoTabLayout(Context context)
{
this(context, null);
}
public AutoTabLayout(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public AutoTabLayout(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
initTextSizeBaseWidth(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabLayout,
defStyleAttr, R.style.Widget_Design_TabLayout);
int tabTextAppearance = a.getResourceId(R.styleable.TabLayout_tabTextAppearance,
R.style.TextAppearance_Design_Tab);
mTextSize = loadTextSizeFromTextAppearance(tabTextAppearance);
a.recycle();
}
private void initTextSizeBaseWidth(Context context, AttributeSet attrs)
{
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoTabLayout);
mTextSizeBaseWidth = a.getBoolean(R.styleable.AutoTabLayout_auto_textSize_base_width, false);
a.recycle();
}
private int loadTextSizeFromTextAppearance(int textAppearanceResId)
{
TypedArray a = getContext().obtainStyledAttributes(textAppearanceResId,
R.styleable.TextAppearance);
try
{
if (!DimenUtils.isPxVal(a.peekValue(R.styleable.TextAppearance_android_textSize)))
return NO_VALID;
return a.getDimensionPixelSize(R.styleable.TextAppearance_android_textSize, NO_VALID);
} finally
{
a.recycle();
}
}
@Override
public void addTab(Tab tab, int position, boolean setSelected)
{
super.addTab(tab, position, setSelected);
setUpTabTextSize(tab);
}
@Override
public void addTab(Tab tab, boolean setSelected)
{
super.addTab(tab, setSelected);
setUpTabTextSize(tab);
}
private void setUpTabTextSize(Tab tab)
{
if (mTextSize == NO_VALID || tab.getCustomView() != null) return;
ViewGroup tabGroup = (ViewGroup) getChildAt(0);
ViewGroup tabContainer = (ViewGroup) tabGroup.getChildAt(tab.getPosition());
TextView textView = (TextView) tabContainer.getChildAt(1);
if (AutoUtils.autoed(textView))
{
return;
}
int autoTextSize = 0 ;
if (mTextSizeBaseWidth)
{
autoTextSize = AutoUtils.getPercentWidthSize(mTextSize);
} else
{
autoTextSize = AutoUtils.getPercentHeightSize(mTextSize);
}
textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, autoTextSize);
}
}
package com.jess.arms.widget;
package com.jess.arms.widget.autolayout;
import android.content.Context;
import android.support.annotation.Nullable;
......
......@@ -11,6 +11,7 @@ public class ImageConfig {
protected String url;
protected ImageView imageView;
protected int placeholder;
protected int errorPic;
public String getUrl() {
......@@ -25,4 +26,7 @@ public class ImageConfig {
return placeholder;
}
public int getErrorPic() {
return errorPic;
}
}
......@@ -15,6 +15,7 @@ public class GlideImageConfig extends ImageConfig{
this.url = builder.url;
this.imageView = builder.imageView;
this.placeholder = builder.placeholder;
this.errorPic = builder.errorPic;
}
public static Buidler builder() {
......@@ -26,6 +27,7 @@ public class GlideImageConfig extends ImageConfig{
private String url;
private ImageView imageView;
private int placeholder;
protected int errorPic;
private Buidler() {
}
......@@ -40,6 +42,11 @@ public class GlideImageConfig extends ImageConfig{
return this;
}
public Buidler errorPic(int errorPic){
this.errorPic = errorPic;
return this;
}
public Buidler imagerView(ImageView imageView) {
this.imageView = imageView;
return this;
......
......@@ -3,6 +3,7 @@ package com.jess.arms.widget.imageloader.glide;
import android.app.Activity;
import android.content.Context;
import com.bumptech.glide.DrawableRequestBuilder;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
......@@ -21,10 +22,17 @@ public class GlideImageLoaderStrategy implements BaseImageLoaderStrategy<GlideIm
else
manager = Glide.with(ctx);
manager.load(config.getUrl())
DrawableRequestBuilder<String> requestBuilder = manager.load(config.getUrl())
.diskCacheStrategy(DiskCacheStrategy.ALL)
.crossFade()
.centerCrop()
.centerCrop();
if (config.getPlaceholder() != 0)//设置占位符
requestBuilder.placeholder(config.getPlaceholder());
if (config.getErrorPic() != 0)//设置错误的图片
requestBuilder.error(config.getErrorPic());
requestBuilder
.into(config.getImageView());
}
}
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="AutoTabLayout">
<attr name="auto_textSize_base_width" format="boolean"></attr>
</declare-styleable>
</resources>
\ No newline at end of file
......@@ -50,6 +50,7 @@ ext {
"okhttp-urlconnection" : "com.squareup.okhttp:okhttp-urlconnection:2.0.0",
"otto" : "com.squareup:otto:1.3.8",
"nineoldandroids" : "com.nineoldandroids:library:2.4.0",
"paginate" : "com.github.markomilos:paginate:0.5.1",
//test
"runner" : 'com.android.support.test:runner:0.5',
"espresso-core" : "com.android.support.test.espresso:espresso-core:${android["espressoSdkVersion"]}",
......
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile "io.reactivex:rxjava:1.1.5"
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/jess/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
package me.jessyan.rxerrorhandler;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}
\ No newline at end of file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="me.jessyan.rxerrorhandler">
<application
android:allowBackup="true"
android:label="@string/app_name"
android:supportsRtl="true">
</application>
</manifest>
package me.jessyan.rxerrorhandler.core;
import android.content.Context;
import me.jessyan.rxerrorhandler.handler.ErrorHandlerFactory;
import me.jessyan.rxerrorhandler.handler.listener.ResponseErroListener;
/**
* Created by jess on 9/2/16 13:27
* Contact with jess.yan.effort@gmail.com
*/
public class RxErrorHandler {
public final String TAG = this.getClass().getSimpleName();
private ErrorHandlerFactory mHandlerFactory;
private RxErrorHandler(Builder builder) {
this.mHandlerFactory = builder.errorHandlerFactory;
}
public static Builder builder() {
return new Builder();
}
public ErrorHandlerFactory getmHandlerFactory() {
return mHandlerFactory;
}
public static final class Builder {
private Context context;
private ResponseErroListener responseErroListener;
private ErrorHandlerFactory errorHandlerFactory;
private Builder() {
}
public Builder with(Context context) {
this.context = context;
return this;
}
public Builder responseErroListener(ResponseErroListener responseErroListener) {
this.responseErroListener = responseErroListener;
return this;
}
public RxErrorHandler build() {
if (context == null)
throw new IllegalStateException("context is required");
if (responseErroListener == null)
throw new IllegalStateException("responseErroListener is required");
this.errorHandlerFactory = new ErrorHandlerFactory(context, responseErroListener);
return new RxErrorHandler(this);
}
}
}
package me.jessyan.rxerrorhandler.handler;
import me.jessyan.rxerrorhandler.core.RxErrorHandler;
import rx.Subscriber;
/**
* Created by jess on 9/2/16 14:41
* Contact with jess.yan.effort@gmail.com
*/
public abstract class ErrorHandleSubscriber<T> extends Subscriber<T> {
private ErrorHandlerFactory mHandlerFactory;
public ErrorHandleSubscriber(RxErrorHandler rxErrorHandler){
this.mHandlerFactory = rxErrorHandler.getmHandlerFactory();
}
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
mHandlerFactory.handleError(e);
}
}
package me.jessyan.rxerrorhandler.handler;
import android.content.Context;
import me.jessyan.rxerrorhandler.handler.listener.ResponseErroListener;
/**
* Created by jess on 9/2/16 13:47
* Contact with jess.yan.effort@gmail.com
*/
public class ErrorHandlerFactory {
public final String TAG = this.getClass().getSimpleName();
private Context mContext;
private ResponseErroListener mResponseErroListener;
public ErrorHandlerFactory(Context mContext, ResponseErroListener mResponseErroListener) {
this.mResponseErroListener = mResponseErroListener;
this.mContext = mContext;
}
/**
* 处理错误
* @param throwable
*/
public void handleError(Throwable throwable) {
mResponseErroListener.handleResponseError(mContext, (Exception) throwable);
}
}
package me.jessyan.rxerrorhandler.handler;
import android.util.Log;
import java.util.concurrent.TimeUnit;
import rx.Observable;
import rx.functions.Func1;
/**
* Created by jess on 9/2/16 14:32
* Contact with jess.yan.effort@gmail.com
*/
public class RetryWithDelay implements
Func1<Observable<? extends Throwable>, Observable<?>> {
public final String TAG = this.getClass().getSimpleName();
private final int maxRetries;
private final int retryDelaySecond;
private int retryCount;
public RetryWithDelay(int maxRetries, int retryDelaySecond) {
this.maxRetries = maxRetries;
this.retryDelaySecond = retryDelaySecond;
}
@Override
public Observable<?> call(Observable<? extends Throwable> attempts) {
return attempts
.flatMap(new Func1<Throwable, Observable<?>>() {
@Override
public Observable<?> call(Throwable throwable) {
if (++retryCount <= maxRetries) {
// When this Observable calls onNext, the original Observable will be retried (i.e. re-subscribed).
Log.d(TAG, "get error, it will try after " + retryDelaySecond
+ " second, retry count " + retryCount);
return Observable.timer(retryDelaySecond,
TimeUnit.SECONDS);
}
// Max retries hit. Just pass the error along.
return Observable.error(throwable);
}
});
}
}
\ No newline at end of file
package me.jessyan.rxerrorhandler.handler.listener;
import android.content.Context;
/**
* Created by jess on 9/2/16 13:58
* Contact with jess.yan.effort@gmail.com
*/
public interface ResponseErroListener {
void handleResponseError(Context context,Exception e);
}
<resources>
<string name="app_name">RxErrorHandler</string>
</resources>
package me.jessyan.rxerrorhandler;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
\ No newline at end of file
include ':app', ':arms'
include ':app', ':arms', ':rxerrorhandler'
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册