init
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
*.iml
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/caches
|
||||||
|
/.idea/libraries
|
||||||
|
/.idea/modules.xml
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/navEditor.xml
|
||||||
|
/.idea/assetWizardSettings.xml
|
||||||
|
.DS_Store
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
.externalNativeBuild
|
||||||
|
.cxx
|
||||||
|
/.idea/
|
||||||
1
app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
194
app/build.gradle
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
static def appName() {
|
||||||
|
return "AndroidAppTemplate"
|
||||||
|
}
|
||||||
|
|
||||||
|
static def releaseTime() {
|
||||||
|
return new Date().format("yyyyMMdd_HHmmss", TimeZone.getDefault())
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 29
|
||||||
|
buildToolsVersion "29.0.3"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "com.ttstd.template"
|
||||||
|
minSdkVersion 26
|
||||||
|
targetSdkVersion 29
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
multiDexEnabled true
|
||||||
|
|
||||||
|
ndk {
|
||||||
|
//选择要添加的对应 cpu 类型的 .so 库。
|
||||||
|
abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', "x86"
|
||||||
|
// 还可以添加 'x86', 'x86_64', 'mips', 'mips64'
|
||||||
|
}
|
||||||
|
|
||||||
|
javaCompileOptions {
|
||||||
|
annotationProcessorOptions {
|
||||||
|
includeCompileClasspath true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
checkReleaseBuilds false
|
||||||
|
// Or, if you prefer, you can continue to check for errors in release builds,
|
||||||
|
// but continue the build even when errors are found:
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
|
|
||||||
|
dexOptions {
|
||||||
|
jumboMode true
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
|
||||||
|
viewBinding{
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
dataBinding {
|
||||||
|
enabled true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//签名
|
||||||
|
signingConfigs {
|
||||||
|
tuixin {// 签名文件
|
||||||
|
storeFile file("keystore/tuixin.jks")
|
||||||
|
storePassword "123456"
|
||||||
|
keyAlias "universal"
|
||||||
|
keyPassword "123456"
|
||||||
|
v2SigningEnabled false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
|
||||||
|
debug {
|
||||||
|
buildConfigField "String", "platform", '"tuixin"'
|
||||||
|
versionNameSuffix "-debug"
|
||||||
|
debuggable true
|
||||||
|
//Zipalign优化
|
||||||
|
zipAlignEnabled true
|
||||||
|
minifyEnabled false
|
||||||
|
signingConfig signingConfigs.tuixin
|
||||||
|
applicationVariants.all { variant ->
|
||||||
|
variant.outputs.each { output ->
|
||||||
|
if (outputFile != null) {
|
||||||
|
def fileName = "${appName()}-${variant.versionCode}-V${variant.versionName}-${releaseTime()}-${buildType.name}.apk"
|
||||||
|
output.outputFileName = fileName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
release {
|
||||||
|
buildConfigField "String", "platform", '"tuixin"'
|
||||||
|
//Zipalign优化
|
||||||
|
zipAlignEnabled true
|
||||||
|
//混淆
|
||||||
|
minifyEnabled false
|
||||||
|
//前一部分代表系统默认的android程序的混淆文件,该文件已经包含了基本的混淆声明,后一个文件是自己的定义混淆文件
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
//签名
|
||||||
|
signingConfig signingConfigs.tuixin
|
||||||
|
// 将release版本的包名重命名,加上版本及日期
|
||||||
|
applicationVariants.all { variant ->
|
||||||
|
variant.outputs.each { output ->
|
||||||
|
def outputFile = ""
|
||||||
|
if (outputFile != null) {
|
||||||
|
def fileName = "${appName()}-${variant.versionCode}-V${variant.versionName}-${releaseTime()}-${buildType.name}.apk"
|
||||||
|
output.outputFileName = new File(outputFile, fileName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
|
||||||
|
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||||
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||||
|
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||||
|
|
||||||
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
|
testImplementation 'junit:junit:4.12'
|
||||||
|
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||||
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||||
|
|
||||||
|
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10'
|
||||||
|
|
||||||
|
//BindView
|
||||||
|
implementation 'com.jakewharton:butterknife:10.2.3'
|
||||||
|
// If you are using Kotlin, replace annotationProcessor with kapt.
|
||||||
|
// annotationProcessor rootProject.ext.dependencies["butterknife-compiler"]
|
||||||
|
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'
|
||||||
|
|
||||||
|
//okhttp
|
||||||
|
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
|
||||||
|
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
|
||||||
|
//Retrofit
|
||||||
|
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
|
||||||
|
implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
|
||||||
|
// gson converter
|
||||||
|
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
|
||||||
|
// 标准转换器,去掉 Retrofit以Mutipart上传参数时,String参数会多一对双引号
|
||||||
|
implementation 'com.squareup.retrofit2:converter-scalars:2.3.0'
|
||||||
|
//RxJava
|
||||||
|
implementation 'io.reactivex.rxjava3:rxjava:3.0.0'
|
||||||
|
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
|
||||||
|
//生命周期管理
|
||||||
|
implementation 'com.trello.rxlifecycle4:rxlifecycle:4.0.2'
|
||||||
|
implementation 'com.trello.rxlifecycle4:rxlifecycle-android:4.0.2'
|
||||||
|
implementation 'com.trello.rxlifecycle4:rxlifecycle-components:4.0.2'
|
||||||
|
implementation 'com.trello.rxlifecycle4:rxlifecycle-components-preference:4.0.2'
|
||||||
|
implementation 'com.trello.rxlifecycle4:rxlifecycle-android-lifecycle:4.0.2'
|
||||||
|
//rxbinding
|
||||||
|
implementation 'com.jakewharton.rxbinding4:rxbinding:4.0.0'
|
||||||
|
//Google
|
||||||
|
implementation 'com.google.code.gson:gson:2.10.1'
|
||||||
|
implementation 'com.google.zxing:core:3.5.0'
|
||||||
|
implementation 'com.google.android.material:material:1.4.0'
|
||||||
|
//图片加载框架
|
||||||
|
implementation 'com.github.bumptech.glide:glide:4.13.2'
|
||||||
|
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2'
|
||||||
|
//磁盘缓存
|
||||||
|
implementation 'com.jakewharton:disklrucache:2.0.2'
|
||||||
|
//Aria
|
||||||
|
implementation 'com.arialyy.aria:core:3.8.15'
|
||||||
|
annotationProcessor 'com.arialyy.aria:compiler:3.8.15'
|
||||||
|
//MMKV
|
||||||
|
implementation 'com.tencent:mmkv-static:1.2.14'
|
||||||
|
//bugly
|
||||||
|
implementation 'com.tencent.bugly:crashreport:4.1.9.2'
|
||||||
|
implementation 'com.iqiyi.xcrash:xcrash-android-lib:3.0.0'
|
||||||
|
//工具类
|
||||||
|
implementation 'com.blankj:utilcodex:1.31.0'
|
||||||
|
//autosize会改变第三方view的大小
|
||||||
|
//https://github.com/JessYanCoding/AndroidAutoSize
|
||||||
|
implementation 'com.github.JessYanCoding:AndroidAutoSize:1.2.1'
|
||||||
|
implementation 'com.flyco.tablayout:FlycoTabLayout_Lib:2.1.2@aar'
|
||||||
|
implementation 'com.github.chrisbanes:PhotoView:2.0.0'
|
||||||
|
//沉浸状态栏
|
||||||
|
implementation 'com.gitee.zackratos:UltimateBarX:0.8.0'
|
||||||
|
// //验证码输入
|
||||||
|
// implementation 'com.jacktuotuo.customview:verificationcodeview:1.0.5'
|
||||||
|
//动态权限框架
|
||||||
|
// implementation 'com.hjq:xxpermissions:6.0'
|
||||||
|
}
|
||||||
BIN
app/keystore/tuixin.jks
Normal file
21
app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.ttstd.template;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ExampleInstrumentedTest {
|
||||||
|
@Test
|
||||||
|
public void useAppContext() {
|
||||||
|
// Context of the app under test.
|
||||||
|
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||||
|
|
||||||
|
assertEquals("com.ttstd.template", appContext.getPackageName());
|
||||||
|
}
|
||||||
|
}
|
||||||
45
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.ttstd.template">
|
||||||
|
|
||||||
|
<!-- 访问网络,网络定位需要上网 -->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:name="com.ttstd.template.base.BaseApplication"
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/AppTheme">
|
||||||
|
<activity
|
||||||
|
android:name="com.ttstd.template.activity.main.MainActivity"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/file_paths" />
|
||||||
|
</provider>
|
||||||
|
|
||||||
|
<!-- 这个 Demo 主要展示副单位的用法, 如果只使用副单位 (pt、in、mm) 就可以直接以像素作为单位填写设计图的尺寸, 不需再把像素转化为 dp-->
|
||||||
|
<meta-data
|
||||||
|
android:name="design_width_in_dp"
|
||||||
|
android:value="1080"/>
|
||||||
|
<meta-data
|
||||||
|
android:name="design_height_in_dp"
|
||||||
|
android:value="1920"/>
|
||||||
|
</application>
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.ttstd.template.activity.main;
|
||||||
|
|
||||||
|
import com.ttstd.template.R;
|
||||||
|
import com.ttstd.template.base.BaseActivity;
|
||||||
|
|
||||||
|
public class MainActivity extends BaseActivity {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLayoutId() {
|
||||||
|
return R.layout.activity_main;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initView() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initData() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package com.ttstd.template.activity.template;
|
||||||
|
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.ttstd.template.R;
|
||||||
|
import com.ttstd.template.base.BaseLightActivity;
|
||||||
|
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
public class TemplateActivity extends BaseLightActivity implements TemplateContact.TemplateView {
|
||||||
|
|
||||||
|
private static final String TAG = TemplateActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
private TemplatePresenter mPresenter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLayoutId() {
|
||||||
|
return R.layout.activity_video;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initView() {
|
||||||
|
ButterKnife.bind(this);
|
||||||
|
mPresenter = new TemplatePresenter(this);
|
||||||
|
mPresenter.setLifecycle(lifecycleSubject);
|
||||||
|
mPresenter.attachView(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initData() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||||
|
super.onConfigurationChanged(newConfig);
|
||||||
|
Configuration config = getResources().getConfiguration();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.ttstd.template.activity.template;
|
||||||
|
|
||||||
|
import com.ttstd.template.base.BasePresenter;
|
||||||
|
import com.ttstd.template.base.BaseView;
|
||||||
|
|
||||||
|
public class TemplateContact {
|
||||||
|
interface Presenter extends BasePresenter<TemplateView> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TemplateView extends BaseView {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.ttstd.template.activity.template;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||||
|
import com.ttstd.template.disklrucache.CacheHelper;
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.subjects.BehaviorSubject;
|
||||||
|
|
||||||
|
|
||||||
|
public class TemplatePresenter implements TemplateContact.Presenter {
|
||||||
|
private static final String TAG = TemplatePresenter.class.getSimpleName();
|
||||||
|
|
||||||
|
private TemplateContact.TemplateView mView;
|
||||||
|
private Context mContext;
|
||||||
|
private CacheHelper mCacheHelper;
|
||||||
|
|
||||||
|
public TemplatePresenter(Context context) {
|
||||||
|
this.mContext = context;
|
||||||
|
this.mCacheHelper = new CacheHelper(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BehaviorSubject<ActivityEvent> lifecycle;
|
||||||
|
|
||||||
|
public void setLifecycle(BehaviorSubject<ActivityEvent> lifecycle) {
|
||||||
|
this.lifecycle = lifecycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BehaviorSubject<ActivityEvent> getLifecycle() {
|
||||||
|
return lifecycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attachView(TemplateContact.TemplateView view) {
|
||||||
|
this.mView = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void detachView() {
|
||||||
|
this.mView = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
134
app/src/main/java/com/ttstd/template/base/BaseActivity.java
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package com.ttstd.template.base;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.CallSuper;
|
||||||
|
import androidx.annotation.CheckResult;
|
||||||
|
import androidx.annotation.ContentView;
|
||||||
|
import androidx.annotation.LayoutRes;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import com.trello.rxlifecycle4.LifecycleProvider;
|
||||||
|
import com.trello.rxlifecycle4.LifecycleTransformer;
|
||||||
|
import com.trello.rxlifecycle4.RxLifecycle;
|
||||||
|
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||||
|
import com.trello.rxlifecycle4.android.RxLifecycleAndroid;
|
||||||
|
import com.ttstd.template.R;
|
||||||
|
import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX;
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.core.Observable;
|
||||||
|
import io.reactivex.rxjava3.subjects.BehaviorSubject;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class BaseActivity extends AppCompatActivity implements LifecycleProvider<ActivityEvent> {
|
||||||
|
public final BehaviorSubject<ActivityEvent> lifecycleSubject = BehaviorSubject.create();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
// StatusBarUtil.init(this);
|
||||||
|
UltimateBarX.statusBar(this)
|
||||||
|
.transparent()
|
||||||
|
.colorRes(R.color.colorPrimaryDark)
|
||||||
|
.light(true)
|
||||||
|
.apply();
|
||||||
|
UltimateBarX.navigationBar(this)
|
||||||
|
.transparent()
|
||||||
|
.colorRes(R.color.colorPrimaryDark)
|
||||||
|
.light(true)
|
||||||
|
.apply();
|
||||||
|
setContentView(this.getLayoutId());
|
||||||
|
initView();
|
||||||
|
initData();
|
||||||
|
//最近任务和应用图标不一样
|
||||||
|
if (Build.VERSION.SDK_INT > 27) {
|
||||||
|
ActivityManager.TaskDescription description = new ActivityManager.TaskDescription(getString(R.string.app_name), R.mipmap.ic_launcher, getColor(R.color.colorPrimary));
|
||||||
|
this.setTaskDescription(description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置布局
|
||||||
|
*/
|
||||||
|
public abstract int getLayoutId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化视图
|
||||||
|
*/
|
||||||
|
public abstract void initView();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化数据
|
||||||
|
*/
|
||||||
|
public abstract void initData();
|
||||||
|
|
||||||
|
public BaseActivity() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ContentView
|
||||||
|
public BaseActivity(@LayoutRes int contentLayoutId) {
|
||||||
|
super(contentLayoutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
@CheckResult
|
||||||
|
public final Observable<ActivityEvent> lifecycle() {
|
||||||
|
return lifecycleSubject.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
@CheckResult
|
||||||
|
public final <T> LifecycleTransformer<T> bindUntilEvent(@NonNull ActivityEvent event) {
|
||||||
|
return RxLifecycle.bindUntilEvent(lifecycleSubject, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
@CheckResult
|
||||||
|
public final <T> LifecycleTransformer<T> bindToLifecycle() {
|
||||||
|
return RxLifecycleAndroid.bindActivity(lifecycleSubject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
lifecycleSubject.onNext(ActivityEvent.START);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
lifecycleSubject.onNext(ActivityEvent.RESUME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
protected void onPause() {
|
||||||
|
lifecycleSubject.onNext(ActivityEvent.PAUSE);
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
protected void onStop() {
|
||||||
|
lifecycleSubject.onNext(ActivityEvent.STOP);
|
||||||
|
super.onStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
protected void onDestroy() {
|
||||||
|
lifecycleSubject.onNext(ActivityEvent.DESTROY);
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package com.ttstd.template.base;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.tencent.mmkv.MMKV;
|
||||||
|
import com.ttstd.template.BuildConfig;
|
||||||
|
import com.ttstd.template.network.NetInterfaceManager;
|
||||||
|
import com.ttstd.template.utils.SystemUtils;
|
||||||
|
|
||||||
|
public class BaseApplication extends Application {
|
||||||
|
private static final String TAG = BaseApplication.class.getSimpleName();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
super.onCreate();
|
||||||
|
//非主进程不初始化
|
||||||
|
if (SystemUtils.isMainProcessName(this, android.os.Process.myPid())) {
|
||||||
|
|
||||||
|
}
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
if (!BuildConfig.DEBUG) {
|
||||||
|
catchException();
|
||||||
|
}
|
||||||
|
String rootDir = MMKV.initialize(this);
|
||||||
|
Log.i(TAG, "mmkv root: " + rootDir);
|
||||||
|
|
||||||
|
|
||||||
|
// CrashReport.initCrashReport(getApplicationContext(), "df75262f6a", false);
|
||||||
|
// CrashReport.setDeviceId(this, Utils.getSerial());
|
||||||
|
xcrash.XCrash.init(this);
|
||||||
|
|
||||||
|
NetInterfaceManager.init(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void catchException() {
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler(
|
||||||
|
new Thread.UncaughtExceptionHandler() {
|
||||||
|
@Override
|
||||||
|
public void uncaughtException(Thread t, Throwable e) {
|
||||||
|
Log.e("捕获异常子线程:", Thread.currentThread().getName() +
|
||||||
|
"在:" + e.getStackTrace()[0].getClassName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
//下面是新增方法!
|
||||||
|
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
Looper.loop(); //会先执行这个方法,然后在执行下面的异常捕获方法!
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("捕获异常主线程:", Thread.currentThread().getName() +
|
||||||
|
"在:" + e.getStackTrace()[0].getClassName());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLowMemory() {
|
||||||
|
super.onLowMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTrimMemory(int level) {
|
||||||
|
super.onTrimMemory(level);
|
||||||
|
}
|
||||||
|
}
|
||||||
156
app/src/main/java/com/ttstd/template/base/BaseFragment.java
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
package com.ttstd.template.base;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import androidx.annotation.CallSuper;
|
||||||
|
import androidx.annotation.CheckResult;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.trello.rxlifecycle4.LifecycleProvider;
|
||||||
|
import com.trello.rxlifecycle4.LifecycleTransformer;
|
||||||
|
import com.trello.rxlifecycle4.RxLifecycle;
|
||||||
|
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||||
|
import com.trello.rxlifecycle4.android.RxLifecycleAndroid;
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.core.Observable;
|
||||||
|
import io.reactivex.rxjava3.subjects.BehaviorSubject;
|
||||||
|
|
||||||
|
public abstract class BaseFragment extends Fragment implements LifecycleProvider<FragmentEvent> {
|
||||||
|
public final BehaviorSubject<FragmentEvent> lifecycleSubject = BehaviorSubject.create();
|
||||||
|
|
||||||
|
protected boolean isViewInitiated;
|
||||||
|
protected boolean isVisibleToUser;
|
||||||
|
protected boolean isDataInitiated;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
@CheckResult
|
||||||
|
public final Observable<FragmentEvent> lifecycle() {
|
||||||
|
return lifecycleSubject.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
@CheckResult
|
||||||
|
public final <T> LifecycleTransformer<T> bindUntilEvent(@NonNull FragmentEvent event) {
|
||||||
|
return RxLifecycle.bindUntilEvent(lifecycleSubject, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
@CheckResult
|
||||||
|
public final <T> LifecycleTransformer<T> bindToLifecycle() {
|
||||||
|
return RxLifecycleAndroid.bindFragment(lifecycleSubject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
public void onAttach(android.app.Activity activity) {
|
||||||
|
super.onAttach(activity);
|
||||||
|
lifecycleSubject.onNext(FragmentEvent.ATTACH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
lifecycleSubject.onNext(FragmentEvent.CREATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
return super.onCreateView(inflater, container, savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityCreated(Bundle savedInstanceState) {
|
||||||
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
isViewInitiated = true;
|
||||||
|
prepareFetchData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||||
|
super.setUserVisibleHint(isVisibleToUser);
|
||||||
|
this.isVisibleToUser = isVisibleToUser;
|
||||||
|
prepareFetchData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void fetchData();
|
||||||
|
|
||||||
|
public boolean prepareFetchData() {
|
||||||
|
return prepareFetchData(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean prepareFetchData(boolean forceUpdate) {
|
||||||
|
if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) {
|
||||||
|
fetchData();
|
||||||
|
//注释掉保证每次都更新数据
|
||||||
|
isDataInitiated = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
lifecycleSubject.onNext(FragmentEvent.CREATE_VIEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
public void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
lifecycleSubject.onNext(FragmentEvent.START);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
public void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
lifecycleSubject.onNext(FragmentEvent.RESUME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
public void onPause() {
|
||||||
|
lifecycleSubject.onNext(FragmentEvent.PAUSE);
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
public void onStop() {
|
||||||
|
lifecycleSubject.onNext(FragmentEvent.STOP);
|
||||||
|
super.onStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
public void onDestroyView() {
|
||||||
|
lifecycleSubject.onNext(FragmentEvent.DESTROY_VIEW);
|
||||||
|
super.onDestroyView();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
public void onDestroy() {
|
||||||
|
lifecycleSubject.onNext(FragmentEvent.DESTROY);
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
public void onDetach() {
|
||||||
|
lifecycleSubject.onNext(FragmentEvent.DETACH);
|
||||||
|
super.onDetach();
|
||||||
|
}
|
||||||
|
}
|
||||||
129
app/src/main/java/com/ttstd/template/base/BaseLightActivity.java
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
package com.ttstd.template.base;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.annotation.CallSuper;
|
||||||
|
import androidx.annotation.CheckResult;
|
||||||
|
import androidx.annotation.ContentView;
|
||||||
|
import androidx.annotation.LayoutRes;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import com.trello.rxlifecycle4.LifecycleProvider;
|
||||||
|
import com.trello.rxlifecycle4.LifecycleTransformer;
|
||||||
|
import com.trello.rxlifecycle4.RxLifecycle;
|
||||||
|
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||||
|
import com.trello.rxlifecycle4.android.RxLifecycleAndroid;
|
||||||
|
import com.ttstd.template.R;
|
||||||
|
import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX;
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.core.Observable;
|
||||||
|
import io.reactivex.rxjava3.subjects.BehaviorSubject;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class BaseLightActivity extends AppCompatActivity implements LifecycleProvider<ActivityEvent> {
|
||||||
|
public final BehaviorSubject<ActivityEvent> lifecycleSubject = BehaviorSubject.create();
|
||||||
|
|
||||||
|
public BaseLightActivity() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ContentView
|
||||||
|
public BaseLightActivity(@LayoutRes int contentLayoutId) {
|
||||||
|
super(contentLayoutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
@CheckResult
|
||||||
|
public final Observable<ActivityEvent> lifecycle() {
|
||||||
|
return lifecycleSubject.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
@CheckResult
|
||||||
|
public final <T> LifecycleTransformer<T> bindUntilEvent(@NonNull ActivityEvent event) {
|
||||||
|
return RxLifecycle.bindUntilEvent(lifecycleSubject, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NonNull
|
||||||
|
@CheckResult
|
||||||
|
public final <T> LifecycleTransformer<T> bindToLifecycle() {
|
||||||
|
return RxLifecycleAndroid.bindActivity(lifecycleSubject);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
lifecycleSubject.onNext(ActivityEvent.CREATE);
|
||||||
|
// StatusBarUtil.init(this);
|
||||||
|
UltimateBarX.statusBar(this)
|
||||||
|
.transparent()
|
||||||
|
.colorRes(R.color.colorPrimaryDark)
|
||||||
|
.light(true)
|
||||||
|
.apply();
|
||||||
|
UltimateBarX.navigationBar(this)
|
||||||
|
.transparent()
|
||||||
|
.colorRes(R.color.colorPrimaryDark)
|
||||||
|
.light(true)
|
||||||
|
.apply();
|
||||||
|
setContentView(this.getLayoutId());
|
||||||
|
initView();
|
||||||
|
initData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置布局
|
||||||
|
*/
|
||||||
|
public abstract int getLayoutId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化视图
|
||||||
|
*/
|
||||||
|
public abstract void initView();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化数据
|
||||||
|
*/
|
||||||
|
public abstract void initData();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
lifecycleSubject.onNext(ActivityEvent.START);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
lifecycleSubject.onNext(ActivityEvent.RESUME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
protected void onPause() {
|
||||||
|
lifecycleSubject.onNext(ActivityEvent.PAUSE);
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
protected void onStop() {
|
||||||
|
lifecycleSubject.onNext(ActivityEvent.STOP);
|
||||||
|
super.onStop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CallSuper
|
||||||
|
protected void onDestroy() {
|
||||||
|
lifecycleSubject.onNext(ActivityEvent.DESTROY);
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.ttstd.template.base;
|
||||||
|
|
||||||
|
public interface BasePresenter<V extends BaseView> {
|
||||||
|
void attachView(V view);
|
||||||
|
|
||||||
|
void detachView();
|
||||||
|
}
|
||||||
4
app/src/main/java/com/ttstd/template/base/BaseView.java
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
package com.ttstd.template.base;
|
||||||
|
|
||||||
|
public interface BaseView {
|
||||||
|
}
|
||||||
24
app/src/main/java/com/ttstd/template/bean/BaseResponse.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package com.ttstd.template.bean;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
|
public class BaseResponse<T> implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 5468533687801294972L;
|
||||||
|
|
||||||
|
public int code;
|
||||||
|
public String msg;
|
||||||
|
public T data;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.ttstd.template.comm;
|
||||||
|
|
||||||
|
public class CommonConfig {
|
||||||
|
public static final String MMKV_ID = "InterProcessKV";
|
||||||
|
}
|
||||||
@@ -0,0 +1,474 @@
|
|||||||
|
package com.ttstd.template.disklrucache;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jakewharton.disklrucache.DiskLruCache;
|
||||||
|
import com.tencent.mmkv.MMKV;
|
||||||
|
import com.ttstd.template.comm.CommonConfig;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 磁盘缓存帮助类
|
||||||
|
*/
|
||||||
|
public class CacheHelper {
|
||||||
|
private static final String TAG = "DiskLruCacheHelper";
|
||||||
|
|
||||||
|
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||||||
|
|
||||||
|
private static final String DIR_NAME = "diskCache";
|
||||||
|
private static final int MAX_COUNT = 1024 * 1024 * 1024;
|
||||||
|
private static final int DEFAULT_APP_VERSION = 1;
|
||||||
|
|
||||||
|
private DiskLruCache mDiskLruCache;
|
||||||
|
|
||||||
|
public CacheHelper(Context context) {
|
||||||
|
mDiskLruCache = generateCache(context, DIR_NAME, MAX_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheHelper(Context context, String dirName) {
|
||||||
|
mDiskLruCache = generateCache(context, dirName, MAX_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheHelper(Context context, String dirName, int maxCount) {
|
||||||
|
mDiskLruCache = generateCache(context, dirName, maxCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
//custom cache dir
|
||||||
|
public CacheHelper(File dir) {
|
||||||
|
mDiskLruCache = generateCache(null, dir, MAX_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheHelper(Context context, File dir) {
|
||||||
|
mDiskLruCache = generateCache(context, dir, MAX_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheHelper(Context context, File dir, int maxCount) {
|
||||||
|
mDiskLruCache = generateCache(context, dir, maxCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DiskLruCache generateCache(Context context, File dir, int maxCount) {
|
||||||
|
if (!dir.exists() || !dir.isDirectory()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
dir + " is not a directory or does not exists. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
int appVersion = context == null ? DEFAULT_APP_VERSION : Utils.getAppVersion(context);
|
||||||
|
|
||||||
|
DiskLruCache diskLruCache = null;
|
||||||
|
try {
|
||||||
|
diskLruCache = DiskLruCache.open(
|
||||||
|
dir,
|
||||||
|
appVersion,
|
||||||
|
DEFAULT_APP_VERSION,
|
||||||
|
maxCount);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return diskLruCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DiskLruCache generateCache(Context context, String dirName, int maxCount) {
|
||||||
|
DiskLruCache diskLruCache = null;
|
||||||
|
try {
|
||||||
|
diskLruCache = DiskLruCache.open(
|
||||||
|
getDiskCacheDir(context, dirName),
|
||||||
|
Utils.getAppVersion(context),
|
||||||
|
DEFAULT_APP_VERSION,
|
||||||
|
maxCount);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return diskLruCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============== String 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
public void put(String key, String value) {
|
||||||
|
Log.e(TAG, "put: key = " + key + " value = " + value);
|
||||||
|
mMMKV.encode(key + "_time", System.currentTimeMillis());
|
||||||
|
mMMKV.encode(key + "_mmkv", value);
|
||||||
|
|
||||||
|
DiskLruCache.Editor edit = null;
|
||||||
|
BufferedWriter bw = null;
|
||||||
|
try {
|
||||||
|
edit = editor(key);
|
||||||
|
if (edit == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OutputStream os = edit.newOutputStream(0);
|
||||||
|
bw = new BufferedWriter(new OutputStreamWriter(os));
|
||||||
|
bw.write(value);
|
||||||
|
edit.commit();//write CLEAN
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Log.e(TAG, "put: " + e.getMessage());
|
||||||
|
try {
|
||||||
|
//s
|
||||||
|
edit.abort();//write REMOVE
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
Log.e(TAG, "put: " + e1.getMessage());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (bw != null) {
|
||||||
|
bw.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Log.e(TAG, "put: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAsString(String key) {
|
||||||
|
Log.e(TAG, "getAsString: " + key);
|
||||||
|
InputStream inputStream = null;
|
||||||
|
try {
|
||||||
|
//write READ
|
||||||
|
inputStream = get(key);
|
||||||
|
if (inputStream == null) {
|
||||||
|
return mMMKV.decodeString(key + "_mmkv", null);
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int len = 0;
|
||||||
|
byte[] buf = new byte[128];
|
||||||
|
while ((len = inputStream.read(buf)) != -1) {
|
||||||
|
sb.append(new String(buf, 0, len));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Log.e(TAG, "getAsString: " + e.getMessage());
|
||||||
|
if (inputStream != null) {
|
||||||
|
try {
|
||||||
|
inputStream.close();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
Log.e(TAG, "getAsString: " + e1.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void put(String key, JSONObject jsonObject) {
|
||||||
|
put(key, jsonObject.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject getAsJson(String key) {
|
||||||
|
String val = getAsString(key);
|
||||||
|
try {
|
||||||
|
if (val != null) {
|
||||||
|
return new JSONObject(val);
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============ JSONArray 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
public void put(String key, JSONArray jsonArray) {
|
||||||
|
put(key, jsonArray.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONArray getAsJSONArray(String key) {
|
||||||
|
String JSONString = getAsString(key);
|
||||||
|
try {
|
||||||
|
JSONArray obj = new JSONArray(JSONString);
|
||||||
|
return obj;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============== byte 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存 byte数据 到 缓存中
|
||||||
|
*
|
||||||
|
* @param key 保存的key
|
||||||
|
* @param value 保存的数据
|
||||||
|
*/
|
||||||
|
public void put(String key, byte[] value) {
|
||||||
|
OutputStream out = null;
|
||||||
|
DiskLruCache.Editor editor = null;
|
||||||
|
try {
|
||||||
|
editor = editor(key);
|
||||||
|
if (editor == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out = editor.newOutputStream(0);
|
||||||
|
out.write(value);
|
||||||
|
out.flush();
|
||||||
|
editor.commit();//write CLEAN
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
try {
|
||||||
|
editor.abort();//write REMOVE
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (out != null) {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public byte[] getAsBytes(String key) {
|
||||||
|
byte[] res = null;
|
||||||
|
InputStream is = get(key);
|
||||||
|
if (is == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
byte[] buf = new byte[256];
|
||||||
|
int len = 0;
|
||||||
|
while ((len = is.read(buf)) != -1) {
|
||||||
|
baos.write(buf, 0, len);
|
||||||
|
}
|
||||||
|
res = baos.toByteArray();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============== 序列化 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
public void put(String key, Serializable value) {
|
||||||
|
DiskLruCache.Editor editor = editor(key);
|
||||||
|
ObjectOutputStream oos = null;
|
||||||
|
if (editor == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
OutputStream os = editor.newOutputStream(0);
|
||||||
|
oos = new ObjectOutputStream(os);
|
||||||
|
oos.writeObject(value);
|
||||||
|
oos.flush();
|
||||||
|
editor.commit();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
try {
|
||||||
|
editor.abort();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (oos != null) {
|
||||||
|
oos.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getAsSerializable(String key) {
|
||||||
|
T t = null;
|
||||||
|
InputStream is = get(key);
|
||||||
|
ObjectInputStream ois = null;
|
||||||
|
if (is == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ois = new ObjectInputStream(is);
|
||||||
|
t = (T) ois.readObject();
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (ois != null) {
|
||||||
|
ois.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============== bitmap 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
public void put(String key, Bitmap bitmap) {
|
||||||
|
put(key, Utils.bitmap2Bytes(bitmap));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap getAsBitmap(String key) {
|
||||||
|
byte[] bytes = getAsBytes(key);
|
||||||
|
if (bytes == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Utils.bytes2Bitmap(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============= drawable 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
public void put(String key, Drawable value) {
|
||||||
|
put(key, Utils.drawable2Bitmap(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable getAsDrawable(String key) {
|
||||||
|
byte[] bytes = getAsBytes(key);
|
||||||
|
if (bytes == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Utils.bitmap2Drawable(Utils.bytes2Bitmap(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============= other methods =============
|
||||||
|
// =======================================
|
||||||
|
public boolean remove(String key) {
|
||||||
|
try {
|
||||||
|
key = Utils.hashKeyForDisk(key);
|
||||||
|
return mDiskLruCache.remove(key);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
mDiskLruCache.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() throws IOException {
|
||||||
|
mDiskLruCache.delete();
|
||||||
|
mMMKV.clearAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() throws IOException {
|
||||||
|
mDiskLruCache.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return mDiskLruCache.isClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long size() {
|
||||||
|
return mDiskLruCache.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxSize(long maxSize) {
|
||||||
|
mDiskLruCache.setMaxSize(maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getDirectory() {
|
||||||
|
return mDiskLruCache.getDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMaxSize() {
|
||||||
|
return mDiskLruCache.getMaxSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ===遇到文件比较大的,可以直接通过流读写 =====
|
||||||
|
// =======================================
|
||||||
|
//basic editor
|
||||||
|
public DiskLruCache.Editor editor(String key) {
|
||||||
|
try {
|
||||||
|
key = Utils.hashKeyForDisk(key);
|
||||||
|
//wirte DIRTY
|
||||||
|
DiskLruCache.Editor edit = mDiskLruCache.edit(key);
|
||||||
|
//edit maybe null :the entry is editing
|
||||||
|
if (edit == null) {
|
||||||
|
Log.w(TAG, "the entry spcified key:" + key + " is editing by other . ");
|
||||||
|
}
|
||||||
|
return edit;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Log.e(TAG, "editor: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//basic get
|
||||||
|
public InputStream get(String key) {
|
||||||
|
try {
|
||||||
|
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(Utils.hashKeyForDisk(key));
|
||||||
|
if (snapshot == null) //not find entry , or entry.readable = false
|
||||||
|
{
|
||||||
|
Log.e(TAG, "not find entry , or entry.readable = false");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//write READ
|
||||||
|
return snapshot.getInputStream(0);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============== 序列化 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
private File getDiskCacheDir(Context context, String uniqueName) {
|
||||||
|
String cachePath;
|
||||||
|
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|
||||||
|
|| !Environment.isExternalStorageRemovable()) {
|
||||||
|
if (context.getExternalCacheDir() != null) {
|
||||||
|
cachePath = context.getExternalCacheDir().getPath();
|
||||||
|
} else if (context.getExternalFilesDir("cache") != null) {
|
||||||
|
cachePath = context.getExternalFilesDir("cache").getPath();
|
||||||
|
} else {
|
||||||
|
cachePath = context.getCacheDir().getPath();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cachePath = context.getCacheDir().getPath();
|
||||||
|
}
|
||||||
|
return new File(cachePath + File.separator + uniqueName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,427 @@
|
|||||||
|
package com.ttstd.template.disklrucache;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.jakewharton.disklrucache.DiskLruCache;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 磁盘缓存帮助类
|
||||||
|
*/
|
||||||
|
public class DiskLruCacheHelper {
|
||||||
|
private static final String DIR_NAME = "diskCache";
|
||||||
|
private static final int MAX_COUNT = 5 * 1024 * 1024;
|
||||||
|
private static final int DEFAULT_APP_VERSION = 1;
|
||||||
|
|
||||||
|
private static final String TAG = "DiskLruCacheHelper";
|
||||||
|
|
||||||
|
private DiskLruCache mDiskLruCache;
|
||||||
|
|
||||||
|
public DiskLruCacheHelper(Context context) throws IOException {
|
||||||
|
mDiskLruCache = generateCache(context, DIR_NAME, MAX_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiskLruCacheHelper(Context context, String dirName) throws IOException {
|
||||||
|
mDiskLruCache = generateCache(context, dirName, MAX_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiskLruCacheHelper(Context context, String dirName, int maxCount) throws IOException {
|
||||||
|
mDiskLruCache = generateCache(context, dirName, maxCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
//custom cache dir
|
||||||
|
public DiskLruCacheHelper(File dir) throws IOException {
|
||||||
|
mDiskLruCache = generateCache(null, dir, MAX_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiskLruCacheHelper(Context context, File dir) throws IOException {
|
||||||
|
mDiskLruCache = generateCache(context, dir, MAX_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DiskLruCacheHelper(Context context, File dir, int maxCount) throws IOException {
|
||||||
|
mDiskLruCache = generateCache(context, dir, maxCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DiskLruCache generateCache(Context context, File dir, int maxCount) throws IOException {
|
||||||
|
if (!dir.exists() || !dir.isDirectory()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
dir + " is not a directory or does not exists. ");
|
||||||
|
}
|
||||||
|
|
||||||
|
int appVersion = context == null ? DEFAULT_APP_VERSION : Utils.getAppVersion(context);
|
||||||
|
|
||||||
|
DiskLruCache diskLruCache = DiskLruCache.open(
|
||||||
|
dir,
|
||||||
|
appVersion,
|
||||||
|
DEFAULT_APP_VERSION,
|
||||||
|
maxCount);
|
||||||
|
|
||||||
|
return diskLruCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DiskLruCache generateCache(Context context, String dirName, int maxCount) throws IOException {
|
||||||
|
DiskLruCache diskLruCache = DiskLruCache.open(
|
||||||
|
getDiskCacheDir(context, dirName),
|
||||||
|
Utils.getAppVersion(context),
|
||||||
|
DEFAULT_APP_VERSION,
|
||||||
|
maxCount);
|
||||||
|
return diskLruCache;
|
||||||
|
}
|
||||||
|
// =======================================
|
||||||
|
// ============== String 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
public void put(String key, String value) {
|
||||||
|
DiskLruCache.Editor edit = null;
|
||||||
|
BufferedWriter bw = null;
|
||||||
|
try {
|
||||||
|
edit = editor(key);
|
||||||
|
if (edit == null) return;
|
||||||
|
OutputStream os = edit.newOutputStream(0);
|
||||||
|
bw = new BufferedWriter(new OutputStreamWriter(os));
|
||||||
|
bw.write(value);
|
||||||
|
edit.commit();//write CLEAN
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
try {
|
||||||
|
//s
|
||||||
|
edit.abort();//write REMOVE
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (bw != null)
|
||||||
|
bw.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAsString(String key) {
|
||||||
|
InputStream inputStream = null;
|
||||||
|
try {
|
||||||
|
//write READ
|
||||||
|
inputStream = get(key);
|
||||||
|
if (inputStream == null) return null;
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int len = 0;
|
||||||
|
byte[] buf = new byte[128];
|
||||||
|
while ((len = inputStream.read(buf)) != -1) {
|
||||||
|
sb.append(new String(buf, 0, len));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
if (inputStream != null)
|
||||||
|
try {
|
||||||
|
inputStream.close();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void put(String key, JSONObject jsonObject) {
|
||||||
|
put(key, jsonObject.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject getAsJson(String key) {
|
||||||
|
String val = getAsString(key);
|
||||||
|
try {
|
||||||
|
if (val != null)
|
||||||
|
return new JSONObject(val);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============ JSONArray 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
public void put(String key, JSONArray jsonArray) {
|
||||||
|
put(key, jsonArray.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONArray getAsJSONArray(String key) {
|
||||||
|
String JSONString = getAsString(key);
|
||||||
|
try {
|
||||||
|
JSONArray obj = new JSONArray(JSONString);
|
||||||
|
return obj;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============== byte 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存 byte数据 到 缓存中
|
||||||
|
*
|
||||||
|
* @param key 保存的key
|
||||||
|
* @param value 保存的数据
|
||||||
|
*/
|
||||||
|
public void put(String key, byte[] value) {
|
||||||
|
OutputStream out = null;
|
||||||
|
DiskLruCache.Editor editor = null;
|
||||||
|
try {
|
||||||
|
editor = editor(key);
|
||||||
|
if (editor == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
out = editor.newOutputStream(0);
|
||||||
|
out.write(value);
|
||||||
|
out.flush();
|
||||||
|
editor.commit();//write CLEAN
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
try {
|
||||||
|
editor.abort();//write REMOVE
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (out != null) {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public byte[] getAsBytes(String key) {
|
||||||
|
byte[] res = null;
|
||||||
|
InputStream is = get(key);
|
||||||
|
if (is == null) return null;
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
byte[] buf = new byte[256];
|
||||||
|
int len = 0;
|
||||||
|
while ((len = is.read(buf)) != -1) {
|
||||||
|
baos.write(buf, 0, len);
|
||||||
|
}
|
||||||
|
res = baos.toByteArray();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============== 序列化 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
public void put(String key, Serializable value) {
|
||||||
|
DiskLruCache.Editor editor = editor(key);
|
||||||
|
ObjectOutputStream oos = null;
|
||||||
|
if (editor == null) return;
|
||||||
|
try {
|
||||||
|
OutputStream os = editor.newOutputStream(0);
|
||||||
|
oos = new ObjectOutputStream(os);
|
||||||
|
oos.writeObject(value);
|
||||||
|
oos.flush();
|
||||||
|
editor.commit();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
try {
|
||||||
|
editor.abort();
|
||||||
|
} catch (IOException e1) {
|
||||||
|
e1.printStackTrace();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (oos != null)
|
||||||
|
oos.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getAsSerializable(String key) {
|
||||||
|
T t = null;
|
||||||
|
InputStream is = get(key);
|
||||||
|
ObjectInputStream ois = null;
|
||||||
|
if (is == null) return null;
|
||||||
|
try {
|
||||||
|
ois = new ObjectInputStream(is);
|
||||||
|
t = (T) ois.readObject();
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (ois != null)
|
||||||
|
ois.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============== bitmap 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
public void put(String key, Bitmap bitmap) {
|
||||||
|
put(key, Utils.bitmap2Bytes(bitmap));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap getAsBitmap(String key) {
|
||||||
|
byte[] bytes = getAsBytes(key);
|
||||||
|
if (bytes == null) return null;
|
||||||
|
return Utils.bytes2Bitmap(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============= drawable 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
public void put(String key, Drawable value) {
|
||||||
|
put(key, Utils.drawable2Bitmap(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable getAsDrawable(String key) {
|
||||||
|
byte[] bytes = getAsBytes(key);
|
||||||
|
if (bytes == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Utils.bitmap2Drawable(Utils.bytes2Bitmap(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============= other methods =============
|
||||||
|
// =======================================
|
||||||
|
public boolean remove(String key) {
|
||||||
|
try {
|
||||||
|
key = Utils.hashKeyForDisk(key);
|
||||||
|
return mDiskLruCache.remove(key);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
mDiskLruCache.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete() throws IOException {
|
||||||
|
mDiskLruCache.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() throws IOException {
|
||||||
|
mDiskLruCache.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return mDiskLruCache.isClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long size() {
|
||||||
|
return mDiskLruCache.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxSize(long maxSize) {
|
||||||
|
mDiskLruCache.setMaxSize(maxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getDirectory() {
|
||||||
|
return mDiskLruCache.getDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getMaxSize() {
|
||||||
|
return mDiskLruCache.getMaxSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ===遇到文件比较大的,可以直接通过流读写 =====
|
||||||
|
// =======================================
|
||||||
|
//basic editor
|
||||||
|
public DiskLruCache.Editor editor(String key) {
|
||||||
|
try {
|
||||||
|
key = Utils.hashKeyForDisk(key);
|
||||||
|
//wirte DIRTY
|
||||||
|
DiskLruCache.Editor edit = mDiskLruCache.edit(key);
|
||||||
|
//edit maybe null :the entry is editing
|
||||||
|
if (edit == null) {
|
||||||
|
Log.w(TAG, "the entry spcified key:" + key + " is editing by other . ");
|
||||||
|
}
|
||||||
|
return edit;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//basic get
|
||||||
|
public InputStream get(String key) {
|
||||||
|
try {
|
||||||
|
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(Utils.hashKeyForDisk(key));
|
||||||
|
if (snapshot == null) //not find entry , or entry.readable = false
|
||||||
|
{
|
||||||
|
Log.e(TAG, "not find entry , or entry.readable = false");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//write READ
|
||||||
|
return snapshot.getInputStream(0);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =======================================
|
||||||
|
// ============== 序列化 数据 读写 =============
|
||||||
|
// =======================================
|
||||||
|
|
||||||
|
private File getDiskCacheDir(Context context, String uniqueName) {
|
||||||
|
String cachePath;
|
||||||
|
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|
||||||
|
|| !Environment.isExternalStorageRemovable()) {
|
||||||
|
cachePath = context.getExternalCacheDir().getPath();
|
||||||
|
} else {
|
||||||
|
cachePath = context.getCacheDir().getPath();
|
||||||
|
}
|
||||||
|
return new File(cachePath + File.separator + uniqueName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
101
app/src/main/java/com/ttstd/template/disklrucache/Utils.java
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package com.ttstd.template.disklrucache;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
public static int getAppVersion(Context context) {
|
||||||
|
try {
|
||||||
|
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||||
|
return info.versionCode;
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static String hashKeyForDisk(String key) {
|
||||||
|
String cacheKey;
|
||||||
|
try {
|
||||||
|
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
|
||||||
|
mDigest.update(key.getBytes());
|
||||||
|
cacheKey = bytesToHexString(mDigest.digest());
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
cacheKey = String.valueOf(key.hashCode());
|
||||||
|
}
|
||||||
|
return cacheKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String bytesToHexString(byte[] bytes) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < bytes.length; i++) {
|
||||||
|
String hex = Integer.toHexString(0xFF & bytes[i]);
|
||||||
|
if (hex.length() == 1) {
|
||||||
|
sb.append('0');
|
||||||
|
}
|
||||||
|
sb.append(hex);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] bitmap2Bytes(Bitmap bm) {
|
||||||
|
if (bm == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap bytes2Bitmap(byte[] bytes) {
|
||||||
|
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drawable → Bitmap
|
||||||
|
*/
|
||||||
|
public static Bitmap drawable2Bitmap(Drawable drawable) {
|
||||||
|
if (drawable == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 取 drawable 的长宽
|
||||||
|
int w = drawable.getIntrinsicWidth();
|
||||||
|
int h = drawable.getIntrinsicHeight();
|
||||||
|
// 取 drawable 的颜色格式
|
||||||
|
Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
|
||||||
|
// 建立对应 bitmap
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(w, h, config);
|
||||||
|
// 建立对应 bitmap 的画布
|
||||||
|
Canvas canvas = new Canvas(bitmap);
|
||||||
|
drawable.setBounds(0, 0, w, h);
|
||||||
|
// 把 drawable 内容画到画布中
|
||||||
|
drawable.draw(canvas);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bitmap → Drawable
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public static Drawable bitmap2Drawable(Bitmap bm) {
|
||||||
|
if (bm == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
BitmapDrawable bd = new BitmapDrawable(bm);
|
||||||
|
bd.setTargetDensity(bm.getDensity());
|
||||||
|
return new BitmapDrawable(bm);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package com.ttstd.template.fragment;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import com.ttstd.template.R;
|
||||||
|
import com.ttstd.template.base.BaseFragment;
|
||||||
|
|
||||||
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple {@link Fragment} subclass.
|
||||||
|
* Use the {@link TemplateFragment#newInstance} factory method to
|
||||||
|
* create an instance of this fragment.
|
||||||
|
*/
|
||||||
|
public class TemplateFragment extends BaseFragment {
|
||||||
|
private static final String TAG = TemplateFragment.class.getSimpleName();
|
||||||
|
|
||||||
|
private View rootView;// 设置为全局的
|
||||||
|
private Activity mContext;
|
||||||
|
|
||||||
|
// TODO: Rename parameter arguments, choose names that match
|
||||||
|
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
||||||
|
private static final String ARG_PARAM1 = "param1";
|
||||||
|
private static final String ARG_PARAM2 = "param2";
|
||||||
|
|
||||||
|
// TODO: Rename and change types of parameters
|
||||||
|
private String mParam1;
|
||||||
|
private String mParam2;
|
||||||
|
|
||||||
|
public TemplateFragment() {
|
||||||
|
// Required empty public constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this factory method to create a new instance of
|
||||||
|
* this fragment using the provided parameters.
|
||||||
|
*
|
||||||
|
* @param param1 Parameter 1.
|
||||||
|
* @param param2 Parameter 2.
|
||||||
|
* @return A new instance of fragment TemplateFragment.
|
||||||
|
*/
|
||||||
|
// TODO: Rename and change types and number of parameters
|
||||||
|
public static TemplateFragment newInstance(String param1, String param2) {
|
||||||
|
TemplateFragment fragment = new TemplateFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putString(ARG_PARAM1, param1);
|
||||||
|
args.putString(ARG_PARAM2, param2);
|
||||||
|
fragment.setArguments(args);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
if (getArguments() != null) {
|
||||||
|
mParam1 = getArguments().getString(ARG_PARAM1);
|
||||||
|
mParam2 = getArguments().getString(ARG_PARAM2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
Log.e(TAG, "onCreateView: ");
|
||||||
|
if (null != rootView) {
|
||||||
|
ViewGroup parent = (ViewGroup) rootView.getParent();
|
||||||
|
if (null != parent) {
|
||||||
|
parent.removeView(rootView);
|
||||||
|
}
|
||||||
|
} else { // 如ongoing果rootView为空 ,就实例化该视图
|
||||||
|
rootView = inflater.inflate(R.layout.fragment_health, container, false);
|
||||||
|
mContext = (Activity) rootView.getContext();
|
||||||
|
ButterKnife.bind(this, rootView);
|
||||||
|
initView();
|
||||||
|
}
|
||||||
|
return rootView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fetchData() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initView() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
112
app/src/main/java/com/ttstd/template/network/MD5Util.java
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
package com.ttstd.template.network;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
|
public class MD5Util {
|
||||||
|
|
||||||
|
public static String packetMD5(String str) {
|
||||||
|
MessageDigest messageDigest = null;
|
||||||
|
try {
|
||||||
|
messageDigest = MessageDigest.getInstance("MD5");
|
||||||
|
|
||||||
|
messageDigest.reset();
|
||||||
|
|
||||||
|
messageDigest.update(str.getBytes("UTF-8"));
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
System.out.println("NoSuchAlgorithmException caught!");
|
||||||
|
System.exit(-1);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] byteArray = messageDigest.digest();
|
||||||
|
|
||||||
|
StringBuffer md5StrBuff = new StringBuffer();
|
||||||
|
|
||||||
|
for (int i = 0; i < byteArray.length; i++) {
|
||||||
|
if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
|
||||||
|
md5StrBuff.append("0").append(
|
||||||
|
Integer.toHexString(0xFF & byteArray[i]));
|
||||||
|
else
|
||||||
|
md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return md5StrBuff.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
public static String getUpperMD5Str(String str) {
|
||||||
|
MessageDigest messageDigest = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
messageDigest = MessageDigest.getInstance("MD5");
|
||||||
|
|
||||||
|
messageDigest.reset();
|
||||||
|
|
||||||
|
messageDigest.update(str.getBytes("UTF-8"));
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
System.out.println("NoSuchAlgorithmException caught!");
|
||||||
|
System.exit(-1);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] byteArray = messageDigest.digest();
|
||||||
|
|
||||||
|
StringBuffer md5StrBuff = new StringBuffer();
|
||||||
|
|
||||||
|
for (int i = 0; i < byteArray.length; i++) {
|
||||||
|
if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
|
||||||
|
md5StrBuff.append("0").append(
|
||||||
|
Integer.toHexString(0xFF & byteArray[i]));
|
||||||
|
else
|
||||||
|
md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return md5StrBuff.toString().toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取16位的MD5 值得
|
||||||
|
*
|
||||||
|
* @param str
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
public static String getUpperMD5Str16(String str) {
|
||||||
|
MessageDigest messageDigest = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
messageDigest = MessageDigest.getInstance("MD5");
|
||||||
|
|
||||||
|
messageDigest.reset();
|
||||||
|
|
||||||
|
messageDigest.update(str.getBytes("UTF-8"));
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
System.out.println("NoSuchAlgorithmException caught!");
|
||||||
|
System.exit(-1);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] byteArray = messageDigest.digest();
|
||||||
|
|
||||||
|
StringBuffer md5StrBuff = new StringBuffer();
|
||||||
|
|
||||||
|
for (int i = 0; i < byteArray.length; i++) {
|
||||||
|
if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
|
||||||
|
md5StrBuff.append("0").append(
|
||||||
|
Integer.toHexString(0xFF & byteArray[i]));
|
||||||
|
else
|
||||||
|
md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return md5StrBuff.toString().toUpperCase().substring(8, 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
package com.ttstd.template.network;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Environment;
|
||||||
|
|
||||||
|
import com.tencent.mmkv.MMKV;
|
||||||
|
import com.ttstd.template.bean.BaseResponse;
|
||||||
|
import com.ttstd.template.comm.CommonConfig;
|
||||||
|
import com.ttstd.template.network.interceptor.RepeatRequestInterceptor;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
|
import okhttp3.Cache;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory;
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
|
|
||||||
|
public class NetInterfaceManager {
|
||||||
|
private static final String TAG = NetInterfaceManager.class.getSimpleName();
|
||||||
|
|
||||||
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
private static NetInterfaceManager INSTANCE;
|
||||||
|
private Context mContext;
|
||||||
|
private ContentResolver crv;
|
||||||
|
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||||||
|
private Retrofit mRetrofit;
|
||||||
|
private OkHttpClient okHttpClient;
|
||||||
|
// private CacheHelper mCacheHelper;
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<String, Long> requestIdsMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
//超时时间
|
||||||
|
public static final int timeOut = 30;
|
||||||
|
// 缓存文件最大限制大小20M
|
||||||
|
private static final long cacheSize = 1024 * 1024 * 64;
|
||||||
|
|
||||||
|
private NetInterfaceManager(Context context) {
|
||||||
|
if (context == null) {
|
||||||
|
throw new RuntimeException("Context is NULL");
|
||||||
|
}
|
||||||
|
this.mContext = context;
|
||||||
|
this.crv = mContext.getContentResolver();
|
||||||
|
// this.mCacheHelper = new CacheHelper(mContext);
|
||||||
|
|
||||||
|
if (null == mRetrofit) {
|
||||||
|
if (okHttpClient == null) {
|
||||||
|
//如果无法生存缓存文件目录,检测权限使用已经加上,检测手机是否把文件读写权限禁止了
|
||||||
|
OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||||
|
builder.connectTimeout(timeOut, TimeUnit.SECONDS); // 设置连接超时时间
|
||||||
|
builder.writeTimeout(timeOut, TimeUnit.SECONDS);// 设置写入超时时间
|
||||||
|
builder.readTimeout(timeOut, TimeUnit.SECONDS);// 设置读取数据超时时间
|
||||||
|
builder.retryOnConnectionFailure(true);// 设置进行连接失败重试
|
||||||
|
builder.addInterceptor(new RepeatRequestInterceptor());
|
||||||
|
|
||||||
|
// 设置缓存文件路径
|
||||||
|
String cacheDirectory = getCacheDir() + "/OkHttpCache";
|
||||||
|
Cache cache = new Cache(new File(cacheDirectory), cacheSize);
|
||||||
|
builder.cache(cache);// 设置缓存
|
||||||
|
okHttpClient = builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
mRetrofit = new Retrofit.Builder()
|
||||||
|
.client(okHttpClient)
|
||||||
|
.baseUrl(UrlAddress.ROOT_URL)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getCacheDir() {
|
||||||
|
String cachePath;
|
||||||
|
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|
||||||
|
|| !Environment.isExternalStorageRemovable()) {
|
||||||
|
if (mContext.getExternalCacheDir() != null) {
|
||||||
|
cachePath = mContext.getExternalCacheDir().getPath();
|
||||||
|
} else if (mContext.getExternalFilesDir("cache") != null) {
|
||||||
|
cachePath = mContext.getExternalFilesDir("cache").getPath();
|
||||||
|
} else {
|
||||||
|
cachePath = mContext.getCacheDir().getPath();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cachePath = mContext.getCacheDir().getPath();
|
||||||
|
}
|
||||||
|
return cachePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init(Context context) {
|
||||||
|
if (context == null) {
|
||||||
|
throw new RuntimeException("context is NULL");
|
||||||
|
}
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
INSTANCE = new NetInterfaceManager(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NetInterfaceManager getInstance() {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
throw new IllegalStateException("You must be init NetworkManager first");
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OkHttpClient getOkHttpClient() {
|
||||||
|
return okHttpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Observable
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* API
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* execution
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
|
||||||
|
public interface ObserverCallback {
|
||||||
|
void onSubscribe(Disposable d);
|
||||||
|
|
||||||
|
void onNext(BaseResponse response);
|
||||||
|
|
||||||
|
void onError(Throwable e);
|
||||||
|
|
||||||
|
void onComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface onCompleteCallback {
|
||||||
|
void onComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface onNextCallback {
|
||||||
|
void onNext(Object o);
|
||||||
|
|
||||||
|
void onError(Object o);
|
||||||
|
|
||||||
|
void onComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package com.ttstd.template.network;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.annotations.NonNull;
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public abstract class RetryCallback<T> implements Callback<T> {
|
||||||
|
|
||||||
|
private static final String TAG = RetryCallback.class.getSimpleName();
|
||||||
|
|
||||||
|
private int mRetryCount;
|
||||||
|
private long mRetryInterval;
|
||||||
|
|
||||||
|
private int mCurrentRetryCount;
|
||||||
|
|
||||||
|
private boolean isExecuting;
|
||||||
|
|
||||||
|
private Call<T> mCall;
|
||||||
|
|
||||||
|
private Timer timer = new Timer();
|
||||||
|
|
||||||
|
public RetryCallback(Call<T> call, int retryCount, long retryInterval) {
|
||||||
|
isExecuting = true;
|
||||||
|
mCall = call;
|
||||||
|
mRetryCount = retryCount;
|
||||||
|
mRetryInterval = retryInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void onResponse(@NonNull Call<T> call, @NonNull Response<T> response) {
|
||||||
|
Log.e(TAG, "onResponse");
|
||||||
|
isExecuting = false;
|
||||||
|
if (!response.isSuccessful() && mCurrentRetryCount < mRetryCount) {
|
||||||
|
mCurrentRetryCount++;
|
||||||
|
retryRequest(call);
|
||||||
|
} else {
|
||||||
|
onRequestResponse(call, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void onFailure(@NonNull Call<T> call, @NonNull Throwable t) {
|
||||||
|
Log.e(TAG, "onFailure");
|
||||||
|
isExecuting = false;
|
||||||
|
if (mCurrentRetryCount < mRetryCount) {
|
||||||
|
mCurrentRetryCount++;
|
||||||
|
Log.e(TAG, "onFailure: " + "RetryCount: " + mCurrentRetryCount);
|
||||||
|
Log.e(TAG, "onFailure: " + "RetryResponse: " + call.request());
|
||||||
|
retryRequest(call);
|
||||||
|
} else {
|
||||||
|
onRequestFail(call, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void retryRequest(final Call<T> call) {
|
||||||
|
Log.e(TAG, "retryRequest");
|
||||||
|
onStartRetry();
|
||||||
|
TimerTask timerTask = new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
synchronized (RetryCallback.this) {
|
||||||
|
mCall = call.clone();
|
||||||
|
mCall.enqueue(RetryCallback.this);
|
||||||
|
isExecuting = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
timer.schedule(timerTask, mRetryInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelCall() {
|
||||||
|
synchronized (this) {
|
||||||
|
if (!isExecuting) {
|
||||||
|
timer.cancel();
|
||||||
|
} else {
|
||||||
|
mCall.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void onRequestResponse(Call call, Response response);
|
||||||
|
|
||||||
|
public abstract void onRequestFail(Call call, Throwable t);
|
||||||
|
|
||||||
|
public abstract void onStartRetry();
|
||||||
|
}
|
||||||
80
app/src/main/java/com/ttstd/template/network/UrlAddress.java
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package com.ttstd.template.network;
|
||||||
|
|
||||||
|
public class UrlAddress {
|
||||||
|
/*主页接口*/
|
||||||
|
public static final String ROOT_URL = "https://led.zuoyepad.com/android/";
|
||||||
|
|
||||||
|
/*设备激活*/
|
||||||
|
public static final String SN_ACTIVATION = "sn/snActivation";
|
||||||
|
/*获取设备是否激活*/
|
||||||
|
public static final String GET_SN_IS_ACTIVATION = "sn/getSnIsActivation";
|
||||||
|
/*获取设备激活二维码链接*/
|
||||||
|
public static final String ACTIVATION_QRCODE = "pay/getActivationQrcode";
|
||||||
|
|
||||||
|
/*获取文件*/
|
||||||
|
public static final String GET_FILES = "file/getFiles";
|
||||||
|
/*获取操作指南*/
|
||||||
|
public static final String GET_OPERATION_GUIDE = "file/getFiles";
|
||||||
|
|
||||||
|
|
||||||
|
/*上传屏幕截图*/
|
||||||
|
public final static String UPLOAD_SCREEN_SNAPSHOT = "sn/uploadScreenshot";
|
||||||
|
/*浏览器网址管控*/
|
||||||
|
public final static String SET_BROWSER_URL = "control/getBrowser";
|
||||||
|
/*浏览器书签管控*/
|
||||||
|
public final static String SET_BROWSER_LABEL = "control/getLabel";
|
||||||
|
/*上传控制面版截图*/
|
||||||
|
public static final String UPLOAD_CONTROL_SCREENSHOT = "sn/uploadControlScreenshot";
|
||||||
|
|
||||||
|
|
||||||
|
/*设备信息接口*/
|
||||||
|
public static final String SNINFO = "sn/getSnInfo";
|
||||||
|
/*获取用户头像和信息*/
|
||||||
|
public static final String GET_USER_AVATAR_INFO = "sn/getUserAvatarInfo";
|
||||||
|
/*获取设备类型*/
|
||||||
|
public static final String GET_SN_TYPE = "sn/getSnType";
|
||||||
|
/*获取正在运行的app*/
|
||||||
|
public static final String RUN_NEW_APP = "app/runNewApp";
|
||||||
|
/*获取所有应用*/
|
||||||
|
public final static String GET_ALL_PACKAGE = "app/queryAllApp";
|
||||||
|
/*绑定设备消息*/
|
||||||
|
public final static String BIND_DEVICES = "sn/bindSn";
|
||||||
|
/*获取系统设置*/
|
||||||
|
public final static String GET_SETTINGS = "control/getSetting";
|
||||||
|
/*获取强制下载*/
|
||||||
|
public final static String GET_FORCE_INSTALL = "app/getForceDownload";
|
||||||
|
/*发送卸载或者安装信息*/
|
||||||
|
public final static String SEND_INSTALLEDORREMOVED = "app/addAppInstall";
|
||||||
|
/*发送设备基本信息*/
|
||||||
|
public final static String UPDATE_SNINFO = "sn/updateAdminSn";
|
||||||
|
/*根据包名获取更新*/
|
||||||
|
public final static String GET_NEWESTAPPUPDATE = "app/newestAppUpdate";
|
||||||
|
/*获取禁用包名*/
|
||||||
|
public static final String GET_APP_ICON = "getAppIcon";
|
||||||
|
/*获取灰度更新*/
|
||||||
|
public static final String GET_TEST_APP_INFO = "app/getTestAppInfo";
|
||||||
|
/*获取wifi*/
|
||||||
|
public static final String GET_WIFI_ALIAS_PW = "getWifi";
|
||||||
|
|
||||||
|
/*获取屏幕管控*/
|
||||||
|
public final static String GET_SCREEN_LOCK = "sn/getScreenshot";
|
||||||
|
/*获取锁屏密码*/
|
||||||
|
public static final String LOCK_SCREEN_PWD = "sn/getLockScreenPwd";
|
||||||
|
/*解除锁屏*/
|
||||||
|
public static final String UPDATE_LOCK_SCREEN = "sn/updateLockScreen";
|
||||||
|
|
||||||
|
/*发送绑定验证码*/
|
||||||
|
public static final String SEND_BIND_VER_CODE = "Sn/sendBindVerCode";
|
||||||
|
/*手动绑定设备*/
|
||||||
|
public static final String EQUIPMENT_BIND = "Sn/equipmentBind";
|
||||||
|
|
||||||
|
/*上传应用图标*/
|
||||||
|
public static final String UPLOAD_APP_IMG = "collectData/uploadAppImg";
|
||||||
|
/*获取应用库是否有图标*/
|
||||||
|
public static final String GET_IS_APP_IMG = "collectData/getIsAppImg";
|
||||||
|
|
||||||
|
|
||||||
|
/*通过ip获取信息*/
|
||||||
|
public static final String PCONLINE_WHOIS = "http://whois.pconline.com.cn/";
|
||||||
|
public static final String WHOIS = "ipJson.jsp";
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package com.ttstd.template.network.interceptor;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.ttstd.template.BuildConfig;
|
||||||
|
import com.ttstd.template.network.MD5Util;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import okhttp3.Interceptor;
|
||||||
|
import okhttp3.Protocol;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
import okio.Buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* v1.0 2022-07-15 16:16:52
|
||||||
|
*/
|
||||||
|
public class RepeatRequestInterceptor implements Interceptor {
|
||||||
|
private static final String TAG = RepeatRequestInterceptor.class.getSimpleName();
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<String, Long> requestIdsMap = new ConcurrentHashMap<>();
|
||||||
|
public static final String REPEAT_REQUEST_PROTOCOL = "OKHTTP_REPEAT_REQUEST_PROTOCOL";
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public Response intercept(@NotNull Chain chain) throws IOException {
|
||||||
|
Request request = chain.request();
|
||||||
|
Response response = chain.proceed(request);
|
||||||
|
ResponseBody responseBody = response.body();
|
||||||
|
|
||||||
|
//会消费请求,导致请求多次
|
||||||
|
String content = responseBody.string();
|
||||||
|
// Response copy = response.newBuilder().body(responseBody).build();
|
||||||
|
ResponseBody copy = ResponseBody.create(responseBody.contentType(), content);
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Log.e(TAG, "请求体返回:| Response: " + request.url() + "\t body: " + content);
|
||||||
|
}
|
||||||
|
//相同的请求
|
||||||
|
String requestKey = MD5Util.getUpperMD5Str(request.method() + request.url().toString() + requestBodyToString(request.body()));
|
||||||
|
long time = System.currentTimeMillis();//请求时间
|
||||||
|
try {
|
||||||
|
if (requestIdsMap.size() > 0 && requestIdsMap.containsKey(requestKey)) {
|
||||||
|
log("重复请求:", requestKey, request);
|
||||||
|
//下面这行写了不会抛出onerror
|
||||||
|
// chain.call().cancel();
|
||||||
|
return new Response.Builder()
|
||||||
|
.protocol(Protocol.get(REPEAT_REQUEST_PROTOCOL))
|
||||||
|
.request(request) //multi thread
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
requestIdsMap.put(requestKey, time);
|
||||||
|
log("注册请求:", requestKey, request);
|
||||||
|
// RepeatRequestInterceptor.Builder builder = request.newBuilder();
|
||||||
|
// builder.addHeader("header", jsonObject.toString());
|
||||||
|
return response.newBuilder().body(copy).build();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "intercept: " + e.getMessage());
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
if (requestIdsMap.containsKey(requestKey) && requestIdsMap.containsValue(time)) {//请求任务完成删除map中的数据
|
||||||
|
requestIdsMap.remove(requestKey);
|
||||||
|
log("移除请求:", requestKey, request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void log(String action, String requestKey, Request request) {
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
Log.e("REPEAT-REQUEST", action + requestKey + " Method @" + request.method() + " --- " + " URL = " + request.url().encodedPath() + "\t" + bodyToString(request));
|
||||||
|
} else {
|
||||||
|
Log.e("REPEAT-REQUEST", action + requestKey + " Method @" + request.method());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String bodyToString(final Request request) {
|
||||||
|
try {
|
||||||
|
final Request copy = request.newBuilder().build();
|
||||||
|
final Buffer buffer = new Buffer();
|
||||||
|
copy.body().writeTo(buffer);
|
||||||
|
if (buffer.size() > 4096) {
|
||||||
|
return "-too long";
|
||||||
|
}
|
||||||
|
return buffer.readUtf8();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String requestBodyToString(RequestBody body) {
|
||||||
|
try {
|
||||||
|
final Buffer buffer = new Buffer();
|
||||||
|
body.writeTo(buffer);
|
||||||
|
if (buffer.size() > 4096) {
|
||||||
|
return "-too long";
|
||||||
|
}
|
||||||
|
return buffer.readUtf8();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
24
app/src/main/java/com/ttstd/template/utils/SystemUtils.java
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package com.ttstd.template.utils;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SystemUtils {
|
||||||
|
|
||||||
|
public static boolean isMainProcessName(Context cxt, int pid) {
|
||||||
|
String packageName = cxt.getPackageName();
|
||||||
|
ActivityManager am = (ActivityManager) cxt.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();
|
||||||
|
if (runningApps == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (ActivityManager.RunningAppProcessInfo procInfo : runningApps) {
|
||||||
|
if (procInfo.pid == pid) {
|
||||||
|
return procInfo.processName.equals(packageName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
30
app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:endX="85.84757"
|
||||||
|
android:endY="92.4963"
|
||||||
|
android:startX="42.9492"
|
||||||
|
android:startY="49.59793"
|
||||||
|
android:type="linear">
|
||||||
|
<item
|
||||||
|
android:color="#44000000"
|
||||||
|
android:offset="0.0" />
|
||||||
|
<item
|
||||||
|
android:color="#00000000"
|
||||||
|
android:offset="1.0" />
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
|
||||||
|
android:strokeWidth="1"
|
||||||
|
android:strokeColor="#00000000" />
|
||||||
|
</vector>
|
||||||
170
app/src/main/res/drawable/ic_launcher_background.xml
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
android:viewportHeight="108">
|
||||||
|
<path
|
||||||
|
android:fillColor="#3DDC84"
|
||||||
|
android:pathData="M0,0h108v108h-108z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M9,0L9,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,0L19,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,0L29,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,0L39,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,0L49,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,0L59,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,0L69,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,0L79,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M89,0L89,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M99,0L99,108"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,9L108,9"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,19L108,19"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,29L108,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,39L108,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,49L108,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,59L108,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,69L108,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,79L108,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,89L108,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,99L108,99"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,29L89,29"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,39L89,39"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,49L89,49"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,59L89,59"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,69L89,69"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,79L89,79"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,19L29,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,19L39,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,19L49,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,19L59,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,19L69,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,19L79,89"
|
||||||
|
android:strokeWidth="0.8"
|
||||||
|
android:strokeColor="#33FFFFFF" />
|
||||||
|
</vector>
|
||||||
14
app/src/main/res/layout/activity_main.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".activity.main.MainActivity">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/content"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
14
app/src/main/res/layout/fragment_health.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".fragment.TemplateFragment">
|
||||||
|
|
||||||
|
<!-- TODO: Update blank fragment layout -->
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:text="@string/hello_blank_fragment" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
</adaptive-icon>
|
||||||
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@drawable/ic_launcher_background" />
|
||||||
|
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||||
|
</adaptive-icon>
|
||||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
248
app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,248 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="colorPrimary">#6200EE</color>
|
||||||
|
<color name="colorPrimaryDark">#3700B3</color>
|
||||||
|
<color name="colorAccent">#03DAC5</color>
|
||||||
|
|
||||||
|
<!--https://www.jianshu.com/p/8dc258dfd189-->
|
||||||
|
<color name="transparent">#00000000</color><!--透明色-->
|
||||||
|
<color name="colorYang">#FFE2C59B</color><!--羊皮纸色-->
|
||||||
|
<color name="ivory">#FFFFFFF0</color><!--象牙色-->
|
||||||
|
<color name="lightYellow">#FFFFFFE0</color><!--亮黄色-->
|
||||||
|
<color name="yellow">#FFFFFF00</color><!--黄色-->
|
||||||
|
<color name="snow">#FFFFFAFA</color><!--雪白色-->
|
||||||
|
<color name="floralWhite">#FFFFFAF0</color><!--花白色-->
|
||||||
|
<color name="lemonChiffon">#FFFFFACD</color><!--柠檬绸色-->
|
||||||
|
<color name="cornSilk">#FFFFF8DC</color><!--米绸色-->
|
||||||
|
<color name="seashell">#FFFFF5EE</color><!--海贝色-->
|
||||||
|
<color name="lavenderBlush">#FFFFF0F5</color><!--淡紫红色-->
|
||||||
|
<color name="papayaWhip">#FFFFEFD5</color><!--番木色-->
|
||||||
|
<color name="blanchedAlmond">#FFFFEBCD</color><!--白杏色-->
|
||||||
|
<color name="mistyRose">#FFFFE4E1</color><!--浅玫瑰色-->
|
||||||
|
<color name="bisque">#FFFFE4C4</color><!--桔黄色-->
|
||||||
|
<color name="moccasin">#FFFFE4B5</color><!--鹿皮色-->
|
||||||
|
<color name="navajoWhite">#FFFFDEAD</color><!--纳瓦白-->
|
||||||
|
<color name="peachPuff">#FFFFDAB9</color><!--桃色-->
|
||||||
|
<color name="gold">#FFFFD700</color><!--金色-->
|
||||||
|
<color name="pink">#FFFFC0CB</color><!--粉红色-->
|
||||||
|
<color name="lightPink">#FFFFB6C1</color><!--亮粉红色-->
|
||||||
|
<color name="orange">#FFFFA500</color><!--橙色-->
|
||||||
|
<color name="lightSalmon">#FFFFA07A</color><!--亮肉色-->
|
||||||
|
<color name="darkOrange">#FFFF8C00</color><!--暗桔黄色-->
|
||||||
|
<color name="coral">#FFFF7F50</color><!--珊瑚色-->
|
||||||
|
<color name="hotPink">#FFFF69B4</color><!--热粉红色-->
|
||||||
|
<color name="tomato">#FFFF6347</color><!--西红柿色-->
|
||||||
|
<color name="orangeRed">#FFFF4500</color><!--红橙色-->
|
||||||
|
<color name="deepPink">#FFFF1493</color><!--深粉红色-->
|
||||||
|
<color name="fuchsia">#FFFF00FF</color><!--紫红色-->
|
||||||
|
<color name="red">#FFFF0000</color><!--红色-->
|
||||||
|
<color name="oldLace">#FFFDF5E6</color><!--老花色-->
|
||||||
|
<color name="lightGoldenrodYellow">#FFFAFAD2</color><!--亮金黄色-->
|
||||||
|
<color name="linen">#FFFAF0E6</color><!--亚麻色-->
|
||||||
|
<color name="antiqueWhite">#FFFAEBD7</color><!--古董白色-->
|
||||||
|
<color name="salmon">#FFFA8072</color><!--鲜肉色-->
|
||||||
|
<color name="ghostWhite">#FFF8F8FF</color><!--幽灵白-->
|
||||||
|
<color name="mintCream">#FFF5FFFA</color><!--薄荷色-->
|
||||||
|
<color name="whiteSmoke">#FFF5F5F5</color><!--烟白色-->
|
||||||
|
<color name="beige">#FFF5F5DC</color><!--米色-->
|
||||||
|
<color name="wheat">#FFF5DEB3</color><!--浅黄色-->
|
||||||
|
<color name="sandyBrown">#FFF4A460</color><!--沙褐色-->
|
||||||
|
<color name="azure">#FFF0FFFF</color><!--天蓝色-->
|
||||||
|
<color name="aliceBlue">#FFF0F8FF</color><!--艾利斯兰色-->
|
||||||
|
<color name="khaki">#FFF0E68C</color><!--黄褐色-->
|
||||||
|
<color name="lightCoral">#FFF08080</color><!--亮珊瑚色-->
|
||||||
|
<color name="paleGoldenrod">#FFEEE8AA</color><!--苍麒麟色-->
|
||||||
|
<color name="violet">#FFEE82EE</color><!--紫罗兰色-->
|
||||||
|
<color name="darkSalmon">#FFE9967A</color><!--暗肉色-->
|
||||||
|
<color name="lavender">#FFE6E6FA</color><!--淡紫色-->
|
||||||
|
<color name="lightCyan">#FFE0FFFF</color><!--亮青色-->
|
||||||
|
<color name="burlyWood">#FFDEB887</color><!--实木色-->
|
||||||
|
<color name="plum">#FFDDA0DD</color><!--洋李色-->
|
||||||
|
<color name="lightGrey">#FFDCDCDC</color><!--淡灰色-->
|
||||||
|
<color name="crimson">#FFDC143C</color><!--暗深红色-->
|
||||||
|
<color name="paleVioletRed">#FFDB7093</color><!--苍紫罗兰色-->
|
||||||
|
<color name="goldenrod">#FFDAA520</color><!--金麒麟色-->
|
||||||
|
<color name="orchid">#FFDA70D6</color><!--淡紫色-->
|
||||||
|
<color name="thistle">#FFD8BFD8</color><!--蓟色-->
|
||||||
|
<color name="lightGray">#FFD3D3D3</color><!--亮灰色-->
|
||||||
|
<color name="tan">#FFD2B48C</color><!--茶色-->
|
||||||
|
<color name="chocolate">#FFD2691E</color><!--巧可力色-->
|
||||||
|
<color name="peru">#FFCD853F</color><!--秘鲁色-->
|
||||||
|
<color name="indianRed">#FFCD5C5C</color><!--印第安红色-->
|
||||||
|
<color name="mediumVioletRed">#FFC71585</color><!--中紫罗兰色-->
|
||||||
|
<color name="silver">#FFC0C0C0</color><!--银色-->
|
||||||
|
<color name="darkKhaki">#FFBDB76B</color><!--暗黄褐色-->
|
||||||
|
<color name="rosyBrown">#FFBC8F8F</color><!--褐玫瑰红色-->
|
||||||
|
<color name="mediumOrchid">#FFBA55D3</color><!--中粉紫色-->
|
||||||
|
<color name="darkGoldenrod">#FFB8860B</color><!--暗金黄色-->
|
||||||
|
<color name="firebrick">#FFB22222</color><!--火砖色-->
|
||||||
|
<color name="powderBlue">#FFB0E0E6</color><!--粉蓝色-->
|
||||||
|
<color name="lightSteelBlue">#FFB0C4DE</color><!--亮钢兰色-->
|
||||||
|
<color name="paleTurquoise">#FFAFEEEE</color><!--苍宝石绿色-->
|
||||||
|
<color name="greenYellow">#FFADFF2F</color><!--黄绿色-->
|
||||||
|
<color name="lightBlue">#FFADD8E6</color><!--亮蓝色-->
|
||||||
|
<color name="darkGray">#FFA9A9A9</color><!--暗灰色-->
|
||||||
|
<color name="brown">#FFA52A2A</color><!--褐色-->
|
||||||
|
<color name="sienna">#FFA0522D</color><!--赭色-->
|
||||||
|
<color name="darkOrchid">#FF9932CC</color><!--暗紫色-->
|
||||||
|
<color name="paleGreen">#FF98FB98</color><!--苍绿色-->
|
||||||
|
<color name="darkViolet">#FF9400D3</color><!--暗紫罗兰色-->
|
||||||
|
<color name="mediumPurple">#FF9370DB</color><!--中紫色-->
|
||||||
|
<color name="lightGreen">#FF90EE90</color><!--亮绿色-->
|
||||||
|
<color name="darkSeaGreen">#FF8FBC8F</color><!--暗海兰色-->
|
||||||
|
<color name="saddleBrown">#FF8B4513</color><!--重褐色-->
|
||||||
|
<color name="darkMagenta">#FF8B008B</color><!--暗洋红色-->
|
||||||
|
<color name="darkRed">#FF8B0000</color><!--暗红色-->
|
||||||
|
<color name="blueViolet">#FF8A2BE2</color><!--紫罗兰蓝色-->
|
||||||
|
<color name="lightSkyBlue">#FF87CEFA</color><!--亮天蓝色-->
|
||||||
|
<color name="skyBlue">#FF87CEEB</color><!--天蓝色-->
|
||||||
|
<color name="gray">#FF808080</color><!--灰色-->
|
||||||
|
<color name="olive">#FF808000</color><!--橄榄色-->
|
||||||
|
<color name="purple">#FF800080</color><!--紫色-->
|
||||||
|
<color name="maroon">#FF800000</color><!--粟色-->
|
||||||
|
<color name="aquamarine">#FF7FFFD4</color><!--碧绿色-->
|
||||||
|
<color name="chartreuse">#FF7FFF00</color><!--黄绿色-->
|
||||||
|
<color name="lawnGreen">#FF7CFC00</color><!--草绿色-->
|
||||||
|
<color name="mediumSlateBlue">#FF7B68EE</color><!--中暗蓝色-->
|
||||||
|
<color name="lightSlateGray">#FF778899</color><!--亮蓝灰色-->
|
||||||
|
<color name="slateGray">#FF708090</color><!--灰石色-->
|
||||||
|
<color name="oliveDrab">#FF6B8E23</color><!--深绿褐色-->
|
||||||
|
<color name="slateBlue">#FF6A5ACD</color><!--石蓝色-->
|
||||||
|
<color name="dimGray">#FF696969</color><!--暗灰色-->
|
||||||
|
<color name="mediumAquamarine">#FF66CDAA</color><!--中绿色-->
|
||||||
|
<color name="cornFlowerBlue">#FF6495ED</color><!--菊兰色-->
|
||||||
|
<color name="cadetBlue">#FF5F9EA0</color><!--军兰色-->
|
||||||
|
<color name="darkOliveGreen">#FF556B2F</color><!--暗橄榄绿色-->
|
||||||
|
<color name="indigo">#FF4B0082</color><!--靛青色-->
|
||||||
|
<color name="mediumTurquoise">#FF48D1CC</color><!--中绿宝石色-->
|
||||||
|
<color name="darkSlateBlue">#FF483D8B</color><!--暗灰蓝色-->
|
||||||
|
<color name="steelBlue">#FF4682B4</color><!--钢兰色-->
|
||||||
|
<color name="royalBlue">#FF4169E1</color><!--皇家蓝色-->
|
||||||
|
<color name="turquoise">#FF40E0D0</color><!--青绿色-->
|
||||||
|
<color name="mediumSeaGreen">#FF3CB371</color><!--中海蓝色-->
|
||||||
|
<color name="limeGreen">#FF32CD32</color><!--橙绿色-->
|
||||||
|
<color name="darkSlateGray">#FF2F4F4F</color><!--暗瓦灰色-->
|
||||||
|
<color name="seaGreen">#FF2E8B57</color><!--海绿色-->
|
||||||
|
<color name="forestGreen">#FF228B22</color><!--森林绿色-->
|
||||||
|
<color name="lightSeaGreen">#FF20B2AA</color><!--亮海蓝色-->
|
||||||
|
<color name="dodgerBlue">#FF1E90FF</color><!--闪兰色-->
|
||||||
|
<color name="midnightBlue">#FF191970</color><!--中灰兰色-->
|
||||||
|
<color name="aqua">#FF00FFFF</color><!--浅绿色-->
|
||||||
|
<color name="springGreen">#FF00FF7F</color><!--春绿色-->
|
||||||
|
<color name="lime">#FF00FF00</color><!--酸橙色-->
|
||||||
|
<color name="mediumSpringGreen">#FF00FA9A</color><!--中春绿色-->
|
||||||
|
<color name="darkTurquoise">#FF00CED1</color><!--暗宝石绿色-->
|
||||||
|
<color name="deepSkyBlue">#FF00BFFF</color><!--深天蓝色-->
|
||||||
|
<color name="darkCyan">#FF008B8B</color><!--暗青色-->
|
||||||
|
<color name="teal">#FF008080</color><!--水鸭色-->
|
||||||
|
<color name="green">#FF008000</color><!--绿色-->
|
||||||
|
<color name="darkGreen">#FF006400</color><!--暗绿色-->
|
||||||
|
<color name="blue">#FF0000FF</color><!--蓝色-->
|
||||||
|
<color name="mediumBlue">#FF0000CD</color><!--中兰色-->
|
||||||
|
<color name="darkBlue">#FF00008B</color><!--暗蓝色-->
|
||||||
|
<color name="navy">#FF000080</color><!--海军色-->
|
||||||
|
<color name="unBlack">#FF2B2B2B</color><!--不知名黑色-->
|
||||||
|
|
||||||
|
<!--https://www.cnblogs.com/elleniou/archive/2012/04/25/2469676.html-->
|
||||||
|
<color name="white">#ffffff</color><!--白色 -->
|
||||||
|
<color name="lightyellow">#ffffe0</color><!--亮黄色 -->
|
||||||
|
<color name="floralwhite">#fffaf0</color><!--花白色 -->
|
||||||
|
<color name="lemonchiffon">#fffacd</color><!--柠檬绸色 -->
|
||||||
|
<color name="cornsilk">#fff8dc</color><!--米绸色 -->
|
||||||
|
<color name="seaShell">#fff5ee</color><!--海贝色 -->
|
||||||
|
<color name="lavenderblush">#fff0f5</color><!--淡紫红 -->
|
||||||
|
<color name="papayawhip">#ffefd5</color><!--番木色 -->
|
||||||
|
<color name="blanchedalmond">#ffebcd</color><!--白杏色 -->
|
||||||
|
<color name="mistyrose">#ffe4e1</color><!--浅玫瑰色 -->
|
||||||
|
<color name="navajowhite">#ffdead</color><!--纳瓦白 -->
|
||||||
|
<color name="peachpuff">#ffdab9</color><!--桃色 -->
|
||||||
|
<color name="lightpink">#ffb6c1</color><!--亮粉红色 -->
|
||||||
|
<color name="lightsalmon">#ffa07a</color><!--亮肉色 -->
|
||||||
|
<color name="darkorange">#ff8c00</color><!--暗桔黄色 -->
|
||||||
|
<color name="hotpink">#ff69b4</color><!--热粉红色 -->
|
||||||
|
<color name="orangered">#ff4500</color><!--红橙色 -->
|
||||||
|
<color name="deeppink">#ff1493</color><!--深粉红色 -->
|
||||||
|
<color name="magenta">#ff00ff</color><!--红紫色 -->
|
||||||
|
<color name="oldlace">#fdf5e6</color><!--老花色 -->
|
||||||
|
<color name="lightgoldenrodyellow">#fafad2</color><!--亮金黄色 -->
|
||||||
|
<color name="antiquewhite">#faebd7</color><!--古董白 -->
|
||||||
|
<color name="ghostwhite">#f8f8ff</color><!--幽灵白 -->
|
||||||
|
<color name="mintcream">#f5fffa</color><!--薄荷色 -->
|
||||||
|
<color name="whitesmoke">#f5f5f5</color><!--烟白色 -->
|
||||||
|
<color name="sandybrown">#f4a460</color><!--沙褐色 -->
|
||||||
|
<color name="honeydew">#f0fff0</color><!--蜜色 -->
|
||||||
|
<color name="aliceblue">#f0f8ff</color><!--艾利斯兰 -->
|
||||||
|
<color name="lightcoral">#f08080</color><!--亮珊瑚色 -->
|
||||||
|
<color name="palegoldenrod">#eee8aa</color><!--苍麒麟色 -->
|
||||||
|
<color name="darksalmon">#e9967a</color><!--暗肉色 -->
|
||||||
|
<color name="lightcyan">#e0ffff</color><!--亮青色 -->
|
||||||
|
<color name="burlywood">#deb887</color><!--实木色 -->
|
||||||
|
<color name="gainsboro">#dcdcdc</color><!--淡灰色 -->
|
||||||
|
<color name="palevioletred">#db7093</color><!--苍紫罗兰色 -->
|
||||||
|
<color name="lightgray">#d3d3d3</color><!--亮灰色 -->
|
||||||
|
<color name="lightgrey">#d3d3d3</color><!--亮灰色 -->
|
||||||
|
<color name="indianred">#cd5c5c</color><!--印第安红 -->
|
||||||
|
<color name="mediumvioletred">#c71585</color><!--中紫罗兰色 -->
|
||||||
|
<color name="darkkhaki">#bdb76b</color><!--暗黄褐色 -->
|
||||||
|
<color name="rosybrown">#bc8f8f</color><!--褐玫瑰红 -->
|
||||||
|
<color name="mediumorchid">#ba55d3</color><!--中粉紫色 -->
|
||||||
|
<color name="darkgoldenrod">#b8860b</color><!--暗金黄色 -->
|
||||||
|
<color name="powderblue">#b0e0e6</color><!--粉蓝色 -->
|
||||||
|
<color name="lightsteelblue">#b0c4de</color><!--亮钢兰色 -->
|
||||||
|
<color name="paleturquoise">#afeeee</color><!--苍宝石绿 -->
|
||||||
|
<color name="greenyellow">#adff2f</color><!--黄绿色 -->
|
||||||
|
<color name="lightblue">#add8e6</color><!--亮蓝色 -->
|
||||||
|
<color name="darkgray">#a9a9a9</color><!--暗灰色 -->
|
||||||
|
<color name="darkgrey">#a9a9a9</color><!--暗灰色 -->
|
||||||
|
<color name="darkorchid">#9932cc</color><!--暗紫色 -->
|
||||||
|
<color name="palegreen">#98fb98</color><!--苍绿色 -->
|
||||||
|
<color name="darkviolet">#9400d3</color><!--暗紫罗兰色 -->
|
||||||
|
<color name="mediumpurple">#9370db</color><!--中紫色 -->
|
||||||
|
<color name="lightgreen">#90ee90</color><!--亮绿色 -->
|
||||||
|
<color name="darkseagreen">#8fbc8f</color><!--暗海兰色 -->
|
||||||
|
<color name="saddlebrown">#8b4513</color><!--重褐色 -->
|
||||||
|
<color name="darkmagenta">#8b008b</color><!--暗洋红 -->
|
||||||
|
<color name="darkred">#8b0000</color><!--暗红色 -->
|
||||||
|
<color name="blueviolet">#8a2be2</color><!--紫罗兰蓝色 -->
|
||||||
|
<color name="lightskyblue">#87cefa</color><!--亮天蓝色 -->
|
||||||
|
<color name="skyblue">#87ceeb</color><!--天蓝色 -->
|
||||||
|
<color name="grey">#808080</color><!--灰色 -->
|
||||||
|
<color name="lawngreen">#7cfc00</color><!--草绿色 -->
|
||||||
|
<color name="mediumslateblue">#7b68ee</color><!--中暗蓝色 -->
|
||||||
|
<color name="lightslategray">#778899</color><!--亮蓝灰 -->
|
||||||
|
<color name="lightslategrey">#778899</color><!--亮蓝灰 -->
|
||||||
|
<color name="slategray">#708090</color><!--灰石色 -->
|
||||||
|
<color name="slategrey">#708090</color><!--灰石色 -->
|
||||||
|
<color name="olivedrab">#6b8e23</color><!--深绿褐色 -->
|
||||||
|
<color name="slateblue">#6a5acd</color><!--石蓝色 -->
|
||||||
|
<color name="dimgray">#696969</color><!--暗灰色 -->
|
||||||
|
<color name="dimgrey">#696969</color><!--暗灰色 -->
|
||||||
|
<color name="mediumaquamarine">#66cdaa</color><!--中绿色 -->
|
||||||
|
<color name="cornflowerblue">#6495ed</color><!--菊兰色 -->
|
||||||
|
<color name="cadetblue">#5f9ea0</color><!--军兰色 -->
|
||||||
|
<color name="darkolivegreen">#556b2f</color><!--暗橄榄绿 -->
|
||||||
|
<color name="mediumturquoise">#48d1cc</color><!--中绿宝石 -->
|
||||||
|
<color name="darkslateblue">#483d8b</color><!--暗灰蓝色 -->
|
||||||
|
<color name="steelblue">#4682b4</color><!--钢兰色 -->
|
||||||
|
<color name="royalblue">#4169e1</color><!--皇家蓝 -->
|
||||||
|
<color name="mediumseagreen">#3cb371</color><!--中海蓝 -->
|
||||||
|
<color name="limegreen">#32cd32</color><!--橙绿色 -->
|
||||||
|
<color name="darkslategray">#2f4f4f</color><!--暗瓦灰色 -->
|
||||||
|
<color name="darkslategrey">#2f4f4f</color><!--暗瓦灰色 -->
|
||||||
|
<color name="seagreen">#2e8b57</color><!--海绿色 -->
|
||||||
|
<color name="forestgreen">#228b22</color><!--森林绿 -->
|
||||||
|
<color name="lightseagreen">#20b2aa</color><!--亮海蓝色 -->
|
||||||
|
<color name="dodgerblue">#1e90ff</color><!--闪兰色 -->
|
||||||
|
<color name="midnightblue">#191970</color><!--中灰兰色 -->
|
||||||
|
<color name="cyan">#00ffff</color><!--青色 -->
|
||||||
|
<color name="springgreen">#00ff7f</color><!--春绿色 -->
|
||||||
|
<color name="mediumspringgreen">#00fa9a</color><!--中春绿色 -->
|
||||||
|
<color name="darkturquoise">#00ced1</color><!--暗宝石绿 -->
|
||||||
|
<color name="deepskyblue">#00bfff</color><!--深天蓝色 -->
|
||||||
|
<color name="darkcyan">#008b8b</color><!--暗青色 -->
|
||||||
|
<color name="darkgreen">#006400</color><!--暗绿色 -->
|
||||||
|
<color name="mediumblue">#0000cd</color><!--中兰色 -->
|
||||||
|
<color name="darkblue">#00008b</color><!--暗蓝色 -->
|
||||||
|
<color name="black">#000000</color><!--黑色 -->
|
||||||
|
|
||||||
|
</resources>
|
||||||
6
app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">AndroidAppTemplate</string>
|
||||||
|
|
||||||
|
<!-- TODO: Remove or change this placeholder text -->
|
||||||
|
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||||
|
</resources>
|
||||||
18
app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">-->
|
||||||
|
<!-- <!– Customize your theme here. –>-->
|
||||||
|
<!-- <item name="colorPrimary">@color/colorPrimary</item>-->
|
||||||
|
<!-- <item name="colorPrimaryDark">@color/colorPrimaryDark</item>-->
|
||||||
|
<!-- <item name="colorAccent">@color/colorAccent</item>-->
|
||||||
|
<!-- </style>-->
|
||||||
|
|
||||||
|
</resources>
|
||||||
9
app/src/main/res/xml/file_paths.xml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths>
|
||||||
|
<external-path
|
||||||
|
name="files_root"
|
||||||
|
path="Android/data/com.herenit.webdoc/" />
|
||||||
|
<external-path
|
||||||
|
name="external_storage_root"
|
||||||
|
path="." />
|
||||||
|
</paths>
|
||||||
4
app/src/main/res/xml/network.xml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<base-config cleartextTrafficPermitted="true" />
|
||||||
|
</network-security-config>
|
||||||
17
app/src/test/java/com/ttstd/template/ExampleUnitTest.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package com.ttstd.template;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
public class ExampleUnitTest {
|
||||||
|
@Test
|
||||||
|
public void addition_isCorrect() {
|
||||||
|
assertEquals(4, 2 + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
35
build.gradle
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
maven { url "https://jitpack.io" }
|
||||||
|
maven {url 'http://developer.huawei.com/repo/'}
|
||||||
|
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
|
||||||
|
maven { url 'http://maven.aliyun.com/nexus/content/repositories/releases/' }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:3.6.4'
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
// in the individual module build.gradle files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
maven { url "https://jitpack.io" }
|
||||||
|
maven {url 'http://developer.huawei.com/repo/'}
|
||||||
|
maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter' }
|
||||||
|
maven { url 'http://maven.aliyun.com/nexus/content/repositories/releases/' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task clean(type: Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
||||||
20
gradle.properties
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Project-wide Gradle settings.
|
||||||
|
# IDE (e.g. Android Studio) users:
|
||||||
|
# Gradle settings configured through the IDE *will override*
|
||||||
|
# any settings specified in this file.
|
||||||
|
# For more details on how to configure your build environment visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
org.gradle.jvmargs=-Xmx1536m
|
||||||
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
|
# org.gradle.parallel=true
|
||||||
|
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||||
|
# Android operating system, and which are packaged with your app's APK
|
||||||
|
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||||
|
android.useAndroidX=true
|
||||||
|
# Automatically convert third-party libraries to use AndroidX
|
||||||
|
android.enableJetifier=true
|
||||||
|
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#Thu Dec 21 10:49:41 CST 2023
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
|
||||||
172
gradlew
vendored
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >/dev/null
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
NONSTOP* )
|
||||||
|
nonstop=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Escape application args
|
||||||
|
save () {
|
||||||
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
|
echo " "
|
||||||
|
}
|
||||||
|
APP_ARGS=$(save "$@")
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
|
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||||
|
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||||
|
cd "$(dirname "$0")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
84
gradlew.bat
vendored
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
@if "%DEBUG%" == "" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS=
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if "%ERRORLEVEL%" == "0" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto init
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:init
|
||||||
|
@rem Get command-line arguments, handling Windows variants
|
||||||
|
|
||||||
|
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||||
|
|
||||||
|
:win9xME_args
|
||||||
|
@rem Slurp the command line arguments.
|
||||||
|
set CMD_LINE_ARGS=
|
||||||
|
set _SKIP=2
|
||||||
|
|
||||||
|
:win9xME_args_slurp
|
||||||
|
if "x%~1" == "x" goto execute
|
||||||
|
|
||||||
|
set CMD_LINE_ARGS=%*
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
2
settings.gradle
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
rootProject.name='AndroidAppTemplate'
|
||||||
|
include ':app'
|
||||||