HeightWrapListView,HeightWrapListViewUtils
说明:高度自适应的ListVive
package com.ruidonghy.widget.listview;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;
/**
* Created by zhou on 2017/12/21.
*/
public class HeightWrapListView extends ListView {
public HeightWrapListView(Context context) {
super(context);
}
public HeightWrapListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
package com.ruidonghy.widget.listview;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.ListView;
/**
* Created by zhou on 2017/12/21.
*/
public class HeightWrapListViewUtils {
public static void setListViewHeightBasedOnChildren(ListView listView) {
// 获取ListView对应的Adapter
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) { // listAdapter.getCount()返回数据项的数目
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0); // 计算子项View 的宽高
totalHeight += listItem.getMeasuredHeight(); // 统计所有子项的总高度
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight
+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));
// listView.getDividerHeight()获取子项间分隔符占用的高度
// params.height最后得到整个ListView完整显示需要的高度
listView.setLayoutParams(params);
}
}
复制代码
数据解释类
说明:为空断网加载中等
package com.ruidonghy.widget.prompt;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.TextView;
import com.ruidonghy.widget.R;
import com.ruidonghy.zbase.base.BaseWidget;
/**
* Created by zhou on 2017/12/22.
*/
public class DataNullView extends BaseWidget implements IChildView{
private ImageView mDataNullIcon;
private TextView mDataNullContent;
public DataNullView(Context context) {
super(context);
}
public DataNullView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public void initView() {
mDataNullIcon = getView().findViewById(R.id.datanull_icon);
mDataNullContent = getView().findViewById(R.id.datanull_content);
}
@Override
public void initInnerEvent() {
}
public void setDataNullIcon(int dataNullDrawable){
mDataNullIcon.setImageResource(dataNullDrawable);
}
public void setDataNullTip(int dataNullTip){
mDataNullContent.setText(dataNullTip);
}
@Override
public int getLayoutId() {
return R.layout.view_datanull;
}
@Override
public void gone() {
setVisibility(GONE);
}
@Override
public void show() {
setVisibility(VISIBLE);
}
}
package com.ruidonghy.widget.prompt;
/**
* Created by zhou on 2017/12/22.
*/
public interface IChildView {
void gone();
void show();
}
package com.ruidonghy.widget.prompt;
import android.support.annotation.DrawableRes;
import android.support.annotation.StringRes;
import android.view.View;
/**
* Created by abbott on 2017/12/7.
*/
public interface IPromptView {
/**
* 初始化 提示控件
* @param loadingTips
* @param dataNullTips
* @param dataNullDrawable
* @param onNoNetClickListener
*/
void init(int loadingTips,int dataNullTips,int dataNullDrawable,View.OnClickListener onNoNetClickListener);
void init(View.OnClickListener onNoNetClickListener);
/**
* 显示加载中
*/
void showLoading();
/**
* 显示数据为空
*/
void showDataNull();
/**
* 显示网络错误
*/
void showNetError();
/**
* 隐藏提示弹窗
*/
void hidden();
}
package com.ruidonghy.widget.prompt;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.TextView;
import com.ruidonghy.widget.R;
import com.ruidonghy.zbase.base.BaseWidget;
/**
* Created by zhou on 2017/12/22.
*/
public class LoadingView extends BaseWidget implements IChildView{
private RotateLoading mLoading;
private TextView mLoadingTips;
public LoadingView(Context context) {
super(context);
}
public LoadingView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public void initView() {
mLoading = getView().findViewById(R.id.rotate_view);
mLoadingTips = getView().findViewById(R.id.loading_tips);
}
@Override
public void initInnerEvent() {
}
public void setLoadingTips(int loadingTips){
mLoadingTips.setText(loadingTips);
}
@Override
public int getLayoutId() {
return R.layout.view_loading;
}
@Override
public void gone() {
if(mLoading.isStart()){
mLoading.stop();
}
setVisibility(GONE);
}
@Override
public void show() {
setVisibility(VISIBLE);
if(!mLoading.isStart()){
mLoading.start();
}
}
}
package com.ruidonghy.widget.prompt;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.widget.TextView;
import com.ruidonghy.widget.R;
import com.ruidonghy.zbase.base.BaseWidget;
/**
* Created by zhou on 2017/12/22.
*/
public class NetErrorView extends BaseWidget implements IChildView{
private TextView mNeterrorRefresh;
public NetErrorView(Context context) {
super(context);
}
public NetErrorView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public void initView() {
mNeterrorRefresh = getView().findViewById(R.id.neterror_refresh);
}
@Override
public void initInnerEvent() {
}
@Override
public int getLayoutId() {
return R.layout.view_neterror;
}
public void setNetErrorClickListener(OnClickListener netErrorClickListener){
mNeterrorRefresh.setOnClickListener(netErrorClickListener);
}
@Override
public void gone() {
setVisibility(GONE);
}
@Override
public void show() {
setVisibility(VISIBLE);
}
}
package com.ruidonghy.widget.prompt;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import com.ruidonghy.widget.R;
import com.ruidonghy.zbase.base.BaseWidget;
import java.util.ArrayList;
/**
* 公共提示加载、缺省view
* Created by yunlong on 2017/12/7.
*
* 修改此类by zhou 2017-12-22
*
*
* 提示文字初始化一次,有则用新的,没有则用默认的
* 网络错点击刷新监听需要开始时初始化。
*/
public class PromptView extends BaseWidget implements IPromptView {
private DataNullView mDataNullView;
private NetErrorView mNetErrorView;
private LoadingView mLoadingView;
private ArrayList<IChildView> mViewList;
public PromptView(Context context) {
super(context);
}
public PromptView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
public void initView() {
mViewList = new ArrayList<>();
mDataNullView = getView().findViewById(R.id.datanull_view);
mNetErrorView = getView().findViewById(R.id.neterror_view);
mLoadingView = getView().findViewById(R.id.loading_view);
mViewList.add(mDataNullView);
mViewList.add(mNetErrorView);
mViewList.add(mLoadingView);
}
@Override
public void initInnerEvent() {
}
@Override
public void init(OnClickListener onNoNetClickListener) {
mNetErrorView.setNetErrorClickListener(onNoNetClickListener);
}
@Override
public void init(int loadingTips, int dataNullTips, int dataNullDrawable, OnClickListener onNoNetClickListener) {
mLoadingView.setLoadingTips(loadingTips);
mDataNullView.setDataNullTip(dataNullTips);
mDataNullView.setDataNullIcon(dataNullDrawable);
mNetErrorView.setNetErrorClickListener(onNoNetClickListener);
}
@Override
public void showLoading() {
setVisibility(VISIBLE);
show(mLoadingView);
}
@Override
public void showDataNull() {
setVisibility(VISIBLE);
show(mDataNullView);
}
@Override
public void showNetError() {
setVisibility(VISIBLE);
show(mNetErrorView);
}
@Override
public void hidden() {
mLoadingView.gone();
setVisibility(GONE);
}
@Override
public int getLayoutId() {
return R.layout.view_prompt;
}
/**
* 内部方法,show传进来的参数,gone其他。
* @param childView
*/
private void show(IChildView childView){
childView.show();
for(int i=0;i<mViewList.size();i++){
if(mViewList.get(i)!=childView){
mViewList.get(i).gone();
}
}
}
}
package com.ruidonghy.widget.prompt;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.animation.LinearInterpolator;
import com.ruidonghy.widget.R;
/**
* RotateLoading
* Created by Victor on 2015/4/28.
*/
public class RotateLoading extends View {
private static final int DEFAULT_WIDTH = 6;
private static final int DEFAULT_SHADOW_POSITION = 2;
private static final int DEFAULT_SPEED_OF_DEGREE = 10;
private Paint mPaint;
private RectF loadingRectF;
private RectF shadowRectF;
private int topDegree = 10;
private int bottomDegree = 190;
private float arc;
private int width;
private boolean changeBigger = true;
private int shadowPosition;
private boolean isStart = false;
private int color;
private int speedOfDegree;
private float speedOfArc;
public RotateLoading(Context context) {
super(context);
initView(context, null);
}
public RotateLoading(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context, attrs);
}
public RotateLoading(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs);
}
private void initView(Context context, AttributeSet attrs) {
color = Color.WHITE;
width = dpToPx(context, DEFAULT_WIDTH);
shadowPosition = dpToPx(getContext(), DEFAULT_SHADOW_POSITION);
speedOfDegree = DEFAULT_SPEED_OF_DEGREE;
if (null != attrs) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RotateLoading);
color = typedArray.getColor(R.styleable.RotateLoading_loading_color, Color.WHITE);
width = typedArray.getDimensionPixelSize(R.styleable.RotateLoading_loading_width, dpToPx(context, DEFAULT_WIDTH));
shadowPosition = typedArray.getInt(R.styleable.RotateLoading_shadow_position, DEFAULT_SHADOW_POSITION);
speedOfDegree = typedArray.getInt(R.styleable.RotateLoading_loading_speed, DEFAULT_SPEED_OF_DEGREE);
typedArray.recycle();
}
speedOfArc = speedOfDegree / 4;
mPaint = new Paint();
mPaint.setColor(color);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(width);
mPaint.setStrokeCap(Paint.Cap.ROUND);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
arc = 10;
loadingRectF = new RectF(2 * width, 2 * width, w - 2 * width, h - 2 * width);
shadowRectF = new RectF(2 * width + shadowPosition, 2 * width + shadowPosition, w - 2 * width + shadowPosition, h - 2 * width + shadowPosition);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (!isStart) {
return;
}
mPaint.setColor(Color.parseColor("#1a000000"));
canvas.drawArc(shadowRectF, topDegree, arc, false, mPaint);
canvas.drawArc(shadowRectF, bottomDegree, arc, false, mPaint);
mPaint.setColor(color);
canvas.drawArc(loadingRectF, topDegree, arc, false, mPaint);
canvas.drawArc(loadingRectF, bottomDegree, arc, false, mPaint);
topDegree += speedOfDegree;
bottomDegree += speedOfDegree;
if (topDegree > 360) {
topDegree = topDegree - 360;
}
if (bottomDegree > 360) {
bottomDegree = bottomDegree - 360;
}
if (changeBigger) {
if (arc < 160) {
arc += speedOfArc;
invalidate();
}
} else {
if (arc > speedOfDegree) {
arc -= 2 * speedOfArc;
invalidate();
}
}
if (arc >= 160 || arc <= 10) {
changeBigger = !changeBigger;
invalidate();
}
}
public void setLoadingColor(int color) {
this.color = color;
}
public int getLoadingColor() {
return color;
}
public void start() {
startAnimator();
isStart = true;
invalidate();
}
public void stop() {
stopAnimator();
invalidate();
}
public boolean isStart() {
return isStart;
}
private void startAnimator() {
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(this, "scaleX", 0.0f, 1);
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(this, "scaleY", 0.0f, 1);
scaleXAnimator.setDuration(300);
scaleXAnimator.setInterpolator(new LinearInterpolator());
scaleYAnimator.setDuration(300);
scaleYAnimator.setInterpolator(new LinearInterpolator());
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(scaleXAnimator, scaleYAnimator);
animatorSet.start();
}
private void stopAnimator() {
ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(this, "scaleX", 1, 0);
ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(this, "scaleY", 1, 0);
scaleXAnimator.setDuration(300);
scaleXAnimator.setInterpolator(new LinearInterpolator());
scaleYAnimator.setDuration(300);
scaleYAnimator.setInterpolator(new LinearInterpolator());
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(scaleXAnimator, scaleYAnimator);
animatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
isStart = false;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
animatorSet.start();
}
public int dpToPx(Context context, float dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics());
}
}
view_datanull.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/datanull_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/no_data" />
<TextView
android:id="@+id/datanull_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_12"
android:textColor="@color/color_CCC"
android:textSize="@dimen/sp_13"
android:text="@string/no_data_txt" />
</LinearLayout>
view_loading.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.ruidonghy.widget.prompt.RotateLoading
android:id="@+id/rotate_view"
android:layout_width="@dimen/rotateloading_width"
android:layout_height="@dimen/rotateloading_height"
app:loading_color="@color/color_loading"
app:loading_speed="10"
app:loading_width="3dp" />
<TextView
android:id="@+id/loading_tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_12"
android:text="@string/prompt_loading"
android:textColor="@color/color_555"
android:textSize="@dimen/sp_13" />
</LinearLayout>
neterror_refresh.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/neterror_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/no_net" />
<TextView
android:id="@+id/neterror_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_12"
android:text="@string/un_connect_net"
android:textColor="@color/color_555"
android:textSize="@dimen/sp_13" />
<TextView
android:id="@+id/neterror_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_12"
android:textColor="@color/color_CCC"
android:textSize="@dimen/sp_13"
android:text="@string/no_net_txt" />
<TextView
android:id="@+id/neterror_refresh"
android:layout_width="@dimen/refresh_width"
android:layout_height="@dimen/refresh_height"
android:layout_marginTop="@dimen/margin_12"
android:background="@drawable/refresh_shape"
android:gravity="center"
android:text="点击刷新"
android:textColor="@color/color_555"
android:textSize="@dimen/sp_14" />
</LinearLayout>
view_prompt.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/common_white"
android:gravity="center"
android:orientation="vertical">
<com.ruidonghy.widget.prompt.DataNullView
android:id="@+id/datanull_view"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<com.ruidonghy.widget.prompt.NetErrorView
android:id="@+id/neterror_view"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<com.ruidonghy.widget.prompt.LoadingView
android:id="@+id/loading_view"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
attrs.xml
<!-- 圆形加载进度条 -->
<declare-styleable name="RotateLoading">
<attr name="loading_width" format="dimension"/>
<attr name="loading_color" format="color"/>
<attr name="shadow_position" format="integer"/>
<attr name="loading_speed" format="integer"/>
</declare-styleable>
复制代码
RoundShadowDrawable
说明:圆角Drawable
package com.ruidonghy.widget.shadow;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
/**
* Created by zcz
*/
public class RoundShadowDrawable extends Drawable {
Paint paint;
Paint paintShadow;
Path path;
RectF rectF;
int x = 20;
int y = 20;
int radius = 20;
public RoundShadowDrawable() {
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);
paintShadow = new Paint();
paintShadow.setColor(Color.WHITE);
paintShadow.setAntiAlias(true);
path = new Path();
}
public void setColor(int color) {
// 设定阴影(柔边, X 轴位移, Y 轴位移, 阴影颜色)
paintShadow.setShadowLayer(20, 0, 2, color);
invalidateSelf();
}
public void setRadius(int radius) {
this.radius = radius;
invalidateSelf();
}
@Override
public void draw(Canvas canvas) {
canvas.drawPath(path, paintShadow);
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
path.reset();
rectF = new RectF(x, y+2, bounds.width() - x, bounds.height()-y);
path.addRoundRect(rectF, new float[]{radius, radius, radius, radius, radius, radius, radius, radius}, Path.Direction.CW);
}
@Override
public void setAlpha(int i) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
}
复制代码
WillUriRouter
说明:自己写的启动其他组件的Router
package com.ruidonghy.zbase.utils;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
/**
* Created by zhou on 2017/11/6 16:30 .
*/
public class WillUriRouter {
//启动activity
public static <T extends Parcelable>void startAct(Context context,String action, T message){
Intent intent = new Intent(action);
intent.putExtra("data",message);
if(context instanceof Activity){//为了后面添加动画,暂时还没添加
((Activity)context).startActivity(intent);
}else{
context.startActivity(intent);
}
}
//启动activity
public static <T extends Parcelable>void startActForFlags(Context context,String action, T message){
Intent intent = new Intent(action);
intent.putExtra("data",message);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
if(context instanceof Activity){//为了后面添加动画,暂时还没添加
((Activity)context).startActivity(intent);
}else{
context.startActivity(intent);
}
}
//启动activity
public static <T extends Parcelable>void startAct(Context context,String action, T message,int other){
Intent intent = new Intent(action);
intent.putExtra("data",message);
intent.putExtra("other",other);
if(context instanceof Activity){//为了后面添加动画,暂时还没添加
((Activity)context).startActivity(intent);
}else{
context.startActivity(intent);
}
}
//启动activity以startActivityForResult的方式
public static <T extends Parcelable>void startActForResult(Activity context,String action, T message,int requestCode){
Intent intent = new Intent(action);
intent.putExtra("data",message);
if(context instanceof Activity){//为了后面添加动画,暂时还没添加
((Activity)context).startActivityForResult(intent,requestCode);
}else{
context.startActivityForResult(intent,requestCode);
}
}
//启动activity以startActivityForResult的方式
public static <T extends Parcelable>void startActForResult(Fragment fragment,String action, T message,int requestCode){
Intent intent = new Intent(action);
intent.putExtra("data",message);
fragment.startActivityForResult(intent,requestCode);
}
//<intent-filter>
// <action android:name="android.intent.action.VIEW"/>
// <category android:name="android.intent.category.DEFAULT"/>
// <category android:name="android.intent.category.BROWSABLE"/>
// <data
// android:host="shortvideo"
// android:pathPrefix="/share"
// android:scheme="xiuba"/>
//</intent-filter>
// uri.getQueryParameter("message");
}
复制代码
WillRequestUtil ,CommParamsModel ,
说明:程序中用到的公参的处理方式
- 加密
- 公参获取
- 公参传递
package com.ruidonghy.zbase.utils;
import com.ruidonghy.zbase.data.CommParamsModel;
import java.util.HashMap;
import java.util.Map;
/**
* Created by zhou on 2017/11/8 11:35 .
*/
public class WillRequestUtil {
/**
* 即需要公参也需要加密
* @param params
* @return
*/
public static Map<String,String> getAppCommParamsASecurity(Map<String, String> params){
return getSecurity(getCommParams(params));//先增加公参,后安全认证
}
/**
* 公参获取方法
* @param params
* @return
*/
private static Map<String,String> getCommParams(Map<String, String> params){
params.put("app_imei", CommParamsModel.instance().getAppImei());
params.put("app_type",CommParamsModel.instance().getAppType());
params.put("app_version",CommParamsModel.instance().getAppVersion());
return params;
}
/**
* 公共加密方法
* @param params
* @return
*/
private static Map<String, String> getSecurity(Map<String, String> params){
Map<String,String> map = new HashMap<String,String>();
String json = WillJsonParseUtils.obj2JsonStr(params, "");
LogUtils.d("okhttp请求入参--->json=",json);
//随机生成16位的AES密钥key
String aesKey = RandomUtil.getRandom(16);
//将json加密 先加密然后Base64转码,然后返回data
String data = null;
try {
data = AESUtils.encodeAES(json, aesKey);
} catch (Exception e) {
e.printStackTrace();
LogUtils.e("AES encode error");
}
//将AES密钥key用rsa加密
String dataKey = null;
try {
// dataKey = new String(Base64.encode(RSAUtils.encrypt(aesKey.getBytes(), RSAUtils.getPublicKey(AppConstants.PUBLICKEY_SERVER)),Base64.DEFAULT),"UTF-8");
LogUtils.d("aesKey="+aesKey);
dataKey = RsaUtils.encryptByPublic(aesKey);
} catch (Exception e) {
e.printStackTrace();
}
map.put("data_key", dataKey);
map.put("data", data);
return map;
}
}
package com.ruidonghy.zbase.data;
/**
* 定义此类为了不让程序多次进行imei 和appversion的获取
* Created by zhou on 2017/11/13 10:42 .
*/
public class CommParamsModel {
private CommParamsModel(){}
private static class ParamsHolder{
private static final CommParamsModel instance = new CommParamsModel();
}
public static final CommParamsModel instance(){
return ParamsHolder.instance;
}
private String appImei;
private String appType;
private String appVersion;
public void initCommParams(String imei,String type,String version){
this.appImei = imei;
this.appType = type;
this.appVersion = version;
}
public String getAppImei() {
return appImei;
}
public String getAppType() {
return appType;
}
public String getAppVersion() {
return appVersion;
}
}
//初始化公参, imei {apptype 1,android} appVersion
CommParamsModel.instance().initCommParams(PhoneUtils.getIMEI(),"1", AppInfo.appVersionName());
package com.ruidonghy.zbase.utils;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* 捕捉Json解析异常,避免出现由此引起 的crash
* @author wjian
* */
public class WillJsonParseUtils
{
private static Gson gson;
static {
gson = new Gson();
}
public static Gson getGson()
{
return gson;
}
/**
* 对象转成json
* @param <T>
*/
public static <T> String obj2JsonStr(T t, String def)
{
try
{
return gson.toJson(t);
} catch (Exception e) {
e.printStackTrace();
LogUtils.e("json解析异常"+t,e.getMessage());
}
return def;
}
/**
* json转成对象
*
* @param <T>
*/
public static <T> T json2Obj(String json, Class<T> clazz)
{
try {
return gson.fromJson(json, clazz);
} catch (JsonSyntaxException e) {
e.printStackTrace();
LogUtils.e("json解析异常"+json,e.getMessage());
}
return null;
}
/**
* json字符串直接转成List
* @param clazz Bean[].class
* @param json String json串
* @param <T>
* @return
*/
// public static final <T> List<T> json2List(final Class<T[]> clazz, final String json)
// {
// final T[] jsonToObject;
// try{
// jsonToObject = gson.fromJson(json, clazz);
// }catch (Exception e){
// e.printStackTrace();
// return new ArrayList<T>();
// }
// return Arrays.asList(jsonToObject);
// }
/**
* json字符直接转成json对象
*/
public static <T> T json2Object(String jsonString, Class<T> cls) {
T t = null;
try {
Gson gson = new Gson();
t = gson.fromJson(jsonString, cls);
} catch (Exception e) {
e.printStackTrace();
LogUtils.e("json解析异常"+jsonString,e.getMessage());
}
return t;
}
public static String getString(JSONObject json, String key)
{
return getString(json, key, "");
}
public static String getString(JSONObject json, String key, String def)
{
String value = def;
if (canParse(json, key)) {
try {
value = json.getString(key);
} catch (JSONException e) {
LogUtils.e("getString=" + e.getMessage());
LogUtils.e("json解析异常"+json,e.getMessage());
}
}
return value;
}
public static int getInt(JSONObject json, String key)
{
return getInt(json, key, -1);
}
public static int getInt(JSONObject json, String key, int def)
{
int value = def;
if (canParse(json, key)) {
try {
value = json.getInt(key);
} catch (JSONException e) {
LogUtils.e("getInt=" + e.getMessage());
}
}
return value;
}
public static long getLong(JSONObject json, String key)
{
return getLong(json, key, -1);
}
public static long getLong(JSONObject json, String key, long def)
{
long value = def;
if (canParse(json, key)) {
try {
value = json.getLong(key);
} catch (JSONException e) {
LogUtils.e("getInt=" + e.getMessage());
}
}
return value;
}
public static JSONObject getJSONObject(JSONArray array, int index)
{
return getJSONObject(array, index, new JSONObject());
}
public static JSONObject getJSONObject(JSONArray array, int index, JSONObject def)
{
JSONObject returnObj = def;
if (array != null && array.length() > 0) {
try {
returnObj = array.getJSONObject(index);
} catch (JSONException e) {
LogUtils.e("getJSONObject=" + e.getMessage());
}
}
return returnObj;
}
public static JSONObject getJSONObject(JSONObject json, String key)
{
return getJSONObject(json, key, new JSONObject());
}
public static JSONObject getJSONObject(JSONObject json, String key, JSONObject def)
{
JSONObject returnObj = def;
if (canParse(json, key)) {
try {
returnObj = json.getJSONObject(key);
} catch (JSONException e) {
LogUtils.e("getJSONObject=" + e.getMessage());
}
}
return returnObj;
}
public static JSONArray getJSONArray(JSONObject json, String key)
{
return getJSONArray(json, key, new JSONArray());
}
public static JSONArray getJSONArray(JSONObject json, String key, JSONArray def)
{
JSONArray array = def;
if (canParse(json, key)) {
try {
array = json.getJSONArray(key);
} catch (JSONException e) {
LogUtils.e("getJSONArray=" + e.getMessage());
}
}
return array;
}
public static JSONObject getJSONObject(byte[] json)
{
return getJSONObject(StringUtils.bytesToString(json,"UTF-8"));
}
public static JSONObject getJSONObject(String json)
{
return getJSONObject(json, new JSONObject());
}
public static JSONObject getJSONObject(String json, JSONObject def)
{
JSONObject jsonObject = def;
try {
jsonObject = new JSONObject(json);
} catch (Exception e) { //不只是JsonException,还可能是别的异常
e.printStackTrace();
}
return jsonObject;
}
public static JSONArray getJSONArray(String json)
{
return getJSONArray(json, new JSONArray());
}
public static JSONArray getJSONArray(String json, JSONArray def)
{
JSONArray jsonArray = def;
try {
jsonArray = new JSONArray(json);
} catch (JSONException e) {
e.printStackTrace();
}
return jsonArray;
}
/**
* 判断数据是否可以解析,可以则return true;
* */
private static boolean canParse(JSONObject json, String key)
{
if (json == null || TextUtils.isEmpty(key)) {
return false;
}
return true;
}
public static <T> List<T> parseJsonArray2List(JSONArray jsonArray, Class<T> clazz)
{
List<T> list = new ArrayList<T>();
if(jsonArray==null) return list;
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = getJSONObject(jsonArray, i, null);
if(jsonObject==null) continue;
T t = (T) json2Obj(jsonObject.toString(),clazz);
list.add(t);
}
return list;
}
public static List<Integer> parseJsonArray2IntegerList(JSONArray jsonArray)
{
List<Integer> list = new ArrayList<Integer>();
if(jsonArray==null) return list;
for (int i = 0; i < jsonArray.length(); i++) {
int anInt = 0;
try {
anInt = jsonArray.getInt(i);
} catch (JSONException e) {
e.printStackTrace();
}
list.add(anInt);
}
return list;
}
public static void putValue(JSONObject json, String key, Object value)
{
try {
json.put(key,value);
} catch (JSONException e) {
e.printStackTrace();
}
}
public static Map<String, Object> jsonToMap(String jsonString) throws JSONException {
JSONObject jsonObject = new JSONObject(jsonString);
Map<String, Object> resultMap = new HashMap<String, Object>();
Iterator<String> iter = jsonObject.keys();
String key=null;
Object value=null;
while (iter.hasNext()) {
key=iter.next();
value=jsonObject.get(key);
resultMap.put(key, value);
}
return resultMap;
}
public static Map<String, String> json2Map(String jsonString) throws JSONException {
JSONObject jsonObject = new JSONObject(jsonString);
Map<String, String> resultMap = new HashMap<String, String>();
Iterator<String> iter = jsonObject.keys();
String key=null;
String value=null;
while (iter.hasNext()) {
key=iter.next();
value=jsonObject.get(key).toString();
resultMap.put(key, value);
}
return resultMap;
}
/**
* map转json
*
* @param map
* @return
* @throws JSONException
*/
public static String map2Json(Map<String, String> map) throws JSONException {
Gson gson = new Gson();
String jsonStr = gson.toJson(map);
return jsonStr;
}
}
package com.ruidonghy.zbase.utils;
import java.util.Random;
/**
* Created by zhou on 2017/11/8 11:32.
*/
public class RandomUtil {
public static Random random = new Random();
public RandomUtil() {
}
public static String getRandom(int length) {
StringBuilder ret = new StringBuilder();
for(int i = 0; i < length; ++i) {
boolean isChar = random.nextInt(2) % 2 == 0;
if(isChar) {
int choice = random.nextInt(2) % 2 == 0?65:97;
ret.append((char)(choice + random.nextInt(26)));
} else {
ret.append(Integer.toString(random.nextInt(10)));
}
}
return ret.toString();
}
}
package com.ruidonghy.zbase.utils;
import android.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* AES加解密
* Created by zhou on 2017/11/8 11:22.
*/
public class AESUtils {
/**
* 密钥算法
*/
private static final String ALGORITHM = "AES";
/**
* 加解密算法/工作模式/填充方式
*/
private static final String ALGORITHM_STR = "AES/CBC/PKCS5Padding";
//AES加密初始向量
public static final String VIPARA = "w2wJCnctEG09danPPI7SxQ=="; //AES 为16bytes. DES 为8byte
/**
* SecretKeySpec类是KeySpec接口的实现类,用于构建秘密密钥规范
*/
private SecretKeySpec key;
public AESUtils(String hexKey) {
key = new SecretKeySpec(hexKey.getBytes(), ALGORITHM);
}
/**
* AES加密
*
* @param data
* @return
* @throws Exception
*/
public String encryptData(String data) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM_STR); // 创建密码器
IvParameterSpec zeroIv = new IvParameterSpec(Base64.decode(VIPARA,Base64.DEFAULT));
cipher.init(Cipher.ENCRYPT_MODE, key,zeroIv);// 初始化
return new String(Base64.encode(cipher.doFinal(data.getBytes("UTF-8")),Base64.DEFAULT),"UTF-8");
}
/**
* AES解密
*
* @return
* @throws Exception
*/
// public String decryptData(String base64Data) throws Exception {
// Cipher cipher = Cipher.getInstance(ALGORITHM_STR);
// cipher.init(Cipher.DECRYPT_MODE, key);
// return StringUtils.bytesToString(cipher.doFinal(Base64Utils.getFromBase64(base64Data).getBytes("UTF-8")),"UTF-8");
// }
// /**
// * hex字符串 转 byte数组
// *
// * @param s
// * @return
// */
// private static byte[] hex2byte(String s) {
// if (s.length() % 2 == 0) {
// return hex2byte(s.getBytes(), 0, s.length() >> 1);
// } else {
// return hex2byte("0" + s);
// }
// }
//
// private static byte[] hex2byte(byte[] b, int offset, int len) {
// byte[] d = new byte[len];
// for (int i = 0; i < len * 2; i++) {
// int shift = i % 2 == 1 ? 0 : 4;
// d[i >> 1] |= Character.digit((char) b[offset + i], 16) << shift;
// }
// return d;
// }
// public static void main(String[] args) throws Exception {
// AESUtils util = new AESUtils("abcdefghijklmnop"); // 密钥
// System.out.println("cardNo:" + util.encryptData("1234")); // 加密
// System.out.println("exp:" + util.decryptData("34+Jzs4KkwaCQWVyyAgwLA==")); // 解密
// }
public static String encodeAES(String json,String aesKey) throws Exception {
AESUtils aes = new AESUtils(aesKey);
return aes.encryptData(json);
}
}
package com.ruidonghy.zbase.utils;
import android.util.Base64;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
/**
* Created by zhou on 2017/11/10 18:50 .
*/
public class RsaUtils {
private static final String RSA_PUBLICE =
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDHrouGyrJsGZLqNiLtAvpOlPpe" +
"UxmQdpfHSvIMqi7kHCe01VeHDFaB2wpOm9Fk2ExNELHd0BNjX7i3esvD319dJpia" +
"qnXpkVesTNAnXj4+KPhUFu0Je26VpTfvBx6PSKrWrGOXPGt0S6BnIFjDL5tXxYsk" +
"RZ2/2jdJMt/YjSnk2wIDAQAB";
private static final String ALGORITHM = "RSA";
/**
* 得到公钥
* @param algorithm
* @param bysKey
* @return
*/
private static PublicKey getPublicKeyFromX509(String algorithm,
String bysKey) throws NoSuchAlgorithmException, Exception {
byte[] decodedKey = Base64.decode(bysKey,Base64.DEFAULT);
X509EncodedKeySpec x509 = new X509EncodedKeySpec(decodedKey);
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
return keyFactory.generatePublic(x509);
}
/**
* 使用公钥加密
* @param content
* @return
*/
public static String encryptByPublic(String content) {
try {
PublicKey pubkey = getPublicKeyFromX509(ALGORITHM, RSA_PUBLICE);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubkey);
byte plaintext[] = content.getBytes("UTF-8");
byte[] output = cipher.doFinal(plaintext);
String s = new String(Base64.encode(output,Base64.DEFAULT));
return s;
} catch (Exception e) {
return null;
}
}
/**
* 使用公钥解密
* @param content 密文
* @return 解密后的字符串
*/
public static String decryptByPublic(String content) {
try {
PublicKey pubkey = getPublicKeyFromX509(ALGORITHM, RSA_PUBLICE);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, pubkey);
InputStream ins = new ByteArrayInputStream(Base64.decode(content,Base64.DEFAULT));
ByteArrayOutputStream writer = new ByteArrayOutputStream();
byte[] buf = new byte[128];
int bufl;
while ((bufl = ins.read(buf)) != -1) {
byte[] block = null;
if (buf.length == bufl) {
block = buf;
} else {
block = new byte[bufl];
for (int i = 0; i < bufl; i++) {
block[i] = buf[i];
}
}
writer.write(cipher.doFinal(block));
}
return new String(writer.toByteArray(), "UTF-8");
} catch (Exception e) {
return null;
}
}
}
复制代码
ServerErrorUtil
说明:
package com.ruidonghy.zbase.net;
import android.widget.Toast;
import com.ruidonghy.zbase.base.BaseApplication;
import com.ruidonghy.zbase.base.BaseResult;
import com.ruidonghy.zbase.utils.LogUtils;
/**
* Created by zhou on 2017/11/13 14:22 .
*
* 公共服务器错误雏形类,目前没有指定的需要拦截的错误码类型,日后会加
*
*/
public class ServerErrorUtil {
public static boolean isSuccess(BaseResult baseResult,boolean isShowErrorMsg){
if (baseResult.code==200){//返回200则请求成功,服务器正常给返回数据
if(baseResult.result==null){//服务器返回200结果Result数据是null,,则 1,log日志在控制台提示 2,返回false,让上层去做处理
LogUtils.e("服务器返回Result为null,请联系服务器人员!");
return false;
}
return true;
}else{
/**
200 => 'SUCCESS',
500 => '服务器内部错误',
4101 => '添加数据失败',
4201 => '请求校验失败',
4202 => 'loginkey无效',
4203 => '缺少参数',
4204 => '参数错误',
4205 => '验证码错误',
4206 => '注册失败',
4207 => '验证码获取失败',
4208 => '验证码获取频繁',
4209 => '绑定失败',
4210 => '已在其他设备登录',
*/
//拦截指定错误码 目前还未有指定
switch(baseResult.code){
case 500://服务器内部错误
;break;
case 4101://添加数据失败
;break;
case 4201://请求校验失败
;break;
case 4202://loginkey无效
;break;
case 4203://缺少参数
;break;
case 4204://参数错误
;break;
case 4205://验证码错误
;break;
case 4206://注册失败
;break;
case 4207://验证码获取失败
;break;
case 4208://验证码获取频繁
;break;
case 4209://绑定失败
;break;
case 4210://已在其他设备登录
;break;
case 4221://评论自己错误
;break;
}
//如果上层需要显示错误信息的话,则用固定的Toast来show错误消息
if (isShowErrorMsg){
Toast.makeText(BaseApplication.instance(),baseResult.message,Toast.LENGTH_LONG).show();
}
return false;
}
}
}
package com.ruidonghy.zbase.net;
import java.net.ConnectException;
import java.net.UnknownHostException;
import retrofit2.HttpException;
/**
* Created by abbott on 2017/12/8.
*/
public class ExceptionUtil {
public static final int SERVER_ERROR = 9000;//服务器异常
public static final int HTTP_ERROR = 9001;//网络异常
public static int errorCode(Throwable e) {
if (e instanceof HttpException || e instanceof UnknownHostException || e instanceof ConnectException) {
return HTTP_ERROR;
} else {
return SERVER_ERROR;
}
}
}
package com.ruidonghy.zbase.net;
/**
* Created by zhou on 2017/11/6 16:48 .
*/
public class URLConfig {
public static final String HOST_ONLINE = "http://api.xxx.com/";//线上环境
public static final String HOST_PRE_ONLINE = "http://api.xxx.com/";//预上线环境
public static final String HOST_TEST = "http://api.xxx.com/";//测试环境
public static final String HOST_DEV = "http://api.xxx.com/";//开发环境
public static final int URL_TYPE = 3;//1是线上 2是预上线 3是测试 4是研发环境,自己随便配置的
public static String getHost() {
String host = "";
switch (URL_TYPE) {
case 1:
host = HOST_ONLINE;
break;
case 2:
host = HOST_PRE_ONLINE;
break;
case 3:
host = HOST_TEST;
break;
case 4:
host = HOST_DEV;
break;
default:
host = HOST_ONLINE;
break;
}
return host;
}
public static String JD_IMAGE_ENDSTR_MID = "?imgalias/img_mid";//?imgalias/img_mid
public static String JD_IMAGE_ENDSTR_SMALL = "?imgalias/img_small";//?imgalias/img_small
}
package com.ruidonghy.zbase.net;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
/**
* Created by zhou on 2017/11/11 17:56 .
*/
public abstract class CallBack<T> implements Observer<T> {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(T value) {
onSuccess(value);
}
@Override
public void onError(Throwable e) {
switch (ExceptionUtil.errorCode(e)){
case ExceptionUtil.SERVER_ERROR:
onServerError();
break;
case ExceptionUtil.HTTP_ERROR:
onHttpError();
break;
}
onFail(e);
}
@Override
public void onComplete() {}
public abstract void onSuccess(T data);
public abstract void onFail(Throwable e);
public void onServerError() {}
public void onHttpError() {}
}
复制代码
StartIndoorRunActivity
说明:
package com.ruidonghy.zbase.data;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by zhou on 2017/11/27 10:23 .
*/
public class StartIndoorRunActivity implements Parcelable {
public static final String ACTION = "com.ruidonghy.run.indoor.IndoorRunActivity";
/**
* 0:为设置距离和时间
* 1:设置了距离
* 2:设置了时间
*/
private int type;
/**
* 设定的距离,单位:公里
*/
private float distance;
/**
* 设定的时间,单位:秒
*/
private long time;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(this.type);
dest.writeFloat(this.distance);
dest.writeLong(this.time);
}
public StartIndoorRunActivity(int type, float distance, long time) {
this.type = type;
this.distance = distance;
this.time = time;
}
protected StartIndoorRunActivity(Parcel in) {
this.type = in.readInt();
this.distance = in.readFloat();
this.time = in.readLong();
}
public static final Parcelable.Creator<StartIndoorRunActivity> CREATOR = new Parcelable.Creator<StartIndoorRunActivity>() {
@Override
public StartIndoorRunActivity createFromParcel(Parcel source) {
return new StartIndoorRunActivity(source);
}
@Override
public StartIndoorRunActivity[] newArray(int size) {
return new StartIndoorRunActivity[size];
}
};
public int getType() {
return type;
}
public float getDistance() {
return distance;
}
public long getTime() {
return time;
}
}
复制代码