项目介绍:项目分为资讯和图片和关于三大类,资讯分为github、hacker、SegmentFault、jobBole、技术头条、Android、ios、和all,图片是美女福利图片、并提供下载。
项目已在应用宝上线:地址http://android.myapp.com/myapp/detail.htm?apkName=com.infomation.haiffeng
项目用到的技术框架
1:采用okhttp3+retrofit2+rxjava+rxandroid+hawk+logging搭建的网络模块,支持离线缓存阅读模式。
2:其他第三方:采用picasso作为图片加载,easyrecyclerview、butterknife、bottom-navigation-bar
3:采用的第三方api:http://geekvi.net/ 和 http://gank.io/
4:根据功能模块分包,采用material design风格设计
效果如图:
1、网络模块,采用的okhttp3+retrofit2封装,是在henlin封装的基础上二次封装,缓存+生命周期。由于是请求不同的Api地址,所以有两个ApiService
public class Api {有两个解析器
private static ApiService SERVICE,SERVICEG;
/**
* 请求超时时间
*/
private static final int DEFAULT_TIMEOUT = 10000;
public static ApiService getDefault() {
if (SERVICE == null) {
//手动创建一个OkHttpClient并设置超时时间
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
httpClientBuilder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.HEADERS));
/**
* 拦截器
*/
httpClientBuilder.addNetworkInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl.Builder authorizedUrlBuilder = request.url()
.newBuilder();
//添加统一参数 如手机唯一标识符,token等
// .addQueryParameter("key1","value1")
// .addQueryParameter("key2", "value2");
Request newRequest = request.newBuilder()
//对所有请求添加请求头
// .header("mobileFlag", "adfsaeefe").addHeader("type", "4")
.method(request.method(), request.body())
.url(authorizedUrlBuilder.build())
.build();
return chain.proceed(newRequest);
}
});
SERVICE = new Retrofit.Builder()
.client(httpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(Url.BASE_URL)
.build().create(ApiService.class);
}
return SERVICE;
}
public static ApiService getGankDefault() {
if (SERVICEG == null) {
//手动创建一个OkHttpClient并设置超时时间
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
httpClientBuilder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.HEADERS));
/**
* 拦截器
*/
httpClientBuilder.addNetworkInterceptor(new Interceptor() {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl.Builder authorizedUrlBuilder = request.url()
.newBuilder();
//添加统一参数 如手机唯一标识符,token等
// .addQueryParameter("key1","value1")
// .addQueryParameter("key2", "value2");
Request newRequest = request.newBuilder()
//对所有请求添加请求头
// .header("mobileFlag", "adfsaeefe").addHeader("type", "4")
.method(request.method(), request.body())
.url(authorizedUrlBuilder.build())
.build();
return chain.proceed(newRequest);
}
});
SERVICEG = new Retrofit.Builder()
.client(httpClientBuilder.build())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(Url.GBASE_URL)
.build().create(ApiService.class);
}
return SERVICEG;
}
}
/** * geek的api * @param <T> * @return */ public static <T> Observable.Transformer<HttpResult<T>, T> handleResult(final ActivityLifeCycleEvent event, final PublishSubject<ActivityLifeCycleEvent> lifecycleSubject) { return new Observable.Transformer<HttpResult<T>, T>() { @Override public Observable<T> call(Observable<HttpResult<T>> tObservable) { Observable<ActivityLifeCycleEvent> compareLifecycleObservable = lifecycleSubject.takeFirst(new Func1<ActivityLifeCycleEvent, Boolean>() { @Override public Boolean call(ActivityLifeCycleEvent activityLifeCycleEvent) { return activityLifeCycleEvent.equals(event); } }); return tObservable.flatMap(new Func1<HttpResult<T>, Observable<T>>() { @Override public Observable<T> call(HttpResult<T> result) { if ("OK".equals(result.getMessage())) { return createData(result.getData()); } else { return Observable.error(new ApiException(0)); } } }).takeUntil(compareLifecycleObservable).subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).subscribeOn(AndroidSchedulers.mainThread()).observeOn(AndroidSchedulers.mainThread()); } }; } /** * gank.io的api * @param <T> * @return */ public static <T> Observable.Transformer<GHttpResult<T>, T> handleResultG(final ActivityLifeCycleEvent event, final PublishSubject<ActivityLifeCycleEvent> lifecycleSubject) { return new Observable.Transformer<GHttpResult<T>, T>() { @Override public Observable<T> call(Observable<GHttpResult<T>> tObservable) { Observable<ActivityLifeCycleEvent> compareLifecycleObservable = lifecycleSubject.takeFirst(new Func1<ActivityLifeCycleEvent, Boolean>() { @Override public Boolean call(ActivityLifeCycleEvent activityLifeCycleEvent) { return activityLifeCycleEvent.equals(event); } }); return tObservable.flatMap(new Func1<GHttpResult<T>, Observable<T>>() { @Override public Observable<T> call(GHttpResult<T> result) { if ("false".equals(result.getError())) { return createData(result.getResults()); } else { return Observable.error(new ApiException(0)); } } }).takeUntil(compareLifecycleObservable).subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).subscribeOn(AndroidSchedulers.mainThread()).observeOn(AndroidSchedulers.mainThread()); } }; }界面主要是 bottom-navigation-bar+fragment+easyrecyclerview。
public void initView() {分享采用的是系统自带的分享
bottomNavigationBar.setMode(BottomNavigationBar.MODE_SHIFTING);
bottomNavigationBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_RIPPLE);
bottomNavigationBar.addItem(new BottomNavigationItem(R.mipmap.information, "文章").setActiveColorResource(R.color.colorPrimary))
.addItem(new BottomNavigationItem(R.mipmap.tuku, "图库").setActiveColorResource(R.color.colorAccent))
.addItem(new BottomNavigationItem(R.mipmap.about, "关于").setActiveColorResource(R.color.colorJu))
.setFirstSelectedPosition(0)
.initialise();
getFragments();
setDefaultFragment();
bottomNavigationBar.setTabSelectedListener(this);
}
public void getFragments() {
fragments = new ArrayList<>();
InformationFragment informationFragment = new InformationFragment();
GalleryFragment galleryFragment = new GalleryFragment();
AboutFragment aboutFragment = new AboutFragment();
fragments.add(informationFragment);
fragments.add(galleryFragment);
fragments.add(aboutFragment);
}
public void setDefaultFragment() {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.frame_layout,fragments.get(0));
transaction.commit();
}
@Override
public void onTabSelected(int position) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
if (fragments.get(position).isAdded()){
transaction.hide(fragments.get(mLastPosition)).show(fragments.get(position));
}else{
transaction.hide(fragments.get(mLastPosition)).add(R.id.frame_layout,fragments.get(position));
}
transaction.commit();
mLastPosition = position;
}
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu,menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.action_share_url: shareUrl(); break; } return super.onOptionsItemSelected(item); } public void shareUrl(){ String url = webView.getUrl(); Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); shareIntent.putExtra(Intent.EXTRA_TEXT, url); shareIntent.setType("text/plain"); startActivity(Intent.createChooser(shareIntent, "分享到")); }图片下载采用的是picasso
Target target = new Target(){ @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { File imgFile = new File(savePath); FileOutputStream ostream = null; try { ostream = new FileOutputStream(imgFile); if (savePath.contains(".PNG")|| savePath.contains(".png")){ bitmap.compress(Bitmap.CompressFormat.PNG, 100, ostream); }else if (savePath.contains(".JPG")|| savePath.contains(".jpg")) { bitmap.compress(Bitmap.CompressFormat.JPEG, 100, ostream); } ostream.close(); } catch (Exception e) { e.printStackTrace(); } Toast.makeText(ImgLookActivity.this,"图片下载至:"+ savePath,Toast.LENGTH_SHORT).show(); } @Override public void onBitmapFailed(Drawable errorDrawable) { } @Override public void onPrepareLoad(Drawable placeHolderDrawable) { } }; Picasso.with(this).load(mData.get(mPosition)).into(target);以上就是部分源码
github地址:https://github.com/Ahuanghaifeng
欢迎下载使用和star