diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index bb17c9a..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -AndroidFrame \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 1a3eaff..f0ee888 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -27,20 +27,5 @@ - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/app/src/main/res/layout/ac_main.xml b/app/src/main/res/layout/ac_main.xml index 890c422..74a2518 100644 --- a/app/src/main/res/layout/ac_main.xml +++ b/app/src/main/res/layout/ac_main.xml @@ -19,7 +19,7 @@ app:starEmpty="@mipmap/star_grey" app:starFill="@mipmap/star_yellow" app:starHalf="@mipmap/star_half_yellow" - app:starImageSize="20dp" + app:starImageSize="30dp" app:starStep="4.5"> extends BaseAdapter -{ - protected Context mContext; - protected List mDatas; - protected LayoutInflater mInflater; - private int layoutId; +public abstract class CommonAdapter extends BaseAdapter { + protected Context mContext; + protected List mDatas; + protected LayoutInflater mInflater; + private int layoutId; - public CommonAdapter(Context context,int layoutId, List datas ) - { - this.mContext = context; - mInflater = LayoutInflater.from(context); - this.mDatas = datas; - this.layoutId = layoutId; - } + public CommonAdapter(Context context, int layoutId, List datas) { + this.mContext = context; + mInflater = LayoutInflater.from(context); + this.mDatas = datas; + this.layoutId = layoutId; + } - @Override - public int getCount() - { - return mDatas.size(); - } + public void notifyDataSetChanged(List datas) { + this.mDatas = datas; + this.notifyDataSetChanged(); + } - @Override - public T getItem(int position) - { - return mDatas.get(position); - } + @Override + public int getCount() { + return mDatas==null?0:mDatas.size(); + } - @Override - public long getItemId(int position) - { - return position; - } + public List getDatas() { + return mDatas; + } + @Override + public T getItem(int position) { + return mDatas.get(position); + } - @Override - public View getView(int position, View convertView, ViewGroup parent) - { - ViewHolder holder = ViewHolder.get(mContext, convertView, parent, - layoutId, position); - convert(holder, getItem(position)); - return holder.getConvertView(); - } + @Override + public long getItemId(int position) { + return position; + } - public abstract void convert(ViewHolder holder, T t); + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder holder = ViewHolder.get(mContext, convertView, parent, + layoutId, position); + convert(holder, getItem(position)); + return holder.getConvertView(); + } + + public abstract void convert(ViewHolder holder, T t); } diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/adapter/common/recyclerview/CommonAdapter.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/adapter/common/recyclerview/CommonAdapter.java index dada422..420eac3 100644 --- a/libray_lxndroid/src/main/java/com/kejiang/yuandl/adapter/common/recyclerview/CommonAdapter.java +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/adapter/common/recyclerview/CommonAdapter.java @@ -53,7 +53,10 @@ public abstract class CommonAdapter extends RecyclerView.Adapter { return true; } - + public void notifyDataSetChanged(List datas) { + this.mDatas = datas; + this.notifyDataSetChanged(); + } protected void setListener(final ViewGroup parent, final ViewHolder viewHolder, int viewType) { @@ -99,7 +102,7 @@ public abstract class CommonAdapter extends RecyclerView.Adapter @Override public int getItemCount() { - return mDatas.size(); + return mDatas==null?0:mDatas.size(); } diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/base/BaseActivity.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/base/BaseActivity.java index 79834d6..ec4459b 100644 --- a/libray_lxndroid/src/main/java/com/kejiang/yuandl/base/BaseActivity.java +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/base/BaseActivity.java @@ -1,21 +1,30 @@ package com.kejiang.yuandl.base; -import android.app.Dialog; +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.Application; import android.content.Context; +import android.content.ContextWrapper; import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; +import android.os.IBinder; +import android.os.Looper; +import android.os.MessageQueue; import android.support.v4.util.ArrayMap; +import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; -import android.view.Window; +import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; import android.widget.FrameLayout; +import android.widget.GridView; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; @@ -30,6 +39,8 @@ import com.kejiang.yuandl.R; import com.kejiang.yuandl.bean.JsonBean; import com.kejiang.yuandl.utils.AppManager; import com.kejiang.yuandl.utils.CheckNetwork; +import com.kejiang.yuandl.utils.Reflector; +import com.kejiang.yuandl.utils.SharedPreferencesUtils; import com.kejiang.yuandl.utils.Tools; import com.kejiang.yuandl.view.LoadingDialog; import com.orhanobut.logger.Logger; @@ -38,13 +49,17 @@ import com.zhy.autolayout.utils.AutoUtils; import org.xutils.common.Callback; import org.xutils.common.util.KeyValue; -import org.xutils.common.util.MD5; import org.xutils.ex.HttpException; import org.xutils.http.RequestParams; import org.xutils.x; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.SocketTimeoutException; import java.util.List; import java.util.Map; +import java.util.Set; /** * com.bm.falvzixun.activities.BaseActivity; @@ -60,7 +75,6 @@ public abstract class BaseActivity extends AutoLayoutActivity implements View.On private LinearLayout llRoot; private LinearLayout layout_titlebar; protected Context context; - Dialog dialog; /** * 加载数据对话框 */ @@ -120,6 +134,10 @@ public abstract class BaseActivity extends AutoLayoutActivity implements View.On } } + protected FrameLayout getContentLayout() { + return mContentLayout; + } + /** * 加载 activity_title 布局 ,并获取标题及两侧按钮 */ @@ -373,216 +391,251 @@ public abstract class BaseActivity extends AutoLayoutActivity implements View.On protected void startActivity(Class c) { startActivity(new Intent(context, c)); } -// -// /** -// * 异步网络请求类 -// * -// * @param requestParams -// */ -// protected void ajax(RequestParams requestParams) { -// if (!CheckNetwork.isNetworkAvailable(context)) { -// showToast("网络不可用,请检查网络连接!"); -// return; -// } -// if (loadingDialog == null) { -// loadingDialog = new LoadingDialog(context); -// } -// if (requestParams != null) { -// String uri = requestParams.getUri(); -// if (!uri.isEmpty()) { -// String[] split = uri.split("/"); -//// Logger.d("split=" + Arrays.toString(split)); -// -// String method = null; -// try { -// method = split[split.length - 1].substring(0, split[split.length - 1].indexOf(".")); -// } catch (Exception e) { -// e.printStackTrace(); -// Logger.d("请检查服务器地址后面是否含有.html"); -// } -// String mode = split[split.length - 2]; -// String sign = MD5.md5(mode + method); -// requestParams.addBodyParameter("sign", sign); -// } -// -// } -// Logger.d("url=" + requestParams.getUri() + "\nrequestParams=" + requestParams.getStringParams().toString()); -// List params = requestParams.getStringParams(); -// for (KeyValue keyValue : params) { -// if (keyValue.key.contains(":")) { -// throw new RuntimeException("参数异常!"); -// } -// } -// // jsonBean = JSON.parseObject(result, JsonBean.class); -// cancelable = x.http().post(requestParams, new Callback.ProgressCallback() { -// -// @Override -// public void onWaiting() { -// } -// -// @Override -// -// public void onStarted() { -// netOnStart(); -// } -// -// @Override -// public void onLoading(long total, long current, boolean isDownloading) { -// netOnLoading(total, current, isDownloading); -// } -// -// @Override -// public void onSuccess(String result) { -// -// Logger.json(result); -// JsonBean jsonBean = null; -// try { -//// jsonBean = JSON.parseObject(result, JsonBean.class); -// jsonBean = jsonParse(result); -// if (jsonBean.getMsg() != null && !jsonBean.getMsg().isEmpty()) { -// showToast(jsonBean.getMsg()); -// } -// if (jsonBean.getCode() == 200) { -// Map data = new ArrayMap(); -// if (null != jsonBean.getData() && jsonBean.getData().size() > 0) { -// data = jsonBean.getData(); -// } -// netOnSuccess(data); -// } else { -// -// netOnOtherStates(jsonBean.getCode(), jsonBean.getMsg()); -// } -// } catch (Exception e) { -// if (loadingDialog != null && loadingDialog.isShowing()) { -// loadingDialog.dismiss(); -// } -// Logger.d(result); -// showToast("服务器异常!"); -// e.printStackTrace(); -// } finally { -// } -// } -// -// @Override -// public void onError(Throwable ex, boolean isOnCallback) { -// netOnFailure(ex); -// -// } -// -// @Override -// public void onCancelled(CancelledException cex) { -// Logger.d("用户取消了访问网络...."); -// netOnCancelled(); -// } -// -// @Override -// public void onFinished() { -// netOnFinish(); -// } -// -// }); -// } -// -// -// private JsonBean jsonParse(String json) throws JSONException { -// ArrayMap arrayMap= JSON.parseObject(json,new TypeReference>(){ -// }.getType()); -// JsonBean jsonBean = new JsonBean(); -// if (arrayMap.containsKey("data")) { -// Object data = arrayMap.get("data"); + + /** + * 异步网络请求类 + * + * @param requestParams + */ + protected void ajax(RequestParams requestParams) { + ajax(requestParams, 0); + } + + /** + * 异步网络请求类 + * + * @param requestParams + * @param requestCode 区分不同的网络请求 + */ + protected void ajax(RequestParams requestParams, int requestCode) { + if (!CheckNetwork.isNetworkAvailable(context)) { + showToast("网络不可用,请检查网络连接!"); + netOnFailure(new Exception("网络不可用"), requestCode); + return; + } + if (loadingDialog == null) { + loadingDialog = new LoadingDialog(context); + } + SharedPreferencesUtils sp = new SharedPreferencesUtils(x.app()); + boolean isLogin = (boolean) sp.getParam("login", false); + if (isLogin) { + requestParams.addBodyParameter("mId", (String) sp.getParam("mId", "")); + } + boolean hasLocation = (boolean) sp.getParam("hasLocation", false); + if (hasLocation) { + requestParams.addBodyParameter("lng", (String) sp.getParam("lng", "")); + requestParams.addBodyParameter("lat", (String) sp.getParam("lat", "")); + } + Logger.d("url=" + requestParams.getUri() + "\nrequestParams=" + requestParams.getStringParams().toString()); + List params = requestParams.getStringParams(); + for (KeyValue keyValue : params) { + if (keyValue.key.contains(":")) { + throw new RuntimeException("参数异常!"); + } + } + cancelable = x.http().post(requestParams, new MyCallback(requestCode)); + } + + private class MyCallback implements Callback.ProgressCallback { + private int requestCode = 0; + + public MyCallback(int requestCode) { + this.requestCode = requestCode; + } + + @Override + public void onWaiting() { + } + + @Override + + public void onStarted() { + netOnStart(); + } + + @Override + public void onLoading(long total, long current, boolean isDownloading) { + netOnLoading(total, current, isDownloading); + } + + @Override + public void onSuccess(String result) { + Logger.json(result); + JsonBean jsonBean = null; + try { + jsonBean = jsonParse(result); + if (jsonBean.getMsg() != null && !jsonBean.getMsg().isEmpty()) { + showToast(jsonBean.getMsg()); + } + if (jsonBean.getStatus() == 1) { + Map data = new ArrayMap(); + if (null != jsonBean.getData() && jsonBean.getData().size() > 0) { + data = jsonBean.getData(); + } + netOnSuccess(data, requestCode); + } else { + netOnOtherStates(jsonBean.getStatus(), jsonBean.getMsg(), requestCode); + } + } catch (Exception e) { + if (loadingDialog != null && loadingDialog.isShowing()) { + loadingDialog.dismiss(); + } + Logger.d(result); + showToast("服务器异常!"); + e.printStackTrace(); + } finally { + } + } + + @Override + public void onError(Throwable ex, boolean isOnCallback) { + netOnFailure(ex, requestCode); + + } + + @Override + public void onCancelled(Callback.CancelledException cex) { + Logger.d("用户取消了访问网络...."); + netOnCancelled(); + } + + @Override + public void onFinished() { + netOnFinish(requestCode); + } + + + } + + private JsonBean jsonParse(String json) throws JSONException { + ArrayMap arrayMap = JSON.parseObject(json, new TypeReference>() { + }.getType()); + JsonBean jsonBean = new JsonBean(); + if (arrayMap.containsKey("data")) { + Object data = arrayMap.get("data"); // System.out.println("data.getClass().getName()=" + data.getClass().getName()); -// ArrayMap rrData = null; -// if (data instanceof String) { + ArrayMap rrData = null; + if (data instanceof String) { // System.out.println("data instanceof String"); -// rrData = new ArrayMap(); -// rrData.put("data", data.toString()); -// } else if (data instanceof JSONArray) { + rrData = new ArrayMap(); + rrData.put("data", data.toString()); + } else if (data instanceof JSONArray) { // System.out.println("data instanceof JSONArray"); -// rrData = new ArrayMap(); -// rrData.put("data", data); -// } else if (data instanceof com.alibaba.fastjson.JSONObject) { + rrData = new ArrayMap(); + rrData.put("data", data); + } else if (data instanceof com.alibaba.fastjson.JSONObject) { // System.out.println("data instanceof JSONObject"); -// rrData = JSON.parseObject(data.toString(),new TypeReference>(){ -// }.getType()); -// } -// jsonBean.setData(rrData); -// } -// jsonBean.setCode(Integer.valueOf(arrayMap.get("code").toString())); -// jsonBean.setMsg(Tools.getValue(arrayMap, "msg")); -// -// return jsonBean; -// } -// -// -// /** -// * 开始访问网络 -// */ -// public void netOnStart() { -// loadingDialog.show("正在获取数据..."); -// } -// -// /** -// * 访问网络的进程 -// */ -// public void netOnLoading(long total, long current, boolean isUploading) { -// } -// -// /** -// * 访问网络成功 -// */ -// public void netOnSuccess(Map data) { -// if (loadingDialog != null) { -// loadingDialog.dismiss(); -// } -// } -// -// /** -// * 访问网络成功的其他状态 -// */ -// public void netOnOtherStates(int code, String msg) { -// if (loadingDialog != null) { -// loadingDialog.dismiss(); -// } -// } -// -// /** -// * 访问网络结束 -// */ -// public void netOnFinish() { -// loadingDialog.dismiss(); -// } -// -// /** -// * 访问网络失败 -// */ -// public void netOnFailure(Throwable ex) { -// if (loadingDialog != null) { -// loadingDialog.dismiss(); -// } -// Logger.d(ex.getMessage()); -// if (ex instanceof HttpException) { // 网络错误 -// HttpException httpEx = (HttpException) ex; -// int responseCode = httpEx.getCode(); -// String responseMsg = httpEx.getMessage(); -// String errorResult = httpEx.getResult(); -// Toast.makeText(x.app(), "网络错误:" + ex.getMessage(), Toast.LENGTH_LONG).show(); -// // ... -// } else { // 其他错误 -// Toast.makeText(context, "连接服务器失败,请稍后再试!ex=" + ex.getMessage(), Toast.LENGTH_SHORT).show(); -// // ... -// } -// -// -// } -// -// /** -// * 取消访问网络 -// */ -// public void netOnCancelled() { -// if (loadingDialog != null) { -// loadingDialog.dismiss(); -// } -// } + rrData = JSON.parseObject(data.toString(), new TypeReference>() { + }.getType()); + } + jsonBean.setData(rrData); + } else { + Set keys = arrayMap.keySet(); + ArrayMap rrData = new ArrayMap<>(); + for (String s : keys) { + if (!s.equals("status")) { + rrData.put(s, arrayMap.get(s)); + } + } + jsonBean.setData(rrData); + } + jsonBean.setStatus(Integer.valueOf(arrayMap.get("status").toString())); + jsonBean.setMsg(Tools.getValue(arrayMap, "msg")); + + return jsonBean; + } + + /** + * 开始访问网络 + */ + protected void netOnStart() { + loadingDialog.show("Loading..."); + } + + /** + * 访问网络的进程 + */ + protected void netOnLoading(long total, long current, boolean isUploading) { + } + + /** + * 访问网络成功 + */ + protected void netOnSuccess(Map data, int requestCode) { + netOnSuccess(data); + } + + /** + * 访问网络成功 + */ + protected void netOnSuccess(Map data) { + + } + + /** + * 访问网络成功的其他状态 + */ + protected void netOnOtherStates(int status, String msg) { + if (loadingDialog != null && loadingDialog.isShowing()) { + loadingDialog.dismiss(); + } + } + + /** + * 访问网络成功的其他状态 + */ + protected void netOnOtherStates(int status, String msg, int requestCode) { + netOnOtherStates(status, msg); + } + + /** + * 访问网络结束 + */ + protected void netOnFinish() { + loadingDialog.dismiss(); + } + + /** + * 访问网络结束 + */ + protected void netOnFinish(int requestCode) { + loadingDialog.dismiss(); + netOnFinish(); + } + + /** + * 访问网络失败 + */ + protected void netOnFailure(Throwable ex, int requestCode) { + netOnFailure(ex); + } + + /** + * 访问网络失败 + */ + protected void netOnFailure(Throwable ex) { + Logger.d(ex.getMessage()); + if (ex instanceof HttpException) { // 网络错误 + HttpException httpEx = (HttpException) ex; + int responseCode = httpEx.getCode(); + String responseMsg = httpEx.getMessage(); + String errorResult = httpEx.getResult(); + Toast.makeText(x.app(), "网络错误:" + ex.getMessage(), Toast.LENGTH_LONG).show(); + // ... + } else if (ex instanceof SocketTimeoutException) { + Toast.makeText(x.app(), "连接服务器超时", Toast.LENGTH_LONG).show(); + } else if (ex != null && "网络不可用".equals(ex.getMessage())) { + } else { // 其他错误 + Toast.makeText(x.app(), "连接服务器失败,请稍后再试!", Toast.LENGTH_SHORT).show(); + // ... + } + } + + /** + * 取消访问网络 + */ + protected void netOnCancelled() { + } @Override public void onBackPressed() { @@ -599,7 +652,7 @@ public abstract class BaseActivity extends AutoLayoutActivity implements View.On } - protected void setEmptyView(ListView listView) { + protected T setEmptyView(ListView listView) { TextView emptyView = new TextView(context); emptyView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); emptyView.setText("暂无数据!"); @@ -608,9 +661,10 @@ public abstract class BaseActivity extends AutoLayoutActivity implements View.On emptyView.setVisibility(View.GONE); ((ViewGroup) listView.getParent()).addView(emptyView); listView.setEmptyView(emptyView); + return (T) emptyView; } - protected void setEmptyView(ListView listView, String text) { + protected T setEmptyView(ListView listView, String text) { TextView emptyView = new TextView(context); emptyView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); emptyView.setText(text); @@ -619,26 +673,121 @@ public abstract class BaseActivity extends AutoLayoutActivity implements View.On emptyView.setVisibility(View.GONE); ((ViewGroup) listView.getParent()).addView(emptyView); listView.setEmptyView(emptyView); + return (T) emptyView; + } + + protected T setEmptyView(GridView gridView) { + TextView emptyView = new TextView(context); + emptyView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + emptyView.setText("暂无数据!"); + emptyView.setGravity(Gravity.CENTER); + emptyView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + emptyView.setVisibility(View.GONE); + ((ViewGroup) gridView.getParent()).addView(emptyView); + gridView.setEmptyView(emptyView); + return (T) emptyView; + } + + protected T setEmptyView(GridView gridView, String text) { + TextView emptyView = new TextView(context); + emptyView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + emptyView.setText(text); + emptyView.setGravity(Gravity.CENTER); + emptyView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + emptyView.setVisibility(View.GONE); + ((ViewGroup) gridView.getParent()).addView(emptyView); + gridView.setEmptyView(emptyView); + return (T) emptyView; } @Override protected void onDestroy() { - super.onDestroy(); +// fixFocusedViewLeak(x.app()); +// fixInputMethodManager(); mContentLayout.removeAllViews(); mContentLayout = null; + if (cancelable != null && !cancelable.isCancelled()) { + cancelable.cancel(); + } AppManager.getAppManager().finishActivity(this); + super.onDestroy(); } @Override - public boolean onTouchEvent(MotionEvent event) { - if (null != this.getCurrentFocus()) { - /** - * 点击空白位置 隐藏软键盘 - */ - InputMethodManager mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); - return mInputMethodManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0); + public boolean dispatchTouchEvent(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + View v = getCurrentFocus(); + if (isShouldHideKeyboard(v, ev)) { + hideKeyboard(v.getWindowToken()); + } } - return super.onTouchEvent(event); + return super.dispatchTouchEvent(ev); } + + /** + * 根据EditText所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘,因为当用户点击EditText时则不能隐藏 + * + * @param v + * @param event + * @return + */ + private boolean isShouldHideKeyboard(View v, MotionEvent event) { + if (v != null && (v instanceof EditText)) { + int[] l = {0, 0}; + v.getLocationInWindow(l); + int left = l[0], + top = l[1], + bottom = top + v.getHeight(), + right = left + v.getWidth(); + if (event.getX() > left && event.getX() < right + && event.getY() > top && event.getY() < bottom) { + // 点击EditText的事件,忽略它。 + return false; + } else { + return true; + } + } + // 如果焦点不是EditText则忽略,这个发生在视图刚绘制完,第一个焦点不在EditText上,和用户用轨迹球选择其他的焦点 + return false; + } + + /** + * 获取InputMethodManager,隐藏软键盘 + * + * @param token + */ + private void hideKeyboard(IBinder token) { + if (token != null) { + InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + im.hideSoftInputFromWindow(token, InputMethodManager.HIDE_NOT_ALWAYS); + } + } + + // @Override +// public boolean onTouchEvent(MotionEvent event) { +// if (null != this.getCurrentFocus()) { +// /** +// * 点击空白位置 隐藏软键盘 +// */ +// InputMethodManager mInputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); +// return mInputMethodManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), 0); +// } +// return super.onTouchEvent(event); +// } + private void fixInputMethodManager() { + final Object imm = getSystemService(Context.INPUT_METHOD_SERVICE); + + final Reflector.TypedObject windowToken + = new Reflector.TypedObject(getWindow().getDecorView().getWindowToken(), IBinder.class); + + Reflector.invokeMethodExceptionSafe(imm, "windowDismissed", windowToken); + + final Reflector.TypedObject view + = new Reflector.TypedObject(null, View.class); + + Reflector.invokeMethodExceptionSafe(imm, "startGettingWindowFocus", view); + } + + } diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/base/BaseFragment.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/base/BaseFragment.java index 3b16f29..ca10fa8 100644 --- a/libray_lxndroid/src/main/java/com/kejiang/yuandl/base/BaseFragment.java +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/base/BaseFragment.java @@ -9,6 +9,7 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.GridView; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; @@ -20,6 +21,7 @@ import com.alibaba.fastjson.TypeReference; import com.kejiang.yuandl.app.MyApplication; import com.kejiang.yuandl.bean.JsonBean; import com.kejiang.yuandl.utils.CheckNetwork; +import com.kejiang.yuandl.utils.SharedPreferencesUtils; import com.kejiang.yuandl.utils.Tools; import com.kejiang.yuandl.view.LoadingDialog; import com.orhanobut.logger.Logger; @@ -35,6 +37,7 @@ import org.xutils.x; import java.net.SocketTimeoutException; import java.util.List; import java.util.Map; +import java.util.Set; /** * com.bm.falvzixun.fragment.BaseFragment @@ -50,7 +53,6 @@ public class BaseFragment extends Fragment { } - private Callback.Cancelable cancelable; /** * 加载数据对话框 @@ -63,7 +65,7 @@ public class BaseFragment extends Fragment { * * @param requestParams */ - private void ajax(RequestParams requestParams) { + protected void ajax(RequestParams requestParams) { ajax(requestParams, 0); } @@ -76,11 +78,24 @@ public class BaseFragment extends Fragment { protected void ajax(RequestParams requestParams, int requestCode) { if (!CheckNetwork.isNetworkAvailable(getContext())) { showToast("网络不可用,请检查网络连接!"); + netOnFailure(new Exception("网络不可用")); return; } if (loadingDialog == null) { loadingDialog = new LoadingDialog(getContext()); } + + SharedPreferencesUtils sp = new SharedPreferencesUtils(x.app()); + boolean isLogin = (boolean) sp.getParam("login", false); + if (isLogin) { + requestParams.addBodyParameter("mId", (String) sp.getParam("mId", "")); + } + boolean hasLocation = (boolean) sp.getParam("hasLocation", false); + if (hasLocation) { + requestParams.addBodyParameter("lng", (String) sp.getParam("lng", "")); + requestParams.addBodyParameter("lat", (String) sp.getParam("lat", "")); + } + Logger.d("url=" + requestParams.getUri() + "\nrequestParams=" + requestParams.getStringParams().toString()); List params = requestParams.getStringParams(); for (KeyValue keyValue : params) { @@ -129,8 +144,7 @@ public class BaseFragment extends Fragment { } netOnSuccess(data, requestCode); } else { - - netOnOtherStates(jsonBean.getStatus(), jsonBean.getMsg()); + netOnOtherStates(jsonBean.getStatus(), jsonBean.getMsg(), requestCode); } } catch (Exception e) { if (loadingDialog != null && loadingDialog.isShowing()) { @@ -157,7 +171,7 @@ public class BaseFragment extends Fragment { @Override public void onFinished() { - netOnFinish(); + netOnFinish(requestCode); } } @@ -168,22 +182,31 @@ public class BaseFragment extends Fragment { JsonBean jsonBean = new JsonBean(); if (arrayMap.containsKey("data")) { Object data = arrayMap.get("data"); - System.out.println("data.getClass().getName()=" + data.getClass().getName()); +// System.out.println("data.getClass().getName()=" + data.getClass().getName()); ArrayMap rrData = null; if (data instanceof String) { - System.out.println("data instanceof String"); +// System.out.println("data instanceof String"); rrData = new ArrayMap(); rrData.put("data", data.toString()); } else if (data instanceof JSONArray) { - System.out.println("data instanceof JSONArray"); +// System.out.println("data instanceof JSONArray"); rrData = new ArrayMap(); rrData.put("data", data); } else if (data instanceof com.alibaba.fastjson.JSONObject) { - System.out.println("data instanceof JSONObject"); +// System.out.println("data instanceof JSONObject"); rrData = JSON.parseObject(data.toString(), new TypeReference>() { }.getType()); } jsonBean.setData(rrData); + } else { + Set keys = arrayMap.keySet(); + ArrayMap rrData = new ArrayMap<>(); + for (String s : keys) { + if (!s.equals("status")) { + rrData.put(s, arrayMap.get(s)); + } + } + jsonBean.setData(rrData); } jsonBean.setStatus(Integer.valueOf(arrayMap.get("status").toString())); jsonBean.setMsg(Tools.getValue(arrayMap, "msg")); @@ -194,50 +217,65 @@ public class BaseFragment extends Fragment { /** * 开始访问网络 */ - public void netOnStart() { + protected void netOnStart() { loadingDialog.show("Loading..."); } /** * 访问网络的进程 */ - public void netOnLoading(long total, long current, boolean isUploading) { + protected void netOnLoading(long total, long current, boolean isUploading) { } /** * 访问网络成功 */ - public void netOnSuccess(Map data, int requestCode) { + protected void netOnSuccess(Map data, int requestCode) { netOnSuccess(data); } /** * 访问网络成功 */ - public void netOnSuccess(Map data) { + protected void netOnSuccess(Map data) { } /** * 访问网络成功的其他状态 */ - public void netOnOtherStates(int status, String msg) { + protected void netOnOtherStates(int status, String msg) { if (loadingDialog != null && loadingDialog.isShowing()) { loadingDialog.dismiss(); } } + /** + * 访问网络成功的其他状态 + */ + protected void netOnOtherStates(int status, String msg, int requestCode) { + netOnOtherStates(status, msg); + } + /** * 访问网络结束 */ - public void netOnFinish() { + protected void netOnFinish() { loadingDialog.dismiss(); } + /** + * 访问网络结束 + */ + protected void netOnFinish(int requestCode) { + loadingDialog.dismiss(); + netOnFinish(); + } + /** * 访问网络失败 */ - public void netOnFailure(Throwable ex) { + protected void netOnFailure(Throwable ex) { Logger.d(ex.getMessage()); if (ex instanceof HttpException) { // 网络错误 HttpException httpEx = (HttpException) ex; @@ -248,8 +286,10 @@ public class BaseFragment extends Fragment { // ... } else if (ex instanceof SocketTimeoutException) { Toast.makeText(x.app(), "连接服务器超时", Toast.LENGTH_LONG).show(); + } else if (ex!= null && "网络不可用".equals(ex.getMessage())) { + } else { // 其他错误 - Toast.makeText(x.app(), "连接服务器失败,请稍后再试!ex=" + ex.getMessage(), Toast.LENGTH_SHORT).show(); + Toast.makeText(x.app(), "连接服务器失败,请稍后再试!", Toast.LENGTH_SHORT).show(); // ... } @@ -358,10 +398,36 @@ public class BaseFragment extends Fragment { listView.setEmptyView(emptyView); } + protected void setEmptyView(GridView gridView) { + TextView emptyView = new TextView(getContext()); + emptyView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + emptyView.setText("暂无数据!"); + emptyView.setGravity(Gravity.CENTER); + emptyView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + emptyView.setVisibility(View.GONE); + ((ViewGroup) gridView.getParent()).addView(emptyView); + gridView.setEmptyView(emptyView); + } + + protected void setEmptyView(GridView gridView, String text) { + TextView emptyView = new TextView(getContext()); + emptyView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + emptyView.setText(text); + emptyView.setGravity(Gravity.CENTER); + emptyView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); + emptyView.setVisibility(View.GONE); + ((ViewGroup) gridView.getParent()).addView(emptyView); + gridView.setEmptyView(emptyView); + } + @Override public void onDestroy() { super.onDestroy(); + if (cancelable != null && !cancelable.isCancelled()) { + cancelable.cancel(); + } RefWatcher refWatcher = MyApplication.getRefWatcher(getActivity()); refWatcher.watch(this); } + } diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/base/BaseNetErrorActivity.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/base/BaseNetErrorActivity.java new file mode 100644 index 0000000..d41df92 --- /dev/null +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/base/BaseNetErrorActivity.java @@ -0,0 +1,49 @@ +package com.kejiang.yuandl.base; + +import android.view.View; +import android.view.ViewStub; + +import com.kejiang.yuandl.R; + +import java.util.Map; + +/** + * com.bm.falvzixun.activities.BaseActivity; + * + * @author yuandl on 2015/12/17. + * 所有页面的基类 + */ +public abstract class BaseNetErrorActivity extends BaseActivity { + private boolean isInflate = false; + + @Override + protected void netOnSuccess(Map data, int requestCode) { + super.netOnSuccess(data, requestCode); + (findViewById(R.id.vs)).setVisibility(View.GONE); + getContentLayout().setVisibility(View.VISIBLE); + } + + @Override + protected void netOnFailure(Throwable ex, int requestCode) { + super.netOnFailure(ex, requestCode); + getContentLayout().setVisibility(View.GONE); + if (!isInflate) { + ((ViewStub) findViewById(R.id.vs)).inflate(); + isInflate = true; + } else { + (findViewById(R.id.vs)).setVisibility(View.VISIBLE); + } + findViewById(R.id.bt_reload).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + reLoad(); + } + }); + } + + /** + * 重新加载数据 + */ + protected abstract void reLoad(); +} + diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/ImageDispose.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/ImageDispose.java index e87b99f..5ead3f5 100644 --- a/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/ImageDispose.java +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/ImageDispose.java @@ -90,7 +90,7 @@ public class ImageDispose { System.gc(); BitmapFactory.Options options = new BitmapFactory.Options(); options.inPurgeable = true; - options.inSampleSize = 2; + options.inSampleSize = inSampleSize; return options; } diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/MyHttpCallback.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/MyHttpCallback.java new file mode 100644 index 0000000..755dd45 --- /dev/null +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/MyHttpCallback.java @@ -0,0 +1,22 @@ +package com.kejiang.yuandl.utils; + +import java.util.Map; + +/** + * Created by yuandl on 2016/6/27 0027. + */ +public interface MyHttpCallback { + void netOnStart(); + + void netOnSuccess(Map data, int requestCode); + + void netOnSuccess(Map data); + + void netOnOtherStatus(int status, String msg, int requestCode); + void netOnOtherStatus(int status, String msg); + + void netOnFinish(); + + void netOnFailure(Throwable ex); + +} diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/MyHttpUtills.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/MyHttpUtills.java new file mode 100644 index 0000000..17c43e6 --- /dev/null +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/MyHttpUtills.java @@ -0,0 +1,304 @@ +package com.kejiang.yuandl.utils; + +import android.content.Context; +import android.support.v4.util.ArrayMap; +import android.widget.Toast; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONException; +import com.alibaba.fastjson.TypeReference; +import com.kejiang.yuandl.bean.JsonBean; +import com.kejiang.yuandl.view.LoadingDialog; +import com.orhanobut.logger.Logger; + +import org.xutils.common.Callback; +import org.xutils.common.util.KeyValue; +import org.xutils.ex.HttpException; +import org.xutils.http.RequestParams; +import org.xutils.x; + +import java.net.SocketTimeoutException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Created by yuandl on 2016/6/27 0027. + */ +public class MyHttpUtills { + + private Callback.Cancelable cancelable; + + private LoadingDialog loadingDialog; + + private Toast toast; + + private Context context; + + private MyHttpCallback myHttpCallback; + + public MyHttpUtills(Context context,MyHttpCallback myHttpCallback) { + this.context = context; + this.myHttpCallback = myHttpCallback; + } + + /** + * 异步网络请求类 + * + * @param requestParams + */ + public void ajax(RequestParams requestParams) { + ajax(requestParams, 0); + } + + /** + * 异步网络请求类 + * + * @param requestParams + * @param requestCode 区分不同的网络请求 + */ + public void ajax(RequestParams requestParams, int requestCode) { + if (!CheckNetwork.isNetworkAvailable(context)) { + showToast("网络不可用,请检查网络连接!"); + return; + } + if (loadingDialog == null) { + loadingDialog = new LoadingDialog(context); + } + SharedPreferencesUtils sp = new SharedPreferencesUtils(x.app()); + boolean isLogin = (boolean) sp.getParam("login", false); + if (isLogin) { + requestParams.addBodyParameter("mId", (String) sp.getParam("mId", "")); + } + boolean hasLocation = (boolean) sp.getParam("hasLocation", false); + if (hasLocation) { + requestParams.addBodyParameter("lng", (String) sp.getParam("lng", "")); + requestParams.addBodyParameter("lat", (String) sp.getParam("lat", "")); + } + Logger.d("url=" + requestParams.getUri() + "\nrequestParams=" + requestParams.getStringParams().toString()); + List params = requestParams.getStringParams(); + for (KeyValue keyValue : params) { + if (keyValue.key.contains(":")) { + throw new RuntimeException("参数异常!"); + } + } + cancelable = x.http().post(requestParams, new MyCallback(requestCode)); + } + + private class MyCallback implements Callback.ProgressCallback { + private int requestCode = 0; + + public MyCallback(int requestCode) { + this.requestCode = requestCode; + } + + @Override + public void onWaiting() { + } + + @Override + + public void onStarted() { + netOnStart(); + } + + @Override + public void onLoading(long total, long current, boolean isDownloading) { + netOnLoading(total, current, isDownloading); + } + + @Override + public void onSuccess(String result) { + Logger.json(result); + JsonBean jsonBean = null; + try { + jsonBean = jsonParse(result); + if (jsonBean.getMsg() != null && !jsonBean.getMsg().isEmpty()) { + showToast(jsonBean.getMsg()); + } + if (jsonBean.getStatus() == 1) { + Map data = new ArrayMap(); + if (null != jsonBean.getData() && jsonBean.getData().size() > 0) { + data = jsonBean.getData(); + } + netOnSuccess(data, requestCode); + } else { + netOnOtherStates(jsonBean.getStatus(), jsonBean.getMsg(), requestCode); + } + } catch (Exception e) { + if (loadingDialog != null && loadingDialog.isShowing()) { + loadingDialog.dismiss(); + } + Logger.d(result); + showToast("服务器异常!"); + e.printStackTrace(); + } finally { + } + } + + @Override + public void onError(Throwable ex, boolean isOnCallback) { + netOnFailure(ex); + + } + + @Override + public void onCancelled(Callback.CancelledException cex) { + Logger.d("用户取消了访问网络...."); + netOnCancelled(); + } + + @Override + public void onFinished() { + netOnFinish(requestCode); + } + + + } + + private JsonBean jsonParse(String json) throws JSONException { + ArrayMap arrayMap = JSON.parseObject(json, new TypeReference>() { + }.getType()); + JsonBean jsonBean = new JsonBean(); + if (arrayMap.containsKey("data")) { + Object data = arrayMap.get("data"); + System.out.println("data.getClass().getName()=" + data.getClass().getName()); + ArrayMap rrData = null; + if (data instanceof String) { + System.out.println("data instanceof String"); + rrData = new ArrayMap(); + rrData.put("data", data.toString()); + } else if (data instanceof JSONArray) { + System.out.println("data instanceof JSONArray"); + rrData = new ArrayMap(); + rrData.put("data", data); + } else if (data instanceof com.alibaba.fastjson.JSONObject) { + System.out.println("data instanceof JSONObject"); + rrData = JSON.parseObject(data.toString(), new TypeReference>() { + }.getType()); + } + jsonBean.setData(rrData); + } else { + Set keys = arrayMap.keySet(); + ArrayMap rrData = new ArrayMap<>(); + for (String s : keys) { + if (!s.equals("status") && !s.equals("msg")) { + rrData.put(s, arrayMap.get(s)); + } + } + jsonBean.setData(rrData); + } + jsonBean.setStatus(Integer.valueOf(arrayMap.get("status").toString())); + jsonBean.setMsg(Tools.getValue(arrayMap, "msg")); + + return jsonBean; + } + + /** + * 开始访问网络 + */ + protected void netOnStart() { + loadingDialog.show("Loading..."); + myHttpCallback.netOnStart(); + } + + /** + * 访问网络的进程 + */ + protected void netOnLoading(long total, long current, boolean isUploading) { + } + + /** + * 访问网络成功 + */ + protected void netOnSuccess(Map data, int requestCode) { + netOnSuccess(data); + myHttpCallback.netOnSuccess(data,requestCode); + } + + /** + * 访问网络成功 + */ + protected void netOnSuccess(Map data) { + myHttpCallback.netOnSuccess(data); + } + + /** + * 访问网络成功的其他状态 + */ + protected void netOnOtherStates(int status, String msg) { + myHttpCallback.netOnOtherStatus(status, msg); + if (loadingDialog != null && loadingDialog.isShowing()) { + loadingDialog.dismiss(); + } + } + + /** + * 访问网络成功的其他状态 + */ + protected void netOnOtherStates(int status, String msg, int requestCode) { + netOnOtherStates(status, msg); + myHttpCallback.netOnOtherStatus(status, msg, requestCode); + } + + /** + * 访问网络结束 + */ + protected void netOnFinish() { + loadingDialog.dismiss(); + myHttpCallback.netOnFinish(); + } + + /** + * 访问网络结束 + */ + protected void netOnFinish(int requestCode) { + loadingDialog.dismiss(); + netOnFinish(); + } + + /** + * 访问网络失败 + */ + protected void netOnFailure(Throwable ex) { + Logger.d(ex.getMessage()); + if (ex instanceof HttpException) { // 网络错误 + HttpException httpEx = (HttpException) ex; + int responseCode = httpEx.getCode(); + String responseMsg = httpEx.getMessage(); + String errorResult = httpEx.getResult(); + Toast.makeText(x.app(), "网络错误:" + ex.getMessage(), Toast.LENGTH_LONG).show(); + // ... + } else if (ex instanceof SocketTimeoutException) { + Toast.makeText(x.app(), "连接服务器超时", Toast.LENGTH_LONG).show(); + } else { // 其他错误 + Toast.makeText(x.app(), "连接服务器失败,请稍后再试!ex=" + ex.getMessage(), Toast.LENGTH_SHORT).show(); + // ... + } + myHttpCallback.netOnFailure(ex); + myHttpCallback.netOnFinish(); + + } + + /** + * 取消访问网络 + */ + protected void netOnCancelled() { + } + + /** + * 弹出Toast便捷方法 + * + * @param charSequence + */ + public void showToast(CharSequence charSequence) { + if (null == toast) { + toast = Toast.makeText(x.app(), charSequence, Toast.LENGTH_SHORT); + } else { + toast.setText(charSequence); + } + toast.show(); + + } +} diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/Reflector.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/Reflector.java new file mode 100644 index 0000000..554547c --- /dev/null +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/Reflector.java @@ -0,0 +1,61 @@ +package com.kejiang.yuandl.utils; + +import java.lang.reflect.Method; + +/** + * Created by yuandl on 2016/7/19 0019. + */ +public class Reflector { + public static final class TypedObject + { + private final Object object; + private final Class type; + + public TypedObject(final Object object, final Class type) + { + this.object = object; + this.type = type; + } + + Object getObject() + { + return object; + } + + Class getType() + { + return type; + } + } + + public static void invokeMethodExceptionSafe(final Object methodOwner, final String method, final TypedObject... arguments) + { + if (null == methodOwner) + { + return; + } + + try + { + final Class[] types = null == arguments ? new Class[0] : new Class[arguments.length]; + final Object[] objects = null == arguments ? new Object[0] : new Object[arguments.length]; + + if (null != arguments) + { + for (int i = 0, limit = types.length; i < limit; i++) + { + types[i] = arguments[i].getType(); + objects[i] = arguments[i].getObject(); + } + } + + final Method declaredMethod = methodOwner.getClass().getDeclaredMethod(method, types); + + declaredMethod.setAccessible(true); + declaredMethod.invoke(methodOwner, objects); + } + catch (final Throwable ignored) + { + } + } +} diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/SeralizableMap.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/SeralizableMap.java new file mode 100644 index 0000000..59f6b33 --- /dev/null +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/SeralizableMap.java @@ -0,0 +1,20 @@ +package com.kejiang.yuandl.utils; + +import java.io.Serializable; +import java.util.Map; + +public class SeralizableMap implements Serializable { + /** + * + */ + private static final long serialVersionUID = 1L; + private Map map; + + public Map getMap() { + return map; + } + + public void setMap(Map map) { + this.map = map; + } +} diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/SharedPreferencesUtils.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/SharedPreferencesUtils.java index 3184510..70a52c1 100644 --- a/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/SharedPreferencesUtils.java +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/utils/SharedPreferencesUtils.java @@ -49,7 +49,7 @@ public class SharedPreferencesUtils { String type = object.getClass().getSimpleName(); SharedPreferences sp = context.getSharedPreferences(FILE_NAME, - Context.MODE_PRIVATE); + Context.MODE_MULTI_PROCESS); SharedPreferences.Editor editor = sp.edit(); if ("String".equals(type)) { editor.putString(key, object.toString()); diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/view/MyGallery.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/view/MyGallery.java index 6e0a75a..a99ffe8 100644 --- a/libray_lxndroid/src/main/java/com/kejiang/yuandl/view/MyGallery.java +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/view/MyGallery.java @@ -140,6 +140,7 @@ public class MyGallery extends Gallery implements OnItemSelectedListener { public void destroy() { timer.cancel(); + mHandler.removeCallbacks(task); } @Override diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/view/RatingBar.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/view/RatingBar.java index 79036fa..4fdb9ca 100644 --- a/libray_lxndroid/src/main/java/com/kejiang/yuandl/view/RatingBar.java +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/view/RatingBar.java @@ -93,7 +93,7 @@ public class RatingBar extends LinearLayout { } if (indexOfChild(v) > fint) { - setStar(indexOfChild(v) + 0.5f); + setStar(indexOfChild(v) + 1); } else if (indexOfChild(v) == fint) { if (imageView.getDrawable().getCurrent().getConstantState().equals(starHalfDrawable.getConstantState())) { setStar(indexOfChild(v) + 1); @@ -101,7 +101,7 @@ public class RatingBar extends LinearLayout { setStar(indexOfChild(v) + 0.5f); } } else { - setStar(indexOfChild(v) + 1); + setStar(indexOfChild(v) + 1f); } } diff --git a/libray_lxndroid/src/main/java/com/kejiang/yuandl/view/SlideDetailsLayout.java b/libray_lxndroid/src/main/java/com/kejiang/yuandl/view/SlideDetailsLayout.java new file mode 100644 index 0000000..7ec4c56 --- /dev/null +++ b/libray_lxndroid/src/main/java/com/kejiang/yuandl/view/SlideDetailsLayout.java @@ -0,0 +1,632 @@ +package com.kejiang.yuandl.view; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.TypedArray; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.v4.view.MotionEventCompat; +import android.support.v4.view.ViewCompat; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.widget.AbsListView; + +import com.kejiang.yuandl.R; + + +/** + * Project: SlideDetailsLayout
+ * Create Date: 16/1/22
+ * Author: Gordon
+ * Description: + * Pull up to open panel, pull down to close panel. + *
+ */ +@SuppressWarnings("unused") +public class SlideDetailsLayout extends ViewGroup { + + /** + * Callback for panel OPEN-CLOSE status changed. + */ + public interface OnSlideDetailsListener { + /** + * Called after status changed. + * + * @param status {@link Status} + */ + void onStatucChanged(Status status); + } + + public enum Status { + /** Panel is closed */ + CLOSE, + /** Panel is opened */ + OPEN; + + public static Status valueOf(int stats) { + if (0 == stats) { + return CLOSE; + } else if (1 == stats) { + return OPEN; + } else { + return CLOSE; + } + } + } + + private static final float DEFAULT_PERCENT = 0.2f; + private static final int DEFAULT_DURATION = 300; + private static final float DEFAULT_MAX_VELOCITY = 2500f; + + private View mFrontView; + private View mBehindView; + + private float mTouchSlop; + private float mInitMotionY; + private float mInitMotionX; + + + private View mTarget; + private float mSlideOffset; + private Status mStatus = Status.CLOSE; + private boolean isFirstShowBehindView = true; + private float mPercent = DEFAULT_PERCENT; + private long mDuration = DEFAULT_DURATION; + private int mDefaultPanel = 0; + private VelocityTracker mVelocityTracker; + + private OnSlideDetailsListener mOnSlideDetailsListener; + + public SlideDetailsLayout(Context context) { + this(context, null); + } + + public SlideDetailsLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SlideDetailsLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlideDetailsLayout, defStyleAttr, 0); + mPercent = a.getFloat(R.styleable.SlideDetailsLayout_percent, DEFAULT_PERCENT); + mDuration = a.getInt(R.styleable.SlideDetailsLayout_duration, DEFAULT_DURATION); + mDefaultPanel = a.getInt(R.styleable.SlideDetailsLayout_default_panel, 0); + a.recycle(); + + mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); + } + + /** + * Set the callback of panel OPEN-CLOSE status. + * + * @param listener {@link OnSlideDetailsListener} + */ + public void setOnSlideDetailsListener(OnSlideDetailsListener listener) { + this.mOnSlideDetailsListener = listener; + } + + /** + * Open pannel smoothly. + * + * @param smooth true, smoothly. false otherwise. + */ + public void smoothOpen(boolean smooth) { + if (mStatus != Status.OPEN) { + mStatus = Status.OPEN; + final float height = -getMeasuredHeight(); + animatorSwitch(0, height, true, smooth ? mDuration : 0); + } + } + + /** + * Close pannel smoothly. + * + * @param smooth true, smoothly. false otherwise. + */ + public void smoothClose(boolean smooth) { + if (mStatus != Status.CLOSE) { + mStatus = Status.OPEN; + final float height = -getMeasuredHeight(); + animatorSwitch(height, 0, true, smooth ? mDuration : 0); + } + } + + /** + * Set the float value for indicate the moment of switch panel + * + * @param percent (0.0, 1.0) + */ + public void setPercent(float percent) { + this.mPercent = percent; + } + + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new MarginLayoutParams(MarginLayoutParams.WRAP_CONTENT, MarginLayoutParams.WRAP_CONTENT); + } + + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new MarginLayoutParams(getContext(), attrs); + } + + @Override + protected LayoutParams generateLayoutParams(LayoutParams p) { + return new MarginLayoutParams(p); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + final int childCount = getChildCount(); + if (1 >= childCount) { + throw new RuntimeException("SlideDetailsLayout only accept childs more than 1!!"); + } + + mFrontView = getChildAt(0); + mBehindView = getChildAt(1); + + // set behindview's visibility to GONE before show. + mBehindView.setVisibility(GONE); + if (mDefaultPanel == 1) { + post(new Runnable() { + @Override + public void run() { + smoothOpen(false); + } + }); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int pWidth = MeasureSpec.getSize(widthMeasureSpec); + final int pHeight = MeasureSpec.getSize(heightMeasureSpec); + + final int childWidthMeasureSpec = + MeasureSpec.makeMeasureSpec(pWidth, MeasureSpec.EXACTLY); + final int childHeightMeasureSpec = + MeasureSpec.makeMeasureSpec(pHeight, MeasureSpec.EXACTLY); + + View child; + for (int i = 0; i < getChildCount(); i++) { + child = getChildAt(i); + // skip measure if gone + if (child.getVisibility() == GONE) { + continue; + } + + measureChild(child, childWidthMeasureSpec, childHeightMeasureSpec); + } + + setMeasuredDimension(pWidth, pHeight); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int left = l; + final int right = r; + int top; + int bottom; + + final int offset = (int) mSlideOffset; + + View child; + for (int i = 0; i < getChildCount(); i++) { + child = getChildAt(i); + + // skip layout + if (child.getVisibility() == GONE) { + continue; + } + + if (child == mBehindView) { + top = b + offset; + bottom = top + b - t; + } else { + top = 0; + bottom = b + offset; + } + + child.layout(left, top, right, bottom); + } + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + ensureTarget(); + if (null == mTarget) { + return false; + } + + if (!isEnabled()) { + return false; + } + + final int aciton = MotionEventCompat.getActionMasked(ev); + + boolean shouldIntercept = false; + switch (aciton) { + case MotionEvent.ACTION_DOWN: { + if (null == mVelocityTracker) { + mVelocityTracker = VelocityTracker.obtain(); + } else { + mVelocityTracker.clear(); + } + mVelocityTracker.addMovement(ev); + + mInitMotionX = ev.getX(); + mInitMotionY = ev.getY(); + shouldIntercept = false; + break; + } + case MotionEvent.ACTION_MOVE: { + final float x = ev.getX(); + final float y = ev.getY(); + + final float xDiff = x - mInitMotionX; + final float yDiff = y - mInitMotionY; + + if (canChildScrollVertically((int) yDiff)) { + shouldIntercept = false; +// if (DEBUG) { +// Log.d(TAG, "intercept, child can scroll vertically, do not intercept"); +// } + } else { + final float xDiffabs = Math.abs(xDiff); + final float yDiffabs = Math.abs(yDiff); + + // intercept rules: + // 1. The vertical displacement is larger than the horizontal displacement; + // 2. Panel stauts is CLOSE:slide up + // 3. Panel status is OPEN:slide down + if (yDiffabs > mTouchSlop && yDiffabs >= xDiffabs + && !(mStatus == Status.CLOSE && yDiff > 0 + || mStatus == Status.OPEN && yDiff < 0)) { + shouldIntercept = true; +// if (DEBUG) { +// Log.d(TAG, "intercept, intercept events"); +// } + } + } + break; + } + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: { + shouldIntercept = false; + break; + } + + } + + return shouldIntercept; + } + + private void recycleVelocityTracker(){ + if(null != mVelocityTracker){ + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + ensureTarget(); + if (null == mTarget) { + return false; + } + + if (!isEnabled()) { + return false; + } + + + boolean wantTouch = true; + final int action = MotionEventCompat.getActionMasked(ev); + + switch (action) { + case MotionEvent.ACTION_DOWN: { + // if target is a view, we want the DOWN action. + if (mTarget instanceof View) { + wantTouch = true; + } + break; + } + + case MotionEvent.ACTION_MOVE: { + mVelocityTracker.addMovement(ev); + mVelocityTracker.computeCurrentVelocity(1000); + final float y = ev.getY(); + final float yDiff = y - mInitMotionY; + if (canChildScrollVertically(((int) yDiff))) { + wantTouch = false; + } else { + processTouchEvent(yDiff); + wantTouch = true; + } + break; + } + + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: { + finishTouchEvent(); + recycleVelocityTracker(); + wantTouch = false; + break; + } + } + return wantTouch; + } + + /** + * @param offset Displacement in vertically. + */ + private void processTouchEvent(final float offset) { + if (Math.abs(offset) < mTouchSlop) { + return; + } + + final float oldOffset = mSlideOffset; + // pull up to open + if (mStatus == Status.CLOSE) { + // reset if pull down + if (offset >= 0) { + mSlideOffset = 0; + } else { + mSlideOffset = offset; + } + + if (mSlideOffset == oldOffset) { + return; + } + + // pull down to close + } else if (mStatus == Status.OPEN) { + final float pHeight = -getMeasuredHeight(); + // reset if pull up + if (offset <= 0) { + mSlideOffset = pHeight; + } else { + final float newOffset = pHeight + offset; + mSlideOffset = newOffset; + } + + if (mSlideOffset == oldOffset) { + return; + } + } + +// if (SlideDebug.DEBUG) { +// Log.v("slide", "process, offset: " + mSlideOffset); +// } + // relayout + requestLayout(); + } + + /** + * Called after gesture is ending. + */ + private void finishTouchEvent() { + final int pHeight = getMeasuredHeight(); + final int percent = (int) (pHeight * mPercent); + final float offset = mSlideOffset; + + boolean changed = false; + final float yVelocity = mVelocityTracker.getYVelocity(); + +// if (DEBUG) { +// Log.v(TAG, "finish, offset: " + offset + ", percent: " + percent + ", yVelocity: " + yVelocity); +// } + + if (Status.CLOSE == mStatus) { + if (offset <= -percent || yVelocity <= -DEFAULT_MAX_VELOCITY) { + mSlideOffset = -pHeight; + mStatus = Status.OPEN; + changed = true; + } else { + // keep panel closed + mSlideOffset = 0; + } + } else if (Status.OPEN == mStatus) { + if ((offset + pHeight) >= percent || yVelocity >= DEFAULT_MAX_VELOCITY) { + mSlideOffset = 0; + mStatus = Status.CLOSE; + changed = true; + } else { + // keep panel opened + mSlideOffset = -pHeight; + } + } + + animatorSwitch(offset, mSlideOffset, changed); + } + + private void animatorSwitch(final float start, final float end) { + animatorSwitch(start, end, true, mDuration); + } + + private void animatorSwitch(final float start, final float end, final long duration) { + animatorSwitch(start, end, true, duration); + } + + private void animatorSwitch(final float start, final float end, final boolean changed) { + animatorSwitch(start, end, changed, mDuration); + } + + private void animatorSwitch(final float start, + final float end, + final boolean changed, + final long duration) { + ValueAnimator animator = ValueAnimator.ofFloat(start, end); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mSlideOffset = (float) animation.getAnimatedValue(); + requestLayout(); + } + }); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + if (changed) { + if (mStatus == Status.OPEN) { + checkAndFirstOpenPanel(); + } + + if (null != mOnSlideDetailsListener) { + mOnSlideDetailsListener.onStatucChanged(mStatus); + } + } + } + }); + animator.setDuration(duration); + animator.start(); + } + + /** + * Whether the closed pannel is opened at first time. + * If open first, we should set the behind view's visibility as VISIBLE. + */ + private void checkAndFirstOpenPanel() { + if (isFirstShowBehindView) { + isFirstShowBehindView = false; + mBehindView.setVisibility(VISIBLE); + } + } + + /** + * When pulling, target view changed by the panel status. If panel opened, the target is behind view. + * Front view is for otherwise. + */ + private void ensureTarget() { + if (mStatus == Status.CLOSE) { + mTarget = mFrontView; + } else { + mTarget = mBehindView; + } + } + + /** + * Check child view can srcollable in vertical direction. + * + * @param direction Negative to check scrolling up, positive to check scrolling down. + * + * @return true if this view can be scrolled in the specified direction, false otherwise. + */ + protected boolean canChildScrollVertically(int direction) { + return innerCanChildScrollVertically(mTarget, -direction); + } + + private boolean innerCanChildScrollVertically(View view, int direction) { + if (view instanceof ViewGroup) { + final ViewGroup vGroup = (ViewGroup) view; + View child; + boolean result; + for (int i = 0; i < vGroup.getChildCount(); i++) { + child = vGroup.getChildAt(i); + if (child instanceof View) { + result = ViewCompat.canScrollVertically(child, direction); + } else { + result = innerCanChildScrollVertically(child, direction); + } + + if (result) { + return true; + } + } + } + + return ViewCompat.canScrollVertically(view, direction); + } + + protected boolean canListViewSroll(AbsListView absListView) { + if (mStatus == Status.OPEN) { + return absListView.getChildCount() > 0 + && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0) + .getTop() < + absListView.getPaddingTop()); + } else { + final int count = absListView.getChildCount(); + return count > 0 + && (absListView.getLastVisiblePosition() < count - 1 + || absListView.getChildAt(count - 1) + .getBottom() > absListView.getMeasuredHeight()); + } + } + + @Override + protected Parcelable onSaveInstanceState() { + SavedState ss = new SavedState(super.onSaveInstanceState()); + ss.offset = mSlideOffset; + ss.status = mStatus.ordinal(); + return ss; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + mSlideOffset = ss.offset; + mStatus = Status.valueOf(ss.status); + + if (mStatus == Status.OPEN) { + mBehindView.setVisibility(VISIBLE); + } + + requestLayout(); + } + + static class SavedState extends BaseSavedState { + + private float offset; + private int status; + + /** + * Constructor used when reading from a parcel. Reads the state of the superclass. + * + * @param source + */ + public SavedState(Parcel source) { + super(source); + offset = source.readFloat(); + status = source.readInt(); + } + + /** + * Constructor called by derived classes when creating their SavedState objects + * + * @param superState The state of the superclass of this view + */ + public SavedState(Parcelable superState) { + super(superState); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeFloat(offset); + out.writeInt(status); + } + + public static final Creator CREATOR = + new Creator() { + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } +} diff --git a/libray_lxndroid/src/main/res/drawable/net_error.png b/libray_lxndroid/src/main/res/drawable/net_error.png new file mode 100644 index 0000000..a30a416 Binary files /dev/null and b/libray_lxndroid/src/main/res/drawable/net_error.png differ diff --git a/libray_lxndroid/src/main/res/drawable/reload.png b/libray_lxndroid/src/main/res/drawable/reload.png new file mode 100644 index 0000000..3cf03f0 Binary files /dev/null and b/libray_lxndroid/src/main/res/drawable/reload.png differ diff --git a/libray_lxndroid/src/main/res/layout/ac_title.xml b/libray_lxndroid/src/main/res/layout/ac_title.xml index 1455f20..61ab346 100644 --- a/libray_lxndroid/src/main/res/layout/ac_title.xml +++ b/libray_lxndroid/src/main/res/layout/ac_title.xml @@ -17,5 +17,9 @@ android:layout_width="match_parent" android:layout_height="match_parent" > - + \ No newline at end of file diff --git a/libray_lxndroid/src/main/res/layout/pub_net_error.xml b/libray_lxndroid/src/main/res/layout/pub_net_error.xml new file mode 100644 index 0000000..4b9980b --- /dev/null +++ b/libray_lxndroid/src/main/res/layout/pub_net_error.xml @@ -0,0 +1,15 @@ + + + +