优化demo代码,demo添加代码使用示例
This commit is contained in:
@@ -1,14 +1,12 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.lyy.frame">
|
||||
package="com.lyy.frame">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true">
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true">
|
||||
|
||||
</application>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
13
AppFrame/src/main/java/com/arialyy/frame/base/BaseApp.java
Normal file
13
AppFrame/src/main/java/com/arialyy/frame/base/BaseApp.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.arialyy.frame.base;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/11/26.
|
||||
*/
|
||||
|
||||
public class BaseApp {
|
||||
public static Context context;
|
||||
public static Application app;
|
||||
}
|
||||
108
AppFrame/src/main/java/com/arialyy/frame/base/BaseDialog.java
Normal file
108
AppFrame/src/main/java/com/arialyy/frame/base/BaseDialog.java
Normal file
@@ -0,0 +1,108 @@
|
||||
package com.arialyy.frame.base;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.IntEvaluator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.app.Dialog;
|
||||
import android.databinding.ViewDataBinding;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.BounceInterpolator;
|
||||
import com.arialyy.frame.core.AbsDialogFragment;
|
||||
import com.arialyy.frame.util.AndroidUtils;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/12/4.
|
||||
*/
|
||||
|
||||
public abstract class BaseDialog<VB extends ViewDataBinding> extends AbsDialogFragment<VB> {
|
||||
private WindowManager.LayoutParams mWpm;
|
||||
private Window mWindow;
|
||||
protected boolean useDefaultAnim = true;
|
||||
|
||||
@Override protected void init(Bundle savedInstanceState) {
|
||||
mWindow = getDialog().getWindow();
|
||||
if (mWindow != null) {
|
||||
mWpm = mWindow.getAttributes();
|
||||
}
|
||||
if (mWpm != null && mWindow != null) {
|
||||
//mView = mWindow.getDecorView();
|
||||
mRootView.setBackgroundColor(Color.WHITE);
|
||||
mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||
//in();
|
||||
if (useDefaultAnim) {
|
||||
in1();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void dismiss() {
|
||||
if (mWpm != null && mWindow != null) {
|
||||
if (useDefaultAnim) {
|
||||
out();
|
||||
}
|
||||
} else {
|
||||
super.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override protected void dataCallback(int result, Object data) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 进场动画
|
||||
*/
|
||||
private void in() {
|
||||
int height = AndroidUtils.getScreenParams(getContext())[1];
|
||||
ValueAnimator animator = ValueAnimator.ofObject(new IntEvaluator(), -height / 2, 0);
|
||||
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mWpm.y = (int) animation.getAnimatedValue();
|
||||
mWindow.setAttributes(mWpm);
|
||||
}
|
||||
});
|
||||
animator.setInterpolator(new BounceInterpolator()); //弹跳
|
||||
Animator alpha = ObjectAnimator.ofFloat(mRootView, "alpha", 0f, 1f);
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
set.play(animator).with(alpha);
|
||||
set.setDuration(2000).start();
|
||||
}
|
||||
|
||||
private void in1() {
|
||||
Animator alpha = ObjectAnimator.ofFloat(mRootView, "alpha", 0f, 1f);
|
||||
alpha.setDuration(800);
|
||||
alpha.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重力动画
|
||||
*/
|
||||
private void out() {
|
||||
int height = AndroidUtils.getScreenParams(getContext())[1];
|
||||
ValueAnimator animator = ValueAnimator.ofObject(new IntEvaluator(), 0, height / 3);
|
||||
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mWpm.y = (int) animation.getAnimatedValue();
|
||||
mWindow.setAttributes(mWpm);
|
||||
}
|
||||
});
|
||||
Animator alpha = ObjectAnimator.ofFloat(mRootView, "alpha", 1f, 0f);
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
set.play(animator).with(alpha);
|
||||
set.addListener(new AnimatorListenerAdapter() {
|
||||
@Override public void onAnimationEnd(Animator animation) {
|
||||
BaseDialog.super.dismiss();
|
||||
}
|
||||
});
|
||||
set.setDuration(600).start();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.arialyy.frame.base;
|
||||
|
||||
import android.databinding.ViewDataBinding;
|
||||
import com.arialyy.frame.core.AbsFragment;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2017/12/1.
|
||||
*/
|
||||
public abstract class BaseFragment<VB extends ViewDataBinding> extends AbsFragment<VB> {
|
||||
public int color;
|
||||
|
||||
@Override protected void dataCallback(int result, Object obj) {
|
||||
|
||||
}
|
||||
|
||||
@Override protected void onDelayLoad() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.arialyy.frame.base;
|
||||
|
||||
import android.arch.lifecycle.ViewModel;
|
||||
import com.arialyy.frame.base.net.NetManager;
|
||||
import com.arialyy.frame.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/11/26.
|
||||
* ViewModule只能是public
|
||||
*/
|
||||
|
||||
public class BaseViewModule extends ViewModel {
|
||||
protected NetManager mNetManager;
|
||||
protected String TAG = "";
|
||||
|
||||
public BaseViewModule() {
|
||||
mNetManager = NetManager.getInstance();
|
||||
TAG = StringUtil.getClassName(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.arialyy.frame.base;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class StatusBarCompat {
|
||||
private static final int INVALID_VAL = -1;
|
||||
private static final int COLOR_DEFAULT = Color.parseColor("#20000000");
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public static void compat(Activity activity, int statusColor) {
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
if (statusColor != INVALID_VAL) {
|
||||
activity.getWindow().setStatusBarColor(statusColor);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
|
||||
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
int color = COLOR_DEFAULT;
|
||||
ViewGroup contentView = activity.findViewById(android.R.id.content);
|
||||
if (statusColor != INVALID_VAL) {
|
||||
color = statusColor;
|
||||
}
|
||||
View statusBarView = new View(activity);
|
||||
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
getStatusBarHeight(activity));
|
||||
statusBarView.setBackgroundColor(color);
|
||||
contentView.addView(statusBarView, lp);
|
||||
}
|
||||
}
|
||||
|
||||
public static void compat(Activity activity) {
|
||||
compat(activity, INVALID_VAL);
|
||||
}
|
||||
|
||||
public static int getStatusBarHeight(Context context) {
|
||||
int result = 0;
|
||||
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
|
||||
if (resourceId > 0) {
|
||||
result = context.getResources().getDimensionPixelSize(resourceId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.arialyy.frame.base.net;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* 自定义Gson描述
|
||||
* Created by “Aria.Lao” on 2016/10/26.
|
||||
*
|
||||
* @param <T> 服务器数据实体
|
||||
*/
|
||||
public class BasicDeserializer<T> implements JsonDeserializer<T> {
|
||||
@Override
|
||||
public T deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
JsonObject root = element.getAsJsonObject();
|
||||
if (JsonCodeAnalysisUtil.isSuccess(root)) {
|
||||
return new Gson().fromJson(root.get("object"), typeOfT);
|
||||
} else {
|
||||
throw new IllegalStateException(root.get("rltmsg").getAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.arialyy.frame.base.net;
|
||||
|
||||
import com.arialyy.frame.util.show.FL;
|
||||
import com.arialyy.frame.util.show.L;
|
||||
import rx.Observable;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.functions.Func1;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Created by “Aria.Lao” on 2016/10/26.
|
||||
* HTTP数据回调
|
||||
*/
|
||||
public abstract class HttpCallback<T> implements INetResponse<T>, Observable.Transformer<T, T> {
|
||||
|
||||
@Override public void onFailure(Throwable e) {
|
||||
L.e("HttpCallback", FL.getExceptionString(e));
|
||||
}
|
||||
|
||||
@Override public Observable<T> call(Observable<T> observable) {
|
||||
Observable<T> tObservable = observable.subscribeOn(Schedulers.io())
|
||||
.unsubscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map(new Func1<T, T>() {
|
||||
@Override public T call(T t) {
|
||||
onResponse(t);
|
||||
return t;
|
||||
}
|
||||
})
|
||||
.onErrorReturn(new Func1<Throwable, T>() {
|
||||
@Override public T call(Throwable throwable) {
|
||||
onFailure(throwable);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
tObservable.subscribe();
|
||||
return tObservable;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.arialyy.frame.base.net;
|
||||
|
||||
/**
|
||||
* Created by “Aria.Lao” on 2016/10/25.
|
||||
* 网络响应接口,所有的网络回调都要继承该接口
|
||||
*
|
||||
* @param <T> 数据实体结构
|
||||
*/
|
||||
public interface INetResponse<T> {
|
||||
|
||||
/**
|
||||
* 网络请求成功
|
||||
*/
|
||||
public void onResponse(T response);
|
||||
|
||||
/**
|
||||
* 请求失败
|
||||
*/
|
||||
public void onFailure(Throwable e);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.arialyy.frame.base.net;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/11/26.
|
||||
*/
|
||||
|
||||
public class JsonCodeAnalysisUtil {
|
||||
|
||||
public static boolean isSuccess(JsonObject obj) {
|
||||
JSONObject object = null;
|
||||
try {
|
||||
object = new JSONObject(obj.toString());
|
||||
return object.optBoolean("success");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.arialyy.frame.base.net;
|
||||
|
||||
import android.util.SparseArray;
|
||||
import com.arialyy.frame.base.BaseApp;
|
||||
import com.arialyy.frame.config.CommonConstant;
|
||||
import com.arialyy.frame.config.NetConstant;
|
||||
import com.franmontiel.persistentcookiejar.ClearableCookieJar;
|
||||
import com.franmontiel.persistentcookiejar.PersistentCookieJar;
|
||||
import com.franmontiel.persistentcookiejar.cache.SetCookieCache;
|
||||
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor;
|
||||
import com.google.gson.Gson;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import okhttp3.OkHttpClient;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
/**
|
||||
* Created by “Aria.Lao” on 2016/10/25.
|
||||
* 网络管理器
|
||||
*/
|
||||
public class NetManager {
|
||||
private static final Object LOCK = new Object();
|
||||
private static volatile NetManager INSTANCE = null;
|
||||
private static final long TIME_OUT = 8 * 1000;
|
||||
private Retrofit mRetrofit;
|
||||
private Retrofit.Builder mBuilder;
|
||||
private SparseArray<GsonConverterFactory> mConverterFactorys = new SparseArray<>();
|
||||
private ClearableCookieJar mCookieJar;
|
||||
|
||||
private NetManager() {
|
||||
init();
|
||||
}
|
||||
|
||||
public static NetManager getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (LOCK) {
|
||||
INSTANCE = new NetManager();
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
OkHttpClient okHttpClient;
|
||||
|
||||
private void init() {
|
||||
mCookieJar = new PersistentCookieJar(new SetCookieCache(),
|
||||
new SharedPrefsCookiePersistor(BaseApp.context));
|
||||
//OkHttpClient okHttpClient = provideOkHttpClient();
|
||||
okHttpClient = provideOkHttpClient();
|
||||
}
|
||||
|
||||
public ClearableCookieJar getCookieJar() {
|
||||
return mCookieJar;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行网络请求
|
||||
*
|
||||
* @param service 服务器返回的实体类型
|
||||
* @param gson gson 为传入的数据解析器,ENTITY 为 网络实体
|
||||
* <pre><code>
|
||||
* Gson gson = new GsonBuilder().registerTypeAdapter(new TypeToken<ENTITY>() {
|
||||
* }.getType(), new BasicDeserializer<ENTITY>()).create();
|
||||
*
|
||||
* //如启动图,需要将‘ENTITY’替换为启动图实体‘LauncherImgEntity’
|
||||
* Gson gson = new GsonBuilder().registerTypeAdapter(new TypeToken<LauncherImgEntity>() {
|
||||
* }.getType(), new BasicDeserializer<LauncherImgEntity>()).create();
|
||||
*
|
||||
* </code></pre>
|
||||
*/
|
||||
public <SERVICE> SERVICE request(Class<SERVICE> service, Gson gson) {
|
||||
GsonConverterFactory f = null;
|
||||
if (gson == null) {
|
||||
f = GsonConverterFactory.create();
|
||||
} else {
|
||||
f = GsonConverterFactory.create(gson);
|
||||
}
|
||||
;
|
||||
final Retrofit.Builder builder = new Retrofit.Builder().client(okHttpClient)
|
||||
.baseUrl(NetConstant.BASE_URL)
|
||||
.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
|
||||
builder.addConverterFactory(f);
|
||||
return builder.build().create(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建OKHTTP
|
||||
*/
|
||||
private OkHttpClient provideOkHttpClient() {
|
||||
final OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||
if (CommonConstant.DEBUG) {
|
||||
//HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
|
||||
//logging.setLevel(HttpLoggingInterceptor.Level.BODY);
|
||||
//builder.addInterceptor(logging);
|
||||
builder.addInterceptor(new OkHttpLogger());
|
||||
}
|
||||
builder.connectTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
|
||||
.readTimeout(TIME_OUT, TimeUnit.MILLISECONDS);
|
||||
builder.cookieJar(mCookieJar);
|
||||
//builder.addInterceptor(chain -> {
|
||||
// //String cookies = CookieUtil.getCookies();
|
||||
// Request request = chain.request().newBuilder()
|
||||
// //.addHeader("Content-Type", "application/x-www-form-urlencoded")
|
||||
// //.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
|
||||
// //.addHeader("Cookie", cookies)
|
||||
// .build();
|
||||
// return chain.proceed(request);
|
||||
//});
|
||||
return builder.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.arialyy.frame.base.net;
|
||||
|
||||
import com.arialyy.frame.util.show.FL;
|
||||
import com.arialyy.frame.util.show.L;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import okhttp3.Headers;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import okio.Buffer;
|
||||
import okio.BufferedSource;
|
||||
|
||||
/**
|
||||
* Created by Lyy on 2016/9/19.
|
||||
* 自定义的 OKHTTP 日志
|
||||
*/
|
||||
public class OkHttpLogger implements Interceptor {
|
||||
final static String TAG = "OKHTTP";
|
||||
|
||||
@Override public Response intercept(Chain chain) throws IOException {
|
||||
Request request = chain.request();
|
||||
long startNs = System.nanoTime();
|
||||
Response response = chain.proceed(request);
|
||||
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
|
||||
ResponseBody responseBody = response.body();
|
||||
long contentLength = responseBody.contentLength();
|
||||
String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length";
|
||||
L.d(TAG, "<-- "
|
||||
+ response.code()
|
||||
+ ' '
|
||||
+ response.message()
|
||||
+ ' '
|
||||
+ response.request().url()
|
||||
+ " ("
|
||||
+ tookMs
|
||||
+ "ms"
|
||||
+ (", " + bodySize + " body")
|
||||
+ ')');
|
||||
//Headers headers = response.headers();
|
||||
//for (int i = 0, count = headers.size(); i < count; i++) {
|
||||
// FL.d(TAG, headers.name(i) + ": " + headers.value(i));
|
||||
//}
|
||||
BufferedSource source = responseBody.source();
|
||||
source.request(Long.MAX_VALUE); // Buffer the entire body.
|
||||
Buffer buffer = source.buffer();
|
||||
Charset UTF8 = Charset.forName("UTF-8");
|
||||
Charset charset = UTF8;
|
||||
MediaType contentType = responseBody.contentType();
|
||||
if (contentType != null) {
|
||||
charset = contentType.charset(UTF8);
|
||||
}
|
||||
if (contentLength != 0) {
|
||||
//FL.j(TAG, buffer.clone().readString(charset));
|
||||
L.j(buffer.clone().readString(charset));
|
||||
}
|
||||
|
||||
L.d(TAG, "<-- END HTTP (" + buffer.size() + "-byte body)");
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -4,25 +4,26 @@ import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.util.LruCache;
|
||||
import android.text.TextUtils;
|
||||
import com.arialyy.frame.cache.diskcache.DiskLruCache;
|
||||
|
||||
import com.arialyy.frame.util.AndroidUtils;
|
||||
import com.arialyy.frame.util.AppUtils;
|
||||
import com.arialyy.frame.util.FileUtil;
|
||||
import com.arialyy.frame.util.StreamUtil;
|
||||
import com.arialyy.frame.util.StringUtil;
|
||||
import com.arialyy.frame.util.show.FL;
|
||||
import com.arialyy.frame.util.show.L;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Created by “AriaLyy@outlook.com” on 2015/4/9.
|
||||
* Created by Lyy on 2015/4/9.
|
||||
* 缓存抽象类,封装了缓存的读写操作
|
||||
*/
|
||||
abstract class AbsCache implements CacheParam {
|
||||
public abstract class AbsCache implements CacheParam {
|
||||
private static final String TAG = "AbsCache";
|
||||
private static final Object LOCK = new Object();
|
||||
/**
|
||||
* 磁盘缓存工具
|
||||
*/
|
||||
@@ -35,34 +36,30 @@ abstract class AbsCache implements CacheParam {
|
||||
* 是否使用内存缓存
|
||||
*/
|
||||
private boolean useMemory = false;
|
||||
/**
|
||||
* 是否使用磁盘缓存
|
||||
*/
|
||||
private boolean useDisk = false;
|
||||
/**
|
||||
* 最大的内存
|
||||
*/
|
||||
private int mMaxMemoryCacheSize;
|
||||
/**
|
||||
* 最大的磁盘大小
|
||||
*/
|
||||
private long mMaxDiskCacheSize;
|
||||
private int mMaxMemory;
|
||||
private Context mContext;
|
||||
private static final Object mDiskCacheLock = new Object();
|
||||
|
||||
/**
|
||||
* 默认使用默认路径
|
||||
*
|
||||
* @param useMemory 是否使用内存缓存
|
||||
*/
|
||||
protected AbsCache(Context context) {
|
||||
this(context, DEFAULT_DIR);
|
||||
protected AbsCache(Context context, boolean useMemory) {
|
||||
this.mContext = context;
|
||||
this.useMemory = useMemory;
|
||||
init(DEFAULT_DIR, 1, SMALL_DISK_CACHE_CAPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定缓存文件夹
|
||||
*
|
||||
* @param useMemory 是否使用内存缓存
|
||||
* @param cacheDir 缓存文件夹
|
||||
*/
|
||||
AbsCache(Context context, @NonNull String cacheDir) {
|
||||
protected AbsCache(Context context, boolean useMemory, @NonNull String cacheDir) {
|
||||
this.mContext = context;
|
||||
this.useMemory = useMemory;
|
||||
init(cacheDir, 1, SMALL_DISK_CACHE_CAPACITY);
|
||||
}
|
||||
|
||||
@@ -74,7 +71,7 @@ abstract class AbsCache implements CacheParam {
|
||||
/**
|
||||
* 初始化磁盘缓存
|
||||
*/
|
||||
private void initDiskCache(String cacheDir, int valueCount, long cacheSize) {
|
||||
protected void initDiskCache(String cacheDir, int valueCount, long cacheSize) {
|
||||
try {
|
||||
File dir = getDiskCacheDir(mContext, cacheDir);
|
||||
if (!dir.exists()) {
|
||||
@@ -90,35 +87,29 @@ abstract class AbsCache implements CacheParam {
|
||||
/**
|
||||
* 初始化内存缓存
|
||||
*/
|
||||
private void initMemoryCache() {
|
||||
if (!useMemory) return;
|
||||
protected void initMemoryCache() {
|
||||
if (!useMemory) {
|
||||
return;
|
||||
}
|
||||
// 获取应用程序最大可用内存
|
||||
mMaxMemoryCacheSize = (int) Runtime.getRuntime().maxMemory();
|
||||
mMaxMemory = (int) Runtime.getRuntime().maxMemory();
|
||||
// 设置图片缓存大小为程序最大可用内存的1/8
|
||||
mMemoryCache = new LruCache<>(mMaxMemoryCacheSize / 8);
|
||||
mMemoryCache = new LruCache<>(mMaxMemory / 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否使用内存缓存
|
||||
*/
|
||||
void setUseMemory(boolean useMemory) {
|
||||
protected void setUseMemory(boolean useMemory) {
|
||||
this.useMemory = useMemory;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否使用磁盘缓存
|
||||
*/
|
||||
void setUseDisk(boolean useDisk) {
|
||||
this.useDisk = useDisk;
|
||||
initMemoryCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内存缓存大小
|
||||
*/
|
||||
void setMemoryCacheSize(int size) {
|
||||
if (useMemory && mMemoryCache != null) {
|
||||
mMemoryCache.resize(size);
|
||||
}
|
||||
protected void setMemoryCache(int size) {
|
||||
mMemoryCache.resize(size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,8 +120,8 @@ abstract class AbsCache implements CacheParam {
|
||||
* @param cacheSize 缓存大小
|
||||
* @see CacheParam
|
||||
*/
|
||||
void openDiskCache(@NonNull String cacheDir, int valueCount, long cacheSize) {
|
||||
synchronized (LOCK) {
|
||||
protected void openDiskCache(@NonNull String cacheDir, int valueCount, long cacheSize) {
|
||||
synchronized (mDiskCacheLock) {
|
||||
if (mDiskLruCache != null && mDiskLruCache.isClosed()) {
|
||||
try {
|
||||
File dir = getDiskCacheDir(mContext, cacheDir);
|
||||
@@ -152,41 +143,35 @@ abstract class AbsCache implements CacheParam {
|
||||
* @param key 缓存的key,通过该key来读写缓存,一般是URL
|
||||
* @param data 缓存的数据
|
||||
*/
|
||||
void writeDiskCache(@NonNull String key, @NonNull byte[] data) {
|
||||
protected void writeDiskCache(@NonNull String key, @NonNull byte[] data) {
|
||||
if (TextUtils.isEmpty(key)) {
|
||||
L.e(TAG, "key 不能为null");
|
||||
return;
|
||||
}
|
||||
String hashKey = StringUtil.keyToHashKey(key);
|
||||
if (useMemory && mMemoryCache != null) {
|
||||
mMemoryCache.put(hashKey, data);
|
||||
}
|
||||
if (useDisk) {
|
||||
synchronized (LOCK) {
|
||||
if (mDiskLruCache != null) {
|
||||
L.i(TAG, "缓存数据到磁盘[key:" + key + ",hashKey:" + hashKey + "]");
|
||||
OutputStream out = null;
|
||||
try {
|
||||
DiskLruCache.Editor editor = mDiskLruCache.edit(hashKey);
|
||||
out = editor.newOutputStream(DISK_CACHE_INDEX);
|
||||
out.write(data, 0, data.length);
|
||||
editor.commit();
|
||||
out.flush();
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
FL.e(this, "writeDiskFailed[key:"
|
||||
+ key
|
||||
+ ",hashKey:"
|
||||
+ hashKey
|
||||
+ "]\n"
|
||||
+ FL.getExceptionString(e));
|
||||
} finally {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
synchronized (mDiskCacheLock) {
|
||||
if (mDiskLruCache != null) {
|
||||
L.i(TAG, "缓存数据到磁盘[key:" + key + ",hashKey:" + hashKey + "]");
|
||||
OutputStream out = null;
|
||||
try {
|
||||
DiskLruCache.Editor editor = mDiskLruCache.edit(hashKey);
|
||||
out = editor.newOutputStream(DISK_CACHE_INDEX);
|
||||
out.write(data, 0, data.length);
|
||||
editor.commit();
|
||||
out.flush();
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
FL.e(this,
|
||||
"writeDiskFailed[key:" + key + ",hashKey:" + hashKey + "]\n" + FL.getExceptionString(
|
||||
e));
|
||||
} finally {
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -200,7 +185,7 @@ abstract class AbsCache implements CacheParam {
|
||||
* @param key 缓存的key,一般是原来的url
|
||||
* @return 缓存数据
|
||||
*/
|
||||
byte[] readDiskCache(@NonNull String key) {
|
||||
protected byte[] readDiskCache(@NonNull String key) {
|
||||
if (TextUtils.isEmpty(key)) {
|
||||
return null;
|
||||
}
|
||||
@@ -211,32 +196,37 @@ abstract class AbsCache implements CacheParam {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
if (useDisk) {
|
||||
synchronized (LOCK) {
|
||||
byte[] data = null;
|
||||
L.i(TAG, "读取磁盘缓存数据[key:" + key + ",hashKey:" + hashKey + "]");
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(hashKey);
|
||||
if (snapshot != null) {
|
||||
inputStream = snapshot.getInputStream(DISK_CACHE_INDEX);
|
||||
data = StreamUtil.readStream(inputStream);
|
||||
return data;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FL.e(this, "readDiskCacheFailed[key:"
|
||||
+ key
|
||||
+ ",hashKey:"
|
||||
+ hashKey
|
||||
+ "]\n"
|
||||
+ FL.getExceptionString(e));
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
synchronized (mDiskCacheLock) {
|
||||
byte[] data = null;
|
||||
L.i(TAG, "读取磁盘缓存数据[key:" + key + ",hashKey:" + hashKey + "]");
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(hashKey);
|
||||
if (snapshot != null) {
|
||||
inputStream = snapshot.getInputStream(DISK_CACHE_INDEX);
|
||||
data = StreamUtil.readStream(inputStream);
|
||||
return data;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
FL.e(this, "readDiskCacheFailed[key:"
|
||||
+ key
|
||||
+ ",hashKey:"
|
||||
+ hashKey
|
||||
+ "]\n"
|
||||
+ FL.getExceptionString(e));
|
||||
} catch (Exception e) {
|
||||
FL.e(this, "readDiskCacheFailed[key:"
|
||||
+ key
|
||||
+ ",hashKey:"
|
||||
+ hashKey
|
||||
+ "]\n"
|
||||
+ FL.getExceptionString(e));
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -254,7 +244,7 @@ abstract class AbsCache implements CacheParam {
|
||||
if (mMemoryCache != null) {
|
||||
mMemoryCache.remove(hashKey);
|
||||
}
|
||||
synchronized (LOCK) {
|
||||
synchronized (mDiskCacheLock) {
|
||||
if (mDiskLruCache != null) {
|
||||
try {
|
||||
mDiskLruCache.remove(hashKey);
|
||||
@@ -270,23 +260,14 @@ abstract class AbsCache implements CacheParam {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭内存缓存
|
||||
*/
|
||||
void closeMemoryCache() {
|
||||
if (mMemoryCache != null) {
|
||||
mMemoryCache.evictAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除所有缓存
|
||||
*/
|
||||
void clearCache() {
|
||||
protected void clearCache() {
|
||||
if (mMemoryCache != null) {
|
||||
mMemoryCache.evictAll();
|
||||
}
|
||||
synchronized (LOCK) {
|
||||
synchronized (mDiskCacheLock) {
|
||||
if (mDiskLruCache != null) {
|
||||
try {
|
||||
mDiskLruCache.delete();
|
||||
@@ -303,8 +284,8 @@ abstract class AbsCache implements CacheParam {
|
||||
* 关闭掉了之后就不能再调用DiskLruCache中任何操作缓存数据的方法,
|
||||
* 通常只应该在Activity的onDestroy()方法中去调用close()方法。
|
||||
*/
|
||||
void closeDiskCache() {
|
||||
synchronized (LOCK) {
|
||||
protected void closeDiskCache() {
|
||||
synchronized (mDiskCacheLock) {
|
||||
if (mDiskLruCache != null) {
|
||||
try {
|
||||
mDiskLruCache.close();
|
||||
@@ -320,8 +301,8 @@ abstract class AbsCache implements CacheParam {
|
||||
* 注意:在写入缓存时需要flush同步一次,并不是每次写入缓存都要调用一次flush()方法的,频繁地调用并不会带来任何好处,
|
||||
* 只会额外增加同步journal文件的时间。比较标准的做法就是在Activity的onPause()方法中去调用一次flush()方法就可以了
|
||||
*/
|
||||
void flushDiskCache() {
|
||||
synchronized (LOCK) {
|
||||
protected void flushDiskCache() {
|
||||
synchronized (mDiskCacheLock) {
|
||||
if (mDiskLruCache != null) {
|
||||
try {
|
||||
mDiskLruCache.flush();
|
||||
@@ -339,16 +320,6 @@ abstract class AbsCache implements CacheParam {
|
||||
return mDiskLruCache.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成缓存文件夹
|
||||
*
|
||||
* @param uniqueName 缓存文件夹名
|
||||
* @return 缓存文件夹
|
||||
*/
|
||||
public static File getDiskCacheDir(Context context, String uniqueName) {
|
||||
return new File(AndroidUtils.getDiskCacheDir(context) + File.separator + uniqueName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换byte数组为String
|
||||
*/
|
||||
@@ -364,4 +335,14 @@ abstract class AbsCache implements CacheParam {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成缓存文件夹
|
||||
*
|
||||
* @param uniqueName 缓存文件夹名
|
||||
* @return 缓存文件夹
|
||||
*/
|
||||
public static File getDiskCacheDir(Context context, String uniqueName) {
|
||||
return new File(AndroidUtils.getDiskCacheDir(context) + File.separator + uniqueName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.arialyy.frame.cache;
|
||||
|
||||
/**
|
||||
* Created by “AriaLyy@outlook.com” on 2015/4/9.
|
||||
* Created by Lyy on 2015/4/9.
|
||||
* 缓存参数
|
||||
*/
|
||||
interface CacheParam {
|
||||
public interface CacheParam {
|
||||
|
||||
/**
|
||||
* 磁盘缓存
|
||||
@@ -17,7 +17,7 @@ interface CacheParam {
|
||||
/**
|
||||
* 内存缓存
|
||||
*/
|
||||
public static final int MEMORY_CACHE_SIZE = 4 * 1024 * 1024;
|
||||
public static final int MEMORY_CACHE_SIZE = 1;
|
||||
/**
|
||||
* 小容量磁盘缓存
|
||||
*/
|
||||
|
||||
@@ -3,13 +3,15 @@ package com.arialyy.frame.cache;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.arialyy.frame.util.DrawableUtil;
|
||||
import com.arialyy.frame.util.show.L;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* Created by “AriaLyy@outlook.com” on 2015/4/9.
|
||||
* Created by AriaLyy on 2015/4/9.
|
||||
* 缓存工具
|
||||
*/
|
||||
public class CacheUtil extends AbsCache {
|
||||
@@ -17,32 +19,28 @@ public class CacheUtil extends AbsCache {
|
||||
|
||||
/**
|
||||
* 默认使用默认路径
|
||||
*
|
||||
* @param useMemory 是否使用内存缓存
|
||||
*/
|
||||
private CacheUtil(Context context) {
|
||||
this(context, DEFAULT_DIR);
|
||||
public CacheUtil(Context context, boolean useMemory) {
|
||||
super(context, useMemory);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定缓存文件夹
|
||||
*
|
||||
* @param cacheDir 缓存文件夹名
|
||||
* @param useMemory 是否使用内存缓存
|
||||
* @param cacheDir 缓存文件夹
|
||||
*/
|
||||
private CacheUtil(Context context, @NonNull String cacheDir) {
|
||||
super(context, cacheDir);
|
||||
public CacheUtil(Context context, boolean useMemory, @NonNull String cacheDir) {
|
||||
super(context, useMemory, cacheDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否使用内存缓存
|
||||
* 设置是否使用内存缓存
|
||||
*/
|
||||
private void setUseMemoryCache(boolean openMemoryCache) {
|
||||
setUseMemory(openMemoryCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否使用磁场缓存
|
||||
*/
|
||||
private void setUseDiskCache(boolean openDiskCache) {
|
||||
setUseMemory(openDiskCache);
|
||||
public void setUseMemoryCache(boolean useMemoryCache) {
|
||||
setUseMemory(useMemoryCache);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,15 +178,14 @@ public class CacheUtil extends AbsCache {
|
||||
/**
|
||||
* 删除所有缓存
|
||||
*/
|
||||
public void clearCache() {
|
||||
super.clearCache();
|
||||
public void removeAll() {
|
||||
clearCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭磁盘缓存
|
||||
*/
|
||||
public void close() {
|
||||
closeMemoryCache();
|
||||
closeDiskCache();
|
||||
}
|
||||
|
||||
@@ -198,65 +195,4 @@ public class CacheUtil extends AbsCache {
|
||||
public long getCacheSize() {
|
||||
return super.getCacheSize();
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
boolean openDiskCache = false;
|
||||
boolean openMemoryCache = false;
|
||||
String cacheDirName = DEFAULT_DIR;
|
||||
long diskCacheSize = NORMAL_DISK_CACHE_CAPACITY;
|
||||
int memoryCacheSize = MEMORY_CACHE_SIZE;
|
||||
Context context;
|
||||
|
||||
public Builder(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开磁盘缓存
|
||||
*/
|
||||
public Builder openDiskCache() {
|
||||
openDiskCache = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开内存缓存
|
||||
*/
|
||||
public Builder openMemoryCache() {
|
||||
openMemoryCache = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存文件夹名,只需要写文件夹名
|
||||
*/
|
||||
public Builder setCacheDirName(String cacheDirName) {
|
||||
this.cacheDirName = cacheDirName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置磁盘缓存大小
|
||||
*/
|
||||
public Builder setDiskCacheSize(long cacheSize) {
|
||||
this.diskCacheSize = cacheSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内存缓存大小
|
||||
*/
|
||||
public Builder setMemoryCacheSize(int cacheSize) {
|
||||
this.memoryCacheSize = cacheSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CacheUtil build() {
|
||||
CacheUtil util = new CacheUtil(context);
|
||||
util.setUseMemoryCache(openMemoryCache);
|
||||
util.setUseDiskCache(openDiskCache);
|
||||
util.setMemoryCacheSize(memoryCacheSize);
|
||||
return new CacheUtil(context, cacheDirName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
968
AppFrame/src/main/java/com/arialyy/frame/cache/DiskLruCache.java
vendored
Normal file
968
AppFrame/src/main/java/com/arialyy/frame/cache/DiskLruCache.java
vendored
Normal file
@@ -0,0 +1,968 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.arialyy.frame.cache;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.Closeable;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Array;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* *****************************************************************************
|
||||
* Taken from the JB source code, can be found in:
|
||||
* libcore/luni/src/main/java/libcore/io/DiskLruCache.java
|
||||
* or direct link:
|
||||
* https://android.googlesource.com/platform/libcore/+/android-4.1.1_r1/luni/src/main/java/libcore/io/DiskLruCache.java
|
||||
* *****************************************************************************
|
||||
*
|
||||
* A cache that uses a bounded amount of space on a filesystem. Each cache
|
||||
* entry has a string key and a fixed number of values. Values are byte
|
||||
* sequences, accessible as streams or files. Each value must be between {@code
|
||||
* 0} and {@code Integer.MAX_VALUE} bytes in length.
|
||||
*
|
||||
* The cache stores its data in a directory on the filesystem. This
|
||||
* directory must be exclusive to the cache; the cache may delete or overwrite
|
||||
* files from its directory. It is an error for multiple processes to use the
|
||||
* same cache directory at the same time.
|
||||
*
|
||||
* This cache limits the number of bytes that it will store on the
|
||||
* filesystem. When the number of stored bytes exceeds the limit, the cache will
|
||||
* remove entries in the background until the limit is satisfied. The limit is
|
||||
* not strict: the cache may temporarily exceed it while waiting for files to be
|
||||
* deleted. The limit does not include filesystem overhead or the cache
|
||||
* journal so space-sensitive applications should set a conservative limit.
|
||||
*
|
||||
* Clients call {@link #edit} to create or update the values of an entry. An
|
||||
* entry may have only one editor at one time; if a value is not available to be
|
||||
* edited then {@link #edit} will return null.
|
||||
*
|
||||
* When an entry is being <strong>created</strong> it is necessary to
|
||||
* supply a full set of values; the empty value should be used as a
|
||||
* placeholder if necessary.
|
||||
* When an entry is being <strong>edited</strong>, it is not necessary
|
||||
* to supply data for every value; values default to their previous
|
||||
* value.
|
||||
*
|
||||
* Clients call {@link #get} to read a snapshot of an entry. The read will
|
||||
* observe the value at the time that {@link #get} was called. Updates and
|
||||
* removals after the call do not impact ongoing reads.
|
||||
*
|
||||
* This class is tolerant of some I/O errors. If files are missing from the
|
||||
* filesystem, the corresponding entries will be dropped from the cache. If
|
||||
* an error occurs while writing a cache value, the edit will fail silently.
|
||||
* Callers should handle other problems by catching {@code IOException} and
|
||||
* responding appropriately.
|
||||
*/
|
||||
public final class DiskLruCache implements Closeable {
|
||||
static final String JOURNAL_FILE = "journal";
|
||||
static final String JOURNAL_FILE_TMP = "journal.tmp";
|
||||
static final String MAGIC = "libcore.io.DiskLruCache";
|
||||
static final String VERSION_1 = "1";
|
||||
static final long ANY_SEQUENCE_NUMBER = -1;
|
||||
private static final String CLEAN = "CLEAN";
|
||||
private static final String DIRTY = "DIRTY";
|
||||
private static final String REMOVE = "REMOVE";
|
||||
private static final String READ = "READ";
|
||||
|
||||
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
private static final int IO_BUFFER_SIZE = 8 * 1024;
|
||||
|
||||
/*
|
||||
* This cache uses a journal file named "journal". A typical journal file
|
||||
* looks like this:
|
||||
* libcore.io.DiskLruCache
|
||||
* 1
|
||||
* 100
|
||||
* 2
|
||||
*
|
||||
* CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
|
||||
* DIRTY 335c4c6028171cfddfbaae1a9c313c52
|
||||
* CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
|
||||
* REMOVE 335c4c6028171cfddfbaae1a9c313c52
|
||||
* DIRTY 1ab96a171faeeee38496d8b330771a7a
|
||||
* CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
|
||||
* READ 335c4c6028171cfddfbaae1a9c313c52
|
||||
* READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
|
||||
*
|
||||
* The first five lines of the journal form its header. They are the
|
||||
* constant string "libcore.io.DiskLruCache", the disk cache's version,
|
||||
* the application's version, the value count, and a blank line.
|
||||
*
|
||||
* Each of the subsequent lines in the file is a record of the state of a
|
||||
* cache entry. Each line contains space-separated values: a state, a key,
|
||||
* and optional state-specific values.
|
||||
* o DIRTY lines track that an entry is actively being created or updated.
|
||||
* Every successful DIRTY action should be followed by a CLEAN or REMOVE
|
||||
* action. DIRTY lines without a matching CLEAN or REMOVE indicate that
|
||||
* temporary files may need to be deleted.
|
||||
* o CLEAN lines track a cache entry that has been successfully published
|
||||
* and may be read. A publish line is followed by the lengths of each of
|
||||
* its values.
|
||||
* o READ lines track accesses for LRU.
|
||||
* o REMOVE lines track entries that have been deleted.
|
||||
*
|
||||
* The journal file is appended to as cache operations occur. The journal may
|
||||
* occasionally be compacted by dropping redundant lines. A temporary file named
|
||||
* "journal.tmp" will be used during compaction; that file should be deleted if
|
||||
* it exists when the cache is opened.
|
||||
*/
|
||||
|
||||
private final File directory;
|
||||
private final File journalFile;
|
||||
private final File journalFileTmp;
|
||||
private final int appVersion;
|
||||
private final long maxSize;
|
||||
private final int valueCount;
|
||||
private long size = 0;
|
||||
private Writer journalWriter;
|
||||
private final LinkedHashMap<String, Entry> lruEntries =
|
||||
new LinkedHashMap<String, Entry>(0, 0.75f, true);
|
||||
private int redundantOpCount;
|
||||
|
||||
/**
|
||||
* To differentiate between old and current snapshots, each entry is given
|
||||
* a sequence number each time an edit is committed. A snapshot is stale if
|
||||
* its sequence number is not equal to its entry's sequence number.
|
||||
*/
|
||||
private long nextSequenceNumber = 0;
|
||||
|
||||
/* From java.util.Arrays */
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T[] copyOfRange(T[] original, int start, int end) {
|
||||
final int originalLength = original.length; // For exception priority compatibility.
|
||||
if (start > end) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (start < 0 || start > originalLength) {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
final int resultLength = end - start;
|
||||
final int copyLength = Math.min(resultLength, originalLength - start);
|
||||
final T[] result =
|
||||
(T[]) Array.newInstance(original.getClass().getComponentType(), resultLength);
|
||||
System.arraycopy(original, start, result, 0, copyLength);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remainder of 'reader' as a string, closing it when done.
|
||||
*/
|
||||
public static String readFully(Reader reader) throws IOException {
|
||||
try {
|
||||
StringWriter writer = new StringWriter();
|
||||
char[] buffer = new char[1024];
|
||||
int count;
|
||||
while ((count = reader.read(buffer)) != -1) {
|
||||
writer.write(buffer, 0, count);
|
||||
}
|
||||
return writer.toString();
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ASCII characters up to but not including the next "\r\n", or
|
||||
* "\n".
|
||||
*
|
||||
* @throws EOFException if the stream is exhausted before the next newline
|
||||
* character.
|
||||
*/
|
||||
public static String readAsciiLine(InputStream in) throws IOException {
|
||||
|
||||
StringBuilder result = new StringBuilder(80);
|
||||
while (true) {
|
||||
int c = in.read();
|
||||
if (c == -1) {
|
||||
throw new EOFException();
|
||||
} else if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
|
||||
result.append((char) c);
|
||||
}
|
||||
int length = result.length();
|
||||
if (length > 0 && result.charAt(length - 1) == '\r') {
|
||||
result.setLength(length - 1);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null.
|
||||
*/
|
||||
public static void closeQuietly(Closeable closeable) {
|
||||
if (closeable != null) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (RuntimeException rethrown) {
|
||||
throw rethrown;
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively delete everything in {@code dir}.
|
||||
*/
|
||||
// TODO: this should specify paths as Strings rather than as Files
|
||||
public static void deleteContents(File dir) throws IOException {
|
||||
File[] files = dir.listFiles();
|
||||
if (files == null) {
|
||||
throw new IllegalArgumentException("not a directory: " + dir);
|
||||
}
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
deleteContents(file);
|
||||
}
|
||||
if (!file.delete()) {
|
||||
throw new IOException("failed to delete file: " + file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This cache uses a single background thread to evict entries.
|
||||
*/
|
||||
private final ExecutorService executorService =
|
||||
new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
private final Callable<Void> cleanupCallable = new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (journalWriter == null) {
|
||||
return null; // closed
|
||||
}
|
||||
trimToSize();
|
||||
if (journalRebuildRequired()) {
|
||||
rebuildJournal();
|
||||
redundantOpCount = 0;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
|
||||
this.directory = directory;
|
||||
this.appVersion = appVersion;
|
||||
this.journalFile = new File(directory, JOURNAL_FILE);
|
||||
this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP);
|
||||
this.valueCount = valueCount;
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the cache in {@code directory}, creating a cache if none exists
|
||||
* there.
|
||||
*
|
||||
* @param directory a writable directory
|
||||
* @param valueCount the number of values per cache entry. Must be positive.
|
||||
* @param maxSize the maximum number of bytes this cache should use to store
|
||||
* @throws IOException if reading or writing the cache directory fails
|
||||
*/
|
||||
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
|
||||
throws IOException {
|
||||
if (maxSize <= 0) {
|
||||
throw new IllegalArgumentException("maxSize <= 0");
|
||||
}
|
||||
if (valueCount <= 0) {
|
||||
throw new IllegalArgumentException("valueCount <= 0");
|
||||
}
|
||||
|
||||
// prefer to pick up where we left off
|
||||
DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
|
||||
if (cache.journalFile.exists()) {
|
||||
try {
|
||||
cache.readJournal();
|
||||
cache.processJournal();
|
||||
cache.journalWriter =
|
||||
new BufferedWriter(new FileWriter(cache.journalFile, true), IO_BUFFER_SIZE);
|
||||
return cache;
|
||||
} catch (IOException journalIsCorrupt) {
|
||||
// System.logW("DiskLruCache " + directory + " is corrupt: "
|
||||
// + journalIsCorrupt.getMessage() + ", removing");
|
||||
cache.delete();
|
||||
}
|
||||
}
|
||||
|
||||
// create a new empty cache
|
||||
directory.mkdirs();
|
||||
cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
|
||||
cache.rebuildJournal();
|
||||
return cache;
|
||||
}
|
||||
|
||||
private void readJournal() throws IOException {
|
||||
InputStream in = new BufferedInputStream(new FileInputStream(journalFile), IO_BUFFER_SIZE);
|
||||
try {
|
||||
String magic = readAsciiLine(in);
|
||||
String version = readAsciiLine(in);
|
||||
String appVersionString = readAsciiLine(in);
|
||||
String valueCountString = readAsciiLine(in);
|
||||
String blank = readAsciiLine(in);
|
||||
if (!MAGIC.equals(magic) || !VERSION_1.equals(version) || !Integer.toString(appVersion)
|
||||
.equals(appVersionString) || !Integer.toString(valueCount).equals(valueCountString) || !""
|
||||
.equals(blank)) {
|
||||
throw new IOException("unexpected journal header: ["
|
||||
+ magic
|
||||
+ ", "
|
||||
+ version
|
||||
+ ", "
|
||||
+ valueCountString
|
||||
+ ", "
|
||||
+ blank
|
||||
+ "]");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
readJournalLine(readAsciiLine(in));
|
||||
} catch (EOFException endOfJournal) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
closeQuietly(in);
|
||||
}
|
||||
}
|
||||
|
||||
private void readJournalLine(String line) throws IOException {
|
||||
String[] parts = line.split(" ");
|
||||
if (parts.length < 2) {
|
||||
throw new IOException("unexpected journal line: " + line);
|
||||
}
|
||||
|
||||
String key = parts[1];
|
||||
if (parts[0].equals(REMOVE) && parts.length == 2) {
|
||||
lruEntries.remove(key);
|
||||
return;
|
||||
}
|
||||
|
||||
Entry entry = lruEntries.get(key);
|
||||
if (entry == null) {
|
||||
entry = new Entry(key);
|
||||
lruEntries.put(key, entry);
|
||||
}
|
||||
|
||||
if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) {
|
||||
entry.readable = true;
|
||||
entry.currentEditor = null;
|
||||
entry.setLengths(copyOfRange(parts, 2, parts.length));
|
||||
} else if (parts[0].equals(DIRTY) && parts.length == 2) {
|
||||
entry.currentEditor = new Editor(entry);
|
||||
} else if (parts[0].equals(READ) && parts.length == 2) {
|
||||
// this work was already done by calling lruEntries.get()
|
||||
} else {
|
||||
throw new IOException("unexpected journal line: " + line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the initial size and collects garbage as a part of opening the
|
||||
* cache. Dirty entries are assumed to be inconsistent and will be deleted.
|
||||
*/
|
||||
private void processJournal() throws IOException {
|
||||
deleteIfExists(journalFileTmp);
|
||||
for (Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) {
|
||||
Entry entry = i.next();
|
||||
if (entry.currentEditor == null) {
|
||||
for (int t = 0; t < valueCount; t++) {
|
||||
size += entry.lengths[t];
|
||||
}
|
||||
} else {
|
||||
entry.currentEditor = null;
|
||||
for (int t = 0; t < valueCount; t++) {
|
||||
deleteIfExists(entry.getCleanFile(t));
|
||||
deleteIfExists(entry.getDirtyFile(t));
|
||||
}
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new journal that omits redundant information. This replaces the
|
||||
* current journal if it exists.
|
||||
*/
|
||||
private synchronized void rebuildJournal() throws IOException {
|
||||
if (journalWriter != null) {
|
||||
journalWriter.close();
|
||||
}
|
||||
|
||||
Writer writer = new BufferedWriter(new FileWriter(journalFileTmp), IO_BUFFER_SIZE);
|
||||
writer.write(MAGIC);
|
||||
writer.write("\n");
|
||||
writer.write(VERSION_1);
|
||||
writer.write("\n");
|
||||
writer.write(Integer.toString(appVersion));
|
||||
writer.write("\n");
|
||||
writer.write(Integer.toString(valueCount));
|
||||
writer.write("\n");
|
||||
writer.write("\n");
|
||||
|
||||
for (Entry entry : lruEntries.values()) {
|
||||
if (entry.currentEditor != null) {
|
||||
writer.write(DIRTY + ' ' + entry.key + '\n');
|
||||
} else {
|
||||
writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
writer.close();
|
||||
journalFileTmp.renameTo(journalFile);
|
||||
journalWriter = new BufferedWriter(new FileWriter(journalFile, true), IO_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
private static void deleteIfExists(File file) throws IOException {
|
||||
// try {
|
||||
// Libcore.os.remove(file.getPath());
|
||||
// } catch (ErrnoException errnoException) {
|
||||
// if (errnoException.errno != OsConstants.ENOENT) {
|
||||
// throw errnoException.rethrowAsIOException();
|
||||
// }
|
||||
// }
|
||||
if (file.exists() && !file.delete()) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a snapshot of the entry named {@code key}, or null if it doesn't
|
||||
* exist is not currently readable. If a value is returned, it is moved to
|
||||
* the head of the LRU queue.
|
||||
*/
|
||||
public synchronized Snapshot get(String key) throws IOException {
|
||||
checkNotClosed();
|
||||
validateKey(key);
|
||||
Entry entry = lruEntries.get(key);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!entry.readable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Open all streams eagerly to guarantee that we see a single published
|
||||
* snapshot. If we opened streams lazily then the streams could come
|
||||
* from different edits.
|
||||
*/
|
||||
InputStream[] ins = new InputStream[valueCount];
|
||||
try {
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
ins[i] = new FileInputStream(entry.getCleanFile(i));
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
// a file must have been deleted manually!
|
||||
return null;
|
||||
}
|
||||
|
||||
redundantOpCount++;
|
||||
journalWriter.append(READ + ' ' + key + '\n');
|
||||
if (journalRebuildRequired()) {
|
||||
executorService.submit(cleanupCallable);
|
||||
}
|
||||
|
||||
return new Snapshot(key, entry.sequenceNumber, ins);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an editor for the entry named {@code key}, or null if another
|
||||
* edit is in progress.
|
||||
*/
|
||||
public Editor edit(String key) throws IOException {
|
||||
return edit(key, ANY_SEQUENCE_NUMBER);
|
||||
}
|
||||
|
||||
private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
|
||||
checkNotClosed();
|
||||
validateKey(key);
|
||||
Entry entry = lruEntries.get(key);
|
||||
if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null
|
||||
|| entry.sequenceNumber != expectedSequenceNumber)) {
|
||||
return null; // snapshot is stale
|
||||
}
|
||||
if (entry == null) {
|
||||
entry = new Entry(key);
|
||||
lruEntries.put(key, entry);
|
||||
} else if (entry.currentEditor != null) {
|
||||
return null; // another edit is in progress
|
||||
}
|
||||
|
||||
Editor editor = new Editor(entry);
|
||||
entry.currentEditor = editor;
|
||||
|
||||
// flush the journal before creating files to prevent file leaks
|
||||
journalWriter.write(DIRTY + ' ' + key + '\n');
|
||||
journalWriter.flush();
|
||||
return editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the directory where this cache stores its data.
|
||||
*/
|
||||
public File getDirectory() {
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of bytes that this cache should use to store
|
||||
* its data.
|
||||
*/
|
||||
public long maxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes currently being used to store the values in
|
||||
* this cache. This may be greater than the max size if a background
|
||||
* deletion is pending.
|
||||
*/
|
||||
public synchronized long size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
private synchronized void completeEdit(Editor editor, boolean success) throws IOException {
|
||||
Entry entry = editor.entry;
|
||||
if (entry.currentEditor != editor) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
// if this edit is creating the entry for the first time, every index must have a value
|
||||
if (success && !entry.readable) {
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
if (!entry.getDirtyFile(i).exists()) {
|
||||
editor.abort();
|
||||
throw new IllegalStateException("edit didn't create file " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
File dirty = entry.getDirtyFile(i);
|
||||
if (success) {
|
||||
if (dirty.exists()) {
|
||||
File clean = entry.getCleanFile(i);
|
||||
dirty.renameTo(clean);
|
||||
long oldLength = entry.lengths[i];
|
||||
long newLength = clean.length();
|
||||
entry.lengths[i] = newLength;
|
||||
size = size - oldLength + newLength;
|
||||
}
|
||||
} else {
|
||||
deleteIfExists(dirty);
|
||||
}
|
||||
}
|
||||
|
||||
redundantOpCount++;
|
||||
entry.currentEditor = null;
|
||||
if (entry.readable | success) {
|
||||
entry.readable = true;
|
||||
journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
|
||||
if (success) {
|
||||
entry.sequenceNumber = nextSequenceNumber++;
|
||||
}
|
||||
} else {
|
||||
lruEntries.remove(entry.key);
|
||||
journalWriter.write(REMOVE + ' ' + entry.key + '\n');
|
||||
}
|
||||
|
||||
if (size > maxSize || journalRebuildRequired()) {
|
||||
executorService.submit(cleanupCallable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We only rebuild the journal when it will halve the size of the journal
|
||||
* and eliminate at least 2000 ops.
|
||||
*/
|
||||
private boolean journalRebuildRequired() {
|
||||
final int REDUNDANT_OP_COMPACT_THRESHOLD = 2000;
|
||||
return redundantOpCount >= REDUNDANT_OP_COMPACT_THRESHOLD
|
||||
&& redundantOpCount >= lruEntries.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops the entry for {@code key} if it exists and can be removed. Entries
|
||||
* actively being edited cannot be removed.
|
||||
*
|
||||
* @return true if an entry was removed.
|
||||
*/
|
||||
public synchronized boolean remove(String key) throws IOException {
|
||||
checkNotClosed();
|
||||
validateKey(key);
|
||||
Entry entry = lruEntries.get(key);
|
||||
if (entry == null || entry.currentEditor != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
File file = entry.getCleanFile(i);
|
||||
if (!file.delete()) {
|
||||
throw new IOException("failed to delete " + file);
|
||||
}
|
||||
size -= entry.lengths[i];
|
||||
entry.lengths[i] = 0;
|
||||
}
|
||||
|
||||
redundantOpCount++;
|
||||
journalWriter.append(REMOVE + ' ' + key + '\n');
|
||||
lruEntries.remove(key);
|
||||
|
||||
if (journalRebuildRequired()) {
|
||||
executorService.submit(cleanupCallable);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this cache has been closed.
|
||||
*/
|
||||
public boolean isClosed() {
|
||||
return journalWriter == null;
|
||||
}
|
||||
|
||||
private void checkNotClosed() {
|
||||
if (journalWriter == null) {
|
||||
throw new IllegalStateException("cache is closed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force buffered operations to the filesystem.
|
||||
*/
|
||||
public synchronized void flush() throws IOException {
|
||||
checkNotClosed();
|
||||
trimToSize();
|
||||
journalWriter.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this cache. Stored values will remain on the filesystem.
|
||||
*/
|
||||
public synchronized void close() throws IOException {
|
||||
if (journalWriter == null) {
|
||||
return; // already closed
|
||||
}
|
||||
for (Entry entry : new ArrayList<Entry>(lruEntries.values())) {
|
||||
if (entry.currentEditor != null) {
|
||||
entry.currentEditor.abort();
|
||||
}
|
||||
}
|
||||
trimToSize();
|
||||
journalWriter.close();
|
||||
journalWriter = null;
|
||||
}
|
||||
|
||||
private void trimToSize() throws IOException {
|
||||
while (size > maxSize) {
|
||||
// Map.Entry<String, Entry> toEvict = lruEntries.eldest();
|
||||
final Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next();
|
||||
remove(toEvict.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the cache and deletes all of its stored values. This will delete
|
||||
* all files in the cache directory including files that weren't created by
|
||||
* the cache.
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
close();
|
||||
deleteContents(directory);
|
||||
}
|
||||
|
||||
private void validateKey(String key) {
|
||||
if (key.contains(" ") || key.contains("\n") || key.contains("\r")) {
|
||||
throw new IllegalArgumentException(
|
||||
"keys must not contain spaces or newlines: \"" + key + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
private static String inputStreamToString(InputStream in) throws IOException {
|
||||
return readFully(new InputStreamReader(in, UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* A snapshot of the values for an entry.
|
||||
*/
|
||||
public final class Snapshot implements Closeable {
|
||||
private final String key;
|
||||
private final long sequenceNumber;
|
||||
private final InputStream[] ins;
|
||||
|
||||
private Snapshot(String key, long sequenceNumber, InputStream[] ins) {
|
||||
this.key = key;
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
this.ins = ins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an editor for this snapshot's entry, or null if either the
|
||||
* entry has changed since this snapshot was created or if another edit
|
||||
* is in progress.
|
||||
*/
|
||||
public Editor edit() throws IOException {
|
||||
return DiskLruCache.this.edit(key, sequenceNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unbuffered stream with the value for {@code index}.
|
||||
*/
|
||||
public InputStream getInputStream(int index) {
|
||||
return ins[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the string value for {@code index}.
|
||||
*/
|
||||
public String getString(int index) throws IOException {
|
||||
return inputStreamToString(getInputStream(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
for (InputStream in : ins) {
|
||||
closeQuietly(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the values for an entry.
|
||||
*/
|
||||
public final class Editor {
|
||||
private final Entry entry;
|
||||
private boolean hasErrors;
|
||||
|
||||
private Editor(Entry entry) {
|
||||
this.entry = entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unbuffered input stream to read the last committed value,
|
||||
* or null if no value has been committed.
|
||||
*/
|
||||
public InputStream newInputStream(int index) throws IOException {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (entry.currentEditor != this) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (!entry.readable) {
|
||||
return null;
|
||||
}
|
||||
return new FileInputStream(entry.getCleanFile(index));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last committed value as a string, or null if no value
|
||||
* has been committed.
|
||||
*/
|
||||
public String getString(int index) throws IOException {
|
||||
InputStream in = newInputStream(index);
|
||||
return in != null ? inputStreamToString(in) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new unbuffered output stream to write the value at
|
||||
* {@code index}. If the underlying output stream encounters errors
|
||||
* when writing to the filesystem, this edit will be aborted when
|
||||
* {@link #commit} is called. The returned output stream does not throw
|
||||
* IOExceptions.
|
||||
*/
|
||||
public OutputStream newOutputStream(int index) throws IOException {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (entry.currentEditor != this) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return new FaultHidingOutputStream(new FileOutputStream(entry.getDirtyFile(index)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value at {@code index} to {@code value}.
|
||||
*/
|
||||
public void set(int index, String value) throws IOException {
|
||||
Writer writer = null;
|
||||
try {
|
||||
writer = new OutputStreamWriter(newOutputStream(index), UTF_8);
|
||||
writer.write(value);
|
||||
} finally {
|
||||
closeQuietly(writer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits this edit so it is visible to readers. This releases the
|
||||
* edit lock so another edit may be started on the same key.
|
||||
*/
|
||||
public void commit() throws IOException {
|
||||
if (hasErrors) {
|
||||
completeEdit(this, false);
|
||||
remove(entry.key); // the previous entry is stale
|
||||
} else {
|
||||
completeEdit(this, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aborts this edit. This releases the edit lock so another edit may be
|
||||
* started on the same key.
|
||||
*/
|
||||
public void abort() throws IOException {
|
||||
completeEdit(this, false);
|
||||
}
|
||||
|
||||
private class FaultHidingOutputStream extends FilterOutputStream {
|
||||
private FaultHidingOutputStream(OutputStream out) {
|
||||
super(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int oneByte) {
|
||||
try {
|
||||
out.write(oneByte);
|
||||
} catch (IOException e) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] buffer, int offset, int length) {
|
||||
try {
|
||||
out.write(buffer, offset, length);
|
||||
} catch (IOException e) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
try {
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class Entry {
|
||||
private final String key;
|
||||
|
||||
/**
|
||||
* Lengths of this entry's files.
|
||||
*/
|
||||
private final long[] lengths;
|
||||
|
||||
/**
|
||||
* True if this entry has ever been published
|
||||
*/
|
||||
private boolean readable;
|
||||
|
||||
/**
|
||||
* The ongoing edit or null if this entry is not being edited.
|
||||
*/
|
||||
private Editor currentEditor;
|
||||
|
||||
/**
|
||||
* The sequence number of the most recently committed edit to this entry.
|
||||
*/
|
||||
private long sequenceNumber;
|
||||
|
||||
private Entry(String key) {
|
||||
this.key = key;
|
||||
this.lengths = new long[valueCount];
|
||||
}
|
||||
|
||||
public String getLengths() throws IOException {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (long size : lengths) {
|
||||
result.append(' ').append(size);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set lengths using decimal numbers like "10123".
|
||||
*/
|
||||
private void setLengths(String[] strings) throws IOException {
|
||||
if (strings.length != valueCount) {
|
||||
throw invalidLengths(strings);
|
||||
}
|
||||
|
||||
try {
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
lengths[i] = Long.parseLong(strings[i]);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
throw invalidLengths(strings);
|
||||
}
|
||||
}
|
||||
|
||||
private IOException invalidLengths(String[] strings) throws IOException {
|
||||
throw new IOException("unexpected journal line: " + Arrays.toString(strings));
|
||||
}
|
||||
|
||||
public File getCleanFile(int i) {
|
||||
return new File(directory, key + "." + i);
|
||||
}
|
||||
|
||||
public File getDirtyFile(int i) {
|
||||
return new File(directory, key + "." + i + ".tmp");
|
||||
}
|
||||
}
|
||||
}
|
||||
21
AppFrame/src/main/java/com/arialyy/frame/cache/PathConstaant.java
vendored
Normal file
21
AppFrame/src/main/java/com/arialyy/frame/cache/PathConstaant.java
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
package com.arialyy.frame.cache;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/11/26.
|
||||
*/
|
||||
|
||||
public class PathConstaant {
|
||||
private static final String WP_DIR = "windPath";
|
||||
|
||||
/**
|
||||
* 获取APK升级路径
|
||||
*/
|
||||
public static String getWpPath() {
|
||||
return Environment.getExternalStorageDirectory().getPath()
|
||||
+ "/"
|
||||
+ WP_DIR
|
||||
+ "/update/windPath.apk";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.arialyy.frame.config;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/11/26.
|
||||
*/
|
||||
|
||||
public interface CommonConstant {
|
||||
boolean DEBUG = true;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.arialyy.frame.config;
|
||||
|
||||
/**
|
||||
* Created by AriaL on 2017/11/26.
|
||||
*/
|
||||
|
||||
public interface NetConstant {
|
||||
String BASE_URL = "http://wwww.baidu.com/";
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.View;
|
||||
|
||||
import com.arialyy.frame.module.AbsModule;
|
||||
import com.arialyy.frame.module.IOCProxy;
|
||||
import com.arialyy.frame.temp.AbsTempView;
|
||||
@@ -17,25 +18,26 @@ import com.arialyy.frame.util.StringUtil;
|
||||
import com.arialyy.frame.util.show.T;
|
||||
|
||||
/**
|
||||
* Created by “AriaLyy@outlook.com” on 2015/11/3.
|
||||
* Created by lyy on 2015/11/3.
|
||||
* 所有的 Activity都应该继承这个类
|
||||
*/
|
||||
public abstract class AbsActivity<VB extends ViewDataBinding> extends AppCompatActivity
|
||||
implements OnTempBtClickListener {
|
||||
protected String TAG = "";
|
||||
protected AbsFrame mAm;
|
||||
protected View mRootView;
|
||||
protected AbsTempView mTempView;
|
||||
protected boolean useTempView = true;
|
||||
private VB mBind;
|
||||
private IOCProxy mProxy;
|
||||
/**
|
||||
* 第一次点击返回的系统时间
|
||||
*/
|
||||
private long mFirstClickTime = 0;
|
||||
protected AbsFrame mAm;
|
||||
protected View mRootView;
|
||||
private ModuleFactory mModuleF;
|
||||
protected AbsTempView mTempView;
|
||||
protected boolean useTempView = true;
|
||||
|
||||
@Override protected void onCreate(Bundle savedInstanceState) {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
initialization();
|
||||
init(savedInstanceState);
|
||||
@@ -55,12 +57,6 @@ public abstract class AbsActivity<VB extends ViewDataBinding> extends AppCompatA
|
||||
}
|
||||
}
|
||||
|
||||
protected void reNewModule() {
|
||||
if (mModuleF == null) {
|
||||
mModuleF = ModuleFactory.newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取填充View
|
||||
*/
|
||||
@@ -115,7 +111,8 @@ public abstract class AbsActivity<VB extends ViewDataBinding> extends AppCompatA
|
||||
*/
|
||||
protected void hintTempView(int delay) {
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
@Override public void run() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mTempView == null || !useTempView) {
|
||||
return;
|
||||
}
|
||||
@@ -126,11 +123,13 @@ public abstract class AbsActivity<VB extends ViewDataBinding> extends AppCompatA
|
||||
}, delay);
|
||||
}
|
||||
|
||||
@Override public void onBtTempClick(View view, int type) {
|
||||
@Override
|
||||
public void onBtTempClick(View view, int type) {
|
||||
|
||||
}
|
||||
|
||||
@Override protected void onDestroy() {
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@@ -138,7 +137,8 @@ public abstract class AbsActivity<VB extends ViewDataBinding> extends AppCompatA
|
||||
|
||||
}
|
||||
|
||||
@Override public void finish() {
|
||||
@Override
|
||||
public void finish() {
|
||||
super.finish();
|
||||
mAm.removeActivity(this);
|
||||
}
|
||||
@@ -228,13 +228,15 @@ public abstract class AbsActivity<VB extends ViewDataBinding> extends AppCompatA
|
||||
mAm.exitApp(false);
|
||||
}
|
||||
|
||||
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||
@NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
PermissionHelp.getInstance().handlePermissionCallback(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
PermissionHelp.getInstance()
|
||||
.handleSpecialPermissionCallback(this, requestCode, resultCode, data);
|
||||
|
||||
@@ -3,9 +3,9 @@ package com.arialyy.frame.core;
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
|
||||
import com.arialyy.frame.module.AbsModule;
|
||||
import com.arialyy.frame.module.IOCProxy;
|
||||
import com.arialyy.frame.util.StringUtil;
|
||||
@@ -34,12 +34,15 @@ public abstract class AbsAlertDialog extends DialogFragment {
|
||||
mObj = obj;
|
||||
}
|
||||
|
||||
@Override public void onCreate(Bundle savedInstanceState) {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
initDialog();
|
||||
}
|
||||
|
||||
@NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return mDialog;
|
||||
}
|
||||
|
||||
@@ -98,13 +101,15 @@ public abstract class AbsAlertDialog extends DialogFragment {
|
||||
|
||||
protected abstract void dataCallback(int result, Object obj);
|
||||
|
||||
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||
@NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
PermissionHelp.getInstance().handlePermissionCallback(requestCode, permissions, grantResults);
|
||||
}
|
||||
|
||||
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
PermissionHelp.getInstance()
|
||||
.handleSpecialPermissionCallback(getContext(), requestCode, resultCode, data);
|
||||
|
||||
@@ -2,16 +2,13 @@ package com.arialyy.frame.core;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
|
||||
import com.arialyy.frame.module.AbsModule;
|
||||
import com.arialyy.frame.module.IOCProxy;
|
||||
import com.arialyy.frame.util.StringUtil;
|
||||
|
||||
|
||||
/**
|
||||
* Created by lyy on 2015/11/4.
|
||||
* 继承Dialog
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.arialyy.frame.module.IOCProxy;
|
||||
import com.arialyy.frame.util.StringUtil;
|
||||
import com.lyy.frame.R;
|
||||
|
||||
|
||||
/**
|
||||
* Created by lyy on 2015/11/4.
|
||||
* DialogFragment
|
||||
@@ -61,10 +62,6 @@ public abstract class AbsDialogFragment<VB extends ViewDataBinding> extends Dial
|
||||
return mRootView;
|
||||
}
|
||||
|
||||
public <V extends View> V findViewById(@IdRes int id) {
|
||||
return mRootView.findViewById(id);
|
||||
}
|
||||
|
||||
@Override public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
if (activity instanceof AbsActivity) {
|
||||
@@ -72,6 +69,10 @@ public abstract class AbsDialogFragment<VB extends ViewDataBinding> extends Dial
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends View> T findViewById(@IdRes int id){
|
||||
return mRootView.findViewById(id);
|
||||
}
|
||||
|
||||
private void initFragment() {
|
||||
TAG = StringUtil.getClassName(this);
|
||||
mProxy = IOCProxy.newInstance(this);
|
||||
|
||||
@@ -29,7 +29,6 @@ import com.arialyy.frame.util.show.L;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
|
||||
/**
|
||||
* Created by lyy on 2015/11/4.
|
||||
* 基础Fragment
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package com.arialyy.frame.core;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.os.Process;
|
||||
|
||||
import com.arialyy.frame.base.BaseApp;
|
||||
import com.arialyy.frame.util.show.FL;
|
||||
import java.io.File;
|
||||
import java.util.Iterator;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Created by “AriaLyy@outlook.com” on 2015/11/4.
|
||||
* Created by lyy on 2015/11/4.
|
||||
* APP生命周期管理类管理
|
||||
*/
|
||||
public class AbsFrame {
|
||||
@@ -23,18 +24,20 @@ public class AbsFrame {
|
||||
|
||||
}
|
||||
|
||||
private AbsFrame(Context context) {
|
||||
mContext = context;
|
||||
private AbsFrame(Application application) {
|
||||
mContext = application.getApplicationContext();
|
||||
BaseApp.context = mContext;
|
||||
BaseApp.app = application;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化框架
|
||||
*/
|
||||
public static AbsFrame init(Context applicationContext) {
|
||||
public static AbsFrame init(Application app) {
|
||||
if (mManager == null) {
|
||||
synchronized (LOCK) {
|
||||
if (mManager == null) {
|
||||
mManager = new AbsFrame(applicationContext);
|
||||
mManager = new AbsFrame(app);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,18 +54,6 @@ public class AbsFrame {
|
||||
return mManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* activity 是否存在
|
||||
*/
|
||||
public boolean activityExists(Class clazz) {
|
||||
for (AbsActivity activity : mActivityStack) {
|
||||
if (activity.getClass().getName().equals(clazz.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Activity栈
|
||||
*/
|
||||
@@ -72,7 +63,7 @@ public class AbsFrame {
|
||||
|
||||
/**
|
||||
* 开启异常捕获
|
||||
* 日志文件位于/data/data/Package Name/cache//crash/2016.10.26_AbsExceptionFile.crash
|
||||
* 日志文件位于/data/data/Package Name/cache//crash/AbsExceptionFile.crash
|
||||
*/
|
||||
public void openCrashHandler() {
|
||||
openCrashHandler("", "");
|
||||
@@ -137,6 +128,7 @@ public class AbsFrame {
|
||||
*/
|
||||
public void finishActivity(AbsActivity activity) {
|
||||
if (activity != null) {
|
||||
mActivityStack.remove(activity);
|
||||
activity.finish();
|
||||
}
|
||||
}
|
||||
@@ -146,10 +138,7 @@ public class AbsFrame {
|
||||
*/
|
||||
public void removeActivity(AbsActivity activity) {
|
||||
if (activity != null) {
|
||||
int i = mActivityStack.search(activity);
|
||||
if (i != -1) {
|
||||
mActivityStack.remove(activity);
|
||||
}
|
||||
mActivityStack.remove(activity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,12 +146,9 @@ public class AbsFrame {
|
||||
* 结束指定类名的Activity
|
||||
*/
|
||||
public void finishActivity(Class<?> cls) {
|
||||
Iterator<AbsActivity> iter = mActivityStack.iterator();
|
||||
while (iter.hasNext()) {
|
||||
AbsActivity activity = iter.next();
|
||||
if (activity.getClass().getName().equals(cls.getName())) {
|
||||
iter.remove();
|
||||
activity.finish();
|
||||
for (AbsActivity activity : mActivityStack) {
|
||||
if (activity.getClass().equals(cls)) {
|
||||
finishActivity(activity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,16 +173,15 @@ public class AbsFrame {
|
||||
public void exitApp(Boolean isBackground) {
|
||||
try {
|
||||
finishAllActivity();
|
||||
//ActivityManager activityMgr =
|
||||
// (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
//activityMgr.restartPackage(mContext.getPackageName());
|
||||
ActivityManager activityMgr =
|
||||
(ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
|
||||
activityMgr.restartPackage(mContext.getPackageName());
|
||||
} catch (Exception e) {
|
||||
FL.e(TAG, FL.getExceptionString(e));
|
||||
} finally {
|
||||
// 注意,如果您有后台程序运行,请不要支持此句子
|
||||
if (!isBackground) {
|
||||
System.exit(0);
|
||||
//Process.killProcess(Process.myPid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,10 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.PopupWindow;
|
||||
|
||||
import com.arialyy.frame.module.AbsModule;
|
||||
import com.arialyy.frame.module.IOCProxy;
|
||||
import com.arialyy.frame.util.StringUtil;
|
||||
|
||||
|
||||
/**
|
||||
* Created by lyy on 2015/12/3.
|
||||
* 抽象的Popupwindow悬浮框
|
||||
@@ -22,7 +20,7 @@ import com.arialyy.frame.util.StringUtil;
|
||||
public abstract class AbsPopupWindow extends PopupWindow {
|
||||
|
||||
protected String TAG;
|
||||
private static Context mContext;
|
||||
private Context mContext;
|
||||
private Drawable mBackground;
|
||||
protected View mView;
|
||||
private Object mObj;
|
||||
@@ -62,14 +60,14 @@ public abstract class AbsPopupWindow extends PopupWindow {
|
||||
TAG = StringUtil.getClassName(this);
|
||||
// 设置SelectPicPopupWindow弹出窗体的宽
|
||||
setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
// 设置SelectPicPopupWindow弹出窗体的高
|
||||
setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
//// 设置SelectPicPopupWindow弹出窗体的高
|
||||
setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
setFocusable(true);
|
||||
// 设置SelectPicPopupWindow弹出窗体动画效果
|
||||
// setAnimationStyle(R.style.wisdom_anim_style);
|
||||
// 实例化一个ColorDrawable颜色为半透明
|
||||
if (mBackground == null) {
|
||||
mBackground = new ColorDrawable(Color.parseColor("#7f000000"));
|
||||
mBackground = new ColorDrawable(Color.parseColor("#4f000000"));
|
||||
}
|
||||
// 设置SelectPicPopupWindow弹出窗体的背景
|
||||
setBackgroundDrawable(mBackground);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.arialyy.frame.core;
|
||||
|
||||
|
||||
import android.databinding.ViewDataBinding;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/9/16.
|
||||
@@ -12,7 +12,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
public class BindingFactory {
|
||||
private final String TAG = "BindingFactory";
|
||||
|
||||
private Map<Integer, ViewDataBinding> mBindings = new ConcurrentHashMap<>();
|
||||
private Map<Integer, ViewDataBinding> mBindings = new HashMap<>();
|
||||
|
||||
private BindingFactory() {
|
||||
|
||||
|
||||
@@ -2,11 +2,13 @@ package com.arialyy.frame.core;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Looper;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.arialyy.frame.http.HttpUtil;
|
||||
import com.arialyy.frame.permission.PermissionManager;
|
||||
import com.arialyy.frame.util.AndroidUtils;
|
||||
import com.arialyy.frame.util.CalendarUtils;
|
||||
import com.arialyy.frame.util.FileUtil;
|
||||
@@ -64,7 +66,8 @@ final class CrashHandler implements Thread.UncaughtExceptionHandler {
|
||||
mPramKey = key;
|
||||
}
|
||||
|
||||
@Override public void uncaughtException(Thread thread, Throwable ex) {
|
||||
@Override
|
||||
public void uncaughtException(Thread thread, Throwable ex) {
|
||||
if (!handleException(ex) && mDefaultHandler != null) {
|
||||
mDefaultHandler.uncaughtException(thread, ex);
|
||||
} else {
|
||||
@@ -90,7 +93,8 @@ final class CrashHandler implements Thread.UncaughtExceptionHandler {
|
||||
}
|
||||
//在这里处理崩溃逻辑,将不再显示FC对话框
|
||||
new Thread() {
|
||||
@Override public void run() {
|
||||
@Override
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
T.showLong(mContext, "很抱歉,程序出现异常,即将退出");
|
||||
Looper.loop();
|
||||
@@ -111,8 +115,8 @@ final class CrashHandler implements Thread.UncaughtExceptionHandler {
|
||||
info.systemVersionCode = Build.VERSION.SDK_INT;
|
||||
info.phoneModel = Build.MODEL;
|
||||
info.exceptionMsg = FL.getExceptionString(ex);
|
||||
if (AndroidUtils.checkPermission(mContext, Manifest.permission.INTERNET)
|
||||
&& AndroidUtils.checkPermission(mContext, Manifest.permission.ACCESS_NETWORK_STATE)) {
|
||||
if (AndroidUtils.checkPermission(mContext, Manifest.permission.INTERNET) &&
|
||||
AndroidUtils.checkPermission(mContext, Manifest.permission.ACCESS_NETWORK_STATE)) {
|
||||
if (NetUtils.isConnected(mContext) && !TextUtils.isEmpty(mServerHost) && !TextUtils.isEmpty(
|
||||
mPramKey)) {
|
||||
String objStr = new Gson().toJson(info);
|
||||
|
||||
@@ -25,7 +25,8 @@ public class DialogSimpleModule extends AbsModule {
|
||||
/**
|
||||
* 可设置参数和回调名的回调函数
|
||||
*/
|
||||
@Deprecated public void onDialog(String methodName, Class<?> param, Object data) {
|
||||
@Deprecated
|
||||
public void onDialog(String methodName, Class<?> param, Object data) {
|
||||
callback(methodName, param, data);
|
||||
}
|
||||
|
||||
@@ -34,7 +35,8 @@ public class DialogSimpleModule extends AbsModule {
|
||||
*
|
||||
* @param b 需要回调的数据
|
||||
*/
|
||||
@Deprecated public void onDialog(Bundle b) {
|
||||
@Deprecated
|
||||
public void onDialog(Bundle b) {
|
||||
callback("onDialog", Bundle.class, b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2015/8/31.
|
||||
@@ -18,7 +17,7 @@ public class ModuleFactory {
|
||||
|
||||
private final String TAG = "ModuleFactory";
|
||||
|
||||
private Map<Integer, AbsModule> mModules = new ConcurrentHashMap<>();
|
||||
private Map<Integer, AbsModule> mModules = new HashMap<>();
|
||||
|
||||
private ModuleFactory() {
|
||||
|
||||
@@ -50,7 +49,6 @@ public class ModuleFactory {
|
||||
Object[] params = { context };
|
||||
try {
|
||||
Constructor<T> con = clazz.getConstructor(paramTypes);
|
||||
con.setAccessible(true);
|
||||
T module = con.newInstance(params);
|
||||
mModules.put(clazz.hashCode(), module);
|
||||
return module;
|
||||
|
||||
@@ -36,7 +36,7 @@ import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
/**
|
||||
* Created by “AriaLyy@outlook.com” on 2015/11/5.
|
||||
* Created by lyy on 2015/11/5.
|
||||
* 网络连接工具
|
||||
*/
|
||||
public class HttpUtil {
|
||||
@@ -56,7 +56,7 @@ public class HttpUtil {
|
||||
|
||||
private HttpUtil(Context context) {
|
||||
mContext = context;
|
||||
mCacheUtil = new CacheUtil.Builder(context).openDiskCache().build();
|
||||
mCacheUtil = new CacheUtil(mContext, false);
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
@@ -110,10 +110,12 @@ public class HttpUtil {
|
||||
* @param key 上传文件键值
|
||||
*/
|
||||
public void uploadFile(@NonNull final String url, @NonNull final String filePath,
|
||||
@NonNull final String key, final String contentType, final Map<String, String> header,
|
||||
@NonNull final String key,
|
||||
final String contentType, final Map<String, String> header,
|
||||
@NonNull final IResponse absResponse) {
|
||||
new Thread(new Runnable() {
|
||||
@Override public void run() {
|
||||
@Override
|
||||
public void run() {
|
||||
File file = new File(filePath);
|
||||
String BOUNDARY = UUID.randomUUID().toString(); // 边界标识 随机生成
|
||||
String PREFIX = "--", LINE_END = "\r\n";
|
||||
@@ -131,9 +133,10 @@ public class HttpUtil {
|
||||
conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);
|
||||
|
||||
if (header != null && header.size() > 0) {
|
||||
Set<String> keys = header.keySet();
|
||||
for (String key : keys) {
|
||||
conn.setRequestProperty(key, header.get(key));
|
||||
Set set = header.entrySet();
|
||||
for (Object aSet : set) {
|
||||
Map.Entry entry = (Map.Entry) aSet;
|
||||
conn.setRequestProperty(entry.getKey() + "", entry.getValue() + "");
|
||||
}
|
||||
}
|
||||
OutputStream outputSteam = conn.getOutputStream();
|
||||
@@ -193,12 +196,13 @@ public class HttpUtil {
|
||||
L.v(TAG, "请求链接 >>>> " + url);
|
||||
String requestUrl = url;
|
||||
if (params != null && params.size() > 0) {
|
||||
Set<String> keys = params.keySet();
|
||||
Set set = params.entrySet();
|
||||
int i = 0;
|
||||
requestUrl += "?";
|
||||
for (String key : keys) {
|
||||
for (Object aSet : set) {
|
||||
i++;
|
||||
requestUrl += key + "=" + params.get(key) + (i < params.size() ? "&" : "");
|
||||
Map.Entry entry = (Map.Entry) aSet;
|
||||
requestUrl += entry.getKey() + "=" + entry.getValue() + (i < params.size() ? "&" : "");
|
||||
}
|
||||
L.v(TAG, "请求参数为 >>>> ");
|
||||
L.m(params);
|
||||
@@ -213,7 +217,8 @@ public class HttpUtil {
|
||||
|
||||
//请求加入调度
|
||||
call.enqueue(new Callback() {
|
||||
@Override public void onFailure(Call call, IOException e) {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
L.e(TAG, "请求链接【" + url + "】失败");
|
||||
String data = null;
|
||||
if (useCache) {
|
||||
@@ -228,7 +233,8 @@ public class HttpUtil {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onResponse(Call call, Response response) throws IOException {
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) throws IOException {
|
||||
String data = response.body().string();
|
||||
L.d(TAG, "数据获取成功,获取到的数据为 >>>> ");
|
||||
L.j(data);
|
||||
@@ -256,18 +262,20 @@ public class HttpUtil {
|
||||
//头数据
|
||||
Headers.Builder hb = new Headers.Builder();
|
||||
if (header != null && header.size() > 0) {
|
||||
Set<String> keys = header.keySet();
|
||||
for (String key : keys) {
|
||||
hb.add(key, header.get(key));
|
||||
Set set = header.entrySet();
|
||||
for (Object aSet : set) {
|
||||
Map.Entry entry = (Map.Entry) aSet;
|
||||
hb.add(entry.getKey() + "", entry.getValue() + "");
|
||||
}
|
||||
L.v(TAG, "请求的头数据为 >>>> ");
|
||||
L.m(header);
|
||||
}
|
||||
//请求参数
|
||||
if (params != null && params.size() > 0) {
|
||||
Set<String> keys = params.keySet();
|
||||
for (String key : keys) {
|
||||
formB.add(key, params.get(key));
|
||||
Set set = params.entrySet();
|
||||
for (Object aSet : set) {
|
||||
Map.Entry entry = (Map.Entry) aSet;
|
||||
formB.add(entry.getKey() + "", entry.getValue() + "");
|
||||
}
|
||||
L.v(TAG, "请求参数为 >>>> ");
|
||||
L.m(params);
|
||||
@@ -279,7 +287,8 @@ public class HttpUtil {
|
||||
new Request.Builder().url(url).post(formB.build()).headers(hb.build()).build();
|
||||
Call call = client.newCall(request);
|
||||
call.enqueue(new Callback() {
|
||||
@Override public void onFailure(Call call, IOException e) {
|
||||
@Override
|
||||
public void onFailure(Call call, IOException e) {
|
||||
L.e(TAG, "请求链接【" + url + "】失败");
|
||||
String data = null;
|
||||
if (useCache) {
|
||||
@@ -294,7 +303,8 @@ public class HttpUtil {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onResponse(Call call, Response response) throws IOException {
|
||||
@Override
|
||||
public void onResponse(Call call, Response response) throws IOException {
|
||||
String data = response.body().string();
|
||||
L.d(TAG, "数据获取成功,获取到的数据为 >>>>");
|
||||
L.j(data);
|
||||
@@ -309,7 +319,8 @@ public class HttpUtil {
|
||||
|
||||
private void setOnError(final Object error, final IResponse response) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override public void run() {
|
||||
@Override
|
||||
public void run() {
|
||||
response.onError(error);
|
||||
}
|
||||
});
|
||||
@@ -317,7 +328,8 @@ public class HttpUtil {
|
||||
|
||||
private void setOnResponse(final String data, final IResponse response) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override public void run() {
|
||||
@Override
|
||||
public void run() {
|
||||
response.onResponse(data);
|
||||
}
|
||||
});
|
||||
@@ -328,11 +340,13 @@ public class HttpUtil {
|
||||
*/
|
||||
public static class AbsResponse implements IResponse {
|
||||
|
||||
@Override public void onResponse(String data) {
|
||||
@Override
|
||||
public void onResponse(String data) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onError(Object error) {
|
||||
@Override
|
||||
public void onError(Object error) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
package com.arialyy.frame.module;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import android.databinding.ViewDataBinding;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.View;
|
||||
|
||||
import com.arialyy.frame.core.AbsActivity;
|
||||
import com.arialyy.frame.core.BindingFactory;
|
||||
import com.arialyy.frame.module.inf.ModuleListener;
|
||||
import com.arialyy.frame.util.ObjUtil;
|
||||
import com.arialyy.frame.util.StringUtil;
|
||||
import com.arialyy.frame.util.show.L;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by AriaLyy on 2015/2/3.
|
||||
* 抽象的module
|
||||
@@ -46,7 +55,9 @@ public class AbsModule {
|
||||
* @param moduleListener Module监听
|
||||
*/
|
||||
public void setModuleListener(ModuleListener moduleListener) {
|
||||
if (moduleListener == null) throw new NullPointerException("ModuleListener不能为空");
|
||||
if (moduleListener == null) {
|
||||
throw new NullPointerException("ModuleListener不能为空");
|
||||
}
|
||||
this.mModuleListener = moduleListener;
|
||||
}
|
||||
|
||||
@@ -126,7 +137,8 @@ public class AbsModule {
|
||||
*
|
||||
* @param method 回调的方法名
|
||||
*/
|
||||
@Deprecated protected void callback(String method) {
|
||||
@Deprecated
|
||||
protected void callback(String method) {
|
||||
mModuleListener.callback(method);
|
||||
}
|
||||
|
||||
@@ -137,7 +149,8 @@ public class AbsModule {
|
||||
* @param dataClassType 回调数据类型
|
||||
* @param data 回调数据
|
||||
*/
|
||||
@Deprecated protected void callback(String method, Class<?> dataClassType, Object data) {
|
||||
@Deprecated
|
||||
protected void callback(String method, Class<?> dataClassType, Object data) {
|
||||
mModuleListener.callback(method, dataClassType, data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,8 @@ public class IOCProxy implements ModuleListener {
|
||||
* @param result 返回码
|
||||
* @param data 回调数据
|
||||
*/
|
||||
@Override public void callback(int result, Object data) {
|
||||
@Override
|
||||
public void callback(int result, Object data) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
Method m = ReflectionUtil.getMethod(mObj.getClass(), mMethod, int.class, Object.class);
|
||||
@@ -69,7 +70,9 @@ public class IOCProxy implements ModuleListener {
|
||||
*
|
||||
* @param method 方法名
|
||||
*/
|
||||
@Override @Deprecated public void callback(String method) {
|
||||
@Override
|
||||
@Deprecated
|
||||
public void callback(String method) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
Method m = mObj.getClass().getDeclaredMethod(method);
|
||||
@@ -93,7 +96,9 @@ public class IOCProxy implements ModuleListener {
|
||||
* @param dataClassType 参数类型,如 int.class
|
||||
* @param data 数据
|
||||
*/
|
||||
@Override @Deprecated public void callback(String method, Class<?> dataClassType, Object data) {
|
||||
@Override
|
||||
@Deprecated
|
||||
public void callback(String method, Class<?> dataClassType, Object data) {
|
||||
synchronized (this) {
|
||||
try {
|
||||
Method m = mObj.getClass().getDeclaredMethod(method, dataClassType);
|
||||
|
||||
@@ -54,8 +54,7 @@ public class ModuleFactory {
|
||||
* @return true : key已经和value对应,false : key没有和value对应
|
||||
*/
|
||||
private boolean checkKey(int key, AbsModule.OnCallback callback) {
|
||||
return mKeyIndex.indexOfKey(key) != -1
|
||||
|| mKeyIndex.indexOfValue(callback.hashCode()) != -1
|
||||
return mKeyIndex.indexOfKey(key) != -1 || mKeyIndex.indexOfValue(callback.hashCode()) != -1
|
||||
&& mKeyIndex.valueAt(callback.hashCode()) == key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,8 +85,10 @@ import java.util.List;
|
||||
* @param obj Activity || Fragment
|
||||
* @param permission 权限
|
||||
*/
|
||||
public void requestPermission(Object obj, OnPermissionCallback callback, String... permission) {
|
||||
requestPermission(obj, "", callback, registerCallback(obj, callback, permission));
|
||||
public PermissionManager requestPermission(Object obj, OnPermissionCallback callback,
|
||||
String... permission) {
|
||||
requestPermissionAndHint(obj, callback, "", registerCallback(obj, callback, permission));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,9 +98,9 @@ import java.util.List;
|
||||
* @param hint 如果框对话框包含“不再询问”选择框的时候的提示用语。
|
||||
* @param permission 权限
|
||||
*/
|
||||
private void requestPermission(Object obj, String hint, OnPermissionCallback callback,
|
||||
public void requestPermissionAndHint(Object obj, OnPermissionCallback callback, String hint,
|
||||
String... permission) {
|
||||
mPu.requestPermission(obj, hint, 0, registerCallback(obj, callback, permission));
|
||||
mPu.requestPermission(obj, 0, hint, registerCallback(obj, callback, permission));
|
||||
}
|
||||
|
||||
private void registerCallback(OnPermissionCallback callback, int hashCode) {
|
||||
|
||||
@@ -45,7 +45,7 @@ import java.util.List;
|
||||
if (!AndroidVersionUtil.hasM()) {
|
||||
return;
|
||||
}
|
||||
requestPermission(obj, "", requestCode, permission);
|
||||
requestPermission(obj, requestCode, "", permission);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,7 +53,7 @@ import java.util.List;
|
||||
*
|
||||
* @param hint 如果框对话框包含”不再询问“选择框的时候的提示用语。
|
||||
*/
|
||||
public void requestPermission(Object obj, String hint, int requestCode, String... permission) {
|
||||
public void requestPermission(Object obj, int requestCode, String hint, String... permission) {
|
||||
if (!AndroidVersionUtil.hasM() || permission == null || permission.length == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -72,12 +72,12 @@ import java.util.List;
|
||||
for (String str : permission) {
|
||||
if (fragment != null) {
|
||||
if (fragment.shouldShowRequestPermissionRationale(str)) {
|
||||
T.showShort(fragment.getContext(), hint);
|
||||
T.showLong(fragment.getContext(), hint);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (activity.shouldShowRequestPermissionRationale(str)) {
|
||||
T.showShort(activity, hint);
|
||||
T.showLong(activity, hint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import android.widget.LinearLayout;
|
||||
import com.arialyy.frame.util.StringUtil;
|
||||
import com.arialyy.frame.util.show.L;
|
||||
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/4/27.
|
||||
* 抽象的填充类
|
||||
@@ -57,7 +56,8 @@ public abstract class AbsTempView extends LinearLayout implements ITempView {
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setType(int type) {
|
||||
@Override
|
||||
public void setType(int type) {
|
||||
mType = type;
|
||||
if (type == LOADING) {
|
||||
onLoading();
|
||||
|
||||
@@ -23,37 +23,43 @@ public class TempView extends AbsTempView {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override protected void init() {
|
||||
@Override
|
||||
protected void init() {
|
||||
mPb = (ProgressBar) findViewById(R.id.pb);
|
||||
mHint = (TextView) findViewById(R.id.hint);
|
||||
mBt = (Button) findViewById(R.id.bt);
|
||||
mErrorContent = (FrameLayout) findViewById(R.id.error);
|
||||
mBt.setOnClickListener(new OnClickListener() {
|
||||
@Override public void onClick(View v) {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onTempBtClick(v, mType);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override protected int setLayoutId() {
|
||||
@Override
|
||||
protected int setLayoutId() {
|
||||
return R.layout.layout_error_temp;
|
||||
}
|
||||
|
||||
@Override public void onError() {
|
||||
@Override
|
||||
public void onError() {
|
||||
mErrorContent.setVisibility(VISIBLE);
|
||||
mPb.setVisibility(GONE);
|
||||
mHint.setText("网络错误");
|
||||
mBt.setText("点击刷新");
|
||||
}
|
||||
|
||||
@Override public void onNull() {
|
||||
@Override
|
||||
public void onNull() {
|
||||
mErrorContent.setVisibility(VISIBLE);
|
||||
mPb.setVisibility(GONE);
|
||||
mHint.setText("数据为空");
|
||||
mBt.setText("点击刷新");
|
||||
}
|
||||
|
||||
@Override public void onLoading() {
|
||||
@Override
|
||||
public void onLoading() {
|
||||
mErrorContent.setVisibility(GONE);
|
||||
mPb.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
@@ -140,7 +140,9 @@ public class AESEncryption {
|
||||
* AES算法的秘钥要求16位
|
||||
*/
|
||||
public static String toHex(byte[] buf) {
|
||||
if (buf == null) return "";
|
||||
if (buf == null) {
|
||||
return "";
|
||||
}
|
||||
StringBuffer result = new StringBuffer(2 * buf.length);
|
||||
for (byte aBuf : buf) {
|
||||
appendHex(result, aBuf);
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package com.arialyy.frame.util;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -21,13 +18,14 @@ import android.os.Environment;
|
||||
import android.os.StatFs;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.format.Formatter;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.arialyy.frame.util.show.FL;
|
||||
import com.arialyy.frame.util.show.L;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
@@ -48,35 +46,18 @@ public class AndroidUtils {
|
||||
|
||||
}
|
||||
|
||||
private static final float DENSITY = Resources.getSystem().getDisplayMetrics().density;
|
||||
|
||||
// 获得机身可用内存
|
||||
public static String getRomAvailableSize(Context context) {
|
||||
File path = Environment.getDataDirectory();
|
||||
StatFs stat = new StatFs(path.getPath());
|
||||
long blockSize = stat.getBlockSize();
|
||||
long availableBlocks = stat.getAvailableBlocks();
|
||||
return Formatter.formatFileSize(context, blockSize * availableBlocks);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重启app
|
||||
* 应用市场是否存在
|
||||
*
|
||||
* @return {@code true}存在
|
||||
*/
|
||||
public static void reStartApp(Context context) {
|
||||
Intent intent = context.getPackageManager()
|
||||
.getLaunchIntentForPackage(context.getPackageName());
|
||||
PendingIntent restartIntent =
|
||||
PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
|
||||
AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // 1秒钟后重启应用
|
||||
System.exit(0);
|
||||
}
|
||||
public static boolean hasAnyMarket(Context context) {
|
||||
Intent intent = new Intent();
|
||||
intent.setData(Uri.parse("market://details?id=android.browser"));
|
||||
List list = context.getPackageManager()
|
||||
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
|
||||
/**
|
||||
* 另外一种dp转PX方法
|
||||
*/
|
||||
public static int dp2px(int dp) {
|
||||
return Math.round(dp * DENSITY);
|
||||
return list != null && list.size() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,6 +129,14 @@ public class AndroidUtils {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取未安装软件包的包名
|
||||
*/
|
||||
public static PackageInfo getApkPackageInfo(Context context, String apkPath) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
return pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否安装
|
||||
*/
|
||||
@@ -196,8 +185,6 @@ public class AndroidUtils {
|
||||
public static void startOtherApp(Context context, String packageName) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
Intent launcherIntent = pm.getLaunchIntentForPackage(packageName);
|
||||
launcherIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
//launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
context.startActivity(launcherIntent);
|
||||
}
|
||||
|
||||
@@ -445,8 +432,8 @@ public class AndroidUtils {
|
||||
* 安装APP
|
||||
*/
|
||||
public static void install(Context context, File file) {
|
||||
L.e(TAG, "install Apk:" + file.getName());
|
||||
context.startActivity(getInstallIntent(file));
|
||||
FL.e(TAG, "install Apk:" + file.getName());
|
||||
context.startActivity(getInstallIntent(context, file));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -464,11 +451,18 @@ public class AndroidUtils {
|
||||
/**
|
||||
* 获取安装应用的Intent
|
||||
*/
|
||||
public static Intent getInstallIntent(File file) {
|
||||
public static Intent getInstallIntent(Context context, File file) {
|
||||
Intent intent = new Intent();
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
Uri contentUri =
|
||||
FileProvider.getUriForFile(context, context.getPackageName() + ".fileProvider", file);
|
||||
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
|
||||
} else {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
|
||||
}
|
||||
return intent;
|
||||
}
|
||||
|
||||
@@ -518,22 +512,6 @@ public class AndroidUtils {
|
||||
return context.getResources().getDisplayMetrics();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取电话号码
|
||||
*/
|
||||
public static String getLocalPhoneNumber(Context context) {
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_SMS)
|
||||
!= PackageManager.PERMISSION_GRANTED
|
||||
&& ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_NUMBERS)
|
||||
!= PackageManager.PERMISSION_GRANTED
|
||||
&& ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
String line1Number = getTelephonyManager(context).getLine1Number();
|
||||
return line1Number == null ? "" : line1Number;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备型号(Nexus5)
|
||||
*/
|
||||
|
||||
@@ -93,7 +93,8 @@ public class AppUtils {
|
||||
public static String getAppName(Context context) {
|
||||
try {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
|
||||
PackageInfo packageInfo = packageManager.getPackageInfo(
|
||||
context.getPackageName(), 0);
|
||||
int labelRes = packageInfo.applicationInfo.labelRes;
|
||||
return context.getResources().getString(labelRes);
|
||||
} catch (NameNotFoundException e) {
|
||||
@@ -110,7 +111,8 @@ public class AppUtils {
|
||||
public static String getVersionName(Context context) {
|
||||
try {
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
|
||||
PackageInfo packageInfo = packageManager.getPackageInfo(
|
||||
context.getPackageName(), 0);
|
||||
return packageInfo.versionName;
|
||||
} catch (NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -9,7 +9,7 @@ import android.util.TypedValue;
|
||||
*/
|
||||
public class DensityUtils {
|
||||
private DensityUtils() {
|
||||
/* cannot be instantiated */
|
||||
/* cannot be instantiated */
|
||||
throw new UnsupportedOperationException("cannot be instantiated");
|
||||
}
|
||||
|
||||
@@ -26,16 +26,16 @@ public class DensityUtils {
|
||||
* dp转px
|
||||
*/
|
||||
public static int dp2px(Context context, float dpVal) {
|
||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal,
|
||||
context.getResources().getDisplayMetrics());
|
||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||||
dpVal, context.getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
/**
|
||||
* sp转px
|
||||
*/
|
||||
public static int sp2px(Context context, float spVal) {
|
||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal,
|
||||
context.getResources().getDisplayMetrics());
|
||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
|
||||
spVal, context.getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -40,7 +40,8 @@ public class DrawableUtil {
|
||||
float scaleWidth = ((float) w / width);
|
||||
float scaleHeight = ((float) h / height);
|
||||
matrix.postScale(scaleWidth, scaleHeight);
|
||||
Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height, matrix, true);
|
||||
Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height,
|
||||
matrix, true);
|
||||
return new BitmapDrawable(null, newbmp);
|
||||
}
|
||||
|
||||
@@ -50,9 +51,9 @@ public class DrawableUtil {
|
||||
public static Bitmap drawableToBitmap(Drawable drawable) {
|
||||
int width = drawable.getIntrinsicWidth();
|
||||
int height = drawable.getIntrinsicHeight();
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height,
|
||||
drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
|
||||
: Bitmap.Config.RGB_565);
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, drawable
|
||||
.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
|
||||
: Bitmap.Config.RGB_565);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, width, height);
|
||||
drawable.draw(canvas);
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package com.arialyy.frame.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.arialyy.frame.util.show.FL;
|
||||
import com.arialyy.frame.util.show.L;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
@@ -29,6 +31,8 @@ import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
@@ -40,11 +44,22 @@ public class FileUtil {
|
||||
private static final String MB = "MB";
|
||||
private static final String GB = "GB";
|
||||
|
||||
private FileUtil() {
|
||||
}
|
||||
|
||||
private static final String TAG = "FileUtil";
|
||||
|
||||
//android获取一个用于打开HTML文件的intent
|
||||
public static Intent getHtmlFileIntent(String Path) {
|
||||
File file = new File(Path);
|
||||
Uri uri = Uri.parse(file.toString())
|
||||
.buildUpon()
|
||||
.encodedAuthority("com.android.htmlfileprovider")
|
||||
.scheme("content")
|
||||
.encodedPath(file.toString())
|
||||
.build();
|
||||
Intent intent = new Intent("android.intent.action.VIEW");
|
||||
intent.setDataAndType(uri, "text/html");
|
||||
return intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件夹大小
|
||||
*/
|
||||
@@ -465,8 +480,8 @@ public class FileUtil {
|
||||
if (dir.isDirectory()) {
|
||||
String[] children = dir.list();
|
||||
// 递归删除目录中的子目录下
|
||||
for (int i = 0; i < children.length; i++) {
|
||||
boolean success = deleteDir(new File(dir, children[i]));
|
||||
for (String aChildren : children) {
|
||||
boolean success = deleteDir(new File(dir, aChildren));
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,11 @@ public class KeyBoardUtils {
|
||||
* @param mContext 上下文
|
||||
*/
|
||||
public static void openKeybord(EditText mEditText, Context mContext) {
|
||||
InputMethodManager imm =
|
||||
(InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
InputMethodManager imm = (InputMethodManager) mContext
|
||||
.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.showSoftInput(mEditText, InputMethodManager.RESULT_SHOWN);
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
|
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,
|
||||
InputMethodManager.HIDE_IMPLICIT_ONLY);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -30,8 +31,8 @@ public class KeyBoardUtils {
|
||||
* @param mContext 上下文
|
||||
*/
|
||||
public static void closeKeybord(EditText mEditText, Context mContext) {
|
||||
InputMethodManager imm =
|
||||
(InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
InputMethodManager imm = (InputMethodManager) mContext
|
||||
.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
83
AppFrame/src/main/java/com/arialyy/frame/util/MediaUtil.java
Normal file
83
AppFrame/src/main/java/com/arialyy/frame/util/MediaUtil.java
Normal file
@@ -0,0 +1,83 @@
|
||||
package com.arialyy.frame.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.media.MediaPlayer;
|
||||
import android.net.Uri;
|
||||
import java.io.IOException;
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Created by Aria.Lao on 2018/1/4.
|
||||
* 多媒体工具
|
||||
*/
|
||||
public class MediaUtil {
|
||||
private MediaUtil() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取音频、视频播放长度
|
||||
*/
|
||||
public static long getDuration(String path) {
|
||||
MediaPlayer mediaPlayer = new MediaPlayer();
|
||||
try {
|
||||
mediaPlayer.setDataSource(path);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return -1;
|
||||
}
|
||||
int duration = mediaPlayer.getDuration();
|
||||
mediaPlayer.release();
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化视频时间
|
||||
*/
|
||||
public static String convertViewTime(long timeMs) {
|
||||
int totalSeconds = (int) (timeMs / 1000);
|
||||
|
||||
int seconds = totalSeconds % 60;
|
||||
int minutes = (totalSeconds / 60) % 60;
|
||||
int hours = totalSeconds / 3600;
|
||||
StringBuilder sFormatBuilder = new StringBuilder();
|
||||
Formatter sFormatter = new Formatter(sFormatBuilder, Locale.getDefault());
|
||||
sFormatBuilder.setLength(0);
|
||||
if (hours > 0) {
|
||||
return sFormatter.format("%02d:%02d:%02d", hours, minutes, seconds).toString();
|
||||
} else {
|
||||
return sFormatter.format("%02d:%02d", minutes, seconds).toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取音频封面
|
||||
*/
|
||||
public static Bitmap getArtwork(Context context, String url) {
|
||||
Uri selectedAudio = Uri.parse(url);
|
||||
MediaMetadataRetriever myRetriever = new MediaMetadataRetriever();
|
||||
myRetriever.setDataSource(context, selectedAudio); // the URI of audio file
|
||||
byte[] artwork;
|
||||
artwork = myRetriever.getEmbeddedPicture();
|
||||
if (artwork != null) {
|
||||
return BitmapFactory.decodeByteArray(artwork, 0, artwork.length);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static byte[] getArtworkAsByte(Context context, String url) {
|
||||
Uri selectedAudio = Uri.parse(url);
|
||||
MediaMetadataRetriever myRetriever = new MediaMetadataRetriever();
|
||||
myRetriever.setDataSource(context, selectedAudio); // the URI of audio file
|
||||
byte[] artwork;
|
||||
artwork = myRetriever.getEmbeddedPicture();
|
||||
if (artwork != null) {
|
||||
return artwork;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ public class NetUtils {
|
||||
public static final int NETWORK_TYPE_WIFI = 4;
|
||||
|
||||
private NetUtils() {
|
||||
/* cannot be instantiated */
|
||||
/* cannot be instantiated */
|
||||
throw new UnsupportedOperationException("cannot be instantiated");
|
||||
}
|
||||
|
||||
@@ -75,8 +75,9 @@ public class NetUtils {
|
||||
netWorkType = NETWORK_TYPE_WIFI;
|
||||
} else if (type.equalsIgnoreCase("MOBILE")) {
|
||||
String proxyHost = android.net.Proxy.getDefaultHost();
|
||||
netWorkType = TextUtils.isEmpty(proxyHost) ? (isFastMobileNetwork(context) ? NETWORK_TYPE_3G
|
||||
: NETWORK_TYPE_2G) : NETWORK_TYPE_WAP;
|
||||
netWorkType = TextUtils.isEmpty(proxyHost)
|
||||
? (isFastMobileNetwork(context) ? NETWORK_TYPE_3G : NETWORK_TYPE_2G)
|
||||
: NETWORK_TYPE_WAP;
|
||||
}
|
||||
} else {
|
||||
netWorkType = NETWORK_TYPE_INVALID;
|
||||
|
||||
@@ -13,8 +13,9 @@ public class RegularExpression {
|
||||
/**
|
||||
* 视频
|
||||
*/
|
||||
public static String VIDEO = "^(.*)\\.(mpeg-4|h.264|h.265|rmvb|xvid|vp6|h.263|mpeg-1|mpeg-2|avi|"
|
||||
+ "mov|mkv|flv|3gp|3g2|asf|wmv|mp4|m4v|tp|ts|mtp|m2t)$";
|
||||
public static String VIDEO =
|
||||
"^(.*)\\.(mpeg-4|h.264|h.265|rmvb|xvid|vp6|h.263|mpeg-1|mpeg-2|avi|" +
|
||||
"mov|mkv|flv|3gp|3g2|asf|wmv|mp4|m4v|tp|ts|mtp|m2t)$";
|
||||
/**
|
||||
* 音频
|
||||
*/
|
||||
|
||||
@@ -44,7 +44,8 @@ public class ScreenUtil {
|
||||
*
|
||||
* @param greyScale true:灰度
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB) public void setGreyScale(View v, boolean greyScale) {
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public void setGreyScale(View v, boolean greyScale) {
|
||||
if (greyScale) {
|
||||
// Create a paint object with 0 saturation (black and white)
|
||||
ColorMatrix cm = new ColorMatrix();
|
||||
@@ -63,7 +64,8 @@ public class ScreenUtil {
|
||||
* 获得屏幕高度
|
||||
*/
|
||||
public int getScreenWidth(Context context) {
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
WindowManager wm = (WindowManager) context
|
||||
.getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics outMetrics = new DisplayMetrics();
|
||||
wm.getDefaultDisplay().getMetrics(outMetrics);
|
||||
return outMetrics.widthPixels;
|
||||
@@ -73,7 +75,8 @@ public class ScreenUtil {
|
||||
* 获得屏幕宽度
|
||||
*/
|
||||
public int getScreenHeight(Context context) {
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
WindowManager wm = (WindowManager) context
|
||||
.getSystemService(Context.WINDOW_SERVICE);
|
||||
DisplayMetrics outMetrics = new DisplayMetrics();
|
||||
wm.getDefaultDisplay().getMetrics(outMetrics);
|
||||
return outMetrics.heightPixels;
|
||||
@@ -88,7 +91,8 @@ public class ScreenUtil {
|
||||
try {
|
||||
Class<?> clazz = Class.forName("com.android.internal.R$dimen");
|
||||
Object object = clazz.newInstance();
|
||||
int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());
|
||||
int height = Integer.parseInt(clazz.getField("status_bar_height")
|
||||
.get(object).toString());
|
||||
statusHeight = context.getResources().getDimensionPixelSize(height);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@@ -134,7 +138,8 @@ public class ScreenUtil {
|
||||
int width = getScreenWidth(activity);
|
||||
int height = getScreenHeight(activity);
|
||||
Bitmap bp = null;
|
||||
bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height - statusBarHeight);
|
||||
bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height
|
||||
- statusBarHeight);
|
||||
view.destroyDrawingCache();
|
||||
return bp;
|
||||
}
|
||||
@@ -145,9 +150,9 @@ public class ScreenUtil {
|
||||
public boolean isAutoBrightness(ContentResolver aContentResolver) {
|
||||
boolean automicBrightness = false;
|
||||
try {
|
||||
automicBrightness =
|
||||
Settings.System.getInt(aContentResolver, Settings.System.SCREEN_BRIGHTNESS_MODE)
|
||||
== Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
|
||||
automicBrightness = Settings.System.getInt(aContentResolver,
|
||||
Settings.System.SCREEN_BRIGHTNESS_MODE)
|
||||
== Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
|
||||
} catch (Settings.SettingNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -161,7 +166,8 @@ public class ScreenUtil {
|
||||
int nowBrightnessValue = 0;
|
||||
ContentResolver resolver = activity.getContentResolver();
|
||||
try {
|
||||
nowBrightnessValue = Settings.System.getInt(resolver, Settings.System.SCREEN_BRIGHTNESS);
|
||||
nowBrightnessValue = Settings.System.getInt(
|
||||
resolver, Settings.System.SCREEN_BRIGHTNESS);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -184,7 +190,8 @@ public class ScreenUtil {
|
||||
* 停止自动亮度调节
|
||||
*/
|
||||
public void stopAutoBrightness(Activity activity) {
|
||||
Settings.System.putInt(activity.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE,
|
||||
Settings.System.putInt(activity.getContentResolver(),
|
||||
Settings.System.SCREEN_BRIGHTNESS_MODE,
|
||||
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
|
||||
}
|
||||
|
||||
@@ -192,7 +199,8 @@ public class ScreenUtil {
|
||||
* 开启亮度自动调节
|
||||
*/
|
||||
public void startAutoBrightness(Activity activity) {
|
||||
Settings.System.putInt(activity.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE,
|
||||
Settings.System.putInt(activity.getContentResolver(),
|
||||
Settings.System.SCREEN_BRIGHTNESS_MODE,
|
||||
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
|
||||
}
|
||||
|
||||
@@ -200,8 +208,10 @@ public class ScreenUtil {
|
||||
* 保存亮度设置状态
|
||||
*/
|
||||
public void saveBrightness(ContentResolver resolver, int brightness) {
|
||||
Uri uri = Settings.System.getUriFor("screen_brightness");
|
||||
Settings.System.putInt(resolver, "screen_brightness", brightness);
|
||||
Uri uri = Settings.System
|
||||
.getUriFor("screen_brightness");
|
||||
Settings.System.putInt(resolver, "screen_brightness",
|
||||
brightness);
|
||||
// resolver.registerContentObserver(uri, true, myContentObserver);
|
||||
resolver.notifyChange(uri, null);
|
||||
}
|
||||
|
||||
@@ -170,7 +170,8 @@ public class ShellUtils {
|
||||
}
|
||||
}
|
||||
return new CommandResult(result, successMsg == null ? null : successMsg.toString(),
|
||||
errorMsg == null ? null : errorMsg.toString());
|
||||
errorMsg == null ? null
|
||||
: errorMsg.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -276,7 +276,7 @@ public class StringUtil {
|
||||
public static double strToDouble(String str) {
|
||||
// double d = Double.parseDouble(str);
|
||||
|
||||
/* 以下代码处理精度问题 */
|
||||
/* 以下代码处理精度问题 */
|
||||
BigDecimal bDeci = new BigDecimal(str);
|
||||
// BigDecimal chushu =new BigDecimal(100000000);
|
||||
// BigDecimal result =bDeci.divide(chushu,new
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
package com.arialyy.frame.util.show;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.arialyy.frame.util.CalendarUtils;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Created by “AriaLyy@outlook.com” on 2015/4/1.
|
||||
* Created by Lyy on 2015/4/1.
|
||||
* 写入文件的log,由于使用到反射和文件流的操作,建议在需要的地方才去使用
|
||||
*/
|
||||
public class FL {
|
||||
public static boolean isDebug = true;// 是否需要打印bug,可以在application的onCreate函数里面初始化
|
||||
public static String PATH = "/GameBar2/log/AriaFrameLog__"; //log路径
|
||||
static String LINE_SEPARATOR = System.getProperty("line.separator"); //等价于"\n\r",唯一的作用是能装逼
|
||||
static int JSON_INDENT = 4;
|
||||
public static boolean isDebug = true;// 是否需要打印bug,可以在application的onCreate函数里面初始化
|
||||
public static String NAME = "AriaFrame"; //log路径
|
||||
|
||||
private static String printLine(String tag, boolean isTop) {
|
||||
String top =
|
||||
@@ -53,15 +56,16 @@ public class FL {
|
||||
message = jsonStr;
|
||||
}
|
||||
|
||||
writeLogToFile(tag, printLine(tag, true));
|
||||
message = LINE_SEPARATOR + message;
|
||||
String temp = "\n" + printLine(tag, true) + "\n";
|
||||
String temp = "";
|
||||
String[] lines = message.split(LINE_SEPARATOR);
|
||||
for (String line : lines) {
|
||||
temp += "║ " + line + "\n";
|
||||
temp += "║ " + line;
|
||||
Log.d(tag, "║ " + line);
|
||||
}
|
||||
temp += printLine(tag, false);
|
||||
writeLogToFile(tag, temp);
|
||||
writeLogToFile(tag, printLine(tag, false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,8 +145,8 @@ public class FL {
|
||||
* 返回日志路径
|
||||
*/
|
||||
public static String getLogPath() {
|
||||
String path = PATH + CalendarUtils.getData() + ".txt";
|
||||
return android.os.Environment.getExternalStorageDirectory().getPath() + File.separator + path;
|
||||
String name = NAME + "_" + CalendarUtils.getData() + ".log";
|
||||
return android.os.Environment.getExternalStorageDirectory().getPath() + File.separator + name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,7 +32,7 @@ public class L {
|
||||
static int JSON_INDENT = 4;
|
||||
|
||||
private L() {
|
||||
/* cannot be instantiated */
|
||||
/* cannot be instantiated */
|
||||
throw new UnsupportedOperationException("cannot be instantiated");
|
||||
}
|
||||
|
||||
@@ -108,73 +108,99 @@ public class L {
|
||||
|
||||
// 下面四个是默认tag的函数
|
||||
public static void i(String... msg) {
|
||||
if (isDebug) printLog(I, msg);
|
||||
if (isDebug) {
|
||||
printLog(I, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void d(String... msg) {
|
||||
if (isDebug) printLog(D, msg);
|
||||
if (isDebug) {
|
||||
printLog(D, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void w(String... msg) {
|
||||
if (isDebug) printLog(W, msg);
|
||||
if (isDebug) {
|
||||
printLog(W, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void e(String... msg) {
|
||||
if (isDebug) printLog(E, msg);
|
||||
}
|
||||
|
||||
public static void e(Throwable tr) {
|
||||
if (isDebug) printLog(E, FL.getExceptionString(tr));
|
||||
if (isDebug) {
|
||||
printLog(E, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void v(String... msg) {
|
||||
if (isDebug) printLog(V, msg);
|
||||
if (isDebug) {
|
||||
printLog(V, msg);
|
||||
}
|
||||
}
|
||||
|
||||
// 下面是传入自定义tag的函数
|
||||
public static void i(String tag, String msg) {
|
||||
if (isDebug) Log.i(tag, msg);
|
||||
if (isDebug) {
|
||||
Log.i(tag, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void d(String tag, String msg) {
|
||||
if (isDebug) Log.d(tag, msg);
|
||||
if (isDebug) {
|
||||
Log.d(tag, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void w(String tag, String msg) {
|
||||
if (isDebug) Log.w(tag, msg);
|
||||
if (isDebug) {
|
||||
Log.w(tag, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void e(String tag, String msg) {
|
||||
if (isDebug) Log.e(tag, msg);
|
||||
if (isDebug) {
|
||||
Log.e(tag, msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void v(String tag, String msg) {
|
||||
if (isDebug) Log.v(tag, msg);
|
||||
if (isDebug) {
|
||||
Log.v(tag, msg);
|
||||
}
|
||||
}
|
||||
|
||||
//带异常的
|
||||
public static void i(String tag, String msg, Throwable tr) {
|
||||
if (isDebug) Log.i(tag, msg, tr);
|
||||
if (isDebug) {
|
||||
Log.i(tag, msg, tr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void d(String tag, String msg, Throwable tr) {
|
||||
if (isDebug) Log.d(tag, msg, tr);
|
||||
if (isDebug) {
|
||||
Log.d(tag, msg, tr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void w(String tag, String msg, Throwable tr) {
|
||||
if (isDebug) Log.w(tag, msg, tr);
|
||||
if (isDebug) {
|
||||
Log.w(tag, msg, tr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void e(String tag, String msg, Throwable tr) {
|
||||
if (isDebug) Log.e(tag, msg, tr);
|
||||
if (isDebug) {
|
||||
Log.e(tag, msg, tr);
|
||||
}
|
||||
}
|
||||
|
||||
public static void v(String tag, String msg, Throwable tr) {
|
||||
if (isDebug) Log.v(tag, msg, tr);
|
||||
if (isDebug) {
|
||||
Log.v(tag, msg, tr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一打印
|
||||
* 同意打印
|
||||
*/
|
||||
private static void printHunk(char type, String str) {
|
||||
switch (type) {
|
||||
|
||||
@@ -22,41 +22,53 @@ public class T {
|
||||
* 短时间显示Toast
|
||||
*/
|
||||
public static void showShort(Context context, CharSequence message) {
|
||||
if (isShow) Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
|
||||
if (isShow) {
|
||||
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 短时间显示Toast
|
||||
*/
|
||||
public static void showShort(Context context, int message) {
|
||||
if (isShow) Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
|
||||
if (isShow) {
|
||||
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 长时间显示Toast
|
||||
*/
|
||||
public static void showLong(Context context, CharSequence message) {
|
||||
if (isShow) Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
||||
if (isShow) {
|
||||
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 长时间显示Toast
|
||||
*/
|
||||
public static void showLong(Context context, int message) {
|
||||
if (isShow) Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
||||
if (isShow) {
|
||||
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义显示Toast时间
|
||||
*/
|
||||
public static void show(Context context, CharSequence message, int duration) {
|
||||
if (isShow) Toast.makeText(context, message, duration).show();
|
||||
if (isShow) {
|
||||
Toast.makeText(context, message, duration).show();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义显示Toast时间
|
||||
*/
|
||||
public static void show(Context context, int message, int duration) {
|
||||
if (isShow) Toast.makeText(context, message, duration).show();
|
||||
if (isShow) {
|
||||
Toast.makeText(context, message, duration).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#005bab"/>
|
||||
<corners android:radius="30dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item android:state_pressed="false">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#095389"/>
|
||||
<corners android:radius="30dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item android:state_pressed="true">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#005bab"/>
|
||||
<corners android:radius="30dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item android:state_pressed="false">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#095389"/>
|
||||
<corners android:radius="30dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
@@ -15,8 +15,8 @@
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/pb"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="80dp"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="background_color">#E5E5E5</color>
|
||||
<color name="white">#fff</color>
|
||||
<color name="text_gray_color">#A5A5A5</color>
|
||||
<color name="background_color">#E5E5E5</color>
|
||||
<color name="white">#fff</color>
|
||||
<color name="bg_line">#757575</color>
|
||||
</resources>
|
||||
@@ -1,3 +1,3 @@
|
||||
<resources>
|
||||
<string name="app_name">Frame</string>
|
||||
<string name="app_name">Frame</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.Dialog.Alert">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
<!-- <item name="android:windowBackground">@drawable/white_pop_normal_background</item>
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.Dialog.Alert">
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
<!-- <item name="android:windowBackground">@drawable/white_pop_normal_background</item>
|
||||
-->
|
||||
<style name="MyDialog" parent="AppTheme">
|
||||
<item name="android:windowFrame">@null</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
</style>
|
||||
<style name="MyDialog" parent="AppTheme">
|
||||
<item name="android:windowFrame">@null</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
</style>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user