源代码备份
This commit is contained in:
8
.github/FUNDING.yml
vendored
Normal file
8
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# These are supported funding model platforms
|
||||||
|
# https://help.github.com/cn/github/administering-a-repository/displaying-a-sponsor-button-in-your-repository
|
||||||
|
# github: ["AriaLyy"]
|
||||||
|
# patreon: AriaLyy
|
||||||
|
# liberapay: Aria
|
||||||
|
open_collective: Aria
|
||||||
|
custom: ["https://paypal.me/arialyy"]
|
||||||
|
|
28
.github/ISSUE_TEMPLATE/Custom.md
vendored
Normal file
28
.github/ISSUE_TEMPLATE/Custom.md
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
name: 问题描述
|
||||||
|
about: 提交问题前,请先阅读文档和搜索issue
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!-- 提交问题前,请先阅读文档和搜索相应问题的issue -->
|
||||||
|
|
||||||
|
## 版本
|
||||||
|
* 框架版本
|
||||||
|
|
||||||
|
* 系统版本
|
||||||
|
|
||||||
|
## 错误的url
|
||||||
|
|
||||||
|
## 错误日志
|
||||||
|
<!-- 请提供详细的错误日志 -->
|
||||||
|
|
||||||
|
|
||||||
|
## 重现步骤
|
||||||
|
<!-- 请提供明确的步骤 -->
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
4.
|
||||||
|
|
||||||
|
|
||||||
|
|
20
.github/stale.yml
vendored
Normal file
20
.github/stale.yml
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Number of days of inactivity before an issue becomes stale
|
||||||
|
daysUntilStale: 7
|
||||||
|
# Number of days of inactivity before a stale issue is closed
|
||||||
|
daysUntilClose: 1000
|
||||||
|
# Issues with these labels will never be considered stale
|
||||||
|
exemptLabels:
|
||||||
|
- bug
|
||||||
|
- adaptation
|
||||||
|
- new features
|
||||||
|
- suggest
|
||||||
|
- pending
|
||||||
|
# Label to use when marking an issue as stale
|
||||||
|
staleLabel: wontfix
|
||||||
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
|
markComment: >
|
||||||
|
This issue has been automatically marked as stale because it has not had
|
||||||
|
recent activity. It will be closed if no further activity occurs. Thank you
|
||||||
|
for your contributions.
|
||||||
|
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||||
|
closeComment: false
|
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
*.iml
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
|
/downloadutil/build
|
||||||
|
/downloadutil/downloadutil.iml
|
||||||
|
/build
|
||||||
|
/captures
|
||||||
|
.externalNativeBuild
|
||||||
|
.idea/misc.xml
|
||||||
|
.gradle
|
||||||
|
/.idea
|
||||||
|
.idea
|
||||||
|
/cache
|
||||||
|
*.log
|
||||||
|
uml
|
||||||
|
*.swp
|
||||||
|
py/.history
|
4
AppFrame/.gitignore
vendored
Normal file
4
AppFrame/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
/build
|
||||||
|
mvvm2.iml
|
||||||
|
#jcenter.gradle
|
||||||
|
gradle.properties
|
201
AppFrame/LICENSE
Normal file
201
AppFrame/LICENSE
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright {yyyy} {name of copyright owner}
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
57
AppFrame/build.gradle
Normal file
57
AppFrame/build.gradle
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
apply plugin: 'com.android.library'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||||
|
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
debug{
|
||||||
|
debuggable true
|
||||||
|
}
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataBinding {
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
lintOptions {
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
api fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', {
|
||||||
|
exclude group: 'com.android.support', module: 'support-annotations'
|
||||||
|
})
|
||||||
|
testImplementation 'junit:junit:4.12'
|
||||||
|
api "androidx.appcompat:appcompat:${rootProject.ext.XAppcompatVersion}"
|
||||||
|
api 'com.google.code.gson:gson:2.8.2'
|
||||||
|
api 'io.reactivex:rxandroid:1.2.0'
|
||||||
|
api 'io.reactivex:rxjava:1.1.5'
|
||||||
|
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
|
||||||
|
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
|
||||||
|
implementation 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
|
||||||
|
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
|
||||||
|
implementation 'com.squareup.okhttp3:logging-interceptor:3.2.0'
|
||||||
|
implementation 'com.github.franmontiel:PersistentCookieJar:v1.0.1'
|
||||||
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
|
|
||||||
|
api 'androidx.lifecycle:lifecycle-runtime:2.0.0'
|
||||||
|
api 'androidx.lifecycle:lifecycle-extensions:2.0.0'
|
||||||
|
kapt 'androidx.lifecycle:lifecycle-compiler:2.0.0'
|
||||||
|
|
||||||
|
}
|
168
AppFrame/jcenter.gradle
Normal file
168
AppFrame/jcenter.gradle
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
group = PROJ_GROUP
|
||||||
|
version = PROJ_VERSION
|
||||||
|
project.archivesBaseName = PROJ_ARTIFACTID
|
||||||
|
apply plugin: 'com.jfrog.bintray'
|
||||||
|
apply plugin: "com.jfrog.artifactory"
|
||||||
|
apply plugin: 'maven-publish'
|
||||||
|
|
||||||
|
task sourcesJar(type: Jar) {
|
||||||
|
from android.sourceSets.main.java.srcDirs
|
||||||
|
classifier = 'sources'
|
||||||
|
}
|
||||||
|
|
||||||
|
task javadoc(type: Javadoc) {
|
||||||
|
source = android.sourceSets.main.java.srcDirs
|
||||||
|
classpath += configurations.compile
|
||||||
|
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
|
||||||
|
}
|
||||||
|
|
||||||
|
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||||
|
classifier = 'javadoc'
|
||||||
|
from javadoc.destinationDir
|
||||||
|
}
|
||||||
|
|
||||||
|
javadoc {
|
||||||
|
options {
|
||||||
|
encoding "UTF-8"
|
||||||
|
charSet 'UTF-8'
|
||||||
|
author true
|
||||||
|
version true
|
||||||
|
links "http://docs.oracle.com/javase/7/docs/api"
|
||||||
|
title PROJ_ARTIFACTID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//添加以下信息避免JAVADOC打包时引用其它类库而出现问题,比如出现以下错误
|
||||||
|
// xxxx.java:20: 错误: 找不到符号
|
||||||
|
// public static <T> T create(JsonElement json, Class<T> classOfModel) {
|
||||||
|
// ^
|
||||||
|
// 符号: 类 JsonElement
|
||||||
|
// 位置: 类 xxxx
|
||||||
|
android.libraryVariants.all { variant ->
|
||||||
|
println variant.javaCompile.classpath.files
|
||||||
|
if (variant.name == 'release') {
|
||||||
|
//我们只需 release 的 javadoc
|
||||||
|
task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) {
|
||||||
|
// title = ''
|
||||||
|
// description = ''
|
||||||
|
source = variant.javaCompile.source
|
||||||
|
classpath = files(variant.javaCompile.classpath.files, project.android.getBootClasspath())
|
||||||
|
options {
|
||||||
|
encoding "utf-8"
|
||||||
|
links "http://docs.oracle.com/javase/7/docs/api/"
|
||||||
|
linksOffline "http://d.android.com/reference", "${android.sdkDirectory}/docs/reference"
|
||||||
|
}
|
||||||
|
exclude '**/BuildConfig.java'
|
||||||
|
exclude '**/R.java'
|
||||||
|
}
|
||||||
|
task("javadoc${variant.name.capitalize()}Jar", type: Jar,
|
||||||
|
dependsOn: "generate${variant.name.capitalize()}Javadoc") {
|
||||||
|
classifier = 'javadoc'
|
||||||
|
from tasks.getByName("generate${variant.name.capitalize()}Javadoc").destinationDir
|
||||||
|
}
|
||||||
|
artifacts {
|
||||||
|
archives tasks.getByName("javadoc${variant.name.capitalize()}Jar")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
archives javadocJar
|
||||||
|
archives sourcesJar
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def pomConfig = {
|
||||||
|
scm {
|
||||||
|
connection PROJ_VCSURL
|
||||||
|
developerConnection PROJ_VCSURL
|
||||||
|
url PROJ_WEBSITEURL
|
||||||
|
}
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name "The Apache Software License, Version 2.0"
|
||||||
|
url "http://www.apache.org/licenses/LICENSE-2.0.txt"
|
||||||
|
distribution "repo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id DEVELOPER_ID
|
||||||
|
name DEVELOPER_NAME
|
||||||
|
email DEVELOPER_EMAIL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"dependencies " {
|
||||||
|
// dependency {
|
||||||
|
// groupId "com.alibaba"
|
||||||
|
// artifactId "fastjson"
|
||||||
|
// "version " "1.2.6"
|
||||||
|
// //同dependencies
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
mavenJava(MavenPublication) {
|
||||||
|
artifactId PROJ_ARTIFACTID
|
||||||
|
artifact javadocJar
|
||||||
|
artifact sourcesJar
|
||||||
|
|
||||||
|
pom {
|
||||||
|
packaging 'aar'
|
||||||
|
}
|
||||||
|
pom.withXml {
|
||||||
|
def root = asNode()
|
||||||
|
root.appendNode('description', PROJ_DESCRIPTION)
|
||||||
|
root.children().last() + pomConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
publishing.publications.mavenJava.artifact(bundleRelease)
|
||||||
|
}
|
||||||
|
|
||||||
|
bintray {
|
||||||
|
user = hasProperty("bintrayUser") ? getProperty("bintrayUser") : getProperty("BINTRAY_USER")
|
||||||
|
key = hasProperty("bintrayKey") ? getProperty("bintrayKey") : getProperty("BINTRAY_KEY")
|
||||||
|
|
||||||
|
configurations = ['archives']
|
||||||
|
publications = ['mavenJava']
|
||||||
|
publish = true
|
||||||
|
|
||||||
|
pkg {
|
||||||
|
repo = 'maven'
|
||||||
|
name = PROJ_NAME
|
||||||
|
desc = PROJ_DESCRIPTION
|
||||||
|
websiteUrl = PROJ_WEBSITEURL
|
||||||
|
issueTrackerUrl = PROJ_ISSUETRACKERURL
|
||||||
|
vcsUrl = PROJ_VCSURL
|
||||||
|
licenses = ['Apache-2.0']
|
||||||
|
publicDownloadNumbers = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
artifactory {
|
||||||
|
contextUrl = 'http://oss.jfrog.org/artifactory'
|
||||||
|
resolve {
|
||||||
|
repository {
|
||||||
|
repoKey = 'libs-release'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
publish {
|
||||||
|
repository {
|
||||||
|
repoKey = 'oss-snapshot-local' //The Artifactory repository key to publish to
|
||||||
|
username = bintray.user
|
||||||
|
password = bintray.key
|
||||||
|
maven = true
|
||||||
|
}
|
||||||
|
defaults {
|
||||||
|
publications('mavenJava')
|
||||||
|
publishArtifacts = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
AppFrame/proguard-rules.pro
vendored
Normal file
25
AppFrame/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# By default, the flags in this file are appended to flags specified
|
||||||
|
# in E:\sdk/tools/proguard/proguard-android.txt
|
||||||
|
# You can edit the include path and order by changing the proguardFiles
|
||||||
|
# directive in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# Add any project specific keep options here:
|
||||||
|
|
||||||
|
# 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,13 @@
|
|||||||
|
package com.lyy.frame;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.test.ApplicationTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
|
||||||
|
*/
|
||||||
|
public class ApplicationTest extends ApplicationTestCase<Application> {
|
||||||
|
public ApplicationTest() {
|
||||||
|
super(Application.class);
|
||||||
|
}
|
||||||
|
}
|
12
AppFrame/src/main/AndroidManifest.xml
Normal file
12
AppFrame/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.lyy.frame">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:supportsRtl="true">
|
||||||
|
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
13
AppFrame/src/main/java/com/arialyy/frame/base/BaseApp.java
Normal file
13
AppFrame/src/main/java/com/arialyy/frame/base/BaseApp.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package com.arialyy.frame.base;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaL on 2017/11/26.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class BaseApp {
|
||||||
|
public static Context context;
|
||||||
|
public static Application app;
|
||||||
|
}
|
105
AppFrame/src/main/java/com/arialyy/frame/base/BaseDialog.java
Normal file
105
AppFrame/src/main/java/com/arialyy/frame/base/BaseDialog.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package com.arialyy.frame.base;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
import android.animation.AnimatorSet;
|
||||||
|
import android.animation.IntEvaluator;
|
||||||
|
import android.animation.ObjectAnimator;
|
||||||
|
import android.animation.ValueAnimator;
|
||||||
|
import androidx.databinding.ViewDataBinding;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.Window;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import android.view.animation.BounceInterpolator;
|
||||||
|
import com.arialyy.frame.core.AbsDialogFragment;
|
||||||
|
import com.arialyy.frame.util.AndroidUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/12/4.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public abstract class BaseDialog<VB extends ViewDataBinding> extends AbsDialogFragment<VB> {
|
||||||
|
private WindowManager.LayoutParams mWpm;
|
||||||
|
private Window mWindow;
|
||||||
|
protected boolean useDefaultAnim = true;
|
||||||
|
|
||||||
|
@Override protected void init(Bundle savedInstanceState) {
|
||||||
|
mWindow = getDialog().getWindow();
|
||||||
|
if (mWindow != null) {
|
||||||
|
mWpm = mWindow.getAttributes();
|
||||||
|
}
|
||||||
|
if (mWpm != null && mWindow != null) {
|
||||||
|
//mView = mWindow.getDecorView();
|
||||||
|
mRootView.setBackgroundColor(Color.WHITE);
|
||||||
|
mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
|
||||||
|
//in();
|
||||||
|
if (useDefaultAnim) {
|
||||||
|
in1();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void dismiss() {
|
||||||
|
if (mWpm != null && mWindow != null) {
|
||||||
|
if (useDefaultAnim) {
|
||||||
|
out();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override protected void dataCallback(int result, Object data) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进场动画
|
||||||
|
*/
|
||||||
|
private void in() {
|
||||||
|
int height = AndroidUtils.getScreenParams(getContext())[1];
|
||||||
|
ValueAnimator animator = ValueAnimator.ofObject(new IntEvaluator(), -height / 2, 0);
|
||||||
|
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||||
|
@Override public void onAnimationUpdate(ValueAnimator animation) {
|
||||||
|
mWpm.y = (int) animation.getAnimatedValue();
|
||||||
|
mWindow.setAttributes(mWpm);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
animator.setInterpolator(new BounceInterpolator()); //弹跳
|
||||||
|
Animator alpha = ObjectAnimator.ofFloat(mRootView, "alpha", 0f, 1f);
|
||||||
|
AnimatorSet set = new AnimatorSet();
|
||||||
|
set.play(animator).with(alpha);
|
||||||
|
set.setDuration(2000).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void in1() {
|
||||||
|
Animator alpha = ObjectAnimator.ofFloat(mRootView, "alpha", 0f, 1f);
|
||||||
|
alpha.setDuration(800);
|
||||||
|
alpha.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重力动画
|
||||||
|
*/
|
||||||
|
private void out() {
|
||||||
|
int height = AndroidUtils.getScreenParams(getContext())[1];
|
||||||
|
ValueAnimator animator = ValueAnimator.ofObject(new IntEvaluator(), 0, height / 3);
|
||||||
|
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||||
|
@Override public void onAnimationUpdate(ValueAnimator animation) {
|
||||||
|
mWpm.y = (int) animation.getAnimatedValue();
|
||||||
|
mWindow.setAttributes(mWpm);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Animator alpha = ObjectAnimator.ofFloat(mRootView, "alpha", 1f, 0f);
|
||||||
|
AnimatorSet set = new AnimatorSet();
|
||||||
|
set.play(animator).with(alpha);
|
||||||
|
set.addListener(new AnimatorListenerAdapter() {
|
||||||
|
@Override public void onAnimationEnd(Animator animation) {
|
||||||
|
BaseDialog.super.dismiss();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
set.setDuration(600).start();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.arialyy.frame.base;
|
||||||
|
|
||||||
|
import androidx.databinding.ViewDataBinding;
|
||||||
|
import com.arialyy.frame.core.AbsFragment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2017/12/1.
|
||||||
|
*/
|
||||||
|
public abstract class BaseFragment<VB extends ViewDataBinding> extends AbsFragment<VB> {
|
||||||
|
public int color;
|
||||||
|
|
||||||
|
|
||||||
|
@Override protected void dataCallback(int result, Object obj) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override protected void onDelayLoad() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.arialyy.frame.base;
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel;
|
||||||
|
import com.arialyy.frame.base.net.NetManager;
|
||||||
|
import com.arialyy.frame.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaL on 2017/11/26.
|
||||||
|
* ViewModule只能是public
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class BaseViewModule extends ViewModel {
|
||||||
|
protected NetManager mNetManager;
|
||||||
|
protected String TAG = "";
|
||||||
|
|
||||||
|
public BaseViewModule() {
|
||||||
|
mNetManager = NetManager.getInstance();
|
||||||
|
TAG = StringUtil.getClassName(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
package com.arialyy.frame.base;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
public class StatusBarCompat {
|
||||||
|
private static final int INVALID_VAL = -1;
|
||||||
|
private static final int COLOR_DEFAULT = Color.parseColor("#20000000");
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
public static void compat(Activity activity, int statusColor) {
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
if (statusColor != INVALID_VAL) {
|
||||||
|
activity.getWindow().setStatusBarColor(statusColor);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT
|
||||||
|
&& Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
int color = COLOR_DEFAULT;
|
||||||
|
ViewGroup contentView = activity.findViewById(android.R.id.content);
|
||||||
|
if (statusColor != INVALID_VAL) {
|
||||||
|
color = statusColor;
|
||||||
|
}
|
||||||
|
View statusBarView = new View(activity);
|
||||||
|
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
getStatusBarHeight(activity));
|
||||||
|
statusBarView.setBackgroundColor(color);
|
||||||
|
contentView.addView(statusBarView, lp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void compat(Activity activity) {
|
||||||
|
compat(activity, INVALID_VAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getStatusBarHeight(Context context) {
|
||||||
|
int result = 0;
|
||||||
|
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
|
||||||
|
if (resourceId > 0) {
|
||||||
|
result = context.getResources().getDimensionPixelSize(resourceId);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.arialyy.frame.base.net;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义Gson描述
|
||||||
|
* Created by “Aria.Lao” on 2016/10/26.
|
||||||
|
*
|
||||||
|
* @param <T> 服务器数据实体
|
||||||
|
*/
|
||||||
|
public class BasicDeserializer<T> implements JsonDeserializer<T> {
|
||||||
|
@Override
|
||||||
|
public T deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context)
|
||||||
|
throws JsonParseException {
|
||||||
|
JsonObject root = element.getAsJsonObject();
|
||||||
|
if (JsonCodeAnalysisUtil.isSuccess(root)) {
|
||||||
|
return new Gson().fromJson(root.get("object"), typeOfT);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException(root.get("rltmsg").getAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.arialyy.frame.base.net;
|
||||||
|
|
||||||
|
import com.arialyy.frame.util.show.FL;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
import rx.Observable;
|
||||||
|
import rx.android.schedulers.AndroidSchedulers;
|
||||||
|
import rx.functions.Func1;
|
||||||
|
import rx.schedulers.Schedulers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by “Aria.Lao” on 2016/10/26.
|
||||||
|
* HTTP数据回调
|
||||||
|
*/
|
||||||
|
public abstract class HttpCallback<T> implements INetResponse<T>, Observable.Transformer<T, T> {
|
||||||
|
|
||||||
|
@Override public void onFailure(Throwable e) {
|
||||||
|
L.e("HttpCallback", FL.getExceptionString(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Observable<T> call(Observable<T> observable) {
|
||||||
|
Observable<T> tObservable = observable.subscribeOn(Schedulers.io())
|
||||||
|
.unsubscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.map(new Func1<T, T>() {
|
||||||
|
@Override public T call(T t) {
|
||||||
|
onResponse(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.onErrorReturn(new Func1<Throwable, T>() {
|
||||||
|
@Override public T call(Throwable throwable) {
|
||||||
|
onFailure(throwable);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
tObservable.subscribe();
|
||||||
|
return tObservable;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.arialyy.frame.base.net;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by “Aria.Lao” on 2016/10/25.
|
||||||
|
* 网络响应接口,所有的网络回调都要继承该接口
|
||||||
|
*
|
||||||
|
* @param <T> 数据实体结构
|
||||||
|
*/
|
||||||
|
public interface INetResponse<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网络请求成功
|
||||||
|
*/
|
||||||
|
public void onResponse(T response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求失败
|
||||||
|
*/
|
||||||
|
public void onFailure(Throwable e);
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.arialyy.frame.base.net;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaL on 2017/11/26.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class JsonCodeAnalysisUtil {
|
||||||
|
|
||||||
|
public static boolean isSuccess(JsonObject obj) {
|
||||||
|
JSONObject object = null;
|
||||||
|
try {
|
||||||
|
object = new JSONObject(obj.toString());
|
||||||
|
return object.optBoolean("success");
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
package com.arialyy.frame.base.net;
|
||||||
|
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import com.arialyy.frame.base.BaseApp;
|
||||||
|
import com.arialyy.frame.config.CommonConstant;
|
||||||
|
import com.arialyy.frame.config.NetConstant;
|
||||||
|
import com.franmontiel.persistentcookiejar.ClearableCookieJar;
|
||||||
|
import com.franmontiel.persistentcookiejar.PersistentCookieJar;
|
||||||
|
import com.franmontiel.persistentcookiejar.cache.SetCookieCache;
|
||||||
|
import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by “Aria.Lao” on 2016/10/25.
|
||||||
|
* 网络管理器
|
||||||
|
*/
|
||||||
|
public class NetManager {
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
private static volatile NetManager INSTANCE = null;
|
||||||
|
private static final long TIME_OUT = 8 * 1000;
|
||||||
|
private Retrofit mRetrofit;
|
||||||
|
private Retrofit.Builder mBuilder;
|
||||||
|
private SparseArray<GsonConverterFactory> mConverterFactorys = new SparseArray<>();
|
||||||
|
private ClearableCookieJar mCookieJar;
|
||||||
|
|
||||||
|
private NetManager() {
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NetManager getInstance() {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
INSTANCE = new NetManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
OkHttpClient okHttpClient;
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
mCookieJar = new PersistentCookieJar(new SetCookieCache(),
|
||||||
|
new SharedPrefsCookiePersistor(BaseApp.context));
|
||||||
|
//OkHttpClient okHttpClient = provideOkHttpClient();
|
||||||
|
okHttpClient = provideOkHttpClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClearableCookieJar getCookieJar() {
|
||||||
|
return mCookieJar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行网络请求
|
||||||
|
*
|
||||||
|
* @param service 服务器返回的实体类型
|
||||||
|
* @param gson gson 为传入的数据解析器,ENTITY 为 网络实体
|
||||||
|
* <pre><code>
|
||||||
|
* Gson gson = new GsonBuilder().registerTypeAdapter(new TypeToken<ENTITY>() {
|
||||||
|
* }.getType(), new BasicDeserializer<ENTITY>()).create();
|
||||||
|
*
|
||||||
|
* //如启动图,需要将‘ENTITY’替换为启动图实体‘LauncherImgEntity’
|
||||||
|
* Gson gson = new GsonBuilder().registerTypeAdapter(new TypeToken<LauncherImgEntity>() {
|
||||||
|
* }.getType(), new BasicDeserializer<LauncherImgEntity>()).create();
|
||||||
|
*
|
||||||
|
* </code></pre>
|
||||||
|
*/
|
||||||
|
public <SERVICE> SERVICE request(Class<SERVICE> service, Gson gson) {
|
||||||
|
GsonConverterFactory f = null;
|
||||||
|
if (gson == null) {
|
||||||
|
f = GsonConverterFactory.create();
|
||||||
|
} else {
|
||||||
|
f = GsonConverterFactory.create(gson);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
final Retrofit.Builder builder = new Retrofit.Builder().client(okHttpClient)
|
||||||
|
.baseUrl(NetConstant.BASE_URL)
|
||||||
|
.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
|
||||||
|
builder.addConverterFactory(f);
|
||||||
|
return builder.build().create(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建OKHTTP
|
||||||
|
*/
|
||||||
|
private OkHttpClient provideOkHttpClient() {
|
||||||
|
final OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||||
|
if (CommonConstant.DEBUG) {
|
||||||
|
//HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
|
||||||
|
//logging.setLevel(HttpLoggingInterceptor.Level.BODY);
|
||||||
|
//builder.addInterceptor(logging);
|
||||||
|
builder.addInterceptor(new OkHttpLogger());
|
||||||
|
}
|
||||||
|
builder.connectTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
|
||||||
|
.readTimeout(TIME_OUT, TimeUnit.MILLISECONDS);
|
||||||
|
builder.cookieJar(mCookieJar);
|
||||||
|
//builder.addInterceptor(chain -> {
|
||||||
|
// //String cookies = CookieUtil.getCookies();
|
||||||
|
// Request request = chain.request().newBuilder()
|
||||||
|
// //.addHeader("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
// //.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
|
||||||
|
// //.addHeader("Cookie", cookies)
|
||||||
|
// .build();
|
||||||
|
// return chain.proceed(request);
|
||||||
|
//});
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package com.arialyy.frame.base.net;
|
||||||
|
|
||||||
|
import com.arialyy.frame.util.show.FL;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import okhttp3.Headers;
|
||||||
|
import okhttp3.Interceptor;
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
import okio.Buffer;
|
||||||
|
import okio.BufferedSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Lyy on 2016/9/19.
|
||||||
|
* 自定义的 OKHTTP 日志
|
||||||
|
*/
|
||||||
|
public class OkHttpLogger implements Interceptor {
|
||||||
|
final static String TAG = "OKHTTP";
|
||||||
|
|
||||||
|
@Override public Response intercept(Chain chain) throws IOException {
|
||||||
|
Request request = chain.request();
|
||||||
|
long startNs = System.nanoTime();
|
||||||
|
Response response = chain.proceed(request);
|
||||||
|
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
|
||||||
|
ResponseBody responseBody = response.body();
|
||||||
|
long contentLength = responseBody.contentLength();
|
||||||
|
String bodySize = contentLength != -1 ? contentLength + "-byte" : "unknown-length";
|
||||||
|
L.d(TAG, "<-- "
|
||||||
|
+ response.code()
|
||||||
|
+ ' '
|
||||||
|
+ response.message()
|
||||||
|
+ ' '
|
||||||
|
+ response.request().url()
|
||||||
|
+ " ("
|
||||||
|
+ tookMs
|
||||||
|
+ "ms"
|
||||||
|
+ (", " + bodySize + " body")
|
||||||
|
+ ')');
|
||||||
|
//Headers headers = response.headers();
|
||||||
|
//for (int i = 0, count = headers.size(); i < count; i++) {
|
||||||
|
// FL.d(TAG, headers.name(i) + ": " + headers.value(i));
|
||||||
|
//}
|
||||||
|
BufferedSource source = responseBody.source();
|
||||||
|
source.request(Long.MAX_VALUE); // Buffer the entire body.
|
||||||
|
Buffer buffer = source.buffer();
|
||||||
|
Charset UTF8 = Charset.forName("UTF-8");
|
||||||
|
Charset charset = UTF8;
|
||||||
|
MediaType contentType = responseBody.contentType();
|
||||||
|
if (contentType != null) {
|
||||||
|
charset = contentType.charset(UTF8);
|
||||||
|
}
|
||||||
|
if (contentLength != 0) {
|
||||||
|
//FL.j(TAG, buffer.clone().readString(charset));
|
||||||
|
L.j(buffer.clone().readString(charset));
|
||||||
|
}
|
||||||
|
|
||||||
|
L.d(TAG, "<-- END HTTP (" + buffer.size() + "-byte body)");
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
345
AppFrame/src/main/java/com/arialyy/frame/cache/AbsCache.java
vendored
Normal file
345
AppFrame/src/main/java/com/arialyy/frame/cache/AbsCache.java
vendored
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
package com.arialyy.frame.cache;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.collection.LruCache;
|
||||||
|
import com.arialyy.frame.util.AndroidUtils;
|
||||||
|
import com.arialyy.frame.util.AppUtils;
|
||||||
|
import com.arialyy.frame.util.StreamUtil;
|
||||||
|
import com.arialyy.frame.util.StringUtil;
|
||||||
|
import com.arialyy.frame.util.show.FL;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Lyy on 2015/4/9.
|
||||||
|
* 缓存抽象类,封装了缓存的读写操作
|
||||||
|
*/
|
||||||
|
public abstract class AbsCache implements CacheParam {
|
||||||
|
private static final String TAG = "AbsCache";
|
||||||
|
/**
|
||||||
|
* 磁盘缓存工具
|
||||||
|
*/
|
||||||
|
private DiskLruCache mDiskLruCache = null;
|
||||||
|
/**
|
||||||
|
* 内存缓存工具
|
||||||
|
*/
|
||||||
|
private LruCache<String, byte[]> mMemoryCache = null;
|
||||||
|
/**
|
||||||
|
* 是否使用内存缓存
|
||||||
|
*/
|
||||||
|
private boolean useMemory = false;
|
||||||
|
private int mMaxMemory;
|
||||||
|
private Context mContext;
|
||||||
|
private static final Object mDiskCacheLock = new Object();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认使用默认路径
|
||||||
|
*
|
||||||
|
* @param useMemory 是否使用内存缓存
|
||||||
|
*/
|
||||||
|
protected AbsCache(Context context, boolean useMemory) {
|
||||||
|
this.mContext = context;
|
||||||
|
this.useMemory = useMemory;
|
||||||
|
init(DEFAULT_DIR, 1, SMALL_DISK_CACHE_CAPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定缓存文件夹
|
||||||
|
*
|
||||||
|
* @param useMemory 是否使用内存缓存
|
||||||
|
* @param cacheDir 缓存文件夹
|
||||||
|
*/
|
||||||
|
protected AbsCache(Context context, boolean useMemory, @NonNull String cacheDir) {
|
||||||
|
this.mContext = context;
|
||||||
|
this.useMemory = useMemory;
|
||||||
|
init(cacheDir, 1, SMALL_DISK_CACHE_CAPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init(String cacheDir, int valueCount, long cacheSize) {
|
||||||
|
initDiskCache(cacheDir, valueCount, cacheSize);
|
||||||
|
initMemoryCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化磁盘缓存
|
||||||
|
*/
|
||||||
|
protected void initDiskCache(String cacheDir, int valueCount, long cacheSize) {
|
||||||
|
try {
|
||||||
|
File dir = getDiskCacheDir(mContext, cacheDir);
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir.mkdirs();
|
||||||
|
}
|
||||||
|
mDiskLruCache =
|
||||||
|
DiskLruCache.open(dir, AppUtils.getVersionNumber(mContext), valueCount, cacheSize);
|
||||||
|
} catch (IOException e) {
|
||||||
|
FL.e(this, "createCacheFailed\n" + FL.getExceptionString(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化内存缓存
|
||||||
|
*/
|
||||||
|
protected void initMemoryCache() {
|
||||||
|
if (!useMemory) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 获取应用程序最大可用内存
|
||||||
|
mMaxMemory = (int) Runtime.getRuntime().maxMemory();
|
||||||
|
// 设置图片缓存大小为程序最大可用内存的1/8
|
||||||
|
mMemoryCache = new LruCache<>(mMaxMemory / 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否使用内存缓存
|
||||||
|
*/
|
||||||
|
protected void setUseMemory(boolean useMemory) {
|
||||||
|
this.useMemory = useMemory;
|
||||||
|
initMemoryCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置内存缓存大小
|
||||||
|
*/
|
||||||
|
protected void setMemoryCache(int size) {
|
||||||
|
mMemoryCache.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开某个目录下的缓存
|
||||||
|
*
|
||||||
|
* @param cacheDir 缓存目录,只需填写文件夹名,不需要写路径
|
||||||
|
* @param valueCount 指定同一个key可以对应多少个缓存文件,基本都是传1
|
||||||
|
* @param cacheSize 缓存大小
|
||||||
|
* @see CacheParam
|
||||||
|
*/
|
||||||
|
protected void openDiskCache(@NonNull String cacheDir, int valueCount, long cacheSize) {
|
||||||
|
synchronized (mDiskCacheLock) {
|
||||||
|
if (mDiskLruCache != null && mDiskLruCache.isClosed()) {
|
||||||
|
try {
|
||||||
|
File dir = getDiskCacheDir(mContext, cacheDir);
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir.mkdirs();
|
||||||
|
}
|
||||||
|
mDiskLruCache =
|
||||||
|
DiskLruCache.open(dir, AppUtils.getVersionNumber(mContext), valueCount, cacheSize);
|
||||||
|
} catch (IOException e) {
|
||||||
|
FL.e(this, "createCacheFailed\n" + FL.getExceptionString(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把缓存写入磁盘
|
||||||
|
*
|
||||||
|
* @param key 缓存的key,通过该key来读写缓存,一般是URL
|
||||||
|
* @param data 缓存的数据
|
||||||
|
*/
|
||||||
|
protected void writeDiskCache(@NonNull String key, @NonNull byte[] data) {
|
||||||
|
if (TextUtils.isEmpty(key)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String hashKey = StringUtil.keyToHashKey(key);
|
||||||
|
if (useMemory && mMemoryCache != null) {
|
||||||
|
mMemoryCache.put(hashKey, data);
|
||||||
|
}
|
||||||
|
synchronized (mDiskCacheLock) {
|
||||||
|
if (mDiskLruCache != null) {
|
||||||
|
L.i(TAG, "缓存数据到磁盘[key:" + key + ",hashKey:" + hashKey + "]");
|
||||||
|
OutputStream out = null;
|
||||||
|
try {
|
||||||
|
DiskLruCache.Editor editor = mDiskLruCache.edit(hashKey);
|
||||||
|
out = editor.newOutputStream(DISK_CACHE_INDEX);
|
||||||
|
out.write(data, 0, data.length);
|
||||||
|
editor.commit();
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
FL.e(this,
|
||||||
|
"writeDiskFailed[key:" + key + ",hashKey:" + hashKey + "]\n" + FL.getExceptionString(
|
||||||
|
e));
|
||||||
|
} finally {
|
||||||
|
if (out != null) {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从磁盘读取缓存
|
||||||
|
*
|
||||||
|
* @param key 缓存的key,一般是原来的url
|
||||||
|
* @return 缓存数据
|
||||||
|
*/
|
||||||
|
protected byte[] readDiskCache(@NonNull String key) {
|
||||||
|
if (TextUtils.isEmpty(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String hashKey = StringUtil.keyToHashKey(key);
|
||||||
|
if (useMemory && mMemoryCache != null) {
|
||||||
|
final byte[] data = mMemoryCache.get(hashKey);
|
||||||
|
if (data != null && data.length != 0) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
synchronized (mDiskCacheLock) {
|
||||||
|
byte[] data = null;
|
||||||
|
L.i(TAG, "读取磁盘缓存数据[key:" + key + ",hashKey:" + hashKey + "]");
|
||||||
|
InputStream inputStream = null;
|
||||||
|
try {
|
||||||
|
DiskLruCache.Snapshot snapshot = mDiskLruCache.get(hashKey);
|
||||||
|
if (snapshot != null) {
|
||||||
|
inputStream = snapshot.getInputStream(DISK_CACHE_INDEX);
|
||||||
|
data = StreamUtil.readStream(inputStream);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
FL.e(this, "readDiskCacheFailed[key:"
|
||||||
|
+ key
|
||||||
|
+ ",hashKey:"
|
||||||
|
+ hashKey
|
||||||
|
+ "]\n"
|
||||||
|
+ FL.getExceptionString(e));
|
||||||
|
} catch (Exception e) {
|
||||||
|
FL.e(this, "readDiskCacheFailed[key:"
|
||||||
|
+ key
|
||||||
|
+ ",hashKey:"
|
||||||
|
+ hashKey
|
||||||
|
+ "]\n"
|
||||||
|
+ FL.getExceptionString(e));
|
||||||
|
} finally {
|
||||||
|
if (inputStream != null) {
|
||||||
|
try {
|
||||||
|
inputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除一条缓存
|
||||||
|
*
|
||||||
|
* @param key 该缓存的key
|
||||||
|
*/
|
||||||
|
protected void removeCache(@NonNull String key) {
|
||||||
|
String hashKey = StringUtil.keyToHashKey(key);
|
||||||
|
if (mMemoryCache != null) {
|
||||||
|
mMemoryCache.remove(hashKey);
|
||||||
|
}
|
||||||
|
synchronized (mDiskCacheLock) {
|
||||||
|
if (mDiskLruCache != null) {
|
||||||
|
try {
|
||||||
|
mDiskLruCache.remove(hashKey);
|
||||||
|
} catch (IOException e) {
|
||||||
|
FL.e(this, "removeCacheFailed[key:"
|
||||||
|
+ key
|
||||||
|
+ ",hashKey:"
|
||||||
|
+ hashKey
|
||||||
|
+ "]\n"
|
||||||
|
+ FL.getExceptionString(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除所有缓存
|
||||||
|
*/
|
||||||
|
protected void clearCache() {
|
||||||
|
if (mMemoryCache != null) {
|
||||||
|
mMemoryCache.evictAll();
|
||||||
|
}
|
||||||
|
synchronized (mDiskCacheLock) {
|
||||||
|
if (mDiskLruCache != null) {
|
||||||
|
try {
|
||||||
|
mDiskLruCache.delete();
|
||||||
|
} catch (IOException e) {
|
||||||
|
FL.e(this, "clearCacheFailed" + FL.getExceptionString(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭磁盘缓存,注意:
|
||||||
|
* 这个方法用于将DiskLruCache关闭掉,是和open()方法对应的一个方法。
|
||||||
|
* 关闭掉了之后就不能再调用DiskLruCache中任何操作缓存数据的方法,
|
||||||
|
* 通常只应该在Activity的onDestroy()方法中去调用close()方法。
|
||||||
|
*/
|
||||||
|
protected void closeDiskCache() {
|
||||||
|
synchronized (mDiskCacheLock) {
|
||||||
|
if (mDiskLruCache != null) {
|
||||||
|
try {
|
||||||
|
mDiskLruCache.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
FL.e(this, "closeDiskCacheFailed" + FL.getExceptionString(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步内存中的缓存操作记录到日志文件(也就是journal文件)
|
||||||
|
* 注意:在写入缓存时需要flush同步一次,并不是每次写入缓存都要调用一次flush()方法的,频繁地调用并不会带来任何好处,
|
||||||
|
* 只会额外增加同步journal文件的时间。比较标准的做法就是在Activity的onPause()方法中去调用一次flush()方法就可以了
|
||||||
|
*/
|
||||||
|
protected void flushDiskCache() {
|
||||||
|
synchronized (mDiskCacheLock) {
|
||||||
|
if (mDiskLruCache != null) {
|
||||||
|
try {
|
||||||
|
mDiskLruCache.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
FL.e(this, "flushDiskCacheFailed" + FL.getExceptionString(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存大小
|
||||||
|
*/
|
||||||
|
protected long getCacheSize() {
|
||||||
|
return mDiskLruCache.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换byte数组为String
|
||||||
|
*/
|
||||||
|
private static String bytesToHexString(byte[] bytes) {
|
||||||
|
// http://stackoverflow.com/questions/332079
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (byte aByte : bytes) {
|
||||||
|
String hex = Integer.toHexString(0xFF & aByte);
|
||||||
|
if (hex.length() == 1) {
|
||||||
|
sb.append('0');
|
||||||
|
}
|
||||||
|
sb.append(hex);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成缓存文件夹
|
||||||
|
*
|
||||||
|
* @param uniqueName 缓存文件夹名
|
||||||
|
* @return 缓存文件夹
|
||||||
|
*/
|
||||||
|
public static File getDiskCacheDir(Context context, String uniqueName) {
|
||||||
|
return new File(AndroidUtils.getDiskCacheDir(context) + File.separator + uniqueName);
|
||||||
|
}
|
||||||
|
}
|
37
AppFrame/src/main/java/com/arialyy/frame/cache/CacheParam.java
vendored
Normal file
37
AppFrame/src/main/java/com/arialyy/frame/cache/CacheParam.java
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package com.arialyy.frame.cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Lyy on 2015/4/9.
|
||||||
|
* 缓存参数
|
||||||
|
*/
|
||||||
|
public interface CacheParam {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 磁盘缓存
|
||||||
|
*/
|
||||||
|
public static final int DISK_CACHE = 0;
|
||||||
|
/**
|
||||||
|
* 默认缓存目录文件夹名
|
||||||
|
*/
|
||||||
|
public static final String DEFAULT_DIR = "defaultDir";
|
||||||
|
/**
|
||||||
|
* 内存缓存
|
||||||
|
*/
|
||||||
|
public static final int MEMORY_CACHE_SIZE = 1;
|
||||||
|
/**
|
||||||
|
* 小容量磁盘缓存
|
||||||
|
*/
|
||||||
|
public static final long SMALL_DISK_CACHE_CAPACITY = 4 * 1024 * 1024;
|
||||||
|
/**
|
||||||
|
* 中型容量磁盘缓存
|
||||||
|
*/
|
||||||
|
public static final long NORMAL_DISK_CACHE_CAPACITY = 10 * 1024 * 1024;
|
||||||
|
/**
|
||||||
|
* 大容量磁盘缓存
|
||||||
|
*/
|
||||||
|
public static final long LARGER_DISKCACHE_CAPACITY = 20 * 1024 * 1024;
|
||||||
|
/**
|
||||||
|
* 缓存index
|
||||||
|
*/
|
||||||
|
public static final int DISK_CACHE_INDEX = 0;
|
||||||
|
}
|
196
AppFrame/src/main/java/com/arialyy/frame/cache/CacheUtil.java
vendored
Normal file
196
AppFrame/src/main/java/com/arialyy/frame/cache/CacheUtil.java
vendored
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
package com.arialyy.frame.cache;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import com.arialyy.frame.util.DrawableUtil;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaLyy on 2015/4/9.
|
||||||
|
* 缓存工具
|
||||||
|
*/
|
||||||
|
public class CacheUtil extends AbsCache {
|
||||||
|
private static final String TAG = "CacheUtil";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认使用默认路径
|
||||||
|
*
|
||||||
|
* @param useMemory 是否使用内存缓存
|
||||||
|
*/
|
||||||
|
public CacheUtil(Context context, boolean useMemory) {
|
||||||
|
super(context, useMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定缓存文件夹
|
||||||
|
*
|
||||||
|
* @param useMemory 是否使用内存缓存
|
||||||
|
* @param cacheDir 缓存文件夹
|
||||||
|
*/
|
||||||
|
public CacheUtil(Context context, boolean useMemory, @NonNull String cacheDir) {
|
||||||
|
super(context, useMemory, cacheDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置是否使用内存缓存
|
||||||
|
*/
|
||||||
|
public void setUseMemoryCache(boolean useMemoryCache) {
|
||||||
|
setUseMemory(useMemoryCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开某个目录下的缓存
|
||||||
|
*
|
||||||
|
* @param cacheDir 缓存目录,只需填写文件夹名,不需要写路径
|
||||||
|
* @param valueCount 指定同一个key可以对应多少个缓存文件,基本都是传1
|
||||||
|
* @param cacheSize 缓存大小
|
||||||
|
* @see CacheParam
|
||||||
|
*/
|
||||||
|
public void openCache(String cacheDir, int valueCount, long cacheSize) {
|
||||||
|
openDiskCache(cacheDir, valueCount, cacheSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入Bitmap类型缓存,注意:需要在特定的时候flush,一般在onPause()里面写,onDestroy()
|
||||||
|
*
|
||||||
|
* @param key 键值,一般是url
|
||||||
|
* @param bitmap 需要写入的数据
|
||||||
|
*/
|
||||||
|
public void putBitmapCache(String key, Bitmap bitmap) {
|
||||||
|
byte[] data = DrawableUtil.getBitmapByte(bitmap);
|
||||||
|
putByteCache(key, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存中的bitmap
|
||||||
|
*/
|
||||||
|
public Bitmap getBitmapCache(String key) {
|
||||||
|
byte[] data = getByteCache(key);
|
||||||
|
return DrawableUtil.getBitmapFromByte(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入String类型缓存,注意:需要在特定的时候flush,一般在onPause()里面写,onDestroy()
|
||||||
|
*
|
||||||
|
* @param key 键值,一般是url
|
||||||
|
* @param data 需要写入的数据
|
||||||
|
*/
|
||||||
|
public void putStringCache(String key, String data) {
|
||||||
|
try {
|
||||||
|
putByteCache(key, data.getBytes("utf-8"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取字符串缓存
|
||||||
|
*/
|
||||||
|
public String getStringCache(String key) {
|
||||||
|
byte[] data = getByteCache(key);
|
||||||
|
String str = "";
|
||||||
|
if (data != null) {
|
||||||
|
try {
|
||||||
|
str = new String(data, "utf-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入byte类型缓存,注意:需要在特定的时候flush,一般在onPause()里面写,onDestroy()
|
||||||
|
*
|
||||||
|
* @param key 键值,一般是url
|
||||||
|
* @param data 需要写入的数据
|
||||||
|
*/
|
||||||
|
public void putByteCache(String key, byte[] data) {
|
||||||
|
writeDiskCache(key, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取byte类型缓存
|
||||||
|
*
|
||||||
|
* @param key 缓存的key
|
||||||
|
*/
|
||||||
|
public byte[] getByteCache(String key) {
|
||||||
|
return readDiskCache(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入对象缓存后,注意:需要在特定的时候flush,一般在onPause()里面写,onDestroy()
|
||||||
|
*
|
||||||
|
* @param clazz 对象类型
|
||||||
|
* @param key 缓存键值
|
||||||
|
* @param object 对象
|
||||||
|
*/
|
||||||
|
public void putObjectCache(Class<?> clazz, String key, Object object) {
|
||||||
|
String json = new Gson().toJson(object, clazz);
|
||||||
|
try {
|
||||||
|
writeDiskCache(key, json.getBytes("utf-8"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
L.e(TAG, "编码转换错误", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取对象缓存
|
||||||
|
*
|
||||||
|
* @param clazz 对象类型
|
||||||
|
* @param key 缓存键值
|
||||||
|
*/
|
||||||
|
public <T> T getObjectCache(Class<T> clazz, String key) {
|
||||||
|
T object = null;
|
||||||
|
try {
|
||||||
|
byte[] data = readDiskCache(key);
|
||||||
|
if (data == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
object = new Gson().fromJson(new String(data, "utf-8"), clazz);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
L.e(TAG, "编码转换错误", e);
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步记录,不同步则提取不了缓存
|
||||||
|
*/
|
||||||
|
public void flush() {
|
||||||
|
flushDiskCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除一条缓存
|
||||||
|
*
|
||||||
|
* @param key 缓存键值
|
||||||
|
*/
|
||||||
|
public void remove(String key) {
|
||||||
|
readDiskCache(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除所有缓存
|
||||||
|
*/
|
||||||
|
public void removeAll() {
|
||||||
|
clearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭磁盘缓存
|
||||||
|
*/
|
||||||
|
public void close() {
|
||||||
|
closeDiskCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存大小
|
||||||
|
*/
|
||||||
|
public long getCacheSize() {
|
||||||
|
return super.getCacheSize();
|
||||||
|
}
|
||||||
|
}
|
967
AppFrame/src/main/java/com/arialyy/frame/cache/DiskLruCache.java
vendored
Normal file
967
AppFrame/src/main/java/com/arialyy/frame/cache/DiskLruCache.java
vendored
Normal file
@ -0,0 +1,967 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.arialyy.frame.cache;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.EOFException;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.FilterOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* *****************************************************************************
|
||||||
|
* Taken from the JB source code, can be found in:
|
||||||
|
* libcore/luni/src/main/java/libcore/io/DiskLruCache.java
|
||||||
|
* or direct link:
|
||||||
|
* https://android.googlesource.com/platform/libcore/+/android-4.1.1_r1/luni/src/main/java/libcore/io/DiskLruCache.java
|
||||||
|
* *****************************************************************************
|
||||||
|
*
|
||||||
|
* A cache that uses a bounded amount of space on a filesystem. Each cache
|
||||||
|
* entry has a string key and a fixed number of values. Values are byte
|
||||||
|
* sequences, accessible as streams or files. Each value must be between {@code
|
||||||
|
* 0} and {@code Integer.MAX_VALUE} bytes in length.
|
||||||
|
*
|
||||||
|
* The cache stores its data in a directory on the filesystem. This
|
||||||
|
* directory must be exclusive to the cache; the cache may delete or overwrite
|
||||||
|
* files from its directory. It is an error for multiple processes to use the
|
||||||
|
* same cache directory at the same time.
|
||||||
|
*
|
||||||
|
* This cache limits the number of bytes that it will store on the
|
||||||
|
* filesystem. When the number of stored bytes exceeds the limit, the cache will
|
||||||
|
* remove entries in the background until the limit is satisfied. The limit is
|
||||||
|
* not strict: the cache may temporarily exceed it while waiting for files to be
|
||||||
|
* deleted. The limit does not include filesystem overhead or the cache
|
||||||
|
* journal so space-sensitive applications should set a conservative limit.
|
||||||
|
*
|
||||||
|
* Clients call {@link #edit} to create or update the values of an entry. An
|
||||||
|
* entry may have only one editor at one time; if a value is not available to be
|
||||||
|
* edited then {@link #edit} will return null.
|
||||||
|
*
|
||||||
|
* When an entry is being <strong>created</strong> it is necessary to
|
||||||
|
* supply a full set of values; the empty value should be used as a
|
||||||
|
* placeholder if necessary.
|
||||||
|
* When an entry is being <strong>edited</strong>, it is not necessary
|
||||||
|
* to supply data for every value; values default to their previous
|
||||||
|
* value.
|
||||||
|
*
|
||||||
|
* Clients call {@link #get} to read a snapshot of an entry. The read will
|
||||||
|
* observe the value at the time that {@link #get} was called. Updates and
|
||||||
|
* removals after the call do not impact ongoing reads.
|
||||||
|
*
|
||||||
|
* This class is tolerant of some I/O errors. If files are missing from the
|
||||||
|
* filesystem, the corresponding entries will be dropped from the cache. If
|
||||||
|
* an error occurs while writing a cache value, the edit will fail silently.
|
||||||
|
* Callers should handle other problems by catching {@code IOException} and
|
||||||
|
* responding appropriately.
|
||||||
|
*/
|
||||||
|
public final class DiskLruCache implements Closeable {
|
||||||
|
static final String JOURNAL_FILE = "journal";
|
||||||
|
static final String JOURNAL_FILE_TMP = "journal.tmp";
|
||||||
|
static final String MAGIC = "libcore.io.DiskLruCache";
|
||||||
|
static final String VERSION_1 = "1";
|
||||||
|
static final long ANY_SEQUENCE_NUMBER = -1;
|
||||||
|
private static final String CLEAN = "CLEAN";
|
||||||
|
private static final String DIRTY = "DIRTY";
|
||||||
|
private static final String REMOVE = "REMOVE";
|
||||||
|
private static final String READ = "READ";
|
||||||
|
|
||||||
|
private static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||||
|
private static final int IO_BUFFER_SIZE = 8 * 1024;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This cache uses a journal file named "journal". A typical journal file
|
||||||
|
* looks like this:
|
||||||
|
* libcore.io.DiskLruCache
|
||||||
|
* 1
|
||||||
|
* 100
|
||||||
|
* 2
|
||||||
|
*
|
||||||
|
* CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
|
||||||
|
* DIRTY 335c4c6028171cfddfbaae1a9c313c52
|
||||||
|
* CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
|
||||||
|
* REMOVE 335c4c6028171cfddfbaae1a9c313c52
|
||||||
|
* DIRTY 1ab96a171faeeee38496d8b330771a7a
|
||||||
|
* CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
|
||||||
|
* READ 335c4c6028171cfddfbaae1a9c313c52
|
||||||
|
* READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
|
||||||
|
*
|
||||||
|
* The first five lines of the journal form its header. They are the
|
||||||
|
* constant string "libcore.io.DiskLruCache", the disk cache's version,
|
||||||
|
* the application's version, the value count, and a blank line.
|
||||||
|
*
|
||||||
|
* Each of the subsequent lines in the file is a record of the state of a
|
||||||
|
* cache entry. Each line contains space-separated values: a state, a key,
|
||||||
|
* and optional state-specific values.
|
||||||
|
* o DIRTY lines track that an entry is actively being created or updated.
|
||||||
|
* Every successful DIRTY action should be followed by a CLEAN or REMOVE
|
||||||
|
* action. DIRTY lines without a matching CLEAN or REMOVE indicate that
|
||||||
|
* temporary files may need to be deleted.
|
||||||
|
* o CLEAN lines track a cache entry that has been successfully published
|
||||||
|
* and may be read. A publish line is followed by the lengths of each of
|
||||||
|
* its values.
|
||||||
|
* o READ lines track accesses for LRU.
|
||||||
|
* o REMOVE lines track entries that have been deleted.
|
||||||
|
*
|
||||||
|
* The journal file is appended to as cache operations occur. The journal may
|
||||||
|
* occasionally be compacted by dropping redundant lines. A temporary file named
|
||||||
|
* "journal.tmp" will be used during compaction; that file should be deleted if
|
||||||
|
* it exists when the cache is opened.
|
||||||
|
*/
|
||||||
|
|
||||||
|
private final File directory;
|
||||||
|
private final File journalFile;
|
||||||
|
private final File journalFileTmp;
|
||||||
|
private final int appVersion;
|
||||||
|
private final long maxSize;
|
||||||
|
private final int valueCount;
|
||||||
|
private long size = 0;
|
||||||
|
private Writer journalWriter;
|
||||||
|
private final LinkedHashMap<String, Entry> lruEntries =
|
||||||
|
new LinkedHashMap<String, Entry>(0, 0.75f, true);
|
||||||
|
private int redundantOpCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To differentiate between old and current snapshots, each entry is given
|
||||||
|
* a sequence number each time an edit is committed. A snapshot is stale if
|
||||||
|
* its sequence number is not equal to its entry's sequence number.
|
||||||
|
*/
|
||||||
|
private long nextSequenceNumber = 0;
|
||||||
|
|
||||||
|
/* From java.util.Arrays */
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <T> T[] copyOfRange(T[] original, int start, int end) {
|
||||||
|
final int originalLength = original.length; // For exception priority compatibility.
|
||||||
|
if (start > end) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
if (start < 0 || start > originalLength) {
|
||||||
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
final int resultLength = end - start;
|
||||||
|
final int copyLength = Math.min(resultLength, originalLength - start);
|
||||||
|
final T[] result =
|
||||||
|
(T[]) Array.newInstance(original.getClass().getComponentType(), resultLength);
|
||||||
|
System.arraycopy(original, start, result, 0, copyLength);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the remainder of 'reader' as a string, closing it when done.
|
||||||
|
*/
|
||||||
|
public static String readFully(Reader reader) throws IOException {
|
||||||
|
try {
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
char[] buffer = new char[1024];
|
||||||
|
int count;
|
||||||
|
while ((count = reader.read(buffer)) != -1) {
|
||||||
|
writer.write(buffer, 0, count);
|
||||||
|
}
|
||||||
|
return writer.toString();
|
||||||
|
} finally {
|
||||||
|
reader.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the ASCII characters up to but not including the next "\r\n", or
|
||||||
|
* "\n".
|
||||||
|
*
|
||||||
|
* @throws EOFException if the stream is exhausted before the next newline
|
||||||
|
* character.
|
||||||
|
*/
|
||||||
|
public static String readAsciiLine(InputStream in) throws IOException {
|
||||||
|
|
||||||
|
StringBuilder result = new StringBuilder(80);
|
||||||
|
while (true) {
|
||||||
|
int c = in.read();
|
||||||
|
if (c == -1) {
|
||||||
|
throw new EOFException();
|
||||||
|
} else if (c == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.append((char) c);
|
||||||
|
}
|
||||||
|
int length = result.length();
|
||||||
|
if (length > 0 && result.charAt(length - 1) == '\r') {
|
||||||
|
result.setLength(length - 1);
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null.
|
||||||
|
*/
|
||||||
|
public static void closeQuietly(Closeable closeable) {
|
||||||
|
if (closeable != null) {
|
||||||
|
try {
|
||||||
|
closeable.close();
|
||||||
|
} catch (RuntimeException rethrown) {
|
||||||
|
throw rethrown;
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively delete everything in {@code dir}.
|
||||||
|
*/
|
||||||
|
public static void deleteContents(File dir) throws IOException {
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
throw new IllegalArgumentException("not a directory: " + dir);
|
||||||
|
}
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
deleteContents(file);
|
||||||
|
}
|
||||||
|
if (!file.delete()) {
|
||||||
|
throw new IOException("failed to delete file: " + file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This cache uses a single background thread to evict entries.
|
||||||
|
*/
|
||||||
|
private final ExecutorService executorService =
|
||||||
|
new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||||
|
private final Callable<Void> cleanupCallable = new Callable<Void>() {
|
||||||
|
@Override
|
||||||
|
public Void call() throws Exception {
|
||||||
|
synchronized (DiskLruCache.this) {
|
||||||
|
if (journalWriter == null) {
|
||||||
|
return null; // closed
|
||||||
|
}
|
||||||
|
trimToSize();
|
||||||
|
if (journalRebuildRequired()) {
|
||||||
|
rebuildJournal();
|
||||||
|
redundantOpCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
|
||||||
|
this.directory = directory;
|
||||||
|
this.appVersion = appVersion;
|
||||||
|
this.journalFile = new File(directory, JOURNAL_FILE);
|
||||||
|
this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP);
|
||||||
|
this.valueCount = valueCount;
|
||||||
|
this.maxSize = maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the cache in {@code directory}, creating a cache if none exists
|
||||||
|
* there.
|
||||||
|
*
|
||||||
|
* @param directory a writable directory
|
||||||
|
* @param valueCount the number of values per cache entry. Must be positive.
|
||||||
|
* @param maxSize the maximum number of bytes this cache should use to store
|
||||||
|
* @throws IOException if reading or writing the cache directory fails
|
||||||
|
*/
|
||||||
|
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
|
||||||
|
throws IOException {
|
||||||
|
if (maxSize <= 0) {
|
||||||
|
throw new IllegalArgumentException("maxSize <= 0");
|
||||||
|
}
|
||||||
|
if (valueCount <= 0) {
|
||||||
|
throw new IllegalArgumentException("valueCount <= 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefer to pick up where we left off
|
||||||
|
DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
|
||||||
|
if (cache.journalFile.exists()) {
|
||||||
|
try {
|
||||||
|
cache.readJournal();
|
||||||
|
cache.processJournal();
|
||||||
|
cache.journalWriter =
|
||||||
|
new BufferedWriter(new FileWriter(cache.journalFile, true), IO_BUFFER_SIZE);
|
||||||
|
return cache;
|
||||||
|
} catch (IOException journalIsCorrupt) {
|
||||||
|
// System.logW("DiskLruCache " + directory + " is corrupt: "
|
||||||
|
// + journalIsCorrupt.getMessage() + ", removing");
|
||||||
|
cache.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new empty cache
|
||||||
|
directory.mkdirs();
|
||||||
|
cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
|
||||||
|
cache.rebuildJournal();
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readJournal() throws IOException {
|
||||||
|
InputStream in = new BufferedInputStream(new FileInputStream(journalFile), IO_BUFFER_SIZE);
|
||||||
|
try {
|
||||||
|
String magic = readAsciiLine(in);
|
||||||
|
String version = readAsciiLine(in);
|
||||||
|
String appVersionString = readAsciiLine(in);
|
||||||
|
String valueCountString = readAsciiLine(in);
|
||||||
|
String blank = readAsciiLine(in);
|
||||||
|
if (!MAGIC.equals(magic) || !VERSION_1.equals(version) || !Integer.toString(appVersion)
|
||||||
|
.equals(appVersionString) || !Integer.toString(valueCount).equals(valueCountString) || !""
|
||||||
|
.equals(blank)) {
|
||||||
|
throw new IOException("unexpected journal header: ["
|
||||||
|
+ magic
|
||||||
|
+ ", "
|
||||||
|
+ version
|
||||||
|
+ ", "
|
||||||
|
+ valueCountString
|
||||||
|
+ ", "
|
||||||
|
+ blank
|
||||||
|
+ "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
readJournalLine(readAsciiLine(in));
|
||||||
|
} catch (EOFException endOfJournal) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
closeQuietly(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readJournalLine(String line) throws IOException {
|
||||||
|
String[] parts = line.split(" ");
|
||||||
|
if (parts.length < 2) {
|
||||||
|
throw new IOException("unexpected journal line: " + line);
|
||||||
|
}
|
||||||
|
|
||||||
|
String key = parts[1];
|
||||||
|
if (parts[0].equals(REMOVE) && parts.length == 2) {
|
||||||
|
lruEntries.remove(key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry entry = lruEntries.get(key);
|
||||||
|
if (entry == null) {
|
||||||
|
entry = new Entry(key);
|
||||||
|
lruEntries.put(key, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) {
|
||||||
|
entry.readable = true;
|
||||||
|
entry.currentEditor = null;
|
||||||
|
entry.setLengths(copyOfRange(parts, 2, parts.length));
|
||||||
|
} else if (parts[0].equals(DIRTY) && parts.length == 2) {
|
||||||
|
entry.currentEditor = new Editor(entry);
|
||||||
|
} else if (parts[0].equals(READ) && parts.length == 2) {
|
||||||
|
// this work was already done by calling lruEntries.get()
|
||||||
|
} else {
|
||||||
|
throw new IOException("unexpected journal line: " + line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the initial size and collects garbage as a part of opening the
|
||||||
|
* cache. Dirty entries are assumed to be inconsistent and will be deleted.
|
||||||
|
*/
|
||||||
|
private void processJournal() throws IOException {
|
||||||
|
deleteIfExists(journalFileTmp);
|
||||||
|
for (Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) {
|
||||||
|
Entry entry = i.next();
|
||||||
|
if (entry.currentEditor == null) {
|
||||||
|
for (int t = 0; t < valueCount; t++) {
|
||||||
|
size += entry.lengths[t];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entry.currentEditor = null;
|
||||||
|
for (int t = 0; t < valueCount; t++) {
|
||||||
|
deleteIfExists(entry.getCleanFile(t));
|
||||||
|
deleteIfExists(entry.getDirtyFile(t));
|
||||||
|
}
|
||||||
|
i.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new journal that omits redundant information. This replaces the
|
||||||
|
* current journal if it exists.
|
||||||
|
*/
|
||||||
|
private synchronized void rebuildJournal() throws IOException {
|
||||||
|
if (journalWriter != null) {
|
||||||
|
journalWriter.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
Writer writer = new BufferedWriter(new FileWriter(journalFileTmp), IO_BUFFER_SIZE);
|
||||||
|
writer.write(MAGIC);
|
||||||
|
writer.write("\n");
|
||||||
|
writer.write(VERSION_1);
|
||||||
|
writer.write("\n");
|
||||||
|
writer.write(Integer.toString(appVersion));
|
||||||
|
writer.write("\n");
|
||||||
|
writer.write(Integer.toString(valueCount));
|
||||||
|
writer.write("\n");
|
||||||
|
writer.write("\n");
|
||||||
|
|
||||||
|
for (Entry entry : lruEntries.values()) {
|
||||||
|
if (entry.currentEditor != null) {
|
||||||
|
writer.write(DIRTY + ' ' + entry.key + '\n');
|
||||||
|
} else {
|
||||||
|
writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.close();
|
||||||
|
journalFileTmp.renameTo(journalFile);
|
||||||
|
journalWriter = new BufferedWriter(new FileWriter(journalFile, true), IO_BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void deleteIfExists(File file) throws IOException {
|
||||||
|
// try {
|
||||||
|
// Libcore.os.remove(file.getPath());
|
||||||
|
// } catch (ErrnoException errnoException) {
|
||||||
|
// if (errnoException.errno != OsConstants.ENOENT) {
|
||||||
|
// throw errnoException.rethrowAsIOException();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
if (file.exists() && !file.delete()) {
|
||||||
|
throw new IOException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a snapshot of the entry named {@code key}, or null if it doesn't
|
||||||
|
* exist is not currently readable. If a value is returned, it is moved to
|
||||||
|
* the head of the LRU queue.
|
||||||
|
*/
|
||||||
|
public synchronized Snapshot get(String key) throws IOException {
|
||||||
|
checkNotClosed();
|
||||||
|
validateKey(key);
|
||||||
|
Entry entry = lruEntries.get(key);
|
||||||
|
if (entry == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!entry.readable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open all streams eagerly to guarantee that we see a single published
|
||||||
|
* snapshot. If we opened streams lazily then the streams could come
|
||||||
|
* from different edits.
|
||||||
|
*/
|
||||||
|
InputStream[] ins = new InputStream[valueCount];
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < valueCount; i++) {
|
||||||
|
ins[i] = new FileInputStream(entry.getCleanFile(i));
|
||||||
|
}
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
// a file must have been deleted manually!
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
redundantOpCount++;
|
||||||
|
journalWriter.append(READ + ' ' + key + '\n');
|
||||||
|
if (journalRebuildRequired()) {
|
||||||
|
executorService.submit(cleanupCallable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Snapshot(key, entry.sequenceNumber, ins);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an editor for the entry named {@code key}, or null if another
|
||||||
|
* edit is in progress.
|
||||||
|
*/
|
||||||
|
public Editor edit(String key) throws IOException {
|
||||||
|
return edit(key, ANY_SEQUENCE_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
|
||||||
|
checkNotClosed();
|
||||||
|
validateKey(key);
|
||||||
|
Entry entry = lruEntries.get(key);
|
||||||
|
if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null
|
||||||
|
|| entry.sequenceNumber != expectedSequenceNumber)) {
|
||||||
|
return null; // snapshot is stale
|
||||||
|
}
|
||||||
|
if (entry == null) {
|
||||||
|
entry = new Entry(key);
|
||||||
|
lruEntries.put(key, entry);
|
||||||
|
} else if (entry.currentEditor != null) {
|
||||||
|
return null; // another edit is in progress
|
||||||
|
}
|
||||||
|
|
||||||
|
Editor editor = new Editor(entry);
|
||||||
|
entry.currentEditor = editor;
|
||||||
|
|
||||||
|
// flush the journal before creating files to prevent file leaks
|
||||||
|
journalWriter.write(DIRTY + ' ' + key + '\n');
|
||||||
|
journalWriter.flush();
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the directory where this cache stores its data.
|
||||||
|
*/
|
||||||
|
public File getDirectory() {
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of bytes that this cache should use to store
|
||||||
|
* its data.
|
||||||
|
*/
|
||||||
|
public long maxSize() {
|
||||||
|
return maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes currently being used to store the values in
|
||||||
|
* this cache. This may be greater than the max size if a background
|
||||||
|
* deletion is pending.
|
||||||
|
*/
|
||||||
|
public synchronized long size() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void completeEdit(Editor editor, boolean success) throws IOException {
|
||||||
|
Entry entry = editor.entry;
|
||||||
|
if (entry.currentEditor != editor) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this edit is creating the entry for the first time, every index must have a value
|
||||||
|
if (success && !entry.readable) {
|
||||||
|
for (int i = 0; i < valueCount; i++) {
|
||||||
|
if (!entry.getDirtyFile(i).exists()) {
|
||||||
|
editor.abort();
|
||||||
|
throw new IllegalStateException("edit didn't create file " + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < valueCount; i++) {
|
||||||
|
File dirty = entry.getDirtyFile(i);
|
||||||
|
if (success) {
|
||||||
|
if (dirty.exists()) {
|
||||||
|
File clean = entry.getCleanFile(i);
|
||||||
|
dirty.renameTo(clean);
|
||||||
|
long oldLength = entry.lengths[i];
|
||||||
|
long newLength = clean.length();
|
||||||
|
entry.lengths[i] = newLength;
|
||||||
|
size = size - oldLength + newLength;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
deleteIfExists(dirty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
redundantOpCount++;
|
||||||
|
entry.currentEditor = null;
|
||||||
|
if (entry.readable | success) {
|
||||||
|
entry.readable = true;
|
||||||
|
journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
|
||||||
|
if (success) {
|
||||||
|
entry.sequenceNumber = nextSequenceNumber++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lruEntries.remove(entry.key);
|
||||||
|
journalWriter.write(REMOVE + ' ' + entry.key + '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > maxSize || journalRebuildRequired()) {
|
||||||
|
executorService.submit(cleanupCallable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We only rebuild the journal when it will halve the size of the journal
|
||||||
|
* and eliminate at least 2000 ops.
|
||||||
|
*/
|
||||||
|
private boolean journalRebuildRequired() {
|
||||||
|
final int REDUNDANT_OP_COMPACT_THRESHOLD = 2000;
|
||||||
|
return redundantOpCount >= REDUNDANT_OP_COMPACT_THRESHOLD
|
||||||
|
&& redundantOpCount >= lruEntries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drops the entry for {@code key} if it exists and can be removed. Entries
|
||||||
|
* actively being edited cannot be removed.
|
||||||
|
*
|
||||||
|
* @return true if an entry was removed.
|
||||||
|
*/
|
||||||
|
public synchronized boolean remove(String key) throws IOException {
|
||||||
|
checkNotClosed();
|
||||||
|
validateKey(key);
|
||||||
|
Entry entry = lruEntries.get(key);
|
||||||
|
if (entry == null || entry.currentEditor != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < valueCount; i++) {
|
||||||
|
File file = entry.getCleanFile(i);
|
||||||
|
if (!file.delete()) {
|
||||||
|
throw new IOException("failed to delete " + file);
|
||||||
|
}
|
||||||
|
size -= entry.lengths[i];
|
||||||
|
entry.lengths[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
redundantOpCount++;
|
||||||
|
journalWriter.append(REMOVE + ' ' + key + '\n');
|
||||||
|
lruEntries.remove(key);
|
||||||
|
|
||||||
|
if (journalRebuildRequired()) {
|
||||||
|
executorService.submit(cleanupCallable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this cache has been closed.
|
||||||
|
*/
|
||||||
|
public boolean isClosed() {
|
||||||
|
return journalWriter == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkNotClosed() {
|
||||||
|
if (journalWriter == null) {
|
||||||
|
throw new IllegalStateException("cache is closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force buffered operations to the filesystem.
|
||||||
|
*/
|
||||||
|
public synchronized void flush() throws IOException {
|
||||||
|
checkNotClosed();
|
||||||
|
trimToSize();
|
||||||
|
journalWriter.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes this cache. Stored values will remain on the filesystem.
|
||||||
|
*/
|
||||||
|
public synchronized void close() throws IOException {
|
||||||
|
if (journalWriter == null) {
|
||||||
|
return; // already closed
|
||||||
|
}
|
||||||
|
for (Entry entry : new ArrayList<Entry>(lruEntries.values())) {
|
||||||
|
if (entry.currentEditor != null) {
|
||||||
|
entry.currentEditor.abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trimToSize();
|
||||||
|
journalWriter.close();
|
||||||
|
journalWriter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void trimToSize() throws IOException {
|
||||||
|
while (size > maxSize) {
|
||||||
|
// Map.Entry<String, Entry> toEvict = lruEntries.eldest();
|
||||||
|
final Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next();
|
||||||
|
remove(toEvict.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the cache and deletes all of its stored values. This will delete
|
||||||
|
* all files in the cache directory including files that weren't created by
|
||||||
|
* the cache.
|
||||||
|
*/
|
||||||
|
public void delete() throws IOException {
|
||||||
|
close();
|
||||||
|
deleteContents(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateKey(String key) {
|
||||||
|
if (key.contains(" ") || key.contains("\n") || key.contains("\r")) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"keys must not contain spaces or newlines: \"" + key + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String inputStreamToString(InputStream in) throws IOException {
|
||||||
|
return readFully(new InputStreamReader(in, UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A snapshot of the values for an entry.
|
||||||
|
*/
|
||||||
|
public final class Snapshot implements Closeable {
|
||||||
|
private final String key;
|
||||||
|
private final long sequenceNumber;
|
||||||
|
private final InputStream[] ins;
|
||||||
|
|
||||||
|
private Snapshot(String key, long sequenceNumber, InputStream[] ins) {
|
||||||
|
this.key = key;
|
||||||
|
this.sequenceNumber = sequenceNumber;
|
||||||
|
this.ins = ins;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an editor for this snapshot's entry, or null if either the
|
||||||
|
* entry has changed since this snapshot was created or if another edit
|
||||||
|
* is in progress.
|
||||||
|
*/
|
||||||
|
public Editor edit() throws IOException {
|
||||||
|
return DiskLruCache.this.edit(key, sequenceNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unbuffered stream with the value for {@code index}.
|
||||||
|
*/
|
||||||
|
public InputStream getInputStream(int index) {
|
||||||
|
return ins[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string value for {@code index}.
|
||||||
|
*/
|
||||||
|
public String getString(int index) throws IOException {
|
||||||
|
return inputStreamToString(getInputStream(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
for (InputStream in : ins) {
|
||||||
|
closeQuietly(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edits the values for an entry.
|
||||||
|
*/
|
||||||
|
public final class Editor {
|
||||||
|
private final Entry entry;
|
||||||
|
private boolean hasErrors;
|
||||||
|
|
||||||
|
private Editor(Entry entry) {
|
||||||
|
this.entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an unbuffered input stream to read the last committed value,
|
||||||
|
* or null if no value has been committed.
|
||||||
|
*/
|
||||||
|
public InputStream newInputStream(int index) throws IOException {
|
||||||
|
synchronized (DiskLruCache.this) {
|
||||||
|
if (entry.currentEditor != this) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
if (!entry.readable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new FileInputStream(entry.getCleanFile(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the last committed value as a string, or null if no value
|
||||||
|
* has been committed.
|
||||||
|
*/
|
||||||
|
public String getString(int index) throws IOException {
|
||||||
|
InputStream in = newInputStream(index);
|
||||||
|
return in != null ? inputStreamToString(in) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new unbuffered output stream to write the value at
|
||||||
|
* {@code index}. If the underlying output stream encounters errors
|
||||||
|
* when writing to the filesystem, this edit will be aborted when
|
||||||
|
* {@link #commit} is called. The returned output stream does not throw
|
||||||
|
* IOExceptions.
|
||||||
|
*/
|
||||||
|
public OutputStream newOutputStream(int index) throws IOException {
|
||||||
|
synchronized (DiskLruCache.this) {
|
||||||
|
if (entry.currentEditor != this) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
return new FaultHidingOutputStream(new FileOutputStream(entry.getDirtyFile(index)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value at {@code index} to {@code value}.
|
||||||
|
*/
|
||||||
|
public void set(int index, String value) throws IOException {
|
||||||
|
Writer writer = null;
|
||||||
|
try {
|
||||||
|
writer = new OutputStreamWriter(newOutputStream(index), UTF_8);
|
||||||
|
writer.write(value);
|
||||||
|
} finally {
|
||||||
|
closeQuietly(writer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commits this edit so it is visible to readers. This releases the
|
||||||
|
* edit lock so another edit may be started on the same key.
|
||||||
|
*/
|
||||||
|
public void commit() throws IOException {
|
||||||
|
if (hasErrors) {
|
||||||
|
completeEdit(this, false);
|
||||||
|
remove(entry.key); // the previous entry is stale
|
||||||
|
} else {
|
||||||
|
completeEdit(this, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aborts this edit. This releases the edit lock so another edit may be
|
||||||
|
* started on the same key.
|
||||||
|
*/
|
||||||
|
public void abort() throws IOException {
|
||||||
|
completeEdit(this, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FaultHidingOutputStream extends FilterOutputStream {
|
||||||
|
private FaultHidingOutputStream(OutputStream out) {
|
||||||
|
super(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int oneByte) {
|
||||||
|
try {
|
||||||
|
out.write(oneByte);
|
||||||
|
} catch (IOException e) {
|
||||||
|
hasErrors = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] buffer, int offset, int length) {
|
||||||
|
try {
|
||||||
|
out.write(buffer, offset, length);
|
||||||
|
} catch (IOException e) {
|
||||||
|
hasErrors = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
hasErrors = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() {
|
||||||
|
try {
|
||||||
|
out.flush();
|
||||||
|
} catch (IOException e) {
|
||||||
|
hasErrors = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class Entry {
|
||||||
|
private final String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lengths of this entry's files.
|
||||||
|
*/
|
||||||
|
private final long[] lengths;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True if this entry has ever been published
|
||||||
|
*/
|
||||||
|
private boolean readable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ongoing edit or null if this entry is not being edited.
|
||||||
|
*/
|
||||||
|
private Editor currentEditor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The sequence number of the most recently committed edit to this entry.
|
||||||
|
*/
|
||||||
|
private long sequenceNumber;
|
||||||
|
|
||||||
|
private Entry(String key) {
|
||||||
|
this.key = key;
|
||||||
|
this.lengths = new long[valueCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLengths() throws IOException {
|
||||||
|
StringBuilder result = new StringBuilder();
|
||||||
|
for (long size : lengths) {
|
||||||
|
result.append(' ').append(size);
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set lengths using decimal numbers like "10123".
|
||||||
|
*/
|
||||||
|
private void setLengths(String[] strings) throws IOException {
|
||||||
|
if (strings.length != valueCount) {
|
||||||
|
throw invalidLengths(strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < strings.length; i++) {
|
||||||
|
lengths[i] = Long.parseLong(strings[i]);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw invalidLengths(strings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IOException invalidLengths(String[] strings) throws IOException {
|
||||||
|
throw new IOException("unexpected journal line: " + Arrays.toString(strings));
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getCleanFile(int i) {
|
||||||
|
return new File(directory, key + "." + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getDirtyFile(int i) {
|
||||||
|
return new File(directory, key + "." + i + ".tmp");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
AppFrame/src/main/java/com/arialyy/frame/cache/PathConstaant.java
vendored
Normal file
21
AppFrame/src/main/java/com/arialyy/frame/cache/PathConstaant.java
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package com.arialyy.frame.cache;
|
||||||
|
|
||||||
|
import android.os.Environment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaL on 2017/11/26.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class PathConstaant {
|
||||||
|
private static final String WP_DIR = "windPath";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取APK升级路径
|
||||||
|
*/
|
||||||
|
public static String getWpPath() {
|
||||||
|
return Environment.getExternalStorageDirectory().getPath()
|
||||||
|
+ "/"
|
||||||
|
+ WP_DIR
|
||||||
|
+ "/update/windPath.apk";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.arialyy.frame.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaL on 2017/11/26.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface CommonConstant {
|
||||||
|
boolean DEBUG = true;
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.arialyy.frame.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaL on 2017/11/26.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface NetConstant {
|
||||||
|
String BASE_URL = "http://wwww.baidu.com/";
|
||||||
|
}
|
243
AppFrame/src/main/java/com/arialyy/frame/core/AbsActivity.java
Normal file
243
AppFrame/src/main/java/com/arialyy/frame/core/AbsActivity.java
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.view.View;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.databinding.ViewDataBinding;
|
||||||
|
import com.arialyy.frame.module.AbsModule;
|
||||||
|
import com.arialyy.frame.module.IOCProxy;
|
||||||
|
import com.arialyy.frame.temp.AbsTempView;
|
||||||
|
import com.arialyy.frame.temp.OnTempBtClickListener;
|
||||||
|
import com.arialyy.frame.temp.TempView;
|
||||||
|
import com.arialyy.frame.util.StringUtil;
|
||||||
|
import com.arialyy.frame.util.show.T;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2015/11/3.
|
||||||
|
* 所有的 Activity都应该继承这个类
|
||||||
|
*/
|
||||||
|
public abstract class AbsActivity<VB extends ViewDataBinding> extends AppCompatActivity
|
||||||
|
implements OnTempBtClickListener {
|
||||||
|
protected String TAG = "";
|
||||||
|
private VB mBind;
|
||||||
|
private IOCProxy mProxy;
|
||||||
|
/**
|
||||||
|
* 第一次点击返回的系统时间
|
||||||
|
*/
|
||||||
|
private long mFirstClickTime = 0;
|
||||||
|
protected AbsFrame mAm;
|
||||||
|
protected View mRootView;
|
||||||
|
private ModuleFactory mModuleF;
|
||||||
|
protected AbsTempView mTempView;
|
||||||
|
protected boolean useTempView = true;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
initialization();
|
||||||
|
init(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initialization() {
|
||||||
|
mAm = AbsFrame.getInstance();
|
||||||
|
mAm.addActivity(this);
|
||||||
|
mBind = DataBindingUtil.setContentView(this, setLayoutId());
|
||||||
|
mProxy = IOCProxy.newInstance(this);
|
||||||
|
TAG = StringUtil.getClassName(this);
|
||||||
|
mModuleF = ModuleFactory.newInstance();
|
||||||
|
mRootView = mBind.getRoot();
|
||||||
|
if (useTempView) {
|
||||||
|
mTempView = new TempView(this);
|
||||||
|
mTempView.setBtListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取填充View
|
||||||
|
*/
|
||||||
|
protected AbsTempView getTempView() {
|
||||||
|
return mTempView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否使用填充界面
|
||||||
|
*/
|
||||||
|
protected void setUseTempView(boolean useTempView) {
|
||||||
|
this.useTempView = useTempView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置自定义的TempView
|
||||||
|
*/
|
||||||
|
protected void setCustomTempView(AbsTempView tempView) {
|
||||||
|
mTempView = tempView;
|
||||||
|
mTempView.setBtListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示占位布局
|
||||||
|
*
|
||||||
|
* @param type {@link TempView#ERROR}
|
||||||
|
* {@link TempView#DATA_NULL}
|
||||||
|
* {@link TempView#LOADING}
|
||||||
|
*/
|
||||||
|
protected void showTempView(int type) {
|
||||||
|
if (mTempView == null || !useTempView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mTempView.setVisibility(View.VISIBLE);
|
||||||
|
mTempView.setType(type);
|
||||||
|
setContentView(mTempView);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModuleFactory getModuleFactory() {
|
||||||
|
return mModuleF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭占位布局
|
||||||
|
*/
|
||||||
|
protected void hintTempView() {
|
||||||
|
hintTempView(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 延时关闭占位布局
|
||||||
|
*/
|
||||||
|
protected void hintTempView(int delay) {
|
||||||
|
new Handler().postDelayed(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (mTempView == null || !useTempView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mTempView.clearFocus();
|
||||||
|
mTempView.setVisibility(View.GONE);
|
||||||
|
setContentView(mRootView);
|
||||||
|
}
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBtTempClick(View view, int type) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void init(Bundle savedInstanceState) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finish() {
|
||||||
|
super.finish();
|
||||||
|
mAm.removeActivity(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getRootView() {
|
||||||
|
return mRootView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置资源布局
|
||||||
|
*/
|
||||||
|
protected abstract int setLayoutId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取binding对象
|
||||||
|
*/
|
||||||
|
protected VB getBinding() {
|
||||||
|
return mBind;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*
|
||||||
|
* @param clazz {@link AbsModule}
|
||||||
|
*/
|
||||||
|
protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz) {
|
||||||
|
M module = mModuleF.getModule(this, clazz);
|
||||||
|
module.setHost(this);
|
||||||
|
mProxy.changeModule(module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*
|
||||||
|
* @param clazz Module class0
|
||||||
|
* @param callback Module回调函数
|
||||||
|
* @param <M> {@link AbsModule}
|
||||||
|
*/
|
||||||
|
protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz,
|
||||||
|
@NonNull AbsModule.OnCallback callback) {
|
||||||
|
M module = mModuleF.getModule(this, clazz);
|
||||||
|
module.setCallback(callback);
|
||||||
|
mProxy.changeModule(module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据回调
|
||||||
|
*/
|
||||||
|
protected abstract void dataCallback(int result, Object data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 双击退出
|
||||||
|
*/
|
||||||
|
private boolean onDoubleClickExit(long timeSpace) {
|
||||||
|
long currentTimeMillis = System.currentTimeMillis();
|
||||||
|
if (currentTimeMillis - mFirstClickTime > timeSpace) {
|
||||||
|
T.showShort(this, "再按一次退出");
|
||||||
|
mFirstClickTime = currentTimeMillis;
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 双击退出,间隔时间为2000ms
|
||||||
|
*/
|
||||||
|
public boolean onDoubleClickExit() {
|
||||||
|
return onDoubleClickExit(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出应用程序
|
||||||
|
*
|
||||||
|
* @param isBackground 是否开开启后台运行,如果为true则为后台运行
|
||||||
|
*/
|
||||||
|
public void exitApp(Boolean isBackground) {
|
||||||
|
mAm.exitApp(isBackground);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出应用程序
|
||||||
|
*/
|
||||||
|
public void exitApp() {
|
||||||
|
mAm.exitApp(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||||
|
@NonNull int[] grantResults) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
PermissionHelp.getInstance().handlePermissionCallback(requestCode, permissions, grantResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
PermissionHelp.getInstance()
|
||||||
|
.handleSpecialPermissionCallback(this, requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import com.arialyy.frame.module.AbsModule;
|
||||||
|
import com.arialyy.frame.module.IOCProxy;
|
||||||
|
import com.arialyy.frame.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2015/11/4.
|
||||||
|
* AlertDialog基类,具有5.0效果,需要配合 AlertDialog.Builder使用
|
||||||
|
*/
|
||||||
|
public abstract class AbsAlertDialog extends DialogFragment {
|
||||||
|
protected String TAG = "";
|
||||||
|
|
||||||
|
private Object mObj; //被观察者
|
||||||
|
private IOCProxy mProxy;
|
||||||
|
private DialogSimpleModule mSimpleModule;
|
||||||
|
private Dialog mDialog;
|
||||||
|
private ModuleFactory mModuleF;
|
||||||
|
|
||||||
|
public AbsAlertDialog() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param obj 被观察的对象
|
||||||
|
*/
|
||||||
|
public AbsAlertDialog(Object obj) {
|
||||||
|
mObj = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
initDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
return mDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建AlertDialog
|
||||||
|
* 建议使用AppCompatDialog,该Dialog具有5.0的效果
|
||||||
|
*/
|
||||||
|
public abstract Dialog initAlertDialog();
|
||||||
|
|
||||||
|
private void initDialog() {
|
||||||
|
TAG = StringUtil.getClassName(this);
|
||||||
|
mProxy = IOCProxy.newInstance(this);
|
||||||
|
if (mObj != null) {
|
||||||
|
mSimpleModule = new DialogSimpleModule(getContext());
|
||||||
|
IOCProxy.newInstance(mObj, mSimpleModule);
|
||||||
|
}
|
||||||
|
mModuleF = ModuleFactory.newInstance();
|
||||||
|
mDialog = initAlertDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*
|
||||||
|
* @param clazz {@link AbsModule}
|
||||||
|
*/
|
||||||
|
protected <M extends AbsModule> M getModule(Class<M> clazz) {
|
||||||
|
M module = mModuleF.getModule(getContext(), clazz);
|
||||||
|
mProxy.changeModule(module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*
|
||||||
|
* @param clazz Module class0
|
||||||
|
* @param callback Module回调函数
|
||||||
|
* @param <M> {@link AbsModule}
|
||||||
|
*/
|
||||||
|
protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz,
|
||||||
|
@NonNull AbsModule.OnCallback callback) {
|
||||||
|
M module = mModuleF.getModule(getContext(), clazz);
|
||||||
|
module.setCallback(callback);
|
||||||
|
mProxy.changeModule(module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取简单打Moduel回调,这个一般用于回调数据给寄主
|
||||||
|
*/
|
||||||
|
protected DialogSimpleModule getSimplerModule() {
|
||||||
|
if (mObj == null) {
|
||||||
|
throw new NullPointerException("必须设置寄主对象");
|
||||||
|
}
|
||||||
|
return mSimpleModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void dataCallback(int result, Object obj);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||||
|
@NonNull int[] grantResults) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
PermissionHelp.getInstance().handlePermissionCallback(requestCode, permissions, grantResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
PermissionHelp.getInstance()
|
||||||
|
.handleSpecialPermissionCallback(getContext(), requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
92
AppFrame/src/main/java/com/arialyy/frame/core/AbsDialog.java
Normal file
92
AppFrame/src/main/java/com/arialyy/frame/core/AbsDialog.java
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.Window;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import com.arialyy.frame.module.AbsModule;
|
||||||
|
import com.arialyy.frame.module.IOCProxy;
|
||||||
|
import com.arialyy.frame.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2015/11/4.
|
||||||
|
* 继承Dialog
|
||||||
|
*/
|
||||||
|
public abstract class AbsDialog extends Dialog {
|
||||||
|
protected String TAG = "";
|
||||||
|
private Object mObj; //被观察者
|
||||||
|
private IOCProxy mProxy;
|
||||||
|
private DialogSimpleModule mSimpleModule;
|
||||||
|
private ModuleFactory mModuleF;
|
||||||
|
|
||||||
|
public AbsDialog(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param obj Dialog的寄主
|
||||||
|
*/
|
||||||
|
public AbsDialog(Context context, Object obj) {
|
||||||
|
super(context);
|
||||||
|
mObj = obj;
|
||||||
|
requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
setContentView(setLayoutId());
|
||||||
|
initDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initDialog() {
|
||||||
|
TAG = StringUtil.getClassName(this);
|
||||||
|
mProxy = IOCProxy.newInstance(this);
|
||||||
|
mModuleF = ModuleFactory.newInstance();
|
||||||
|
if (mObj != null) {
|
||||||
|
mSimpleModule = new DialogSimpleModule(getContext());
|
||||||
|
IOCProxy.newInstance(mObj, mSimpleModule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取简单打Moduel回调,这个一般用于回调数据给寄主
|
||||||
|
*/
|
||||||
|
protected DialogSimpleModule getSimplerModule() {
|
||||||
|
if (mObj == null) {
|
||||||
|
throw new NullPointerException("必须设置寄主对象");
|
||||||
|
}
|
||||||
|
return mSimpleModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*
|
||||||
|
* @param clazz {@link AbsModule}
|
||||||
|
*/
|
||||||
|
protected <M extends AbsModule> M getModule(Class<M> clazz) {
|
||||||
|
M module = mModuleF.getModule(getContext(), clazz);
|
||||||
|
mProxy.changeModule(module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*
|
||||||
|
* @param clazz Module class0
|
||||||
|
* @param callback Module回调函数
|
||||||
|
* @param <M> {@link AbsModule}
|
||||||
|
*/
|
||||||
|
protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz,
|
||||||
|
@NonNull AbsModule.OnCallback callback) {
|
||||||
|
M module = mModuleF.getModule(getContext(), clazz);
|
||||||
|
module.setCallback(callback);
|
||||||
|
mProxy.changeModule(module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置资源布局
|
||||||
|
*/
|
||||||
|
protected abstract int setLayoutId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据回调
|
||||||
|
*/
|
||||||
|
protected abstract void dataCallback(int result, Object obj);
|
||||||
|
}
|
@ -0,0 +1,159 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import androidx.annotation.IdRes;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.databinding.ViewDataBinding;
|
||||||
|
import androidx.fragment.app.DialogFragment;
|
||||||
|
import com.arialyy.frame.module.AbsModule;
|
||||||
|
import com.arialyy.frame.module.IOCProxy;
|
||||||
|
import com.arialyy.frame.util.StringUtil;
|
||||||
|
import com.lyy.frame.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2015/11/4.
|
||||||
|
* DialogFragment
|
||||||
|
*/
|
||||||
|
public abstract class AbsDialogFragment<VB extends ViewDataBinding> extends DialogFragment {
|
||||||
|
protected String TAG = "";
|
||||||
|
private VB mBind;
|
||||||
|
protected Object mObj;
|
||||||
|
protected View mRootView;
|
||||||
|
protected IOCProxy mProxy;
|
||||||
|
protected DialogSimpleModule mSimpleModule;
|
||||||
|
protected AbsActivity mActivity;
|
||||||
|
private ModuleFactory mModuleF;
|
||||||
|
|
||||||
|
public AbsDialogFragment() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param obj 被观察的对象
|
||||||
|
*/
|
||||||
|
public AbsDialogFragment(Object obj) {
|
||||||
|
this(STYLE_NO_TITLE, R.style.MyDialog, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param style DialogFragment.STYLE_NO_TITLE , STYLE_NO_FRAME; STYLE_NO_FRAME | STYLE_NO_TITLE
|
||||||
|
* @param theme Dialog风格
|
||||||
|
* @param obj 被观察的对象
|
||||||
|
*/
|
||||||
|
private AbsDialogFragment(int style, int theme, Object obj) {
|
||||||
|
setStyle(style, theme);
|
||||||
|
mObj = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
|
||||||
|
@Nullable Bundle savedInstanceState) {
|
||||||
|
mBind = DataBindingUtil.inflate(inflater, setLayoutId(), container, false);
|
||||||
|
mRootView = mBind.getRoot();
|
||||||
|
initFragment();
|
||||||
|
return mRootView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onAttach(Activity activity) {
|
||||||
|
super.onAttach(activity);
|
||||||
|
if (activity instanceof AbsActivity) {
|
||||||
|
mActivity = (AbsActivity) activity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends View> T findViewById(@IdRes int id) {
|
||||||
|
return mRootView.findViewById(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initFragment() {
|
||||||
|
TAG = StringUtil.getClassName(this);
|
||||||
|
mProxy = IOCProxy.newInstance(this);
|
||||||
|
mModuleF = ModuleFactory.newInstance();
|
||||||
|
if (mObj != null) {
|
||||||
|
mSimpleModule = new DialogSimpleModule(getContext());
|
||||||
|
IOCProxy.newInstance(mObj, mSimpleModule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
init(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void init(Bundle savedInstanceState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取简单打Moduel回调,这个一般用于回调数据给寄主
|
||||||
|
*/
|
||||||
|
protected DialogSimpleModule getSimplerModule() {
|
||||||
|
if (mObj == null) {
|
||||||
|
throw new NullPointerException("必须设置寄主对象");
|
||||||
|
}
|
||||||
|
return mSimpleModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置资源布局
|
||||||
|
*/
|
||||||
|
protected abstract int setLayoutId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取binding对象
|
||||||
|
*/
|
||||||
|
protected VB getBinding() {
|
||||||
|
return mBind;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*
|
||||||
|
* @param clazz {@link AbsModule}
|
||||||
|
*/
|
||||||
|
protected <M extends AbsModule> M getModule(Class<M> clazz) {
|
||||||
|
M module = mModuleF.getModule(getContext(), clazz);
|
||||||
|
module.setHost(this);
|
||||||
|
mProxy.changeModule(module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*
|
||||||
|
* @param clazz Module class0
|
||||||
|
* @param callback Module回调函数
|
||||||
|
* @param <M> {@link AbsModule}
|
||||||
|
*/
|
||||||
|
protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz,
|
||||||
|
@NonNull AbsModule.OnCallback callback) {
|
||||||
|
M module = mModuleF.getModule(getContext(), clazz);
|
||||||
|
module.setCallback(callback);
|
||||||
|
mProxy.changeModule(module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一的回调接口
|
||||||
|
*
|
||||||
|
* @param result 返回码,用来判断是哪个接口进行回调
|
||||||
|
* @param data 回调数据
|
||||||
|
*/
|
||||||
|
protected abstract void dataCallback(int result, Object data);
|
||||||
|
|
||||||
|
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||||
|
@NonNull int[] grantResults) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
PermissionHelp.getInstance().handlePermissionCallback(requestCode, permissions, grantResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
PermissionHelp.getInstance()
|
||||||
|
.handleSpecialPermissionCallback(getContext(), requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
271
AppFrame/src/main/java/com/arialyy/frame/core/AbsFragment.java
Normal file
271
AppFrame/src/main/java/com/arialyy/frame/core/AbsFragment.java
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.RelativeLayout;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.databinding.DataBindingUtil;
|
||||||
|
import androidx.databinding.ViewDataBinding;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.FragmentContainer;
|
||||||
|
import androidx.viewpager.widget.ViewPager;
|
||||||
|
import com.arialyy.frame.module.AbsModule;
|
||||||
|
import com.arialyy.frame.module.IOCProxy;
|
||||||
|
import com.arialyy.frame.temp.AbsTempView;
|
||||||
|
import com.arialyy.frame.temp.OnTempBtClickListener;
|
||||||
|
import com.arialyy.frame.temp.TempView;
|
||||||
|
import com.arialyy.frame.util.ReflectionUtil;
|
||||||
|
import com.arialyy.frame.util.StringUtil;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2015/11/4.
|
||||||
|
* 基础Fragment
|
||||||
|
*/
|
||||||
|
public abstract class AbsFragment<VB extends ViewDataBinding> extends Fragment
|
||||||
|
implements OnTempBtClickListener {
|
||||||
|
protected String TAG = "";
|
||||||
|
private VB mBind;
|
||||||
|
private IOCProxy mProxy;
|
||||||
|
protected View mRootView;
|
||||||
|
protected AbsActivity mActivity;
|
||||||
|
private ModuleFactory mModuleF;
|
||||||
|
protected boolean isInit;
|
||||||
|
protected AbsTempView mTempView;
|
||||||
|
protected boolean useTempView = true;
|
||||||
|
private ViewGroup mParent;
|
||||||
|
|
||||||
|
@Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
mBind = DataBindingUtil.inflate(inflater, setLayoutId(), container, false);
|
||||||
|
initFragment();
|
||||||
|
mRootView = mBind.getRoot();
|
||||||
|
return mRootView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initFragment() {
|
||||||
|
TAG = StringUtil.getClassName(this);
|
||||||
|
mProxy = IOCProxy.newInstance(this);
|
||||||
|
mModuleF = ModuleFactory.newInstance();
|
||||||
|
if (useTempView) {
|
||||||
|
mTempView = new TempView(getContext());
|
||||||
|
mTempView.setBtListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onAttach(Context context) {
|
||||||
|
super.onAttach(context);
|
||||||
|
if (context instanceof AbsActivity) {
|
||||||
|
mActivity = (AbsActivity) context;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onActivityCreated(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onActivityCreated(savedInstanceState);
|
||||||
|
Field field = ReflectionUtil.getField(getClass(), "mContainerId");
|
||||||
|
Field containerField = ReflectionUtil.getField(getFragmentManager().getClass(), "mContainer");
|
||||||
|
try {
|
||||||
|
int id = (int) field.get(this);
|
||||||
|
FragmentContainer container = (FragmentContainer) containerField.get(getFragmentManager());
|
||||||
|
mParent = (ViewGroup) container.onFindViewById(id);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
init(savedInstanceState);
|
||||||
|
isInit = true;
|
||||||
|
if (getUserVisibleHint()) {
|
||||||
|
onDelayLoad();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||||
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
Field field = ReflectionUtil.getField(getClass(), "mContainer");
|
||||||
|
try {
|
||||||
|
mParent = (ViewGroup) field.get(this);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||||
|
super.setUserVisibleHint(isVisibleToUser);
|
||||||
|
if (isVisibleToUser && isInit) {
|
||||||
|
isInit = false;
|
||||||
|
onDelayLoad();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void init(Bundle savedInstanceState);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否使用填充界面
|
||||||
|
*/
|
||||||
|
protected void setUseTempView(boolean useTempView) {
|
||||||
|
this.useTempView = useTempView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置自定义的TempView
|
||||||
|
*/
|
||||||
|
protected void setCustomTempView(AbsTempView tempView) {
|
||||||
|
mTempView = tempView;
|
||||||
|
mTempView.setBtListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 显示占位布局
|
||||||
|
*
|
||||||
|
* @param type {@link TempView#ERROR}
|
||||||
|
* {@link TempView#DATA_NULL}
|
||||||
|
* {@link TempView#LOADING}
|
||||||
|
*/
|
||||||
|
protected void showTempView(int type) {
|
||||||
|
if (mTempView == null || !useTempView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mTempView.setType(type);
|
||||||
|
if (mParent != null) {
|
||||||
|
int size = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||||
|
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(size, size);
|
||||||
|
if (mParent instanceof ViewPager) {
|
||||||
|
// ViewPager vp = (ViewPager) mParent;
|
||||||
|
// int position = vp.getCurrentItem();
|
||||||
|
// View child = vp.getChildAt(position);
|
||||||
|
// L.d(TAG, "hashcode ==> " + child.hashCode());
|
||||||
|
View child = mRootView;
|
||||||
|
if (child != null) {
|
||||||
|
if (child instanceof LinearLayout) {
|
||||||
|
LinearLayout ll = (LinearLayout) child;
|
||||||
|
ll.removeView(mTempView);
|
||||||
|
ll.addView(mTempView, 0, lp);
|
||||||
|
} else if (child instanceof RelativeLayout || child instanceof FrameLayout) {
|
||||||
|
ViewGroup vg = (ViewGroup) child;
|
||||||
|
vg.removeView(mTempView);
|
||||||
|
vg.addView(mTempView, lp);
|
||||||
|
} else {
|
||||||
|
L.e(TAG, "框架的填充只支持,LinearLayout、RelativeLayout、FrameLayout");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mParent.removeView(mTempView);
|
||||||
|
mParent.addView(mTempView, lp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭占位布局
|
||||||
|
*/
|
||||||
|
protected void hintTempView() {
|
||||||
|
hintTempView(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 延时关闭占位布局
|
||||||
|
*/
|
||||||
|
protected void hintTempView(int delay) {
|
||||||
|
new Handler().postDelayed(new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
if (mTempView == null || !useTempView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mTempView.clearFocus();
|
||||||
|
if (mParent != null) {
|
||||||
|
if (mParent instanceof ViewPager) {
|
||||||
|
// ViewPager vp = (ViewPager) mParent;
|
||||||
|
// int position = vp.getCurrentItem();
|
||||||
|
// View child = vp.getChildAt(position);
|
||||||
|
View child = mRootView;
|
||||||
|
ViewGroup vg = (ViewGroup) child;
|
||||||
|
if (vg != null) {
|
||||||
|
vg.removeView(mTempView);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mParent.removeView(mTempView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onBtTempClick(View view, int type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取填充View
|
||||||
|
*/
|
||||||
|
protected AbsTempView getTempView() {
|
||||||
|
return mTempView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取binding对象
|
||||||
|
*/
|
||||||
|
protected VB getBinding() {
|
||||||
|
return mBind;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*
|
||||||
|
* @param clazz {@link AbsModule}
|
||||||
|
*/
|
||||||
|
protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz) {
|
||||||
|
M module = mModuleF.getModule(getContext(), clazz);
|
||||||
|
module.setHost(this);
|
||||||
|
mProxy.changeModule(module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*
|
||||||
|
* @param clazz Module class0
|
||||||
|
* @param callback Module回调函数
|
||||||
|
* @param <M> {@link AbsModule}
|
||||||
|
*/
|
||||||
|
protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz,
|
||||||
|
@NonNull AbsModule.OnCallback callback) {
|
||||||
|
M module = mModuleF.getModule(getContext(), clazz);
|
||||||
|
module.setCallback(callback);
|
||||||
|
mProxy.changeModule(module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 延时加载
|
||||||
|
*/
|
||||||
|
protected abstract void onDelayLoad();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置资源布局
|
||||||
|
*/
|
||||||
|
protected abstract int setLayoutId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据回调
|
||||||
|
*/
|
||||||
|
protected abstract void dataCallback(int result, Object obj);
|
||||||
|
|
||||||
|
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||||
|
@NonNull int[] grantResults) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
PermissionHelp.getInstance().handlePermissionCallback(requestCode, permissions, grantResults);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
PermissionHelp.getInstance()
|
||||||
|
.handleSpecialPermissionCallback(getContext(), requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
188
AppFrame/src/main/java/com/arialyy/frame/core/AbsFrame.java
Normal file
188
AppFrame/src/main/java/com/arialyy/frame/core/AbsFrame.java
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.arialyy.frame.base.BaseApp;
|
||||||
|
import com.arialyy.frame.util.show.FL;
|
||||||
|
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2015/11/4.
|
||||||
|
* APP生命周期管理类管理
|
||||||
|
*/
|
||||||
|
public class AbsFrame {
|
||||||
|
private static final String TAG = "AbsFrame";
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
private volatile static AbsFrame mManager = null;
|
||||||
|
private Context mContext;
|
||||||
|
private Stack<AbsActivity> mActivityStack = new Stack<>();
|
||||||
|
|
||||||
|
private AbsFrame() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private AbsFrame(Application application) {
|
||||||
|
mContext = application.getApplicationContext();
|
||||||
|
BaseApp.context = mContext;
|
||||||
|
BaseApp.app = application;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化框架
|
||||||
|
*/
|
||||||
|
public static AbsFrame init(Application app) {
|
||||||
|
if (mManager == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (mManager == null) {
|
||||||
|
mManager = new AbsFrame(app);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取AppManager管流程实例
|
||||||
|
*/
|
||||||
|
public static AbsFrame getInstance() {
|
||||||
|
if (mManager == null) {
|
||||||
|
throw new NullPointerException("请在application 的 onCreate 方法里面使用MVVMFrame.init()方法进行初始化操作");
|
||||||
|
}
|
||||||
|
return mManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Activity栈
|
||||||
|
*/
|
||||||
|
public Stack<AbsActivity> getActivityStack() {
|
||||||
|
return mActivityStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开启异常捕获
|
||||||
|
* 日志文件位于/data/data/Package Name/cache//crash/AbsExceptionFile.crash
|
||||||
|
*/
|
||||||
|
public void openCrashHandler() {
|
||||||
|
openCrashHandler("", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开启异常捕获
|
||||||
|
* 需要网络权限,get请求,异常参数,需要下面两个网络权限
|
||||||
|
* android:name="android.permission.INTERNET"
|
||||||
|
* android:name="android.permission.ACCESS_NETWORK_STATE"
|
||||||
|
*
|
||||||
|
* @param serverHost 服务器地址
|
||||||
|
* @param key 数据传输键值
|
||||||
|
*/
|
||||||
|
public AbsFrame openCrashHandler(String serverHost, String key) {
|
||||||
|
CrashHandler handler = CrashHandler.getInstance(mContext);
|
||||||
|
handler.setServerHost(serverHost, key);
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler(handler);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 堆栈大小
|
||||||
|
*/
|
||||||
|
public int getActivitySize() {
|
||||||
|
return mActivityStack.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定的Activity
|
||||||
|
*/
|
||||||
|
public AbsActivity getActivity(int location) {
|
||||||
|
return mActivityStack.get(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加Activity到堆栈
|
||||||
|
*/
|
||||||
|
public void addActivity(AbsActivity activity) {
|
||||||
|
if (mActivityStack == null) {
|
||||||
|
mActivityStack = new Stack<>();
|
||||||
|
}
|
||||||
|
mActivityStack.add(activity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前Activity(堆栈中最后一个压入的)
|
||||||
|
*/
|
||||||
|
public AbsActivity getCurrentActivity() {
|
||||||
|
return mActivityStack.lastElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束当前Activity(堆栈中最后一个压入的)
|
||||||
|
*/
|
||||||
|
public void finishActivity() {
|
||||||
|
finishActivity(mActivityStack.lastElement());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束指定的Activity
|
||||||
|
*/
|
||||||
|
public void finishActivity(AbsActivity activity) {
|
||||||
|
if (activity != null) {
|
||||||
|
mActivityStack.remove(activity);
|
||||||
|
activity.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除指定的Activity
|
||||||
|
*/
|
||||||
|
public void removeActivity(AbsActivity activity) {
|
||||||
|
if (activity != null) {
|
||||||
|
mActivityStack.remove(activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束指定类名的Activity
|
||||||
|
*/
|
||||||
|
public void finishActivity(Class<?> cls) {
|
||||||
|
for (AbsActivity activity : mActivityStack) {
|
||||||
|
if (activity.getClass().equals(cls)) {
|
||||||
|
finishActivity(activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束所有Activity
|
||||||
|
*/
|
||||||
|
public void finishAllActivity() {
|
||||||
|
for (int i = 0, size = mActivityStack.size(); i < size; i++) {
|
||||||
|
if (mActivityStack.get(i) != null && mActivityStack.size() > 0) {
|
||||||
|
mActivityStack.get(i).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mActivityStack.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出应用程序
|
||||||
|
*
|
||||||
|
* @param isBackground 是否开开启后台运行
|
||||||
|
*/
|
||||||
|
public void exitApp(Boolean isBackground) {
|
||||||
|
try {
|
||||||
|
finishAllActivity();
|
||||||
|
ActivityManager activityMgr =
|
||||||
|
(ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
activityMgr.restartPackage(mContext.getPackageName());
|
||||||
|
} catch (Exception e) {
|
||||||
|
FL.e(TAG, FL.getExceptionString(e));
|
||||||
|
} finally {
|
||||||
|
// 注意,如果您有后台程序运行,请不要支持此句子
|
||||||
|
if (!isBackground) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,131 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.PopupWindow;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import com.arialyy.frame.module.AbsModule;
|
||||||
|
import com.arialyy.frame.module.IOCProxy;
|
||||||
|
import com.arialyy.frame.util.StringUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2015/12/3.
|
||||||
|
* 抽象的Popupwindow悬浮框
|
||||||
|
*/
|
||||||
|
public abstract class AbsPopupWindow extends PopupWindow {
|
||||||
|
|
||||||
|
protected String TAG;
|
||||||
|
private Context mContext;
|
||||||
|
private Drawable mBackground;
|
||||||
|
protected View mView;
|
||||||
|
private Object mObj;
|
||||||
|
protected IOCProxy mProxy;
|
||||||
|
protected DialogSimpleModule mSimpleModule;
|
||||||
|
private ModuleFactory mModuleF;
|
||||||
|
|
||||||
|
public AbsPopupWindow(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbsPopupWindow(Context context, Drawable background) {
|
||||||
|
this(context, background, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbsPopupWindow(Context context, Drawable background, Object obj) {
|
||||||
|
mContext = context;
|
||||||
|
mBackground = background;
|
||||||
|
initPopupWindow();
|
||||||
|
mProxy = IOCProxy.newInstance(this);
|
||||||
|
if (obj != null) {
|
||||||
|
mObj = obj;
|
||||||
|
mSimpleModule = new DialogSimpleModule(getContext());
|
||||||
|
IOCProxy.newInstance(mObj, mSimpleModule);
|
||||||
|
}
|
||||||
|
mModuleF = ModuleFactory.newInstance();
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initPopupWindow() {
|
||||||
|
mView = LayoutInflater.from(mContext).inflate(setLayoutId(), null);
|
||||||
|
setContentView(mView);
|
||||||
|
TAG = StringUtil.getClassName(this);
|
||||||
|
// 设置SelectPicPopupWindow弹出窗体的宽
|
||||||
|
setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
|
||||||
|
//// 设置SelectPicPopupWindow弹出窗体的高
|
||||||
|
setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
setFocusable(true);
|
||||||
|
// 设置SelectPicPopupWindow弹出窗体动画效果
|
||||||
|
// setAnimationStyle(R.style.wisdom_anim_style);
|
||||||
|
// 实例化一个ColorDrawable颜色为半透明
|
||||||
|
if (mBackground == null) {
|
||||||
|
mBackground = new ColorDrawable(Color.parseColor("#4f000000"));
|
||||||
|
}
|
||||||
|
// 设置SelectPicPopupWindow弹出窗体的背景
|
||||||
|
setBackgroundDrawable(mBackground);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <T extends View> T getViewWithTag(Object tag) {
|
||||||
|
T result = (T) mView.findViewWithTag(tag);
|
||||||
|
if (result == null) throw new NullPointerException("没有找到tag为【" + tag + "】的控件");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*
|
||||||
|
* @param clazz {@link AbsModule}
|
||||||
|
*/
|
||||||
|
protected <M extends AbsModule> M getModule(Class<M> clazz) {
|
||||||
|
M module = mModuleF.getModule(getContext(), clazz);
|
||||||
|
mProxy.changeModule(module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*
|
||||||
|
* @param clazz Module class0
|
||||||
|
* @param callback Module回调函数
|
||||||
|
* @param <M> {@link AbsModule}
|
||||||
|
*/
|
||||||
|
protected <M extends AbsModule> M getModule(@NonNull Class<M> clazz,
|
||||||
|
@NonNull AbsModule.OnCallback callback) {
|
||||||
|
M module = mModuleF.getModule(getContext(), clazz);
|
||||||
|
module.setCallback(callback);
|
||||||
|
mProxy.changeModule(module);
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取简单打Moduel回调,这个一般用于回调数据给寄主
|
||||||
|
*/
|
||||||
|
protected DialogSimpleModule getSimplerModule() {
|
||||||
|
if (mObj == null) {
|
||||||
|
throw new NullPointerException("必须设置寄主对象");
|
||||||
|
}
|
||||||
|
return mSimpleModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Context getContext() {
|
||||||
|
return mContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置资源布局
|
||||||
|
*/
|
||||||
|
protected abstract int setLayoutId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据回调
|
||||||
|
*/
|
||||||
|
protected abstract void dataCallback(int result, Object obj);
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import androidx.databinding.ViewDataBinding;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/9/16.
|
||||||
|
* Binding工厂
|
||||||
|
*/
|
||||||
|
public class BindingFactory {
|
||||||
|
private final String TAG = "BindingFactory";
|
||||||
|
|
||||||
|
private Map<Integer, ViewDataBinding> mBindings = new HashMap<>();
|
||||||
|
|
||||||
|
private BindingFactory() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要保证每个对象都有独立的享元工厂
|
||||||
|
*/
|
||||||
|
public static BindingFactory newInstance() {
|
||||||
|
return new BindingFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Binding
|
||||||
|
*
|
||||||
|
* @param obj Module寄主
|
||||||
|
*/
|
||||||
|
public <VB extends ViewDataBinding> VB getBinding(Object obj, Class<VB> clazz) {
|
||||||
|
VB vb = (VB) mBindings.get(clazz.hashCode());
|
||||||
|
if (vb == null) {
|
||||||
|
vb = loadBind(obj, clazz);
|
||||||
|
}
|
||||||
|
return vb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从其它组件中加载binding
|
||||||
|
*
|
||||||
|
* @param obj Module寄主
|
||||||
|
* @param clazz 具体的Binding
|
||||||
|
* @param <VB> ViewDataBinding
|
||||||
|
*/
|
||||||
|
private <VB extends ViewDataBinding> VB loadBind(Object obj, Class<VB> clazz) {
|
||||||
|
VB vb = null;
|
||||||
|
if (obj instanceof AbsActivity) {
|
||||||
|
vb = (VB) ((AbsActivity) obj).getBinding();
|
||||||
|
} else if (obj instanceof AbsFragment) {
|
||||||
|
vb = (VB) ((AbsFragment) obj).getBinding();
|
||||||
|
} else if (obj instanceof AbsDialogFragment) {
|
||||||
|
vb = (VB) ((AbsDialogFragment) obj).getBinding();
|
||||||
|
}
|
||||||
|
mBindings.put(clazz.hashCode(), vb);
|
||||||
|
return vb;
|
||||||
|
}
|
||||||
|
}
|
171
AppFrame/src/main/java/com/arialyy/frame/core/CrashHandler.java
Normal file
171
AppFrame/src/main/java/com/arialyy/frame/core/CrashHandler.java
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.arialyy.frame.http.HttpUtil;
|
||||||
|
import com.arialyy.frame.permission.PermissionManager;
|
||||||
|
import com.arialyy.frame.util.AndroidUtils;
|
||||||
|
import com.arialyy.frame.util.CalendarUtils;
|
||||||
|
import com.arialyy.frame.util.FileUtil;
|
||||||
|
import com.arialyy.frame.util.NetUtils;
|
||||||
|
import com.arialyy.frame.util.show.FL;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
import com.arialyy.frame.util.show.T;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/4/21.
|
||||||
|
* 异常捕获
|
||||||
|
*/
|
||||||
|
final class CrashHandler implements Thread.UncaughtExceptionHandler {
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
private static volatile CrashHandler INSTANCE = null;
|
||||||
|
private static final String TAG = "CrashHandler";
|
||||||
|
private Thread.UncaughtExceptionHandler mDefaultHandler;
|
||||||
|
private Context mContext;
|
||||||
|
private String mServerHost, mPramKey;
|
||||||
|
private String mExceptionFileName = "AbsExceptionFile.crash";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取CrashHandler实例 ,单例模式
|
||||||
|
*/
|
||||||
|
public static CrashHandler getInstance(Context context) {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
INSTANCE = new CrashHandler(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CrashHandler(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开启异常捕获
|
||||||
|
* 需要网络权限,get请求,异常参数
|
||||||
|
*
|
||||||
|
* @param serverHost 服务器地址
|
||||||
|
* @param key 数据传输键值
|
||||||
|
*/
|
||||||
|
public void setServerHost(String serverHost, String key) {
|
||||||
|
mServerHost = serverHost;
|
||||||
|
mPramKey = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void uncaughtException(Thread thread, Throwable ex) {
|
||||||
|
if (!handleException(ex) && mDefaultHandler != null) {
|
||||||
|
mDefaultHandler.uncaughtException(thread, ex);
|
||||||
|
} else {
|
||||||
|
// Sleep一会后结束程序
|
||||||
|
try {
|
||||||
|
Thread.sleep(2000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//不要把线程都杀了,否则连日志都看不了
|
||||||
|
// android.os.Process.killProcess(android.os.Process.myPid());
|
||||||
|
//如果把这句话注释掉,有异常都不会退出
|
||||||
|
System.exit(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理捕获到的异常
|
||||||
|
*/
|
||||||
|
private boolean handleException(Throwable ex) {
|
||||||
|
if (ex == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//在这里处理崩溃逻辑,将不再显示FC对话框
|
||||||
|
new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Looper.prepare();
|
||||||
|
T.showLong(mContext, "很抱歉,程序出现异常,即将退出");
|
||||||
|
Looper.loop();
|
||||||
|
}
|
||||||
|
}.start();
|
||||||
|
sendExceptionInfo(ex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送异常数据给服务器
|
||||||
|
*/
|
||||||
|
private void sendExceptionInfo(final Throwable ex) {
|
||||||
|
ExceptionInfo info = new ExceptionInfo();
|
||||||
|
info.time = CalendarUtils.getNowDataTime();
|
||||||
|
info.versionCode = AndroidUtils.getVersionCode(mContext);
|
||||||
|
info.versionName = AndroidUtils.getVersionName(mContext);
|
||||||
|
info.systemVersionCode = Build.VERSION.SDK_INT;
|
||||||
|
info.phoneModel = Build.MODEL;
|
||||||
|
info.exceptionMsg = FL.getExceptionString(ex);
|
||||||
|
if (AndroidUtils.checkPermission(mContext, Manifest.permission.INTERNET) &&
|
||||||
|
AndroidUtils.checkPermission(mContext, Manifest.permission.ACCESS_NETWORK_STATE)) {
|
||||||
|
if (NetUtils.isConnected(mContext) && !TextUtils.isEmpty(mServerHost) && !TextUtils.isEmpty(
|
||||||
|
mPramKey)) {
|
||||||
|
String objStr = new Gson().toJson(info);
|
||||||
|
HttpUtil util = HttpUtil.getInstance(mContext);
|
||||||
|
Map<String, String> params = new WeakHashMap<>();
|
||||||
|
params.put(mPramKey, objStr);
|
||||||
|
util.get(mServerHost, params, new HttpUtil.AbsResponse());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
L.e(TAG,
|
||||||
|
"请在manifest文件定义android.permission.INTERNET和android.permission.ACCESS_NETWORK_STATE权限");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
File file = new File(mContext.getCacheDir().getPath() + "/crash/" + mExceptionFileName);
|
||||||
|
if (!file.exists()) {
|
||||||
|
FileUtil.createFile(file.getPath());
|
||||||
|
}
|
||||||
|
writeExceptionToFile(info.exceptionMsg, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将异常日志写入文件
|
||||||
|
*/
|
||||||
|
private void writeExceptionToFile(String message, File crashFile) {
|
||||||
|
StringBuffer stringBuffer = new StringBuffer();
|
||||||
|
stringBuffer.append(CalendarUtils.getNowDataTime());
|
||||||
|
stringBuffer.append("\n");
|
||||||
|
stringBuffer.append(message);
|
||||||
|
stringBuffer.append("\n");
|
||||||
|
PrintWriter writer = null;
|
||||||
|
try {
|
||||||
|
writer = new PrintWriter(new FileWriter(crashFile, true));
|
||||||
|
writer.append(stringBuffer);
|
||||||
|
writer.flush();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
if (writer != null) {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ExceptionInfo {
|
||||||
|
int versionCode;
|
||||||
|
String versionName;
|
||||||
|
int systemVersionCode;
|
||||||
|
String exceptionMsg;
|
||||||
|
String phoneModel;
|
||||||
|
String time;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import com.arialyy.frame.module.AbsModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaLyy on 2015/2/9.
|
||||||
|
* 框架提供的默认的对话框的Module
|
||||||
|
*/
|
||||||
|
public class DialogSimpleModule extends AbsModule {
|
||||||
|
|
||||||
|
public DialogSimpleModule(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一的回调
|
||||||
|
*/
|
||||||
|
public void onDialog(int result, Object data) {
|
||||||
|
callback(result, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 可设置参数和回调名的回调函数
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void onDialog(String methodName, Class<?> param, Object data) {
|
||||||
|
callback(methodName, param, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dialog的默认回调
|
||||||
|
*
|
||||||
|
* @param b 需要回调的数据
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void onDialog(Bundle b) {
|
||||||
|
callback("onDialog", Bundle.class, b);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.arialyy.frame.module.AbsModule;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2015/8/31.
|
||||||
|
* Module共享工厂
|
||||||
|
*/
|
||||||
|
public class ModuleFactory {
|
||||||
|
|
||||||
|
private final String TAG = "ModuleFactory";
|
||||||
|
|
||||||
|
private Map<Integer, AbsModule> mModules = new HashMap<>();
|
||||||
|
|
||||||
|
private ModuleFactory() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要保证每个对象都有独立的享元工厂
|
||||||
|
*/
|
||||||
|
public static ModuleFactory newInstance() {
|
||||||
|
return new ModuleFactory();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Module
|
||||||
|
*/
|
||||||
|
public <M extends AbsModule> M getModule(Context context, Class<M> clazz) {
|
||||||
|
M module = (M) mModules.get(clazz.hashCode());
|
||||||
|
if (module == null) {
|
||||||
|
return newInstanceModule(context, clazz);
|
||||||
|
}
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造一个新的Module
|
||||||
|
*/
|
||||||
|
private <T extends AbsModule> T newInstanceModule(Context context, Class<T> clazz) {
|
||||||
|
Class[] paramTypes = { Context.class };
|
||||||
|
Object[] params = { context };
|
||||||
|
try {
|
||||||
|
Constructor<T> con = clazz.getConstructor(paramTypes);
|
||||||
|
T module = con.newInstance(params);
|
||||||
|
mModules.put(clazz.hashCode(), module);
|
||||||
|
return module;
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InstantiationException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import com.arialyy.frame.util.ReflectionUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/4/5.
|
||||||
|
* 更新帮助类
|
||||||
|
*/
|
||||||
|
public class NotifyHelp {
|
||||||
|
private static volatile NotifyHelp INSTANCE = null;
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
private SparseArray<SparseArray<OnNotifyCallback>> mNotifyObjs = new SparseArray<>();
|
||||||
|
|
||||||
|
public interface OnNotifyCallback {
|
||||||
|
public void onNotify(int action, Object obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NotifyHelp getInstance() {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
INSTANCE = new NotifyHelp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private NotifyHelp() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addObj(int flag, OnNotifyCallback callback) {
|
||||||
|
SparseArray<OnNotifyCallback> array = mNotifyObjs.get(flag);
|
||||||
|
if (array == null) {
|
||||||
|
array = new SparseArray<>();
|
||||||
|
}
|
||||||
|
array.put(callback.hashCode(), callback);
|
||||||
|
mNotifyObjs.put(flag, array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeObj(int flag) {
|
||||||
|
mNotifyObjs.delete(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
mNotifyObjs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(int flag) {
|
||||||
|
update(flag, -1, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(int flag, int action) {
|
||||||
|
update(flag, action, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(int flag, int action, Object obj) {
|
||||||
|
if (mNotifyObjs == null || mNotifyObjs.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SparseArray<OnNotifyCallback> array = mNotifyObjs.get(flag);
|
||||||
|
if (array == null || array.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int[] keys = (int[]) ReflectionUtil.getField(SparseArray.class, "mKeys").get(array);
|
||||||
|
for (int key : keys) {
|
||||||
|
if (key == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
OnNotifyCallback callback = array.get(key);
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onNotify(action, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,69 @@
|
|||||||
|
package com.arialyy.frame.core;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import com.arialyy.frame.permission.OnPermissionCallback;
|
||||||
|
import com.arialyy.frame.permission.PermissionManager;
|
||||||
|
import com.arialyy.frame.util.AndroidVersionUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/4/12.
|
||||||
|
* 权限回调帮助类
|
||||||
|
*/
|
||||||
|
class PermissionHelp {
|
||||||
|
public static final Object LOCK = new Object();
|
||||||
|
public volatile static PermissionHelp INSTANCE = null;
|
||||||
|
public PermissionManager mPm;
|
||||||
|
|
||||||
|
public static PermissionHelp getInstance() {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
INSTANCE = new PermissionHelp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PermissionHelp() {
|
||||||
|
mPm = PermissionManager.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理权限申请回调
|
||||||
|
*/
|
||||||
|
public void handlePermissionCallback(int requestCode, @NonNull String[] permissions,
|
||||||
|
@NonNull int[] grantResults) {
|
||||||
|
for (int state : grantResults) {
|
||||||
|
if (state == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
mPm.onSuccess(permissions);
|
||||||
|
} else {
|
||||||
|
mPm.onFail(permissions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理特殊权限申请,如悬浮框,系统设置修改等特殊权限
|
||||||
|
*/
|
||||||
|
public void handleSpecialPermissionCallback(Context context, int requestCode, int resultCode,
|
||||||
|
Intent data) {
|
||||||
|
if (AndroidVersionUtil.hasM()) {
|
||||||
|
if (requestCode == OnPermissionCallback.PERMISSION_ALERT_WINDOW) {
|
||||||
|
if (Settings.canDrawOverlays(context)) { //在这判断是否请求权限成功
|
||||||
|
mPm.onSuccess(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
|
||||||
|
} else {
|
||||||
|
mPm.onFail(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
|
||||||
|
}
|
||||||
|
} else if (requestCode == OnPermissionCallback.PERMISSION_WRITE_SETTING) {
|
||||||
|
if (Settings.System.canWrite(context)) {
|
||||||
|
mPm.onSuccess(Settings.ACTION_MANAGE_WRITE_SETTINGS);
|
||||||
|
} else {
|
||||||
|
mPm.onFail(Settings.ACTION_MANAGE_WRITE_SETTINGS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
348
AppFrame/src/main/java/com/arialyy/frame/http/HttpUtil.java
Normal file
348
AppFrame/src/main/java/com/arialyy/frame/http/HttpUtil.java
Normal file
@ -0,0 +1,348 @@
|
|||||||
|
package com.arialyy.frame.http;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import com.arialyy.frame.cache.CacheUtil;
|
||||||
|
import com.arialyy.frame.http.inf.IResponse;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import okhttp3.Call;
|
||||||
|
import okhttp3.Callback;
|
||||||
|
import okhttp3.FormBody;
|
||||||
|
import okhttp3.Headers;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2015/11/5.
|
||||||
|
* 网络连接工具
|
||||||
|
*/
|
||||||
|
public class HttpUtil {
|
||||||
|
private static final String TAG = "HttpUtil";
|
||||||
|
private Context mContext = null;
|
||||||
|
private static volatile HttpUtil mUtil = null;
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
private CacheUtil mCacheUtil;
|
||||||
|
private Handler mHandler;
|
||||||
|
private static final int TIME_OUT = 5000;
|
||||||
|
public static final String CONTENT_TYPE_IMG = "image/*";
|
||||||
|
public static final String CONTENT_TYPE_TEXT = "text/*";
|
||||||
|
public static final String CONTENT_TYPE_FILE = "application/octet-stream";
|
||||||
|
|
||||||
|
private HttpUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpUtil(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
mCacheUtil = new CacheUtil(mContext, false);
|
||||||
|
mHandler = new Handler(Looper.getMainLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpUtil getInstance(Context context) {
|
||||||
|
if (mUtil == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (mUtil == null) {
|
||||||
|
mUtil = new HttpUtil(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void get(final @NonNull String url, @NonNull final IResponse absResponse) {
|
||||||
|
get(url, null, absResponse, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void get(final @NonNull String url, @NonNull final IResponse absResponse,
|
||||||
|
boolean useCache) {
|
||||||
|
get(url, null, absResponse, useCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void get(final @NonNull String url, final Map<String, String> params,
|
||||||
|
@NonNull final IResponse absResponse) {
|
||||||
|
get(url, params, absResponse, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void post(final @NonNull String url, @NonNull final IResponse absResponse) {
|
||||||
|
post(url, null, null, absResponse, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void post(final @NonNull String url, final Map<String, String> params,
|
||||||
|
@NonNull final IResponse absResponse) {
|
||||||
|
post(url, params, null, absResponse, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void post(final @NonNull String url, final Map<String, String> params,
|
||||||
|
@NonNull final IResponse absResponse, final boolean useCache) {
|
||||||
|
post(url, params, null, absResponse, useCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void post(final @NonNull String url, final Map<String, String> params,
|
||||||
|
final Map<String, String> header, @NonNull final IResponse absResponse) {
|
||||||
|
post(url, params, header, absResponse, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传文件
|
||||||
|
*
|
||||||
|
* @param key 上传文件键值
|
||||||
|
*/
|
||||||
|
public void uploadFile(@NonNull final String url, @NonNull final String filePath,
|
||||||
|
@NonNull final String key,
|
||||||
|
final String contentType, final Map<String, String> header,
|
||||||
|
@NonNull final IResponse absResponse) {
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
File file = new File(filePath);
|
||||||
|
String BOUNDARY = UUID.randomUUID().toString(); // 边界标识 随机生成
|
||||||
|
String PREFIX = "--", LINE_END = "\r\n";
|
||||||
|
String CONTENT_TYPE = "multipart/form-data"; // 内容类型
|
||||||
|
try {
|
||||||
|
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||||
|
conn.setReadTimeout(5000);
|
||||||
|
conn.setConnectTimeout(5000);
|
||||||
|
conn.setDoInput(true);
|
||||||
|
conn.setDoOutput(true);
|
||||||
|
conn.setUseCaches(false);
|
||||||
|
conn.setRequestMethod("POST");
|
||||||
|
conn.setRequestProperty("Charset", "utf-8"); // 设置编码
|
||||||
|
conn.setRequestProperty("connection", "keep-alive");
|
||||||
|
conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY);
|
||||||
|
|
||||||
|
if (header != null && header.size() > 0) {
|
||||||
|
Set set = header.entrySet();
|
||||||
|
for (Object aSet : set) {
|
||||||
|
Map.Entry entry = (Map.Entry) aSet;
|
||||||
|
conn.setRequestProperty(entry.getKey() + "", entry.getValue() + "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutputStream outputSteam = conn.getOutputStream();
|
||||||
|
DataOutputStream dos = new DataOutputStream(outputSteam);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(PREFIX);
|
||||||
|
sb.append(BOUNDARY);
|
||||||
|
sb.append(LINE_END);
|
||||||
|
sb.append("Content-Disposition: form-data; name=\"")
|
||||||
|
.append(key)
|
||||||
|
.append("\"; filename=\"")
|
||||||
|
.append(file.getName())
|
||||||
|
.append("\"")
|
||||||
|
.append(LINE_END);
|
||||||
|
sb.append("Content-Type:").append(contentType).append("; charset=utf-8").append(LINE_END);
|
||||||
|
sb.append(LINE_END);
|
||||||
|
dos.write(sb.toString().getBytes());
|
||||||
|
InputStream is = new FileInputStream(file);
|
||||||
|
byte[] bytes = new byte[1024];
|
||||||
|
int len = 0;
|
||||||
|
while ((len = is.read(bytes)) != -1) {
|
||||||
|
dos.write(bytes, 0, len);
|
||||||
|
}
|
||||||
|
is.close();
|
||||||
|
dos.write(LINE_END.getBytes());
|
||||||
|
byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes();
|
||||||
|
dos.write(end_data);
|
||||||
|
dos.flush();
|
||||||
|
int res = conn.getResponseCode();
|
||||||
|
if (res == 200) {
|
||||||
|
BufferedInputStream inputStream = new BufferedInputStream(conn.getInputStream());
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
while (inputStream.read(buf) > 0) {
|
||||||
|
stringBuilder.append(new String(buf, 0, buf.length));
|
||||||
|
}
|
||||||
|
String data = stringBuilder.toString();
|
||||||
|
L.j(data);
|
||||||
|
absResponse.onResponse(data);
|
||||||
|
} else {
|
||||||
|
absResponse.onError("error");
|
||||||
|
}
|
||||||
|
} catch (MalformedURLException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基本get方法
|
||||||
|
*/
|
||||||
|
public void get(final @NonNull String url, final Map<String, String> params,
|
||||||
|
@NonNull final IResponse absResponse, final boolean useCache) {
|
||||||
|
L.v(TAG, "请求链接 >>>> " + url);
|
||||||
|
String requestUrl = url;
|
||||||
|
if (params != null && params.size() > 0) {
|
||||||
|
Set set = params.entrySet();
|
||||||
|
int i = 0;
|
||||||
|
requestUrl += "?";
|
||||||
|
for (Object aSet : set) {
|
||||||
|
i++;
|
||||||
|
Map.Entry entry = (Map.Entry) aSet;
|
||||||
|
requestUrl += entry.getKey() + "=" + entry.getValue() + (i < params.size() ? "&" : "");
|
||||||
|
}
|
||||||
|
L.v(TAG, "请求参数为 >>>> ");
|
||||||
|
L.m(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
OkHttpClient client = new OkHttpClient.Builder().connectTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
|
||||||
|
.writeTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
|
||||||
|
.readTimeout(300000, TimeUnit.MILLISECONDS)
|
||||||
|
.build();
|
||||||
|
final Request request = new Request.Builder().url(requestUrl).build();
|
||||||
|
Call call = client.newCall(request);
|
||||||
|
|
||||||
|
//请求加入调度
|
||||||
|
call.enqueue(new Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call call, IOException e) {
|
||||||
|
L.e(TAG, "请求链接【" + url + "】失败");
|
||||||
|
String data = null;
|
||||||
|
if (useCache) {
|
||||||
|
data = mCacheUtil.getStringCache(url + L.m2s(params));
|
||||||
|
L.d(TAG, "数据获取成功,获取到的数据为 >>>> ");
|
||||||
|
L.j(data);
|
||||||
|
}
|
||||||
|
if (TextUtils.isEmpty(data)) {
|
||||||
|
setOnError(request, absResponse);
|
||||||
|
} else {
|
||||||
|
setOnResponse(data, absResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call call, Response response) throws IOException {
|
||||||
|
String data = response.body().string();
|
||||||
|
L.d(TAG, "数据获取成功,获取到的数据为 >>>> ");
|
||||||
|
L.j(data);
|
||||||
|
if (useCache) {
|
||||||
|
L.v(TAG, "缓存链接【" + url + "】的数据");
|
||||||
|
mCacheUtil.putStringCache(url + L.m2s(params), data);
|
||||||
|
}
|
||||||
|
setOnResponse(data, absResponse);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基本的Post方法
|
||||||
|
*/
|
||||||
|
public void post(final @NonNull String url, final Map<String, String> params,
|
||||||
|
final Map<String, String> header, @NonNull final IResponse absResponse,
|
||||||
|
final boolean useCache) {
|
||||||
|
L.v(TAG, "请求链接 >>>> " + url);
|
||||||
|
OkHttpClient client = new OkHttpClient.Builder().connectTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
|
||||||
|
.writeTimeout(TIME_OUT, TimeUnit.MILLISECONDS)
|
||||||
|
.readTimeout(300000, TimeUnit.MILLISECONDS)
|
||||||
|
.build();
|
||||||
|
FormBody.Builder formB = new FormBody.Builder();
|
||||||
|
//头数据
|
||||||
|
Headers.Builder hb = new Headers.Builder();
|
||||||
|
if (header != null && header.size() > 0) {
|
||||||
|
Set set = header.entrySet();
|
||||||
|
for (Object aSet : set) {
|
||||||
|
Map.Entry entry = (Map.Entry) aSet;
|
||||||
|
hb.add(entry.getKey() + "", entry.getValue() + "");
|
||||||
|
}
|
||||||
|
L.v(TAG, "请求的头数据为 >>>> ");
|
||||||
|
L.m(header);
|
||||||
|
}
|
||||||
|
//请求参数
|
||||||
|
if (params != null && params.size() > 0) {
|
||||||
|
Set set = params.entrySet();
|
||||||
|
for (Object aSet : set) {
|
||||||
|
Map.Entry entry = (Map.Entry) aSet;
|
||||||
|
formB.add(entry.getKey() + "", entry.getValue() + "");
|
||||||
|
}
|
||||||
|
L.v(TAG, "请求参数为 >>>> ");
|
||||||
|
L.m(params);
|
||||||
|
} else {
|
||||||
|
formB.add("null", "null");
|
||||||
|
}
|
||||||
|
|
||||||
|
Request request =
|
||||||
|
new Request.Builder().url(url).post(formB.build()).headers(hb.build()).build();
|
||||||
|
Call call = client.newCall(request);
|
||||||
|
call.enqueue(new Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call call, IOException e) {
|
||||||
|
L.e(TAG, "请求链接【" + url + "】失败");
|
||||||
|
String data = null;
|
||||||
|
if (useCache) {
|
||||||
|
data = mCacheUtil.getStringCache(url + L.m2s(params));
|
||||||
|
L.d(TAG, "从缓存读取的数据为 >>>> ");
|
||||||
|
L.j(data);
|
||||||
|
}
|
||||||
|
if (TextUtils.isEmpty(data)) {
|
||||||
|
setOnError(call, absResponse);
|
||||||
|
} else {
|
||||||
|
setOnResponse(data, absResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call call, Response response) throws IOException {
|
||||||
|
String data = response.body().string();
|
||||||
|
L.d(TAG, "数据获取成功,获取到的数据为 >>>>");
|
||||||
|
L.j(data);
|
||||||
|
if (useCache) {
|
||||||
|
L.v(TAG, "缓存链接【" + url + "】的数据");
|
||||||
|
mCacheUtil.putStringCache(url + L.m2s(params), data);
|
||||||
|
}
|
||||||
|
setOnResponse(data, absResponse);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setOnError(final Object error, final IResponse response) {
|
||||||
|
mHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
response.onError(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setOnResponse(final String data, final IResponse response) {
|
||||||
|
mHandler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
response.onResponse(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回String类型的响应
|
||||||
|
*/
|
||||||
|
public static class AbsResponse implements IResponse {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(String data) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Object error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
//package com.arialyy.frame.http;
|
||||||
|
//
|
||||||
|
//import java.util.concurrent.TimeUnit;
|
||||||
|
//
|
||||||
|
//import javax.inject.Singleton;
|
||||||
|
//
|
||||||
|
//import okhttp3.OkHttpClient;
|
||||||
|
//import dagger.Module;
|
||||||
|
//import dagger.Provides;
|
||||||
|
//import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
|
//import retrofit2.Retrofit;
|
||||||
|
//import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
|
||||||
|
//import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
|
//
|
||||||
|
//@Module
|
||||||
|
//public class WebApiModule {
|
||||||
|
// @Provides
|
||||||
|
// @Singleton
|
||||||
|
// public OkHttpClient provideOkHttpClient() {
|
||||||
|
// final OkHttpClient.Builder builder = new OkHttpClient.Builder();
|
||||||
|
//// if (BuildConfig.DEBUG) {
|
||||||
|
// HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
|
||||||
|
// logging.setLevel(HttpLoggingInterceptor.Level.BODY);
|
||||||
|
// builder.addInterceptor(logging);
|
||||||
|
//// }
|
||||||
|
// builder.connectTimeout(60 * 1000, TimeUnit.MILLISECONDS)
|
||||||
|
// .readTimeout(60 * 1000, TimeUnit.MILLISECONDS);
|
||||||
|
// return builder.build();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Provides
|
||||||
|
// @Singleton
|
||||||
|
// public Retrofit provideRetrofit(OkHttpClient okHttpClient) {
|
||||||
|
// Retrofit.Builder builder = new Retrofit.Builder();
|
||||||
|
// builder.client(okHttpClient)
|
||||||
|
//// .baseUrl(GameConstant.PACKAGE_TEST_BASE_URL)
|
||||||
|
// .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||||
|
// .addConverterFactory(GsonConverterFactory.create());
|
||||||
|
// return builder.build();
|
||||||
|
// }
|
||||||
|
//}
|
@ -0,0 +1,39 @@
|
|||||||
|
package com.arialyy.frame.http.inf;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 网络请求类
|
||||||
|
*/
|
||||||
|
public interface IRequest<T> {
|
||||||
|
/**
|
||||||
|
* post请求
|
||||||
|
*
|
||||||
|
* @param url 请求连接
|
||||||
|
* @param param 请求参数
|
||||||
|
* @param headers 请求头信息
|
||||||
|
* @param usCache 是否使用缓存
|
||||||
|
* @param body 请求主体
|
||||||
|
* @param response 回调接口
|
||||||
|
*/
|
||||||
|
public void post(@NonNull String url, T param, T headers, boolean usCache, byte[] body,
|
||||||
|
@NonNull IResponse response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get请求
|
||||||
|
*
|
||||||
|
* @param url 请求连接
|
||||||
|
* @param param 请求参数
|
||||||
|
* @param headers 请求头信息
|
||||||
|
* @param usCache 是否使用缓存
|
||||||
|
* @param body 请求主体
|
||||||
|
* @param response 回调接口
|
||||||
|
*/
|
||||||
|
public void get(@NonNull String url, T param, T headers, boolean usCache, byte[] body,
|
||||||
|
@NonNull IResponse response);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认缓存文件夹
|
||||||
|
*/
|
||||||
|
public static final String NET_CACHE_DIR = "HttpCache";
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.arialyy.frame.http.inf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据响应接口
|
||||||
|
*/
|
||||||
|
public interface IResponse {
|
||||||
|
/**
|
||||||
|
* 响应的数据回调
|
||||||
|
*/
|
||||||
|
public void onResponse(String data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误返回回掉
|
||||||
|
*/
|
||||||
|
public void onError(Object error);
|
||||||
|
}
|
147
AppFrame/src/main/java/com/arialyy/frame/module/AbsModule.java
Normal file
147
AppFrame/src/main/java/com/arialyy/frame/module/AbsModule.java
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
package com.arialyy.frame.module;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import androidx.databinding.ViewDataBinding;
|
||||||
|
|
||||||
|
import com.arialyy.frame.core.AbsActivity;
|
||||||
|
import com.arialyy.frame.core.BindingFactory;
|
||||||
|
import com.arialyy.frame.module.inf.ModuleListener;
|
||||||
|
import com.arialyy.frame.util.StringUtil;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaLyy on 2015/2/3.
|
||||||
|
* 抽象的module
|
||||||
|
*/
|
||||||
|
public class AbsModule {
|
||||||
|
public String TAG = "";
|
||||||
|
private Context mContext;
|
||||||
|
private ModuleListener mModuleListener;
|
||||||
|
private OnCallback mCallback;
|
||||||
|
private BindingFactory mBindingFactory;
|
||||||
|
private Object mHost;
|
||||||
|
|
||||||
|
public interface OnCallback {
|
||||||
|
public void onSuccess(int result, Object success);
|
||||||
|
|
||||||
|
public void onError(int result, Object error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbsModule(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化一些东西
|
||||||
|
*/
|
||||||
|
private void init() {
|
||||||
|
TAG = StringUtil.getClassName(this);
|
||||||
|
mBindingFactory = BindingFactory.newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置Module监听
|
||||||
|
*
|
||||||
|
* @param moduleListener Module监听
|
||||||
|
*/
|
||||||
|
public void setModuleListener(ModuleListener moduleListener) {
|
||||||
|
if (moduleListener == null) {
|
||||||
|
throw new NullPointerException("ModuleListener不能为空");
|
||||||
|
}
|
||||||
|
this.mModuleListener = moduleListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 为Binding设置寄主
|
||||||
|
*/
|
||||||
|
public void setHost(Object host) {
|
||||||
|
mHost = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功的回调
|
||||||
|
*/
|
||||||
|
private void successCallback(int key, Object obj) {
|
||||||
|
if (mCallback == null) {
|
||||||
|
L.e(TAG, "OnCallback 为 null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mCallback.onSuccess(key, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 失败的回调
|
||||||
|
*/
|
||||||
|
public void errorCallback(int key, Object obj) {
|
||||||
|
if (mCallback == null) {
|
||||||
|
L.e(TAG, "OnCallback 为 null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mCallback.onError(key, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Context
|
||||||
|
*
|
||||||
|
* @return Context
|
||||||
|
*/
|
||||||
|
public Context getContext() {
|
||||||
|
return mContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置Module回调
|
||||||
|
*
|
||||||
|
* @param callback Module 回调
|
||||||
|
*/
|
||||||
|
public void setCallback(OnCallback callback) {
|
||||||
|
mCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取ViewDataBinding
|
||||||
|
*
|
||||||
|
* @param clazz ViewDataBinding实例
|
||||||
|
*/
|
||||||
|
protected <VB extends ViewDataBinding> VB getBinding(Class<VB> clazz) {
|
||||||
|
return mBindingFactory.getBinding(mHost, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一的回调,如果已经设置了OnCallback,则使用OnCallback;
|
||||||
|
* 否则将使用dataCallback,{@link AbsActivity#dataCallback(int, Object)}
|
||||||
|
*
|
||||||
|
* @param result 返回码
|
||||||
|
* @param data 回调数据
|
||||||
|
*/
|
||||||
|
protected void callback(final int result, final Object data) {
|
||||||
|
if (mCallback != null) {
|
||||||
|
successCallback(result, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mModuleListener.callback(result, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* module回调
|
||||||
|
*
|
||||||
|
* @param method 回调的方法名
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
protected void callback(String method) {
|
||||||
|
mModuleListener.callback(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带参数的module回调
|
||||||
|
*
|
||||||
|
* @param method 回调的方法名
|
||||||
|
* @param dataClassType 回调数据类型
|
||||||
|
* @param data 回调数据
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
protected void callback(String method, Class<?> dataClassType, Object data) {
|
||||||
|
mModuleListener.callback(method, dataClassType, data);
|
||||||
|
}
|
||||||
|
}
|
117
AppFrame/src/main/java/com/arialyy/frame/module/IOCProxy.java
Normal file
117
AppFrame/src/main/java/com/arialyy/frame/module/IOCProxy.java
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
package com.arialyy.frame.module;
|
||||||
|
|
||||||
|
import com.arialyy.frame.module.inf.ModuleListener;
|
||||||
|
import com.arialyy.frame.util.ReflectionUtil;
|
||||||
|
import com.arialyy.frame.util.show.FL;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaLyy on 2015/2/3.
|
||||||
|
* 代理对象
|
||||||
|
*/
|
||||||
|
public class IOCProxy implements ModuleListener {
|
||||||
|
private static final String TAG = "IOCProxy";
|
||||||
|
private static final String mMethod = "dataCallback";
|
||||||
|
|
||||||
|
private Object mObj;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化静态代理
|
||||||
|
*/
|
||||||
|
public static IOCProxy newInstance(Object obj, AbsModule module) {
|
||||||
|
return new IOCProxy(obj, module);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IOCProxy newInstance(Object obj) {
|
||||||
|
return new IOCProxy(obj, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 被代理对象
|
||||||
|
*/
|
||||||
|
private IOCProxy(Object obj, AbsModule module) {
|
||||||
|
this.mObj = obj;
|
||||||
|
|
||||||
|
if (module != null) {
|
||||||
|
module.setModuleListener(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void changeModule(AbsModule module) {
|
||||||
|
module.setModuleListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一的数据回调
|
||||||
|
*
|
||||||
|
* @param result 返回码
|
||||||
|
* @param data 回调数据
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void callback(int result, Object data) {
|
||||||
|
synchronized (this) {
|
||||||
|
try {
|
||||||
|
Method m = ReflectionUtil.getMethod(mObj.getClass(), mMethod, int.class, Object.class);
|
||||||
|
m.setAccessible(true);
|
||||||
|
m.invoke(mObj, result, data);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据回调
|
||||||
|
*
|
||||||
|
* @param method 方法名
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void callback(String method) {
|
||||||
|
synchronized (this) {
|
||||||
|
try {
|
||||||
|
Method m = mObj.getClass().getDeclaredMethod(method);
|
||||||
|
m.setAccessible(true);
|
||||||
|
m.invoke(mObj);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
L.e(TAG, "无法找到" + method + "方法");
|
||||||
|
FL.e(TAG, FL.getExceptionString(e));
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带参数的回调
|
||||||
|
*
|
||||||
|
* @param method 方法名
|
||||||
|
* @param dataClassType 参数类型,如 int.class
|
||||||
|
* @param data 数据
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void callback(String method, Class<?> dataClassType, Object data) {
|
||||||
|
synchronized (this) {
|
||||||
|
try {
|
||||||
|
Method m = mObj.getClass().getDeclaredMethod(method, dataClassType);
|
||||||
|
m.setAccessible(true);
|
||||||
|
m.invoke(mObj, data);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
L.e(TAG, "无法找到" + method + "方法");
|
||||||
|
FL.e(TAG, FL.getExceptionString(e));
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
package com.arialyy.frame.module;
|
||||||
|
|
||||||
|
import android.util.SparseIntArray;
|
||||||
|
|
||||||
|
import com.arialyy.frame.util.ObjUtil;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/7/7.
|
||||||
|
*/
|
||||||
|
public class ModuleFactory {
|
||||||
|
private Map<Set<Integer>, AbsModule.OnCallback> mPool = new HashMap<>();
|
||||||
|
private SparseIntArray mKeyIndex = new SparseIntArray();
|
||||||
|
private static final String TAG = "ModuleFactory";
|
||||||
|
|
||||||
|
public ModuleFactory() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addCallback(int key, AbsModule.OnCallback callback) {
|
||||||
|
if (checkKey(key, callback)) {
|
||||||
|
L.e(TAG, "key 已经和 callback对应");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mPool.containsValue(callback)) {
|
||||||
|
Set<Integer> oldKeys = ObjUtil.getKeyByValue(mPool, callback);
|
||||||
|
if (oldKeys != null) {
|
||||||
|
if (!oldKeys.contains(key)) {
|
||||||
|
oldKeys.add(key);
|
||||||
|
mKeyIndex.put(key, callback.hashCode());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
oldKeys = new HashSet<>();
|
||||||
|
oldKeys.add(key);
|
||||||
|
mPool.put(oldKeys, callback);
|
||||||
|
mKeyIndex.put(key, callback.hashCode());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Set<Integer> newKeys = new HashSet<>();
|
||||||
|
newKeys.add(key);
|
||||||
|
mPool.put(newKeys, callback);
|
||||||
|
mKeyIndex.put(key, callback.hashCode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查key和callback的对应关系
|
||||||
|
*
|
||||||
|
* @return true : key已经和value对应,false : key没有和value对应
|
||||||
|
*/
|
||||||
|
private boolean checkKey(int key, AbsModule.OnCallback callback) {
|
||||||
|
return mKeyIndex.indexOfKey(key) != -1 || mKeyIndex.indexOfValue(callback.hashCode()) != -1
|
||||||
|
&& mKeyIndex.valueAt(callback.hashCode()) == key;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.arialyy.frame.module.inf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaLyy on 2015/2/3.
|
||||||
|
* Module监听
|
||||||
|
*/
|
||||||
|
public interface ModuleListener {
|
||||||
|
/**
|
||||||
|
* 无参的回调
|
||||||
|
*
|
||||||
|
* @param method 方法名
|
||||||
|
*/
|
||||||
|
public void callback(String method);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带参数的回调
|
||||||
|
*
|
||||||
|
* @param method 方法名
|
||||||
|
* @param dataClassType 参数类型
|
||||||
|
* @param data 数据
|
||||||
|
*/
|
||||||
|
public void callback(String method, Class<?> dataClassType, Object data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一接口的回调,回调接口为dataCallback
|
||||||
|
*
|
||||||
|
* @param result 返回码
|
||||||
|
* @param data 回调数据
|
||||||
|
*/
|
||||||
|
public void callback(int result, Object data);
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package com.arialyy.frame.permission;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/4/11.
|
||||||
|
* 权限回调
|
||||||
|
*/
|
||||||
|
public interface OnPermissionCallback {
|
||||||
|
public static final int PERMISSION_ALERT_WINDOW = 0xad1;
|
||||||
|
public static final int PERMISSION_WRITE_SETTING = 0xad2;
|
||||||
|
|
||||||
|
public void onSuccess(String... permissions);
|
||||||
|
|
||||||
|
public void onFail(String... permissions);
|
||||||
|
}
|
@ -0,0 +1,143 @@
|
|||||||
|
package com.arialyy.frame.permission;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/4/11.
|
||||||
|
* 权限管理工具类
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.M) public class PermissionManager implements OnPermissionCallback {
|
||||||
|
private static final String TAG = "PermissionManager";
|
||||||
|
private PermissionUtil mPu;
|
||||||
|
private SparseArray<OnPermissionCallback> mCallbacks = new SparseArray<>();
|
||||||
|
private static volatile PermissionManager INSTANCE = null;
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
|
||||||
|
public static PermissionManager getInstance() {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
INSTANCE = new PermissionManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PermissionManager() {
|
||||||
|
mPu = PermissionUtil.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查权限
|
||||||
|
*
|
||||||
|
* @param permission 需要检查的权限
|
||||||
|
* @return true:已经授权
|
||||||
|
*/
|
||||||
|
public boolean checkPermission(Activity activity, String permission) {
|
||||||
|
return mPu.checkPermission(activity, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查权限
|
||||||
|
*
|
||||||
|
* @param permission 需要检查的权限
|
||||||
|
* @return true:已经授权
|
||||||
|
*/
|
||||||
|
public boolean checkPermission(Fragment fragment, String permission) {
|
||||||
|
Activity activity = fragment.getActivity();
|
||||||
|
return checkPermission(activity, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请悬浮框权限
|
||||||
|
*
|
||||||
|
* @param obj obj 只能是Activity、Fragment 的子类及其衍生类
|
||||||
|
*/
|
||||||
|
public void requestAlertWindowPermission(Object obj, OnPermissionCallback callback) {
|
||||||
|
int hashCode = Arrays.hashCode(new String[] { Settings.ACTION_MANAGE_OVERLAY_PERMISSION });
|
||||||
|
registerCallback(callback, hashCode);
|
||||||
|
mPu.requestAlertWindowPermission(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请修改系统设置权限
|
||||||
|
*
|
||||||
|
* @param obj obj 只能是Activity、Fragment 的子类及其衍生类
|
||||||
|
*/
|
||||||
|
public void requestWriteSettingPermission(Object obj, OnPermissionCallback callback) {
|
||||||
|
int hashCode = Arrays.hashCode(new String[] { Settings.ACTION_MANAGE_WRITE_SETTINGS });
|
||||||
|
registerCallback(callback, hashCode);
|
||||||
|
mPu.requestWriteSetting(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请权限
|
||||||
|
*
|
||||||
|
* @param obj Activity || Fragment
|
||||||
|
* @param permission 权限
|
||||||
|
*/
|
||||||
|
public PermissionManager requestPermission(Object obj, OnPermissionCallback callback,
|
||||||
|
String... permission) {
|
||||||
|
requestPermissionAndHint(obj, callback, "", registerCallback(obj, callback, permission));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请权限
|
||||||
|
*
|
||||||
|
* @param obj Activity || Fragment
|
||||||
|
* @param hint 如果框对话框包含“不再询问”选择框的时候的提示用语。
|
||||||
|
* @param permission 权限
|
||||||
|
*/
|
||||||
|
public void requestPermissionAndHint(Object obj, OnPermissionCallback callback, String hint,
|
||||||
|
String... permission) {
|
||||||
|
mPu.requestPermission(obj, 0, hint, registerCallback(obj, callback, permission));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerCallback(OnPermissionCallback callback, int hashCode) {
|
||||||
|
OnPermissionCallback c = mCallbacks.get(hashCode);
|
||||||
|
if (c == null) {
|
||||||
|
mCallbacks.append(hashCode, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] registerCallback(Object obj, OnPermissionCallback callback,
|
||||||
|
String... permission) {
|
||||||
|
List<String> list = mPu.checkPermission(obj, permission);
|
||||||
|
if (list == null || list.size() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String[] denyPermission = mPu.list2Array(list);
|
||||||
|
int hashCode = Arrays.hashCode(denyPermission);
|
||||||
|
OnPermissionCallback c = mCallbacks.get(hashCode);
|
||||||
|
if (c == null) {
|
||||||
|
mCallbacks.append(hashCode, callback);
|
||||||
|
}
|
||||||
|
return denyPermission;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onSuccess(String... permissions) {
|
||||||
|
int hashCode = Arrays.hashCode(permissions);
|
||||||
|
OnPermissionCallback c = mCallbacks.get(hashCode);
|
||||||
|
if (c != null) {
|
||||||
|
c.onSuccess(permissions);
|
||||||
|
mCallbacks.remove(hashCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onFail(String... permissions) {
|
||||||
|
int hashCode = Arrays.hashCode(permissions);
|
||||||
|
OnPermissionCallback c = mCallbacks.get(hashCode);
|
||||||
|
if (c != null) {
|
||||||
|
c.onFail(permissions);
|
||||||
|
mCallbacks.remove(hashCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,199 @@
|
|||||||
|
package com.arialyy.frame.permission;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import com.arialyy.frame.util.AndroidVersionUtil;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
import com.arialyy.frame.util.show.T;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/4/11.
|
||||||
|
* 6.0权限帮助工具
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.M) class PermissionUtil {
|
||||||
|
public static final Object LOCK = new Object();
|
||||||
|
public volatile static PermissionUtil INSTANCE = null;
|
||||||
|
private static final String TAG = "PermissionUtil";
|
||||||
|
|
||||||
|
public static PermissionUtil getInstance() {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
INSTANCE = new PermissionUtil();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PermissionUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请权限
|
||||||
|
*/
|
||||||
|
public void requestPermission(Object obj, int requestCode, String... permission) {
|
||||||
|
if (!AndroidVersionUtil.hasM()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
requestPermission(obj, requestCode, "", permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请权限
|
||||||
|
*
|
||||||
|
* @param hint 如果框对话框包含”不再询问“选择框的时候的提示用语。
|
||||||
|
*/
|
||||||
|
public void requestPermission(Object obj, int requestCode, String hint, String... permission) {
|
||||||
|
if (!AndroidVersionUtil.hasM() || permission == null || permission.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Activity activity = null;
|
||||||
|
Fragment fragment = null;
|
||||||
|
if (obj instanceof Activity) {
|
||||||
|
activity = (Activity) obj;
|
||||||
|
} else if (obj instanceof Fragment) {
|
||||||
|
fragment = (Fragment) obj;
|
||||||
|
activity = fragment.getActivity();
|
||||||
|
} else {
|
||||||
|
L.e(TAG, "obj 只能是 Activity 或者 fragment 及其子类");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!TextUtils.isEmpty(hint)) {
|
||||||
|
for (String str : permission) {
|
||||||
|
if (fragment != null) {
|
||||||
|
if (fragment.shouldShowRequestPermissionRationale(str)) {
|
||||||
|
T.showLong(fragment.getContext(), hint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (activity.shouldShowRequestPermissionRationale(str)) {
|
||||||
|
T.showLong(activity, hint);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fragment != null) {
|
||||||
|
fragment.requestPermissions(permission, requestCode);
|
||||||
|
} else {
|
||||||
|
activity.requestPermissions(permission, requestCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String[] list2Array(List<String> denyPermission) {
|
||||||
|
String[] array = new String[denyPermission.size()];
|
||||||
|
for (int i = 0, count = denyPermission.size(); i < count; i++) {
|
||||||
|
array[i] = denyPermission.get(i);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查没有被授权的权限
|
||||||
|
*/
|
||||||
|
public List<String> checkPermission(Object obj, String... permission) {
|
||||||
|
if (!AndroidVersionUtil.hasM() || permission == null || permission.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Activity activity = null;
|
||||||
|
if (obj instanceof Activity) {
|
||||||
|
activity = (Activity) obj;
|
||||||
|
} else if (obj instanceof Fragment) {
|
||||||
|
activity = ((Fragment) obj).getActivity();
|
||||||
|
} else {
|
||||||
|
L.e(TAG, "obj 只能是 Activity 或者 fragment 及其子类");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<String> denyPermissions = new ArrayList<>();
|
||||||
|
for (String p : permission) {
|
||||||
|
if (activity.checkSelfPermission(p) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
denyPermissions.add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return denyPermissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查应用是否有该权限
|
||||||
|
*
|
||||||
|
* @param permission 权限,Manifest.permission.CAMERA
|
||||||
|
* @return true ==> 已经授权
|
||||||
|
*/
|
||||||
|
public boolean checkPermission(Activity activity, String permission) {
|
||||||
|
return AndroidVersionUtil.hasM()
|
||||||
|
&& activity.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 请求悬浮权限
|
||||||
|
* 在onActivityResult里面添加以下代码
|
||||||
|
* protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
* super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
* if (requestCode == OnPermissionCallback.PERMISSION_ALERT_WINDOW) {
|
||||||
|
* if (Settings.canDrawOverlays(this)) { //在这判断是否请求权限成功
|
||||||
|
* Log.i(LOGTAG, "onActivityResult granted");
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param obj
|
||||||
|
*/
|
||||||
|
public void requestAlertWindowPermission(Object obj) {
|
||||||
|
if (!AndroidVersionUtil.hasM()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Activity activity = null;
|
||||||
|
Fragment fragment = null;
|
||||||
|
if (obj instanceof Activity) {
|
||||||
|
activity = (Activity) obj;
|
||||||
|
} else if (obj instanceof Fragment) {
|
||||||
|
fragment = (Fragment) obj;
|
||||||
|
activity = fragment.getActivity();
|
||||||
|
} else {
|
||||||
|
L.e(TAG, "obj 只能是 Activity 或者 fragment 及其衍生类");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
|
||||||
|
intent.setData(Uri.parse("package:" + activity.getPackageName()));
|
||||||
|
if (fragment != null) {
|
||||||
|
fragment.startActivityForResult(intent, OnPermissionCallback.PERMISSION_ALERT_WINDOW);
|
||||||
|
} else {
|
||||||
|
activity.startActivityForResult(intent, OnPermissionCallback.PERMISSION_ALERT_WINDOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求修改系统设置权限
|
||||||
|
*/
|
||||||
|
public void requestWriteSetting(Object obj) {
|
||||||
|
if (!AndroidVersionUtil.hasM()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Activity activity = null;
|
||||||
|
Fragment fragment = null;
|
||||||
|
if (obj instanceof Activity) {
|
||||||
|
activity = (Activity) obj;
|
||||||
|
} else if (obj instanceof Fragment) {
|
||||||
|
fragment = (Fragment) obj;
|
||||||
|
activity = fragment.getActivity();
|
||||||
|
} else {
|
||||||
|
L.e(TAG, "obj 只能是 Activity 或者 fragment 及其衍生类");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
|
||||||
|
intent.setData(Uri.parse("package:" + activity.getPackageName()));
|
||||||
|
if (fragment != null) {
|
||||||
|
fragment.startActivityForResult(intent, OnPermissionCallback.PERMISSION_WRITE_SETTING);
|
||||||
|
} else {
|
||||||
|
activity.startActivityForResult(intent, OnPermissionCallback.PERMISSION_WRITE_SETTING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
package com.arialyy.frame.temp;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import com.arialyy.frame.util.StringUtil;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/4/27.
|
||||||
|
* 抽象的填充类
|
||||||
|
*/
|
||||||
|
public abstract class AbsTempView extends LinearLayout implements ITempView {
|
||||||
|
private OnTempBtClickListener mBtListener;
|
||||||
|
private static String TAG;
|
||||||
|
protected int mType = ERROR;
|
||||||
|
|
||||||
|
public AbsTempView(Context context) {
|
||||||
|
this(context, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbsTempView(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
initView(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initView(Context context) {
|
||||||
|
View view = LayoutInflater.from(context).inflate(setLayoutId(), this);
|
||||||
|
TAG = StringUtil.getClassName(this);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果界面有按钮,则需要对着按钮的点击事件进行监听
|
||||||
|
*/
|
||||||
|
public void setBtListener(@NonNull OnTempBtClickListener listener) {
|
||||||
|
mBtListener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract int setLayoutId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将按钮点击事件传递给TempView调用类
|
||||||
|
*
|
||||||
|
* @param type {@link ITempView}
|
||||||
|
*/
|
||||||
|
protected void onTempBtClick(View view, int type) {
|
||||||
|
if (mBtListener != null) {
|
||||||
|
mBtListener.onBtTempClick(view, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setType(int type) {
|
||||||
|
mType = type;
|
||||||
|
if (type == LOADING) {
|
||||||
|
onLoading();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (type == ERROR) {
|
||||||
|
onError();
|
||||||
|
} else if (type == DATA_NULL) {
|
||||||
|
onNull();
|
||||||
|
} else {
|
||||||
|
L.e(TAG, "类型错误");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
AppFrame/src/main/java/com/arialyy/frame/temp/ITempView.java
Normal file
34
AppFrame/src/main/java/com/arialyy/frame/temp/ITempView.java
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package com.arialyy.frame.temp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/4/27.
|
||||||
|
*/
|
||||||
|
public interface ITempView {
|
||||||
|
public static final int ERROR = 0xaff1;
|
||||||
|
public static final int DATA_NULL = 0xaff2;
|
||||||
|
public static final int LOADING = 0xaff3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置填充界面类型
|
||||||
|
*
|
||||||
|
* @param type {@link ITempView#ERROR}
|
||||||
|
* {@link ITempView#DATA_NULL}
|
||||||
|
* {@link ITempView#LOADING}
|
||||||
|
*/
|
||||||
|
public void setType(int type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在这处理type = ITempView#ERROR 时的逻辑
|
||||||
|
*/
|
||||||
|
public void onError();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在这处理type = ITempView#DATA_NULL 时的逻辑
|
||||||
|
*/
|
||||||
|
public void onNull();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在这处理type = ITempView#LOADING 时的逻辑
|
||||||
|
*/
|
||||||
|
public void onLoading();
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.arialyy.frame.temp;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
public interface OnTempBtClickListener {
|
||||||
|
/**
|
||||||
|
* @param type {@link ITempView#ERROR}, {@link ITempView#DATA_NULL}, {@link ITempView#LOADING}
|
||||||
|
*/
|
||||||
|
public void onBtTempClick(View view, int type);
|
||||||
|
}
|
66
AppFrame/src/main/java/com/arialyy/frame/temp/TempView.java
Normal file
66
AppFrame/src/main/java/com/arialyy/frame/temp/TempView.java
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package com.arialyy.frame.temp;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.lyy.frame.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/1/11.
|
||||||
|
* 错误填充View
|
||||||
|
*/
|
||||||
|
public class TempView extends AbsTempView {
|
||||||
|
ProgressBar mPb;
|
||||||
|
TextView mHint;
|
||||||
|
Button mBt;
|
||||||
|
FrameLayout mErrorContent;
|
||||||
|
|
||||||
|
public TempView(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
mPb = (ProgressBar) findViewById(R.id.pb);
|
||||||
|
mHint = (TextView) findViewById(R.id.hint);
|
||||||
|
mBt = (Button) findViewById(R.id.bt);
|
||||||
|
mErrorContent = (FrameLayout) findViewById(R.id.error);
|
||||||
|
mBt.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
onTempBtClick(v, mType);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int setLayoutId() {
|
||||||
|
return R.layout.layout_error_temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError() {
|
||||||
|
mErrorContent.setVisibility(VISIBLE);
|
||||||
|
mPb.setVisibility(GONE);
|
||||||
|
mHint.setText("网络错误");
|
||||||
|
mBt.setText("点击刷新");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNull() {
|
||||||
|
mErrorContent.setVisibility(VISIBLE);
|
||||||
|
mPb.setVisibility(GONE);
|
||||||
|
mHint.setText("数据为空");
|
||||||
|
mBt.setText("点击刷新");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoading() {
|
||||||
|
mErrorContent.setVisibility(GONE);
|
||||||
|
mPb.setVisibility(VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
156
AppFrame/src/main/java/com/arialyy/frame/util/AESEncryption.java
Normal file
156
AppFrame/src/main/java/com/arialyy/frame/util/AESEncryption.java
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import java.io.File;
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import javax.crypto.Cipher;
|
||||||
|
import javax.crypto.KeyGenerator;
|
||||||
|
import javax.crypto.SecretKey;
|
||||||
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AES加密
|
||||||
|
*
|
||||||
|
* author lyy
|
||||||
|
*/
|
||||||
|
public class AESEncryption {
|
||||||
|
/**
|
||||||
|
* 4.4的要Cipher cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding");
|
||||||
|
*/
|
||||||
|
private static final int JELLY_BEAN_4_2 = 17;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密文件
|
||||||
|
*
|
||||||
|
* @param filePath 原始文件路径
|
||||||
|
* @return 加密后的文件路径
|
||||||
|
*/
|
||||||
|
public static String encryptFile(@NonNull String filePath) {
|
||||||
|
File file = new File(filePath);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密函数
|
||||||
|
*
|
||||||
|
* @param seed 密钥
|
||||||
|
* @param cleartext 说要进行加密的密码
|
||||||
|
* @return 返回的是16进制的加密类型
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String encryptString(String seed, String cleartext) throws Exception {
|
||||||
|
byte[] rawKey = getRawKey(seed.getBytes());
|
||||||
|
byte[] result = encryptByte(rawKey, cleartext.getBytes());
|
||||||
|
return toHex(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解密函数
|
||||||
|
*
|
||||||
|
* @param seed 密钥
|
||||||
|
* @param encrypted 进行加密后的密码
|
||||||
|
* @return 返回原来的密码
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String decryptString(String seed, String encrypted) throws Exception {
|
||||||
|
byte[] rawKey = getRawKey(seed.getBytes());
|
||||||
|
byte[] enc = toByte(encrypted);
|
||||||
|
byte[] result = decryptByte(rawKey, enc);
|
||||||
|
return new String(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取key
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@SuppressLint("DeletedProvider") private static byte[] getRawKey(byte[] seed) throws Exception {
|
||||||
|
KeyGenerator kgen = KeyGenerator.getInstance("AES");
|
||||||
|
|
||||||
|
SecureRandom sr = null;
|
||||||
|
if (android.os.Build.VERSION.SDK_INT >= JELLY_BEAN_4_2) {
|
||||||
|
sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
|
||||||
|
} else {
|
||||||
|
sr = SecureRandom.getInstance("SHA1PRNG");
|
||||||
|
}
|
||||||
|
// SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
|
||||||
|
sr.setSeed(seed);
|
||||||
|
kgen.init(128, sr); // 192 and 256 bits may not be available
|
||||||
|
SecretKey skey = kgen.generateKey();
|
||||||
|
return skey.getEncoded();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4.3以上的要用cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding");
|
||||||
|
* 加密byte流
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private static byte[] encryptByte(byte[] raw, byte[] clear) throws Exception {
|
||||||
|
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
|
||||||
|
Cipher cipher = null;
|
||||||
|
if (android.os.Build.VERSION.SDK_INT > JELLY_BEAN_4_2) {
|
||||||
|
cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding");
|
||||||
|
} else {
|
||||||
|
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||||
|
}
|
||||||
|
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
|
||||||
|
return cipher.doFinal(clear);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4.3以上的要用cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding");
|
||||||
|
* 解密byte流
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private static byte[] decryptByte(byte[] raw, byte[] encrypted) throws Exception {
|
||||||
|
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
|
||||||
|
Cipher cipher = null;
|
||||||
|
if (android.os.Build.VERSION.SDK_INT > JELLY_BEAN_4_2) {
|
||||||
|
cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding");
|
||||||
|
} else {
|
||||||
|
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||||
|
}
|
||||||
|
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
|
||||||
|
return cipher.doFinal(encrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toHex(String txt) {
|
||||||
|
return toHex(txt.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String fromHex(String hex) {
|
||||||
|
return new String(toByte(hex));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] toByte(String hexString) {
|
||||||
|
int len = hexString.length() / 2;
|
||||||
|
byte[] result = new byte[len];
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把用户的key转换为16为的key
|
||||||
|
* AES算法的秘钥要求16位
|
||||||
|
*/
|
||||||
|
public static String toHex(byte[] buf) {
|
||||||
|
if (buf == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
StringBuffer result = new StringBuffer(2 * buf.length);
|
||||||
|
for (byte aBuf : buf) {
|
||||||
|
appendHex(result, aBuf);
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static String HEX = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
private static void appendHex(StringBuffer sb, byte b) {
|
||||||
|
sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));
|
||||||
|
}
|
||||||
|
}
|
669
AppFrame/src/main/java/com/arialyy/frame/util/AndroidUtils.java
Normal file
669
AppFrame/src/main/java/com/arialyy/frame/util/AndroidUtils.java
Normal file
@ -0,0 +1,669 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.ActivityManager;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.os.StatFs;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.core.content.FileProvider;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
import com.arialyy.frame.util.show.FL;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* android系统工具类
|
||||||
|
*/
|
||||||
|
public class AndroidUtils {
|
||||||
|
private static final String TAG = "AndroidUtils";
|
||||||
|
|
||||||
|
private AndroidUtils() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用市场是否存在
|
||||||
|
*
|
||||||
|
* @return {@code true}存在
|
||||||
|
*/
|
||||||
|
public static boolean hasAnyMarket(Context context) {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setData(Uri.parse("market://details?id=android.browser"));
|
||||||
|
List list = context.getPackageManager()
|
||||||
|
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||||
|
|
||||||
|
return list != null && list.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查权限
|
||||||
|
*
|
||||||
|
* @param permission android.permission.WRITE_EXTERNAL_STORAGE
|
||||||
|
* @return manifest 已经定义了则返回true
|
||||||
|
*/
|
||||||
|
public static boolean checkPermission(@NonNull Context context, @NonNull String permission) {
|
||||||
|
return context.checkCallingOrSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 申请root权限
|
||||||
|
*
|
||||||
|
* @return 应用程序是/否获取Root权限
|
||||||
|
*/
|
||||||
|
public static boolean getRootPermission(String pkgCodePath) {
|
||||||
|
Process process = null;
|
||||||
|
DataOutputStream os = null;
|
||||||
|
try {
|
||||||
|
String cmd = "chmod 777 " + pkgCodePath;
|
||||||
|
process = Runtime.getRuntime().exec("su"); //切换到root帐号
|
||||||
|
os = new DataOutputStream(process.getOutputStream());
|
||||||
|
os.writeBytes(cmd + "\n");
|
||||||
|
os.writeBytes("exit\n");
|
||||||
|
os.flush();
|
||||||
|
return process.waitFor() == 0;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (os != null) {
|
||||||
|
os.close();
|
||||||
|
}
|
||||||
|
if (process != null) {
|
||||||
|
process.destroy();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定包名的包信息
|
||||||
|
*/
|
||||||
|
public static PackageInfo getAppInfo(Context context, String packageName) {
|
||||||
|
try {
|
||||||
|
return context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取未安装软件包的包名
|
||||||
|
*/
|
||||||
|
public static String getApkPackageName(Context context, String apkPath) {
|
||||||
|
PackageManager pm = context.getPackageManager();
|
||||||
|
PackageInfo info = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
|
||||||
|
if (info != null) {
|
||||||
|
ApplicationInfo appInfo = info.applicationInfo;
|
||||||
|
appInfo.sourceDir = apkPath;
|
||||||
|
appInfo.publicSourceDir = apkPath;
|
||||||
|
return appInfo.packageName;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取未安装软件包的包名
|
||||||
|
*/
|
||||||
|
public static PackageInfo getApkPackageInfo(Context context, String apkPath) {
|
||||||
|
PackageManager pm = context.getPackageManager();
|
||||||
|
return pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否安装
|
||||||
|
*/
|
||||||
|
public static boolean apkIsInstall(Context context, String apkPath) {
|
||||||
|
PackageManager pm = context.getPackageManager();
|
||||||
|
PackageInfo info = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES);
|
||||||
|
if (info != null) {
|
||||||
|
ApplicationInfo appInfo = info.applicationInfo;
|
||||||
|
appInfo.sourceDir = apkPath;
|
||||||
|
appInfo.publicSourceDir = apkPath;
|
||||||
|
try {
|
||||||
|
pm.getPackageInfo(appInfo.packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
|
||||||
|
return true;
|
||||||
|
} catch (PackageManager.NameNotFoundException localNameNotFoundException) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断服务是否后台运行
|
||||||
|
*
|
||||||
|
* @param context Context
|
||||||
|
* @return true 在运行 false 不在运行
|
||||||
|
*/
|
||||||
|
public static boolean isServiceRun(Context context, Class<?> clazz) {
|
||||||
|
boolean isRun = false;
|
||||||
|
ActivityManager activityManager =
|
||||||
|
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
List<ActivityManager.RunningServiceInfo> serviceList =
|
||||||
|
activityManager.getRunningServices(Integer.MAX_VALUE);
|
||||||
|
int size = serviceList.size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
if (serviceList.get(i).service.getClassName().equals(clazz.getName())) {
|
||||||
|
isRun = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isRun;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动另外一个App
|
||||||
|
*/
|
||||||
|
public static void startOtherApp(Context context, String packageName) {
|
||||||
|
PackageManager pm = context.getPackageManager();
|
||||||
|
Intent launcherIntent = pm.getLaunchIntentForPackage(packageName);
|
||||||
|
context.startActivity(launcherIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断手机是否拥有Root权限。
|
||||||
|
*
|
||||||
|
* @return 有root权限返回true,否则返回false。
|
||||||
|
*/
|
||||||
|
public static boolean isRoot() {
|
||||||
|
String binPath = "/system/bin/su";
|
||||||
|
String xBinPath = "/system/xbin/su";
|
||||||
|
return new File(binPath).exists() && isExecutable(binPath)
|
||||||
|
|| new File(xBinPath).exists() && isExecutable(xBinPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isExecutable(String filePath) {
|
||||||
|
Process p = null;
|
||||||
|
try {
|
||||||
|
p = Runtime.getRuntime().exec("ls -l " + filePath);
|
||||||
|
// 获取返回内容
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
|
||||||
|
String str = in.readLine();
|
||||||
|
L.i(TAG, str);
|
||||||
|
if (str != null && str.length() >= 4) {
|
||||||
|
char flag = str.charAt(3);
|
||||||
|
if (flag == 's' || flag == 'x') return true;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
if (p != null) {
|
||||||
|
p.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静默卸载
|
||||||
|
*/
|
||||||
|
public static boolean uninstallInBackground(String packageName) {
|
||||||
|
String command = "pm uninstall -k " + packageName + "\n";
|
||||||
|
ShellUtils.CommandResult result = ShellUtils.execCommand(command, true);
|
||||||
|
String errorMsg = result.errorMsg;
|
||||||
|
L.d(TAG, "error msg = " + result.errorMsg);
|
||||||
|
L.d(TAG, "success msg = " + result.successMsg);
|
||||||
|
int res = result.result;
|
||||||
|
return res == 0 && !errorMsg.contains("Failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静默安装APk
|
||||||
|
* 执行具体的静默安装逻辑,需要手机ROOT。
|
||||||
|
*
|
||||||
|
* @param apkPath 要安装的apk文件的路径
|
||||||
|
* @return 安装成功返回true,安装失败返回false。
|
||||||
|
*/
|
||||||
|
public static boolean installInBackground(String apkPath) {
|
||||||
|
String command = "pm install -r " + apkPath + "\n";
|
||||||
|
ShellUtils.CommandResult result = ShellUtils.execCommand(command, true);
|
||||||
|
String errorMsg = result.errorMsg;
|
||||||
|
L.d(TAG, "error msg = " + result.errorMsg);
|
||||||
|
L.d(TAG, "success msg = " + result.successMsg);
|
||||||
|
int res = result.result;
|
||||||
|
return res == 0 && !errorMsg.contains("Failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取状态栏高度
|
||||||
|
*/
|
||||||
|
public static int getStatusBarHeight(Context context) {
|
||||||
|
int result = 0;
|
||||||
|
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
|
||||||
|
if (resourceId > 0) {
|
||||||
|
result = context.getResources().getDimensionPixelSize(resourceId);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取导航栏高度
|
||||||
|
*/
|
||||||
|
public static int getNavigationBarHeight(Context context) {
|
||||||
|
Resources resources = context.getResources();
|
||||||
|
int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
|
||||||
|
if (resourceId > 0) {
|
||||||
|
return resources.getDimensionPixelSize(resourceId);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前窗口的高度, 该高度是不包含导航栏和状态栏的
|
||||||
|
*/
|
||||||
|
public static int getWindowHeight(Activity activity) {
|
||||||
|
return activity.getWindow().getWindowManager().getDefaultDisplay().getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前窗口的宽度
|
||||||
|
*/
|
||||||
|
public static int getWindowWidth(Activity activity) {
|
||||||
|
return activity.getWindow().getWindowManager().getDefaultDisplay().getWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取屏幕参数,这个获取到的高是包含导航栏和状态栏的
|
||||||
|
*/
|
||||||
|
public static int[] getScreenParams(Context context) {
|
||||||
|
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
return new int[] { wm.getDefaultDisplay().getWidth(), wm.getDefaultDisplay().getHeight() };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查手机是否安装了指定的APK
|
||||||
|
*
|
||||||
|
* @param packageName 该APK的包名
|
||||||
|
*/
|
||||||
|
public static boolean checkApkExists(Context context, String packageName) {
|
||||||
|
List<PackageInfo> packageInfos = getAllApps(context);
|
||||||
|
for (PackageInfo pi : packageInfos) {
|
||||||
|
if (pi.packageName.equals(packageName)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询手机内所有应用
|
||||||
|
*/
|
||||||
|
public static List<PackageInfo> getAllApps(Context context) {
|
||||||
|
List<PackageInfo> apps = new ArrayList<PackageInfo>();
|
||||||
|
PackageManager pManager = context.getPackageManager();
|
||||||
|
//获取手机内所有应用
|
||||||
|
List<PackageInfo> paklist = pManager.getInstalledPackages(0);
|
||||||
|
for (int i = 0; i < paklist.size(); i++) {
|
||||||
|
PackageInfo pak = paklist.get(i);
|
||||||
|
apps.add(pak);
|
||||||
|
}
|
||||||
|
return apps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询手机内非系统应用
|
||||||
|
*/
|
||||||
|
public static List<PackageInfo> getAllNoSystemApps(Context context) {
|
||||||
|
List<PackageInfo> apps = new ArrayList<PackageInfo>();
|
||||||
|
PackageManager pManager = context.getPackageManager();
|
||||||
|
//获取手机内所有应用
|
||||||
|
List<PackageInfo> paklist = pManager.getInstalledPackages(0);
|
||||||
|
for (int i = 0; i < paklist.size(); i++) {
|
||||||
|
PackageInfo pak = paklist.get(i);
|
||||||
|
//判断是否为非系统预装的应用程序
|
||||||
|
if ((pak.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) <= 0) {
|
||||||
|
// customs applications
|
||||||
|
apps.add(pak);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return apps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取目录
|
||||||
|
*/
|
||||||
|
public static String getSourcePath(Context context, String packageName) {
|
||||||
|
ApplicationInfo appInfo = null;
|
||||||
|
try {
|
||||||
|
appInfo = context.getPackageManager().getApplicationInfo(packageName, 0);
|
||||||
|
return appInfo.sourceDir;
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取包名
|
||||||
|
*/
|
||||||
|
public static String getPackageName(Context context) {
|
||||||
|
return getPackageInfo(context).packageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取应用名
|
||||||
|
*/
|
||||||
|
public static String getAppName(Context context) {
|
||||||
|
try {
|
||||||
|
return context.getString(context.getApplicationInfo().labelRes);
|
||||||
|
} catch (Resources.NotFoundException e) {
|
||||||
|
FL.e(TAG, FL.getExceptionString(e));
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备的唯一ID
|
||||||
|
*/
|
||||||
|
public static String getAndroidId(Context context) {
|
||||||
|
return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回版本名称
|
||||||
|
*/
|
||||||
|
public static String getVersionName(Context context) {
|
||||||
|
return getPackageInfo(context).versionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回版本号
|
||||||
|
*/
|
||||||
|
public static int getVersionCode(Context context) {
|
||||||
|
return getPackageInfo(context).versionCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开一个隐藏了图标的APP
|
||||||
|
*/
|
||||||
|
public static void openAppWithAction(Context context, String packageName, String activity) {
|
||||||
|
ComponentName componentName = new ComponentName(packageName, activity);
|
||||||
|
try {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setComponent(componentName);
|
||||||
|
context.startActivity(intent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
FL.e(TAG, "没有找到应用程序:packageName:" + packageName + " activity:" + activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用是否被安装
|
||||||
|
*/
|
||||||
|
public static boolean isInstall(Context context, String packageName) {
|
||||||
|
PackageInfo packageInfo = null;
|
||||||
|
try {
|
||||||
|
packageInfo = context.getPackageManager().getPackageInfo(packageName, 0);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
}
|
||||||
|
return packageInfo != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 安装APP
|
||||||
|
*/
|
||||||
|
public static void install(Context context, File file) {
|
||||||
|
FL.e(TAG, "install Apk:" + file.getName());
|
||||||
|
context.startActivity(getInstallIntent(context, file));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 卸载APk
|
||||||
|
*
|
||||||
|
* @param packageName 包名
|
||||||
|
*/
|
||||||
|
public static void uninstall(Context context, String packageName) {
|
||||||
|
Uri packageURI = Uri.parse("package:" + packageName);
|
||||||
|
Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
|
||||||
|
uninstallIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
context.startActivity(uninstallIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取安装应用的Intent
|
||||||
|
*/
|
||||||
|
public static Intent getInstallIntent(Context context, File file) {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setAction(Intent.ACTION_VIEW);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||||
|
Uri contentUri =
|
||||||
|
FileProvider.getUriForFile(context, context.getPackageName() + ".fileProvider", file);
|
||||||
|
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
|
||||||
|
} else {
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
|
||||||
|
}
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拷贝Assets中的文件到指定目录
|
||||||
|
*/
|
||||||
|
public static boolean copyFileFromAssets(Context context, String fileName, String path) {
|
||||||
|
boolean copyIsFinish = false;
|
||||||
|
try {
|
||||||
|
InputStream is = context.getAssets().open(fileName);
|
||||||
|
File file = FileUtil.createFile(path);
|
||||||
|
FileOutputStream fos = new FileOutputStream(file);
|
||||||
|
byte[] temp = new byte[1024];
|
||||||
|
int i = 0;
|
||||||
|
while ((i = is.read(temp)) > 0) {
|
||||||
|
fos.write(temp, 0, i);
|
||||||
|
}
|
||||||
|
fos.close();
|
||||||
|
is.close();
|
||||||
|
copyIsFinish = true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return copyIsFinish;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取版本信息
|
||||||
|
*/
|
||||||
|
public static PackageInfo getPackageInfo(Context context) {
|
||||||
|
PackageInfo pkg = null;
|
||||||
|
if (context == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
pkg = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return pkg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备的显示属性
|
||||||
|
*/
|
||||||
|
public static DisplayMetrics getDisplayMetrics(Context context) {
|
||||||
|
return context.getResources().getDisplayMetrics();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取设备型号(Nexus5)
|
||||||
|
*/
|
||||||
|
public static String getDeviceModel() {
|
||||||
|
return Build.MODEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取电话通讯管理(可以通过这个对象获取手机号码等)
|
||||||
|
*/
|
||||||
|
public static TelephonyManager getTelephonyManager(Context context) {
|
||||||
|
return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取版本号
|
||||||
|
*/
|
||||||
|
public static String getSystemVersion() {
|
||||||
|
// 获取android版本号
|
||||||
|
return Build.VERSION.RELEASE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回ApplicationInfo(可以通过这个读取meta-data等等)
|
||||||
|
*/
|
||||||
|
public static ApplicationInfo getApplicationInfo(Context context) {
|
||||||
|
if (context == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ApplicationInfo applicationInfo = null;
|
||||||
|
try {
|
||||||
|
applicationInfo = context.getPackageManager()
|
||||||
|
.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return applicationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取MetaData的Bundle
|
||||||
|
*/
|
||||||
|
public static Bundle getMetaData(Context context) {
|
||||||
|
ApplicationInfo applicationInfo = getApplicationInfo(context);
|
||||||
|
if (applicationInfo == null) {
|
||||||
|
return new Bundle();
|
||||||
|
}
|
||||||
|
return applicationInfo.metaData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用是否启动
|
||||||
|
*/
|
||||||
|
public static boolean appIsRunning(Context context) {
|
||||||
|
boolean isAppRunning = false;
|
||||||
|
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
|
||||||
|
List<ActivityManager.RunningTaskInfo> list = am.getRunningTasks(100);
|
||||||
|
String packageName = getPackageInfo(context).packageName;
|
||||||
|
for (ActivityManager.RunningTaskInfo info : list) {
|
||||||
|
if (info.topActivity.getPackageName().equals(packageName)
|
||||||
|
&& info.baseActivity.getPackageName().equals(packageName)) {
|
||||||
|
isAppRunning = true;
|
||||||
|
//find it, break
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isAppRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查系统是否有这个Intent,在启动Intent的时候需要检查,因为启动一个没有的Intent程序会Crash
|
||||||
|
*/
|
||||||
|
public static boolean isIntentSafe(Context context, Intent intent) {
|
||||||
|
PackageManager packageManager = context.getPackageManager();
|
||||||
|
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
|
||||||
|
return activities.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前包的系统缓存目录
|
||||||
|
* "/Android/data/" + context.getPackageName() + "/cache"
|
||||||
|
*/
|
||||||
|
public static String getDiskCacheDir(Context context) {
|
||||||
|
// Check if media is mounted or storage is built-in, if so, try and use external cache dir
|
||||||
|
// otherwise use internal cache dir
|
||||||
|
File cacheDirPath = getExternalCacheDir(context);
|
||||||
|
if (cacheDirPath == null) {
|
||||||
|
cacheDirPath = context.getCacheDir();
|
||||||
|
}
|
||||||
|
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|
||||||
|
|| !isExternalStorageRemovable() ? cacheDirPath.getPath() : context.getCacheDir().getPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前包的外置路径
|
||||||
|
* "/Android/data/" + context.getPackageName()
|
||||||
|
*/
|
||||||
|
public static String getDiskPackage(Context context) {
|
||||||
|
return new File(getDiskCacheDir(context)).getParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if external storage is built-in or removable.
|
||||||
|
*
|
||||||
|
* @return True if external storage is removable (like an SD card), false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.GINGERBREAD) public static boolean isExternalStorageRemovable() {
|
||||||
|
return !AndroidVersionUtil.hasGingerbread() || Environment.isExternalStorageRemovable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the external app cache directory.
|
||||||
|
*
|
||||||
|
* @param context The context to use
|
||||||
|
* @return The external cache dir
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.FROYO) public static File getExternalCacheDir(Context context) {
|
||||||
|
if (AndroidVersionUtil.hasFroyo()) {
|
||||||
|
File cacheDir;
|
||||||
|
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
|
||||||
|
|| !Environment.isExternalStorageRemovable()) {
|
||||||
|
// /sdcard/Android/data/<application package>/cache
|
||||||
|
if (context == null) {
|
||||||
|
NullPointerException ex = new NullPointerException("context == null");
|
||||||
|
FL.e(TAG, FL.getExceptionString(ex));
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
cacheDir = context.getExternalCacheDir();
|
||||||
|
} else {
|
||||||
|
// /data/data/<application package>/cache
|
||||||
|
cacheDir = context.getCacheDir();
|
||||||
|
}
|
||||||
|
return cacheDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Before Froyo we need to construct the external cache dir ourselves
|
||||||
|
final String cacheDir = "/Android/data/" + context.getPackageName() + "/cache/";
|
||||||
|
return new File(Environment.getExternalStorageDirectory().getPath() + cacheDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check how much usable space is available at a given path.
|
||||||
|
*
|
||||||
|
* @param path The path to check
|
||||||
|
* @return The space available in bytes
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.GINGERBREAD) public static long getUsableSpace(File path) {
|
||||||
|
if (AndroidVersionUtil.hasGingerbread()) {
|
||||||
|
return path.getUsableSpace();
|
||||||
|
}
|
||||||
|
final StatFs stats = new StatFs(path.getPath());
|
||||||
|
return (long) stats.getBlockSize() * (long) stats.getAvailableBlocks();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* android版本检测工具
|
||||||
|
*
|
||||||
|
* @author lyy
|
||||||
|
*/
|
||||||
|
public class AndroidVersionUtil {
|
||||||
|
private AndroidVersionUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前Android系统版本是否在( Donut) Android 1.6或以上
|
||||||
|
*/
|
||||||
|
public static boolean hasDonut() {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.DONUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前Android系统版本是否在( Eclair) Android 2.0或 以上
|
||||||
|
*/
|
||||||
|
public static boolean hasEclair() {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前Android系统版本是否在( Froyo) Android 2.2或 Android 2.2以上
|
||||||
|
*/
|
||||||
|
public static boolean hasFroyo() {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前Android系统版本是否在( Gingerbread) Android 2.3x或 Android 2.3x 以上
|
||||||
|
*/
|
||||||
|
public static boolean hasGingerbread() {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前Android系统版本是否在( Honeycomb) Android3.1或 Android3.1以上
|
||||||
|
*/
|
||||||
|
public static boolean hasHoneycomb() {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前Android系统版本是否在( HoneycombMR1) Android3.1.1或 Android3.1.1以上
|
||||||
|
*/
|
||||||
|
public static boolean hasHoneycombMR1() {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前Android系统版本是否在( IceCreamSandwich) Android4.0或 Android4.0以上
|
||||||
|
*/
|
||||||
|
public static boolean hasIcecreamsandwich() {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前android系统版本是否在(JellyBean)Android4.1或android4.1以上
|
||||||
|
*/
|
||||||
|
public static boolean hasJellyBean() {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前android系统版本是否在(KitKat)Android4.4或android4.4以上
|
||||||
|
*/
|
||||||
|
public static boolean hasKitKat() {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前是否在5.0以上
|
||||||
|
*/
|
||||||
|
public static boolean hasLollipop() {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前是否在6.0以上
|
||||||
|
*/
|
||||||
|
public static boolean hasM() {
|
||||||
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.Signature;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用签名信息
|
||||||
|
* Created by YangQiang on 2014/11/27.
|
||||||
|
*/
|
||||||
|
public class AppSigning {
|
||||||
|
public final static String MD5 = "MD5";
|
||||||
|
public final static String SHA1 = "SHA1";
|
||||||
|
public final static String SHA256 = "SHA256";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回一个签名的对应类型的字符串
|
||||||
|
*/
|
||||||
|
public static ArrayList<String> getSingInfo(Context context, String packageName, String type) {
|
||||||
|
ArrayList<String> result = new ArrayList<String>();
|
||||||
|
try {
|
||||||
|
Signature[] signs = getSignatures(context, packageName);
|
||||||
|
for (Signature sig : signs) {
|
||||||
|
String tmp = "error!";
|
||||||
|
if (MD5.equals(type)) {
|
||||||
|
tmp = getSignatureString(sig, MD5);
|
||||||
|
} else if (SHA1.equals(type)) {
|
||||||
|
tmp = getSignatureString(sig, SHA1);
|
||||||
|
} else if (SHA256.equals(type)) {
|
||||||
|
tmp = getSignatureString(sig, SHA256);
|
||||||
|
}
|
||||||
|
result.add(tmp);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回对应包的签名信息
|
||||||
|
*/
|
||||||
|
public static Signature[] getSignatures(Context context, String packageName) {
|
||||||
|
PackageInfo packageInfo = null;
|
||||||
|
try {
|
||||||
|
packageInfo =
|
||||||
|
context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
|
||||||
|
return packageInfo.signatures;
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取相应的类型的字符串(把签名的byte[]信息转换成16进制)
|
||||||
|
*/
|
||||||
|
public static String getSignatureString(Signature sig, String type) {
|
||||||
|
byte[] hexBytes = sig.toByteArray();
|
||||||
|
String fingerprint = "error!";
|
||||||
|
try {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance(type);
|
||||||
|
if (digest != null) {
|
||||||
|
byte[] digestBytes = digest.digest(hexBytes);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (byte digestByte : digestBytes) {
|
||||||
|
sb.append((Integer.toHexString((digestByte & 0xFF) | 0x100)).substring(1, 3));
|
||||||
|
}
|
||||||
|
fingerprint = sb.toString();
|
||||||
|
}
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return fingerprint;
|
||||||
|
}
|
||||||
|
}
|
137
AppFrame/src/main/java/com/arialyy/frame/util/AppUtils.java
Normal file
137
AppFrame/src/main/java/com/arialyy/frame/util/AppUtils.java
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
|
import android.content.pm.Signature;
|
||||||
|
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跟App相关的辅助类
|
||||||
|
*/
|
||||||
|
public class AppUtils {
|
||||||
|
/**
|
||||||
|
* 应用签名信息
|
||||||
|
*/
|
||||||
|
public final static String MD5 = "MD5";
|
||||||
|
public final static String SHA1 = "SHA1";
|
||||||
|
public final static String SHA256 = "SHA256";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回一个签名的对应类型的字符串
|
||||||
|
*/
|
||||||
|
public static ArrayList<String> getSingInfo(Context context, String packageName, String type) {
|
||||||
|
ArrayList<String> result = new ArrayList<String>();
|
||||||
|
try {
|
||||||
|
Signature[] signs = getSignatures(context, packageName);
|
||||||
|
for (Signature sig : signs) {
|
||||||
|
String tmp = "error!";
|
||||||
|
if (MD5.equals(type)) {
|
||||||
|
tmp = getSignatureString(sig, MD5);
|
||||||
|
} else if (SHA1.equals(type)) {
|
||||||
|
tmp = getSignatureString(sig, SHA1);
|
||||||
|
} else if (SHA256.equals(type)) {
|
||||||
|
tmp = getSignatureString(sig, SHA256);
|
||||||
|
}
|
||||||
|
result.add(tmp);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回对应包的签名信息
|
||||||
|
*/
|
||||||
|
public static Signature[] getSignatures(Context context, String packageName) {
|
||||||
|
PackageInfo packageInfo = null;
|
||||||
|
try {
|
||||||
|
packageInfo =
|
||||||
|
context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
|
||||||
|
return packageInfo.signatures;
|
||||||
|
} catch (NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取相应的类型的字符串(把签名的byte[]信息转换成16进制)
|
||||||
|
*/
|
||||||
|
public static String getSignatureString(Signature sig, String type) {
|
||||||
|
byte[] hexBytes = sig.toByteArray();
|
||||||
|
String fingerprint = "error!";
|
||||||
|
try {
|
||||||
|
MessageDigest digest = MessageDigest.getInstance(type);
|
||||||
|
if (digest != null) {
|
||||||
|
byte[] digestBytes = digest.digest(hexBytes);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (byte digestByte : digestBytes) {
|
||||||
|
sb.append((Integer.toHexString((digestByte & 0xFF) | 0x100)).substring(1, 3));
|
||||||
|
}
|
||||||
|
fingerprint = sb.toString();
|
||||||
|
}
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return fingerprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AppUtils() {
|
||||||
|
throw new UnsupportedOperationException("cannot be instantiated");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取应用程序名称
|
||||||
|
*/
|
||||||
|
public static String getAppName(Context context) {
|
||||||
|
try {
|
||||||
|
PackageManager packageManager = context.getPackageManager();
|
||||||
|
PackageInfo packageInfo = packageManager.getPackageInfo(
|
||||||
|
context.getPackageName(), 0);
|
||||||
|
int labelRes = packageInfo.applicationInfo.labelRes;
|
||||||
|
return context.getResources().getString(labelRes);
|
||||||
|
} catch (NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [获取应用程序版本名称信息]
|
||||||
|
*
|
||||||
|
* @return 当前应用的版本名称
|
||||||
|
*/
|
||||||
|
public static String getVersionName(Context context) {
|
||||||
|
try {
|
||||||
|
PackageManager packageManager = context.getPackageManager();
|
||||||
|
PackageInfo packageInfo = packageManager.getPackageInfo(
|
||||||
|
context.getPackageName(), 0);
|
||||||
|
return packageInfo.versionName;
|
||||||
|
} catch (NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取应用版本号
|
||||||
|
*
|
||||||
|
* @return 当前应用版本
|
||||||
|
*/
|
||||||
|
public static int getVersionNumber(Context context) {
|
||||||
|
try {
|
||||||
|
PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
||||||
|
return info.versionCode;
|
||||||
|
} catch (NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
299
AppFrame/src/main/java/com/arialyy/frame/util/CalendarUtils.java
Normal file
299
AppFrame/src/main/java/com/arialyy/frame/util/CalendarUtils.java
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import com.arialyy.frame.util.show.FL;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日历工具类 Create by lyy on 13-7-8.
|
||||||
|
*/
|
||||||
|
public class CalendarUtils {
|
||||||
|
private static final String TAG = "CalendarUtils";
|
||||||
|
/**
|
||||||
|
* 完整的日期时间格式
|
||||||
|
*/
|
||||||
|
public final static String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
/**
|
||||||
|
* 只有日期的格式
|
||||||
|
*/
|
||||||
|
public final static String DATE_FORMAT = "yyyy-MM-dd";
|
||||||
|
/**
|
||||||
|
* 只有时间的格式
|
||||||
|
*/
|
||||||
|
public final static String TIME_FORMAT = "HH:mm:ss";
|
||||||
|
/**
|
||||||
|
* 带中文的日期格式(2000年01月01日)
|
||||||
|
*/
|
||||||
|
public final static String DATE_FORMAT_WITH_CHINESE = "yyyy年MM月dd日";
|
||||||
|
/**
|
||||||
|
* 短时间格式(HH:mm)
|
||||||
|
*/
|
||||||
|
public final static String SHORT_TIME_FORMAT = "HH:mm";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 私有构造
|
||||||
|
*/
|
||||||
|
private CalendarUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把String类型的日期转换成Calendar对象
|
||||||
|
*
|
||||||
|
* @param string (日期时间:2000-00-00 00:00:00)
|
||||||
|
*/
|
||||||
|
public static Calendar transformStringToCalendar(String string) {
|
||||||
|
return transformStringToCalendar(string, DATE_TIME_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过SimpleDataFormat格式把string转换成Calendar
|
||||||
|
*
|
||||||
|
* @param string 日期字符串
|
||||||
|
* @param format 目标日期格式
|
||||||
|
*/
|
||||||
|
public static Calendar transformStringToCalendar(String string, String format) {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(format);
|
||||||
|
Date date = null;
|
||||||
|
try {
|
||||||
|
date = sdf.parse(string);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
calendar.setTime(date);
|
||||||
|
return calendar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把日期字符串转换成TimeMillis
|
||||||
|
*/
|
||||||
|
public static long transformStringToMillis(String string) {
|
||||||
|
return transformStringToCalendar(string).getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过TimeMillis转换成秒钟
|
||||||
|
*
|
||||||
|
* @param millis TimeMillis
|
||||||
|
*/
|
||||||
|
public static long getSecondWithTimeMillis(long millis) {
|
||||||
|
return millis / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回两个日期相差的秒
|
||||||
|
*/
|
||||||
|
public static long getIntervalInSeconds(Calendar calendar, Calendar targetCalendar) {
|
||||||
|
return (calendar.getTimeInMillis() - targetCalendar.getTimeInMillis()) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化日期
|
||||||
|
*
|
||||||
|
* @param string 有效的日期字符
|
||||||
|
* @param format 格式化的格式
|
||||||
|
*/
|
||||||
|
public static String formatWithString(String string, String format) {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(format);
|
||||||
|
return sdf.format(transformStringToCalendar(string).getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化日期
|
||||||
|
*
|
||||||
|
* @param src 源日期字符
|
||||||
|
* @param srcFormat 源日期格式
|
||||||
|
* @param targetFormat 目标日期格式
|
||||||
|
*/
|
||||||
|
public static String formatWithString(String src, String srcFormat, String targetFormat) {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(srcFormat);
|
||||||
|
try {
|
||||||
|
Date date = sdf.parse(src);
|
||||||
|
SimpleDateFormat targetSdf = new SimpleDateFormat(targetFormat);
|
||||||
|
return targetSdf.format(date);
|
||||||
|
} catch (Exception e) {
|
||||||
|
FL.e(TAG, "src=" + src + " " + srcFormat + " " + targetFormat);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化成日期时间
|
||||||
|
*
|
||||||
|
* @param string 将要被格式化的日期字符串
|
||||||
|
* @return 格式:(2000-00-00 00:00:00)
|
||||||
|
*/
|
||||||
|
public static String formatDateTimeWithString(String string) {
|
||||||
|
return formatWithString(string, DATE_TIME_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化日期
|
||||||
|
*
|
||||||
|
* @param srcDate 源日期字符
|
||||||
|
* @param srcDateFormat 源日期格式
|
||||||
|
* @param targetFormat 目标格式
|
||||||
|
*/
|
||||||
|
public static String formatDateTimeWithString(String srcDate, String srcDateFormat,
|
||||||
|
String targetFormat) {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(srcDateFormat);
|
||||||
|
try {
|
||||||
|
Date date = sdf.parse(srcDate);
|
||||||
|
SimpleDateFormat parseSdf = new SimpleDateFormat(targetFormat);
|
||||||
|
return parseSdf.format(date);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
FL.e(TAG, "srcDate:"
|
||||||
|
+ srcDate
|
||||||
|
+ " srcDateFormat:"
|
||||||
|
+ srcDateFormat
|
||||||
|
+ " targetFormat"
|
||||||
|
+ targetFormat);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化日期
|
||||||
|
*
|
||||||
|
* @param string 将要被格式化的日期字符串
|
||||||
|
* @return 格式:(2000-00-00)
|
||||||
|
*/
|
||||||
|
public static String formatDateWithString(String string) {
|
||||||
|
return formatWithString(string, DATE_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化日期
|
||||||
|
*
|
||||||
|
* @param string 将要被格式化的日期字符串
|
||||||
|
* @return 格式:(00:00:00)
|
||||||
|
*/
|
||||||
|
public static String formatTimeWithString(String string) {
|
||||||
|
return formatWithString(string, TIME_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化日期
|
||||||
|
*
|
||||||
|
* @param string 将要被格式化的日期字符串
|
||||||
|
* @return 格式:(2000年01月01日)
|
||||||
|
*/
|
||||||
|
public static String formatStringToChinese(String string) {
|
||||||
|
return formatWithString(string, DATE_FORMAT_WITH_CHINESE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data日期格式化成String
|
||||||
|
*
|
||||||
|
* @param date 将要被格式化的data
|
||||||
|
* @return 格式:(2000-00-00 00:00:00)
|
||||||
|
*/
|
||||||
|
public static String formatDateTimeWithDate(Date date) {
|
||||||
|
return formatStringWithDate(date, DATE_TIME_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间戳格式的数据格式化成需要的格式
|
||||||
|
*
|
||||||
|
* @param string 将要被格式化的时间戳
|
||||||
|
* @return 格式:(2000-00-00 00:00:00)
|
||||||
|
*/
|
||||||
|
public static String formatDateTimeWithTime(String string) {
|
||||||
|
return formatStringWithDate(timeToData(string), DATE_TIME_FORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把中文日期(2000年01月01日)格式化成标准日期(2000-01-01)
|
||||||
|
*
|
||||||
|
* @param data 将要格式化的日期字符串
|
||||||
|
* @return 格式:(2000-00-00);
|
||||||
|
*/
|
||||||
|
public static String formatChineseDataToData(String data) {
|
||||||
|
data = data.replace("年", "-");
|
||||||
|
data = data.replace("月", "-");
|
||||||
|
data = data.replace("日", "");
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期格式化成String
|
||||||
|
*
|
||||||
|
* @param date 将要格式化的日期字符串
|
||||||
|
* @return 格式:(format格式)
|
||||||
|
*/
|
||||||
|
public static String formatStringWithDate(Date date, String format) {
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(format);
|
||||||
|
return sdf.format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把String类型的时间转换成Calendar
|
||||||
|
*
|
||||||
|
* @param time 时间格式:00:00:00
|
||||||
|
*/
|
||||||
|
public static Calendar transformStringTimeToCalendar(String time) {
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
String[] split = time.split(":");
|
||||||
|
if (split.length > 0) {
|
||||||
|
calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(split[0]));
|
||||||
|
}
|
||||||
|
if (split.length > 1) {
|
||||||
|
calendar.set(Calendar.MINUTE, Integer.parseInt(split[1]));
|
||||||
|
}
|
||||||
|
if (split.length > 2) {
|
||||||
|
calendar.set(Calendar.SECOND, Integer.parseInt(split[2]));
|
||||||
|
}
|
||||||
|
return calendar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把时间戳:1234567890123,转换成Date对象
|
||||||
|
*/
|
||||||
|
public static Date timeToData(String time) {
|
||||||
|
return new Date(Long.parseLong(time));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较两个字符串日期的大小
|
||||||
|
*
|
||||||
|
* @return 小于0:srcData 小于 tagData;
|
||||||
|
* 等于0:则srcData = tagData;
|
||||||
|
* 大于0:则srcData 大余 tagData
|
||||||
|
*/
|
||||||
|
public static int compare(String srcDate, String tagDate) {
|
||||||
|
return srcDate.compareTo(tagDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回现在的日期和时间
|
||||||
|
*
|
||||||
|
* @return 格式:2000-00-00 00:00:00
|
||||||
|
*/
|
||||||
|
public static String getNowDataTime() {
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
return formatDateTimeWithDate(calendar.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回当前的日期
|
||||||
|
*
|
||||||
|
* @return 格式:2000-00-00
|
||||||
|
*/
|
||||||
|
public static String getData() {
|
||||||
|
return getNowDataTime().split(" ")[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回当前时间
|
||||||
|
*
|
||||||
|
* @return 格式:00:00:00
|
||||||
|
*/
|
||||||
|
public static String getTime() {
|
||||||
|
return getNowDataTime().split(" ")[1];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.util.TypedValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 常用单位转换的辅助类
|
||||||
|
*/
|
||||||
|
public class DensityUtils {
|
||||||
|
private DensityUtils() {
|
||||||
|
/* cannot be instantiated */
|
||||||
|
throw new UnsupportedOperationException("cannot be instantiated");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final float DENSITY = Resources.getSystem().getDisplayMetrics().density;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 另外一种dp转PX方法
|
||||||
|
*/
|
||||||
|
public static int dp2px(int dp) {
|
||||||
|
return Math.round(dp * DENSITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dp转px
|
||||||
|
*/
|
||||||
|
public static int dp2px(Context context, float dpVal) {
|
||||||
|
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
||||||
|
dpVal, context.getResources().getDisplayMetrics());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sp转px
|
||||||
|
*/
|
||||||
|
public static int sp2px(Context context, float spVal) {
|
||||||
|
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
|
||||||
|
spVal, context.getResources().getDisplayMetrics());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* px转dp
|
||||||
|
*/
|
||||||
|
public static float px2dp(Context context, float pxVal) {
|
||||||
|
final float scale = context.getResources().getDisplayMetrics().density;
|
||||||
|
return (pxVal / scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* px转sp
|
||||||
|
*/
|
||||||
|
public static float px2sp(Context context, float pxVal) {
|
||||||
|
return (pxVal / context.getResources().getDisplayMetrics().scaledDensity);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.PixelFormat;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class DrawableUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View 转换为bitmap
|
||||||
|
*/
|
||||||
|
public static Bitmap convertViewToBitmap(View v) {
|
||||||
|
v.setDrawingCacheEnabled(true);
|
||||||
|
v.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
|
||||||
|
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
|
||||||
|
v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
|
||||||
|
|
||||||
|
v.buildDrawingCache(true);
|
||||||
|
Bitmap b = Bitmap.createBitmap(v.getDrawingCache());
|
||||||
|
v.setDrawingCacheEnabled(false); // clear drawing cache
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收缩图片
|
||||||
|
*/
|
||||||
|
public static Drawable zoomDrawable(Drawable drawable, int w, int h) {
|
||||||
|
int width = drawable.getIntrinsicWidth();
|
||||||
|
int height = drawable.getIntrinsicHeight();
|
||||||
|
Bitmap oldbmp = drawableToBitmap(drawable);
|
||||||
|
Matrix matrix = new Matrix();
|
||||||
|
float scaleWidth = ((float) w / width);
|
||||||
|
float scaleHeight = ((float) h / height);
|
||||||
|
matrix.postScale(scaleWidth, scaleHeight);
|
||||||
|
Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height,
|
||||||
|
matrix, true);
|
||||||
|
return new BitmapDrawable(null, newbmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drawable转bitMap
|
||||||
|
*/
|
||||||
|
public static Bitmap drawableToBitmap(Drawable drawable) {
|
||||||
|
int width = drawable.getIntrinsicWidth();
|
||||||
|
int height = drawable.getIntrinsicHeight();
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(width, height, drawable
|
||||||
|
.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
|
||||||
|
: Bitmap.Config.RGB_565);
|
||||||
|
Canvas canvas = new Canvas(bitmap);
|
||||||
|
drawable.setBounds(0, 0, width, height);
|
||||||
|
drawable.draw(canvas);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BitMap2Byte
|
||||||
|
*/
|
||||||
|
public static byte[] getBitmapByte(Bitmap bitmap) {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
|
||||||
|
try {
|
||||||
|
out.flush();
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return out.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Byte2BitMap
|
||||||
|
*/
|
||||||
|
public static Bitmap getBitmapFromByte(byte[] temp) {
|
||||||
|
if (temp != null) {
|
||||||
|
Bitmap bitmap = BitmapFactory.decodeByteArray(temp, 0, temp.length);
|
||||||
|
return bitmap;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
531
AppFrame/src/main/java/com/arialyy/frame/util/FileUtil.java
Normal file
531
AppFrame/src/main/java/com/arialyy/frame/util/FileUtil.java
Normal file
@ -0,0 +1,531 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import com.arialyy.frame.util.show.FL;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.BufferedOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件操作工具 可以创建和删除文件等
|
||||||
|
*/
|
||||||
|
public class FileUtil {
|
||||||
|
private static final String KB = "KB";
|
||||||
|
private static final String MB = "MB";
|
||||||
|
private static final String GB = "GB";
|
||||||
|
|
||||||
|
private static final String TAG = "FileUtil";
|
||||||
|
|
||||||
|
//android获取一个用于打开HTML文件的intent
|
||||||
|
public static Intent getHtmlFileIntent(String Path) {
|
||||||
|
File file = new File(Path);
|
||||||
|
Uri uri = Uri.parse(file.toString())
|
||||||
|
.buildUpon()
|
||||||
|
.encodedAuthority("com.android.htmlfileprovider")
|
||||||
|
.scheme("content")
|
||||||
|
.encodedPath(file.toString())
|
||||||
|
.build();
|
||||||
|
Intent intent = new Intent("android.intent.action.VIEW");
|
||||||
|
intent.setDataAndType(uri, "text/html");
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件夹大小
|
||||||
|
*/
|
||||||
|
public static long getDirSize(String filePath) {
|
||||||
|
long size = 0;
|
||||||
|
File f = new File(filePath);
|
||||||
|
if (f.isDirectory()) {
|
||||||
|
File[] files = f.listFiles();
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
size += getDirSize(file.getPath());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
size += file.length();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
size += f.length();
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储bitmap
|
||||||
|
*/
|
||||||
|
public static void saveBitmap(@NonNull String filePath, @NonNull Bitmap bitmap) {
|
||||||
|
File file = createFile(filePath);
|
||||||
|
try {
|
||||||
|
FileOutputStream os = new FileOutputStream(file);
|
||||||
|
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, os);
|
||||||
|
os.flush();
|
||||||
|
os.close();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化文件大小
|
||||||
|
*
|
||||||
|
* @param size file.length() 获取文件大小
|
||||||
|
*/
|
||||||
|
public static String formatFileSize(double size) {
|
||||||
|
double kiloByte = size / 1024;
|
||||||
|
if (kiloByte < 1) {
|
||||||
|
return size + "B";
|
||||||
|
}
|
||||||
|
|
||||||
|
double megaByte = kiloByte / 1024;
|
||||||
|
if (megaByte < 1) {
|
||||||
|
BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
|
||||||
|
return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "KB";
|
||||||
|
}
|
||||||
|
|
||||||
|
double gigaByte = megaByte / 1024;
|
||||||
|
if (gigaByte < 1) {
|
||||||
|
BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
|
||||||
|
return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "MB";
|
||||||
|
}
|
||||||
|
|
||||||
|
double teraBytes = gigaByte / 1024;
|
||||||
|
if (teraBytes < 1) {
|
||||||
|
BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
|
||||||
|
return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "GB";
|
||||||
|
}
|
||||||
|
BigDecimal result4 = new BigDecimal(teraBytes);
|
||||||
|
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "TB";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件后缀名
|
||||||
|
*/
|
||||||
|
public static String getFileExtensionName(String fileName) {
|
||||||
|
if (TextUtils.isEmpty(fileName)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
int endP = fileName.lastIndexOf(".");
|
||||||
|
return endP > -1 ? fileName.substring(endP + 1, fileName.length()) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验文件MD5码
|
||||||
|
*/
|
||||||
|
public static boolean checkMD5(String md5, File updateFile) {
|
||||||
|
if (TextUtils.isEmpty(md5) || updateFile == null) {
|
||||||
|
L.e(TAG, "MD5 string empty or updateFile null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String calculatedDigest = getFileMD5(updateFile);
|
||||||
|
if (calculatedDigest == null) {
|
||||||
|
L.e(TAG, "calculatedDigest null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return calculatedDigest.equalsIgnoreCase(md5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件MD5码
|
||||||
|
*/
|
||||||
|
public static String getFileMD5(File updateFile) {
|
||||||
|
MessageDigest digest;
|
||||||
|
try {
|
||||||
|
digest = MessageDigest.getInstance("MD5");
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
L.e(TAG, "Exception while getting digest", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream is;
|
||||||
|
try {
|
||||||
|
is = new FileInputStream(updateFile);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
L.e(TAG, "Exception while getting FileInputStream", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] buffer = new byte[8192];
|
||||||
|
int read;
|
||||||
|
try {
|
||||||
|
while ((read = is.read(buffer)) > 0) {
|
||||||
|
digest.update(buffer, 0, read);
|
||||||
|
}
|
||||||
|
byte[] md5sum = digest.digest();
|
||||||
|
BigInteger bigInt = new BigInteger(1, md5sum);
|
||||||
|
String output = bigInt.toString(16);
|
||||||
|
// Fill to 32 chars
|
||||||
|
output = String.format("%32s", output).replace(' ', '0');
|
||||||
|
return output;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Unable to process file for MD5", e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
L.e(TAG, "Exception on closing MD5 input stream", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解压缩功能.
|
||||||
|
* 将ZIP_FILENAME文件解压到ZIP_DIR目录下.
|
||||||
|
*
|
||||||
|
* @param zipFile 压缩文件
|
||||||
|
* @param folderPath 解压目录
|
||||||
|
*/
|
||||||
|
public static int unZipFile(File zipFile, String folderPath) {
|
||||||
|
ZipFile zfile = null;
|
||||||
|
try {
|
||||||
|
zfile = new ZipFile(zipFile);
|
||||||
|
Enumeration zList = zfile.entries();
|
||||||
|
ZipEntry ze = null;
|
||||||
|
byte[] buf = new byte[1024];
|
||||||
|
while (zList.hasMoreElements()) {
|
||||||
|
ze = (ZipEntry) zList.nextElement();
|
||||||
|
if (ze.isDirectory()) {
|
||||||
|
// L.d(TAG, "ze.getName() = " + ze.getName());
|
||||||
|
String dirstr = folderPath + ze.getName();
|
||||||
|
//dirstr.trim();
|
||||||
|
dirstr = new String(dirstr.getBytes("8859_1"), "GB2312");
|
||||||
|
// L.d(TAG, "str = " + dirstr);
|
||||||
|
File f = new File(dirstr);
|
||||||
|
f.mkdir();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// L.d(TAG, "ze.getName() = " + ze.getName());
|
||||||
|
OutputStream os = new BufferedOutputStream(
|
||||||
|
new FileOutputStream(getRealFileName(folderPath, ze.getName())));
|
||||||
|
InputStream is = new BufferedInputStream(zfile.getInputStream(ze));
|
||||||
|
int readLen = 0;
|
||||||
|
while ((readLen = is.read(buf)) != -1) {
|
||||||
|
os.write(buf, 0, readLen);
|
||||||
|
}
|
||||||
|
is.close();
|
||||||
|
os.close();
|
||||||
|
}
|
||||||
|
zfile.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 给定根目录,返回一个相对路径所对应的实际文件名.
|
||||||
|
*
|
||||||
|
* @param baseDir 指定根目录
|
||||||
|
* @param absFileName 相对路径名,来自于ZipEntry中的name
|
||||||
|
* @return java.io.File 实际的文件
|
||||||
|
*/
|
||||||
|
private static File getRealFileName(String baseDir, String absFileName) {
|
||||||
|
String[] dirs = absFileName.split("/");
|
||||||
|
File ret = new File(baseDir);
|
||||||
|
String substr = null;
|
||||||
|
if (dirs.length > 1) {
|
||||||
|
for (int i = 0; i < dirs.length - 1; i++) {
|
||||||
|
substr = dirs[i];
|
||||||
|
try {
|
||||||
|
//substr.trim();
|
||||||
|
substr = new String(substr.getBytes("8859_1"), "GB2312");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
ret = new File(ret, substr);
|
||||||
|
}
|
||||||
|
// L.d("upZipFile", "1ret = " + ret);
|
||||||
|
if (!ret.exists()) ret.mkdirs();
|
||||||
|
substr = dirs[dirs.length - 1];
|
||||||
|
try {
|
||||||
|
//substr.trim();
|
||||||
|
substr = new String(substr.getBytes("8859_1"), "GB2312");
|
||||||
|
// L.d("upZipFile", "substr = " + substr);
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
ret = new File(ret, substr);
|
||||||
|
// L.d("upZipFile", "2ret = " + ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过流创建文件
|
||||||
|
*/
|
||||||
|
public static void createFileFormInputStream(InputStream is, String path) {
|
||||||
|
try {
|
||||||
|
FileOutputStream fos = new FileOutputStream(path);
|
||||||
|
byte[] buf = new byte[1376];
|
||||||
|
while (is.read(buf) > 0) {
|
||||||
|
fos.write(buf, 0, buf.length);
|
||||||
|
}
|
||||||
|
is.close();
|
||||||
|
fos.flush();
|
||||||
|
fos.close();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从文件读取对象
|
||||||
|
*/
|
||||||
|
public static Object readObj(String path) {
|
||||||
|
FileInputStream fis = null;
|
||||||
|
ObjectInputStream ois = null;
|
||||||
|
try {
|
||||||
|
fis = new FileInputStream(path);
|
||||||
|
ois = new ObjectInputStream(fis);
|
||||||
|
return ois.readObject();
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
FL.e(TAG, FL.getExceptionString(e));
|
||||||
|
} catch (IOException e) {
|
||||||
|
FL.e(TAG, FL.getExceptionString(e));
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
FL.e(TAG, FL.getExceptionString(e));
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (fis != null) {
|
||||||
|
fis.close();
|
||||||
|
}
|
||||||
|
if (ois != null) {
|
||||||
|
ois.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
FL.e(TAG, FL.getExceptionString(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储对象到文件,只有实现了Serailiable接口的对象才能被存储
|
||||||
|
*/
|
||||||
|
public static void writeObj(String path, Object object) {
|
||||||
|
FileOutputStream fos = null;
|
||||||
|
ObjectOutputStream oos = null;
|
||||||
|
File file = new File(path);
|
||||||
|
if (!file.getParentFile().exists()) {
|
||||||
|
file.mkdirs();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
fos = new FileOutputStream(path);
|
||||||
|
oos = new ObjectOutputStream(fos);
|
||||||
|
oos.writeObject(object);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
FL.e(TAG, FL.getExceptionString(e));
|
||||||
|
} catch (IOException e) {
|
||||||
|
FL.e(TAG, FL.getExceptionString(e));
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (fos != null) {
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
if (oos != null) {
|
||||||
|
oos.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
FL.e(TAG, FL.getExceptionString(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建文件 当文件不存在的时候就创建一个文件,否则直接返回文件
|
||||||
|
*/
|
||||||
|
public static File createFile(String path) {
|
||||||
|
File file = new File(path);
|
||||||
|
if (!file.getParentFile().exists()) {
|
||||||
|
FL.d(TAG, "目标文件所在路径不存在,准备创建……");
|
||||||
|
if (!createDir(file.getParent())) {
|
||||||
|
FL.d(TAG, "创建目录文件所在的目录失败!文件路径【" + path + "】");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 创建目标文件
|
||||||
|
try {
|
||||||
|
if (!file.exists()) {
|
||||||
|
if (file.createNewFile()) {
|
||||||
|
FL.d(TAG, "创建文件成功:" + file.getAbsolutePath());
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
} else {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建目录 当目录不存在的时候创建文件,否则返回false
|
||||||
|
*/
|
||||||
|
public static boolean createDir(String path) {
|
||||||
|
File file = new File(path);
|
||||||
|
if (!file.exists()) {
|
||||||
|
if (!file.mkdirs()) {
|
||||||
|
FL.d(TAG, "创建失败,请检查路径和是否配置文件权限!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拷贝文件
|
||||||
|
*/
|
||||||
|
public static boolean copy(String fromPath, String toPath) {
|
||||||
|
File file = new File(fromPath);
|
||||||
|
if (!file.exists()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
createFile(toPath);
|
||||||
|
return copyFile(fromPath, toPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拷贝文件
|
||||||
|
*/
|
||||||
|
private static boolean copyFile(String fromFile, String toFile) {
|
||||||
|
InputStream fosfrom = null;
|
||||||
|
OutputStream fosto = null;
|
||||||
|
try {
|
||||||
|
fosfrom = new FileInputStream(fromFile);
|
||||||
|
fosto = new FileOutputStream(toFile);
|
||||||
|
byte bt[] = new byte[1024];
|
||||||
|
int c;
|
||||||
|
while ((c = fosfrom.read(bt)) > 0) {
|
||||||
|
fosto.write(bt, 0, c);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (fosfrom != null) {
|
||||||
|
fosfrom.close();
|
||||||
|
}
|
||||||
|
if (fosto != null) {
|
||||||
|
fosto.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除文件 如果文件存在删除文件,否则返回false
|
||||||
|
*/
|
||||||
|
public static boolean deleteFile(String path) {
|
||||||
|
File file = new File(path);
|
||||||
|
if (file.exists()) {
|
||||||
|
file.delete();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归删除目录下的所有文件及子目录下所有文件
|
||||||
|
*
|
||||||
|
* @param dir 将要删除的文件目录
|
||||||
|
* @return 删除成功返回true,否则返回false,如果文件是空,那么永远返回true
|
||||||
|
*/
|
||||||
|
public static boolean deleteDir(File dir) {
|
||||||
|
if (dir == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (dir.isDirectory()) {
|
||||||
|
String[] children = dir.list();
|
||||||
|
// 递归删除目录中的子目录下
|
||||||
|
for (String aChildren : children) {
|
||||||
|
boolean success = deleteDir(new File(dir, aChildren));
|
||||||
|
if (!success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 目录此时为空,可以删除
|
||||||
|
return dir.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归返回文件或者目录的大小(单位:KB)
|
||||||
|
* 不建议使用这个方法,有点坑
|
||||||
|
* 可以使用下面的方法:http://blog.csdn.net/loongggdroid/article/details/12304695
|
||||||
|
*/
|
||||||
|
private static float getSize(String path, Float size) {
|
||||||
|
File file = new File(path);
|
||||||
|
if (file.exists()) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
String[] children = file.list();
|
||||||
|
for (int fileIndex = 0; fileIndex < children.length; ++fileIndex) {
|
||||||
|
float tmpSize =
|
||||||
|
getSize(file.getPath() + File.separator + children[fileIndex], size) / 1000;
|
||||||
|
size += tmpSize;
|
||||||
|
}
|
||||||
|
} else if (file.isFile()) {
|
||||||
|
size += file.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取apk文件的icon
|
||||||
|
*
|
||||||
|
* @param path apk文件路径
|
||||||
|
*/
|
||||||
|
public static Drawable getApkIcon(Context context, String path) {
|
||||||
|
PackageManager pm = context.getPackageManager();
|
||||||
|
PackageInfo info = pm.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);
|
||||||
|
if (info != null) {
|
||||||
|
ApplicationInfo appInfo = info.applicationInfo;
|
||||||
|
//android有bug,需要下面这两句话来修复才能获取apk图片
|
||||||
|
appInfo.sourceDir = path;
|
||||||
|
appInfo.publicSourceDir = path;
|
||||||
|
// String packageName = appInfo.packageName; //得到安装包名称
|
||||||
|
// String version=info.versionName; //得到版本信息
|
||||||
|
return pm.getApplicationIcon(appInfo);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
import android.widget.EditText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开或关闭软键盘
|
||||||
|
*
|
||||||
|
* @author zhy
|
||||||
|
*/
|
||||||
|
public class KeyBoardUtils {
|
||||||
|
/**
|
||||||
|
* 打卡软键盘
|
||||||
|
*
|
||||||
|
* @param mEditText 输入框
|
||||||
|
* @param mContext 上下文
|
||||||
|
*/
|
||||||
|
public static void openKeybord(EditText mEditText, Context mContext) {
|
||||||
|
InputMethodManager imm = (InputMethodManager) mContext
|
||||||
|
.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
imm.showSoftInput(mEditText, InputMethodManager.RESULT_SHOWN);
|
||||||
|
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,
|
||||||
|
InputMethodManager.HIDE_IMPLICIT_ONLY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭软键盘
|
||||||
|
*
|
||||||
|
* @param mEditText 输入框
|
||||||
|
* @param mContext 上下文
|
||||||
|
*/
|
||||||
|
public static void closeKeybord(EditText mEditText, Context mContext) {
|
||||||
|
InputMethodManager imm = (InputMethodManager) mContext
|
||||||
|
.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
|
imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
|
||||||
|
}
|
||||||
|
}
|
47
AppFrame/src/main/java/com/arialyy/frame/util/MathUtil.java
Normal file
47
AppFrame/src/main/java/com/arialyy/frame/util/MathUtil.java
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaLyy on 2015/1/4.
|
||||||
|
* 精度转换
|
||||||
|
*/
|
||||||
|
public class MathUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* http://spiritfrog.iteye.com/blog/602144
|
||||||
|
*/
|
||||||
|
public class MBigDecimal {
|
||||||
|
public static final int ROUND_UP = 0;
|
||||||
|
public static final int ROUND_DOWN = 1;
|
||||||
|
public static final int ROUND_CEILING = 2;
|
||||||
|
public static final int ROUND_FLOOR = 3;
|
||||||
|
public static final int ROUND_HALF_UP = 4;
|
||||||
|
public static final int ROUND_HALF_DOWN = 5;
|
||||||
|
public static final int ROUND_HALF_EVEN = 6;
|
||||||
|
public static final int ROUND_UNNECESSARY = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置精度
|
||||||
|
* float/double的精度取值方式分为以下几种: <br>
|
||||||
|
* java.math.BigDecimal.ROUND_UP <br>
|
||||||
|
* java.math.BigDecimal.ROUND_DOWN <br>
|
||||||
|
* java.math.BigDecimal.ROUND_CEILING <br>
|
||||||
|
* java.math.BigDecimal.ROUND_FLOOR <br>
|
||||||
|
* java.math.BigDecimal.ROUND_HALF_UP<br>
|
||||||
|
* java.math.BigDecimal.ROUND_HALF_DOWN <br>
|
||||||
|
* java.math.BigDecimal.ROUND_HALF_EVEN <br>
|
||||||
|
*
|
||||||
|
* @param scale 精度位数(保留的小数位数)
|
||||||
|
* @param roundingMode 精度取值方式
|
||||||
|
* @return 精度计算后的数据
|
||||||
|
*/
|
||||||
|
public static double round(double value, int scale, int roundingMode) {
|
||||||
|
BigDecimal bd = new BigDecimal(value);
|
||||||
|
bd = bd.setScale(scale, roundingMode);
|
||||||
|
double d = bd.doubleValue();
|
||||||
|
bd = null;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
83
AppFrame/src/main/java/com/arialyy/frame/util/MediaUtil.java
Normal file
83
AppFrame/src/main/java/com/arialyy/frame/util/MediaUtil.java
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.media.MediaMetadataRetriever;
|
||||||
|
import android.media.MediaPlayer;
|
||||||
|
import android.net.Uri;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Formatter;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Aria.Lao on 2018/1/4.
|
||||||
|
* 多媒体工具
|
||||||
|
*/
|
||||||
|
public class MediaUtil {
|
||||||
|
private MediaUtil() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取音频、视频播放长度
|
||||||
|
*/
|
||||||
|
public static long getDuration(String path) {
|
||||||
|
MediaPlayer mediaPlayer = new MediaPlayer();
|
||||||
|
try {
|
||||||
|
mediaPlayer.setDataSource(path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int duration = mediaPlayer.getDuration();
|
||||||
|
mediaPlayer.release();
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化视频时间
|
||||||
|
*/
|
||||||
|
public static String convertViewTime(long timeMs) {
|
||||||
|
int totalSeconds = (int) (timeMs / 1000);
|
||||||
|
|
||||||
|
int seconds = totalSeconds % 60;
|
||||||
|
int minutes = (totalSeconds / 60) % 60;
|
||||||
|
int hours = totalSeconds / 3600;
|
||||||
|
StringBuilder sFormatBuilder = new StringBuilder();
|
||||||
|
Formatter sFormatter = new Formatter(sFormatBuilder, Locale.getDefault());
|
||||||
|
sFormatBuilder.setLength(0);
|
||||||
|
if (hours > 0) {
|
||||||
|
return sFormatter.format("%02d:%02d:%02d", hours, minutes, seconds).toString();
|
||||||
|
} else {
|
||||||
|
return sFormatter.format("%02d:%02d", minutes, seconds).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取音频封面
|
||||||
|
*/
|
||||||
|
public static Bitmap getArtwork(Context context, String url) {
|
||||||
|
Uri selectedAudio = Uri.parse(url);
|
||||||
|
MediaMetadataRetriever myRetriever = new MediaMetadataRetriever();
|
||||||
|
myRetriever.setDataSource(context, selectedAudio); // the URI of audio file
|
||||||
|
byte[] artwork;
|
||||||
|
artwork = myRetriever.getEmbeddedPicture();
|
||||||
|
if (artwork != null) {
|
||||||
|
return BitmapFactory.decodeByteArray(artwork, 0, artwork.length);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] getArtworkAsByte(Context context, String url) {
|
||||||
|
Uri selectedAudio = Uri.parse(url);
|
||||||
|
MediaMetadataRetriever myRetriever = new MediaMetadataRetriever();
|
||||||
|
myRetriever.setDataSource(context, selectedAudio); // the URI of audio file
|
||||||
|
byte[] artwork;
|
||||||
|
artwork = myRetriever.getEmbeddedPicture();
|
||||||
|
if (artwork != null) {
|
||||||
|
return artwork;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
147
AppFrame/src/main/java/com/arialyy/frame/util/NetUtils.java
Normal file
147
AppFrame/src/main/java/com/arialyy/frame/util/NetUtils.java
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跟网络相关的工具类
|
||||||
|
*/
|
||||||
|
public class NetUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 没有网络
|
||||||
|
*/
|
||||||
|
public static final int NETWORK_TYPE_INVALID = 0;
|
||||||
|
/**
|
||||||
|
* wap网络
|
||||||
|
*/
|
||||||
|
public static final int NETWORK_TYPE_WAP = 1;
|
||||||
|
/**
|
||||||
|
* 2G网络
|
||||||
|
*/
|
||||||
|
public static final int NETWORK_TYPE_2G = 2;
|
||||||
|
/**
|
||||||
|
* 3G和3G以上网络,或统称为快速网络
|
||||||
|
*/
|
||||||
|
public static final int NETWORK_TYPE_3G = 3;
|
||||||
|
/**
|
||||||
|
* wifi网络
|
||||||
|
*/
|
||||||
|
public static final int NETWORK_TYPE_WIFI = 4;
|
||||||
|
|
||||||
|
private NetUtils() {
|
||||||
|
/* cannot be instantiated */
|
||||||
|
throw new UnsupportedOperationException("cannot be instantiated");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断网络是否连接
|
||||||
|
*/
|
||||||
|
public static boolean isConnected(Context context) {
|
||||||
|
ConnectivityManager cm =
|
||||||
|
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
NetworkInfo ni = cm.getActiveNetworkInfo();
|
||||||
|
return ni != null && ni.isConnectedOrConnecting();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否是wifi连接
|
||||||
|
*/
|
||||||
|
public static boolean isWifi(Context context) {
|
||||||
|
return getNetWorkType(context) == NETWORK_TYPE_WIFI;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取网络状态,wifi,wap,2g,3g.
|
||||||
|
*
|
||||||
|
* @param context 上下文
|
||||||
|
* @return int 网络状态 {@link #NETWORK_TYPE_2G},{@link #NETWORK_TYPE_3G},
|
||||||
|
* {@link #NETWORK_TYPE_INVALID},{@link #NETWORK_TYPE_WAP},{@link #NETWORK_TYPE_WIFI}
|
||||||
|
*/
|
||||||
|
public static int getNetWorkType(Context context) {
|
||||||
|
int netWorkType = -1;
|
||||||
|
ConnectivityManager manager =
|
||||||
|
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
|
||||||
|
if (networkInfo != null && networkInfo.isConnected()) {
|
||||||
|
String type = networkInfo.getTypeName();
|
||||||
|
if (type.equalsIgnoreCase("WIFI")) {
|
||||||
|
netWorkType = NETWORK_TYPE_WIFI;
|
||||||
|
} else if (type.equalsIgnoreCase("MOBILE")) {
|
||||||
|
String proxyHost = android.net.Proxy.getDefaultHost();
|
||||||
|
netWorkType = TextUtils.isEmpty(proxyHost)
|
||||||
|
? (isFastMobileNetwork(context) ? NETWORK_TYPE_3G : NETWORK_TYPE_2G)
|
||||||
|
: NETWORK_TYPE_WAP;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
netWorkType = NETWORK_TYPE_INVALID;
|
||||||
|
}
|
||||||
|
return netWorkType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isFastMobileNetwork(Context context) {
|
||||||
|
TelephonyManager telephonyManager =
|
||||||
|
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
|
switch (telephonyManager.getNetworkType()) {
|
||||||
|
case TelephonyManager.NETWORK_TYPE_1xRTT:
|
||||||
|
return false; // ~ 50-100 kbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_CDMA:
|
||||||
|
return false; // ~ 14-64 kbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_EDGE:
|
||||||
|
return false; // ~ 50-100 kbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_EVDO_0:
|
||||||
|
return true; // ~ 400-1000 kbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_EVDO_A:
|
||||||
|
return true; // ~ 600-1400 kbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_GPRS:
|
||||||
|
return false; // ~ 100 kbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_HSDPA:
|
||||||
|
return true; // ~ 2-14 Mbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_HSPA:
|
||||||
|
return true; // ~ 700-1700 kbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_HSUPA:
|
||||||
|
return true; // ~ 1-23 Mbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_UMTS:
|
||||||
|
return true; // ~ 400-7000 kbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_EHRPD:
|
||||||
|
return true; // ~ 1-2 Mbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_EVDO_B:
|
||||||
|
return true; // ~ 5 Mbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_HSPAP:
|
||||||
|
return true; // ~ 10-20 Mbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_IDEN:
|
||||||
|
return false; // ~25 kbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_LTE:
|
||||||
|
return true; // ~ 10+ Mbps
|
||||||
|
case TelephonyManager.NETWORK_TYPE_UNKNOWN:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开网络设置界面
|
||||||
|
*/
|
||||||
|
public static void openSetting(Context context) {
|
||||||
|
if (AndroidVersionUtil.hasHoneycomb()) {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS);
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
context.startActivity(intent);
|
||||||
|
} else {
|
||||||
|
Intent intent = new Intent("/");
|
||||||
|
ComponentName cm =
|
||||||
|
new ComponentName("com.android.settings", "com.android.settings.WirelessSettings");
|
||||||
|
intent.setComponent(cm);
|
||||||
|
intent.setAction("android.intent.action.VIEW");
|
||||||
|
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
context.startActivity(intent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,224 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.NinePatchDrawable;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载。9图片
|
||||||
|
* Time: 2:37 PM
|
||||||
|
*/
|
||||||
|
public class NinePatchBitmapFactory {
|
||||||
|
|
||||||
|
private static final int NO_COLOR = 0x00000001;
|
||||||
|
|
||||||
|
private static final int TRANSPARENT_COLOR = 0x00000000;
|
||||||
|
|
||||||
|
public static NinePatchDrawable createNinePatchDrawable(Resources res, Bitmap bitmap) {
|
||||||
|
RangeLists rangeLists = checkBitmap(bitmap);
|
||||||
|
Bitmap trimedBitmap = trimBitmap(bitmap);
|
||||||
|
return createNinePatchWithCapInsets(res, trimedBitmap, rangeLists.rangeListX,
|
||||||
|
rangeLists.rangeListY, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NinePatchDrawable createNinePatchWithCapInsets(Resources res, Bitmap bitmap,
|
||||||
|
List<Range> rangeListX, List<Range> rangeListY, String srcName) {
|
||||||
|
ByteBuffer buffer = getByteBuffer(rangeListX, rangeListY);
|
||||||
|
return new NinePatchDrawable(res, bitmap, buffer.array(), new Rect(), srcName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ByteBuffer getByteBuffer(List<Range> rangeListX, List<Range> rangeListY) {
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(
|
||||||
|
4 + 4 * 7 + 4 * 2 * rangeListX.size() + 4 * 2 * rangeListY.size() + 4 * 9)
|
||||||
|
.order(ByteOrder.nativeOrder());
|
||||||
|
buffer.put((byte) 0x01); // was serialised
|
||||||
|
buffer.put((byte) (rangeListX.size() * 2)); // x div
|
||||||
|
buffer.put((byte) (rangeListY.size() * 2)); // y div
|
||||||
|
buffer.put((byte) 0x09); // color
|
||||||
|
|
||||||
|
// skip
|
||||||
|
buffer.putInt(0);
|
||||||
|
buffer.putInt(0);
|
||||||
|
|
||||||
|
// padding
|
||||||
|
buffer.putInt(0);
|
||||||
|
buffer.putInt(0);
|
||||||
|
buffer.putInt(0);
|
||||||
|
buffer.putInt(0);
|
||||||
|
|
||||||
|
// skip 4 bytes
|
||||||
|
buffer.putInt(0);
|
||||||
|
|
||||||
|
for (Range range : rangeListX) {
|
||||||
|
buffer.putInt(range.start);
|
||||||
|
buffer.putInt(range.end);
|
||||||
|
}
|
||||||
|
for (Range range : rangeListY) {
|
||||||
|
buffer.putInt(range.start);
|
||||||
|
buffer.putInt(range.end);
|
||||||
|
}
|
||||||
|
buffer.putInt(NO_COLOR);
|
||||||
|
buffer.putInt(NO_COLOR);
|
||||||
|
buffer.putInt(NO_COLOR);
|
||||||
|
buffer.putInt(NO_COLOR);
|
||||||
|
buffer.putInt(NO_COLOR);
|
||||||
|
buffer.putInt(NO_COLOR);
|
||||||
|
buffer.putInt(NO_COLOR);
|
||||||
|
buffer.putInt(NO_COLOR);
|
||||||
|
buffer.putInt(NO_COLOR);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RangeLists {
|
||||||
|
public List<Range> rangeListX;
|
||||||
|
public List<Range> rangeListY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Range {
|
||||||
|
public int start;
|
||||||
|
public int end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RangeLists checkBitmap(Bitmap bitmap) {
|
||||||
|
int width = bitmap.getWidth();
|
||||||
|
int height = bitmap.getHeight();
|
||||||
|
|
||||||
|
List<Range> rangeListX = new ArrayList<Range>();
|
||||||
|
|
||||||
|
int pos = -1;
|
||||||
|
for (int i = 1; i < width - 1; i++) {
|
||||||
|
int color = bitmap.getPixel(i, 0);
|
||||||
|
int alpha = Color.alpha(color);
|
||||||
|
int red = Color.red(color);
|
||||||
|
int green = Color.green(color);
|
||||||
|
int blue = Color.blue(color);
|
||||||
|
// System.out.println( String.valueOf(alpha) + "," + String.valueOf(red) + "," + String.valueOf(green) + "," + String.valueOf(blue) );
|
||||||
|
if (alpha == 255 && red == 0 && green == 0 && blue == 0) {
|
||||||
|
if (pos == -1) {
|
||||||
|
pos = i - 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pos != -1) {
|
||||||
|
Range range = new Range();
|
||||||
|
range.start = pos;
|
||||||
|
range.end = i - 1;
|
||||||
|
rangeListX.add(range);
|
||||||
|
pos = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pos != -1) {
|
||||||
|
Range range = new Range();
|
||||||
|
range.start = pos;
|
||||||
|
range.end = width - 2;
|
||||||
|
rangeListX.add(range);
|
||||||
|
}
|
||||||
|
for (Range range : rangeListX) {
|
||||||
|
System.out.println("(" + range.start + "," + range.end + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Range> rangeListY = new ArrayList<Range>();
|
||||||
|
|
||||||
|
pos = -1;
|
||||||
|
for (int i = 1; i < height - 1; i++) {
|
||||||
|
int color = bitmap.getPixel(0, i);
|
||||||
|
int alpha = Color.alpha(color);
|
||||||
|
int red = Color.red(color);
|
||||||
|
int green = Color.green(color);
|
||||||
|
int blue = Color.blue(color);
|
||||||
|
if (alpha == 255 && red == 0 && green == 0 && blue == 0) {
|
||||||
|
if (pos == -1) {
|
||||||
|
pos = i - 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pos != -1) {
|
||||||
|
Range range = new Range();
|
||||||
|
range.start = pos;
|
||||||
|
range.end = i - 1;
|
||||||
|
rangeListY.add(range);
|
||||||
|
pos = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pos != -1) {
|
||||||
|
Range range = new Range();
|
||||||
|
range.start = pos;
|
||||||
|
range.end = height - 2;
|
||||||
|
rangeListY.add(range);
|
||||||
|
}
|
||||||
|
for (Range range : rangeListY) {
|
||||||
|
System.out.println("(" + range.start + "," + range.end + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
RangeLists rangeLists = new RangeLists();
|
||||||
|
rangeLists.rangeListX = rangeListX;
|
||||||
|
rangeLists.rangeListY = rangeListY;
|
||||||
|
|
||||||
|
return rangeLists;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap trimBitmap(Bitmap bitmap) {
|
||||||
|
int width = bitmap.getWidth();
|
||||||
|
int height = bitmap.getHeight();
|
||||||
|
|
||||||
|
Bitmap result = Bitmap.createBitmap(bitmap, 1, 1, width - 2, height - 2);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap loadBitmap(File file) {
|
||||||
|
BufferedInputStream bis = null;
|
||||||
|
try {
|
||||||
|
bis = new BufferedInputStream(new FileInputStream(file));
|
||||||
|
return BitmapFactory.decodeStream(bis);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
bis.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDensityPostfix(Resources res) {
|
||||||
|
String result = null;
|
||||||
|
switch (res.getDisplayMetrics().densityDpi) {
|
||||||
|
case DisplayMetrics.DENSITY_LOW:
|
||||||
|
result = "ldpi";
|
||||||
|
break;
|
||||||
|
case DisplayMetrics.DENSITY_MEDIUM:
|
||||||
|
result = "mdpi";
|
||||||
|
break;
|
||||||
|
case DisplayMetrics.DENSITY_HIGH:
|
||||||
|
result = "hdpi";
|
||||||
|
break;
|
||||||
|
case DisplayMetrics.DENSITY_XHIGH:
|
||||||
|
result = "xhdpi";
|
||||||
|
break;
|
||||||
|
case DisplayMetrics.DENSITY_XXHIGH:
|
||||||
|
result = "xxhdpi";
|
||||||
|
break;
|
||||||
|
case DisplayMetrics.DENSITY_XXXHIGH:
|
||||||
|
result = "xxxhdpi";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
49
AppFrame/src/main/java/com/arialyy/frame/util/ObjUtil.java
Normal file
49
AppFrame/src/main/java/com/arialyy/frame/util/ObjUtil.java
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/7/6.
|
||||||
|
*/
|
||||||
|
public class ObjUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印Map
|
||||||
|
*/
|
||||||
|
public static String getMapString(Map map) {
|
||||||
|
Set set = map.keySet();
|
||||||
|
if (set.size() < 1) {
|
||||||
|
return "[]";
|
||||||
|
}
|
||||||
|
StringBuilder strBuilder = new StringBuilder();
|
||||||
|
Object[] array = set.toArray();
|
||||||
|
strBuilder.append("[").append(array[0]).append("=").append(map.get(array[0]));
|
||||||
|
for (int i = 1; i < array.length; ++i) {
|
||||||
|
strBuilder.append(", ");
|
||||||
|
strBuilder.append(array[i]).append("=");
|
||||||
|
strBuilder.append(map.get(array[i]));
|
||||||
|
}
|
||||||
|
strBuilder.append("]");
|
||||||
|
return strBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过Value 获取key
|
||||||
|
*/
|
||||||
|
public static <T, E> T getKeyByValue(Map<T, E> map, E value) {
|
||||||
|
for (Map.Entry<T, E> entry : map.entrySet()) {
|
||||||
|
if (equals(value, entry.getValue())) {
|
||||||
|
return entry.getKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较两个对象是否相等
|
||||||
|
*/
|
||||||
|
public static boolean equals(Object a, Object b) {
|
||||||
|
return (a == null) ? (b == null) : a.equals(b);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,150 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.AssetManager;
|
||||||
|
import android.content.res.XmlResourceParser;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.arialyy.frame.util.show.FL;
|
||||||
|
import com.arialyy.frame.util.show.L;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import dalvik.system.PathClassLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2015/7/30.
|
||||||
|
* 反射工具类
|
||||||
|
*/
|
||||||
|
public class ReflectionUtil {
|
||||||
|
private static final String TAG = "ReflectionUtil";
|
||||||
|
private static final String ID = "$id";
|
||||||
|
private static final String LAYOUT = "$layout";
|
||||||
|
private static final String STYLE = "$style";
|
||||||
|
private static final String STRING = "$string";
|
||||||
|
private static final String DRAWABLE = "$drawable";
|
||||||
|
private static final String ARRAY = "$array";
|
||||||
|
private static final String COLOR = "color";
|
||||||
|
private static final String ANIM = "anim";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从SDcard读取layout
|
||||||
|
*/
|
||||||
|
public static XmlPullParser getLayoutXmlPullParser(Context context, String filePath,
|
||||||
|
String fileName) {
|
||||||
|
XmlResourceParser paser = null;
|
||||||
|
AssetManager asset = context.getResources().getAssets();
|
||||||
|
try {
|
||||||
|
Method method = asset.getClass().getMethod("addAssetPath", String.class);
|
||||||
|
int cookie = (Integer) method.invoke(asset, filePath);
|
||||||
|
if (cookie == 0) {
|
||||||
|
FL.e(TAG, "加载路径失败");
|
||||||
|
}
|
||||||
|
paser = asset.openXmlResourceParser(cookie, fileName + ".xml");
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return paser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取类里面的所在字段
|
||||||
|
*/
|
||||||
|
public static Field[] getFields(Class clazz) {
|
||||||
|
Field[] fields = null;
|
||||||
|
fields = clazz.getDeclaredFields();
|
||||||
|
if (fields == null || fields.length == 0) {
|
||||||
|
Class superClazz = clazz.getSuperclass();
|
||||||
|
if (superClazz != null) {
|
||||||
|
fields = getFields(superClazz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取类里面的指定对象,如果该类没有则从父类查询
|
||||||
|
*/
|
||||||
|
public static Field getField(Class clazz, String name) {
|
||||||
|
Field field = null;
|
||||||
|
try {
|
||||||
|
field = clazz.getDeclaredField(name);
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
try {
|
||||||
|
field = clazz.getField(name);
|
||||||
|
} catch (NoSuchFieldException e1) {
|
||||||
|
if (clazz.getSuperclass() == null) {
|
||||||
|
return field;
|
||||||
|
} else {
|
||||||
|
field = getField(clazz.getSuperclass(), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (field != null) {
|
||||||
|
field.setAccessible(true);
|
||||||
|
}
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 利用递归找一个类的指定方法,如果找不到,去父亲里面找直到最上层Object对象为止。
|
||||||
|
*
|
||||||
|
* @param clazz 目标类
|
||||||
|
* @param methodName 方法名
|
||||||
|
* @param params 方法参数类型数组
|
||||||
|
* @return 方法对象
|
||||||
|
*/
|
||||||
|
public static Method getMethod(Class clazz, String methodName, final Class<?>... params) {
|
||||||
|
Method method = null;
|
||||||
|
try {
|
||||||
|
method = clazz.getDeclaredMethod(methodName, params);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
try {
|
||||||
|
method = clazz.getMethod(methodName, params);
|
||||||
|
} catch (NoSuchMethodException ex) {
|
||||||
|
if (clazz.getSuperclass() == null) {
|
||||||
|
L.e(TAG, "无法找到" + methodName + "方法");
|
||||||
|
FL.e(TAG, FL.getExceptionString(e));
|
||||||
|
return method;
|
||||||
|
} else {
|
||||||
|
method = getMethod(clazz.getSuperclass(), methodName, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (method != null) {
|
||||||
|
method.setAccessible(true);
|
||||||
|
}
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载指定的反射类
|
||||||
|
*/
|
||||||
|
public static Class<?> loadClass(Context context, String ClassName) {
|
||||||
|
String packageName = AndroidUtils.getPackageName(context);
|
||||||
|
String sourcePath = AndroidUtils.getSourcePath(context, packageName);
|
||||||
|
if (!TextUtils.isEmpty(sourcePath)) {
|
||||||
|
PathClassLoader cl =
|
||||||
|
new PathClassLoader(sourcePath, "/data/app/", ClassLoader.getSystemClassLoader());
|
||||||
|
try {
|
||||||
|
return cl.loadClass(ClassName);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FL.e(TAG, "没有【" + sourcePath + "】目录");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaLyy on 2015/1/10.
|
||||||
|
* 正则表达式规则
|
||||||
|
*/
|
||||||
|
public class RegularExpression {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* APK包
|
||||||
|
*/
|
||||||
|
public static String APK = "^(.*)\\.(apk)$";
|
||||||
|
/**
|
||||||
|
* 视频
|
||||||
|
*/
|
||||||
|
public static String VIDEO =
|
||||||
|
"^(.*)\\.(mpeg-4|h.264|h.265|rmvb|xvid|vp6|h.263|mpeg-1|mpeg-2|avi|" +
|
||||||
|
"mov|mkv|flv|3gp|3g2|asf|wmv|mp4|m4v|tp|ts|mtp|m2t)$";
|
||||||
|
/**
|
||||||
|
* 音频
|
||||||
|
*/
|
||||||
|
public static String MUSIC = "^(.*)\\.(aac|vorbis|flac|mp3|mp2|wma)$";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本
|
||||||
|
*/
|
||||||
|
public static String TEXT = "^(.*)\\.(txt|xml|html)$";
|
||||||
|
/**
|
||||||
|
* 压缩包
|
||||||
|
*/
|
||||||
|
public static String ZIP = "^(.*)\\.(zip|rar|7z)$";
|
||||||
|
/**
|
||||||
|
* DOC
|
||||||
|
*/
|
||||||
|
public static String DOC = "^(.*)\\.(doc|docx)";
|
||||||
|
/**
|
||||||
|
* PPT
|
||||||
|
*/
|
||||||
|
public static String PPT = "^(.*)\\.(ppt|pptx)";
|
||||||
|
/**
|
||||||
|
* xls
|
||||||
|
*/
|
||||||
|
public static String XLS = "^(.*)\\.(xls|xlsx)";
|
||||||
|
/**
|
||||||
|
* vcf
|
||||||
|
*/
|
||||||
|
public static String VCF = "^(.*)\\.(vcf)";
|
||||||
|
/**
|
||||||
|
* pdf
|
||||||
|
*/
|
||||||
|
public static String PDF = "^(.*)\\.(pdf)";
|
||||||
|
/**
|
||||||
|
* SQL
|
||||||
|
*/
|
||||||
|
public static String SQL = "^(.*)\\.(sql|db)";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片
|
||||||
|
*/
|
||||||
|
public static String IMG = "^(.*)\\.(jpg|bmp|png|gif|jpeg|psd)";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 中文
|
||||||
|
*/
|
||||||
|
public static String CHINESE = "[\\u4e00-\\u9fa5]";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首尾空白字符
|
||||||
|
*/
|
||||||
|
public static String START_OR_END_NONE = "^\\s*|\\s*";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 空白行
|
||||||
|
*/
|
||||||
|
public static String NOTE_ITEM = "\\n\\s*\\r";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 邮箱
|
||||||
|
*/
|
||||||
|
public static String EMAIL = "\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* url
|
||||||
|
*/
|
||||||
|
public static String URL = "[a-zA-z]+://[^\\s]*";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QQ
|
||||||
|
*/
|
||||||
|
public static String QQ = "[1-9][0-9]{4,}";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IP
|
||||||
|
*/
|
||||||
|
public static String IP =
|
||||||
|
"([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
|
||||||
|
}
|
218
AppFrame/src/main/java/com/arialyy/frame/util/ScreenUtil.java
Normal file
218
AppFrame/src/main/java/com/arialyy/frame/util/ScreenUtil.java
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.ColorMatrix;
|
||||||
|
import android.graphics.ColorMatrixColorFilter;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaLyy on 2015/1/22.
|
||||||
|
* 屏幕工具
|
||||||
|
*/
|
||||||
|
public class ScreenUtil {
|
||||||
|
|
||||||
|
private volatile static ScreenUtil mUtil = null;
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
|
||||||
|
private ScreenUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScreenUtil getInstance() {
|
||||||
|
if (mUtil == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (mUtil == null) {
|
||||||
|
mUtil = new ScreenUtil();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置灰度
|
||||||
|
*
|
||||||
|
* @param greyScale true:灰度
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||||
|
public void setGreyScale(View v, boolean greyScale) {
|
||||||
|
if (greyScale) {
|
||||||
|
// Create a paint object with 0 saturation (black and white)
|
||||||
|
ColorMatrix cm = new ColorMatrix();
|
||||||
|
cm.setSaturation(0);
|
||||||
|
Paint greyScalePaint = new Paint();
|
||||||
|
greyScalePaint.setColorFilter(new ColorMatrixColorFilter(cm));
|
||||||
|
// Create a hardware layer with the greyScale paint
|
||||||
|
v.setLayerType(View.LAYER_TYPE_HARDWARE, greyScalePaint);
|
||||||
|
} else {
|
||||||
|
// Remove the hardware layer
|
||||||
|
v.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得屏幕高度
|
||||||
|
*/
|
||||||
|
public int getScreenWidth(Context context) {
|
||||||
|
WindowManager wm = (WindowManager) context
|
||||||
|
.getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
DisplayMetrics outMetrics = new DisplayMetrics();
|
||||||
|
wm.getDefaultDisplay().getMetrics(outMetrics);
|
||||||
|
return outMetrics.widthPixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得屏幕宽度
|
||||||
|
*/
|
||||||
|
public int getScreenHeight(Context context) {
|
||||||
|
WindowManager wm = (WindowManager) context
|
||||||
|
.getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
DisplayMetrics outMetrics = new DisplayMetrics();
|
||||||
|
wm.getDefaultDisplay().getMetrics(outMetrics);
|
||||||
|
return outMetrics.heightPixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得状态栏的高度
|
||||||
|
*/
|
||||||
|
public int getStatusHeight(Context context) {
|
||||||
|
|
||||||
|
int statusHeight = -1;
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName("com.android.internal.R$dimen");
|
||||||
|
Object object = clazz.newInstance();
|
||||||
|
int height = Integer.parseInt(clazz.getField("status_bar_height")
|
||||||
|
.get(object).toString());
|
||||||
|
statusHeight = context.getResources().getDimensionPixelSize(height);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return statusHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前屏幕截图,包含状态栏
|
||||||
|
*
|
||||||
|
* @return error return null
|
||||||
|
*/
|
||||||
|
public Bitmap snapShotWithStatusBar(Activity activity) {
|
||||||
|
final View view = activity.getWindow().getDecorView();
|
||||||
|
view.setDrawingCacheEnabled(true);
|
||||||
|
view.buildDrawingCache();
|
||||||
|
int width = getScreenWidth(activity);
|
||||||
|
int height = getScreenHeight(activity);
|
||||||
|
// view.layout(0, 0, width, height);
|
||||||
|
|
||||||
|
Bitmap bmp = view.getDrawingCache();
|
||||||
|
if (bmp == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Bitmap bp = null;
|
||||||
|
bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
|
||||||
|
view.destroyDrawingCache();
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前屏幕截图,不包含状态栏
|
||||||
|
*/
|
||||||
|
public Bitmap snapShotWithoutStatusBar(Activity activity) {
|
||||||
|
View view = activity.getWindow().getDecorView();
|
||||||
|
view.setDrawingCacheEnabled(true);
|
||||||
|
view.buildDrawingCache();
|
||||||
|
Bitmap bmp = view.getDrawingCache();
|
||||||
|
Rect frame = new Rect();
|
||||||
|
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
|
||||||
|
int statusBarHeight = frame.top;
|
||||||
|
|
||||||
|
int width = getScreenWidth(activity);
|
||||||
|
int height = getScreenHeight(activity);
|
||||||
|
Bitmap bp = null;
|
||||||
|
bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height
|
||||||
|
- statusBarHeight);
|
||||||
|
view.destroyDrawingCache();
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否开启了自动亮度调节
|
||||||
|
*/
|
||||||
|
public boolean isAutoBrightness(ContentResolver aContentResolver) {
|
||||||
|
boolean automicBrightness = false;
|
||||||
|
try {
|
||||||
|
automicBrightness = Settings.System.getInt(aContentResolver,
|
||||||
|
Settings.System.SCREEN_BRIGHTNESS_MODE)
|
||||||
|
== Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
|
||||||
|
} catch (Settings.SettingNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return automicBrightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取屏幕的亮度
|
||||||
|
*/
|
||||||
|
public float getScreenBrightness(Activity activity) {
|
||||||
|
int nowBrightnessValue = 0;
|
||||||
|
ContentResolver resolver = activity.getContentResolver();
|
||||||
|
try {
|
||||||
|
nowBrightnessValue = Settings.System.getInt(
|
||||||
|
resolver, Settings.System.SCREEN_BRIGHTNESS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return nowBrightnessValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置亮度(手动设置亮度,需要关闭自动设置亮度的开关)
|
||||||
|
*
|
||||||
|
* @param brightness 0-1
|
||||||
|
*/
|
||||||
|
public void setBrightness(Activity activity, float brightness) {
|
||||||
|
stopAutoBrightness(activity);
|
||||||
|
WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
|
||||||
|
lp.screenBrightness = brightness * (1f / 255f);
|
||||||
|
activity.getWindow().setAttributes(lp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止自动亮度调节
|
||||||
|
*/
|
||||||
|
public void stopAutoBrightness(Activity activity) {
|
||||||
|
Settings.System.putInt(activity.getContentResolver(),
|
||||||
|
Settings.System.SCREEN_BRIGHTNESS_MODE,
|
||||||
|
Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开启亮度自动调节
|
||||||
|
*/
|
||||||
|
public void startAutoBrightness(Activity activity) {
|
||||||
|
Settings.System.putInt(activity.getContentResolver(),
|
||||||
|
Settings.System.SCREEN_BRIGHTNESS_MODE,
|
||||||
|
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存亮度设置状态
|
||||||
|
*/
|
||||||
|
public void saveBrightness(ContentResolver resolver, int brightness) {
|
||||||
|
Uri uri = Settings.System
|
||||||
|
.getUriFor("screen_brightness");
|
||||||
|
Settings.System.putInt(resolver, "screen_brightness",
|
||||||
|
brightness);
|
||||||
|
// resolver.registerContentObserver(uri, true, myContentObserver);
|
||||||
|
resolver.notifyChange(uri, null);
|
||||||
|
}
|
||||||
|
}
|
145
AppFrame/src/main/java/com/arialyy/frame/util/SharePreUtil.java
Normal file
145
AppFrame/src/main/java/com/arialyy/frame/util/SharePreUtil.java
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.Editor;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置文件工具类
|
||||||
|
*
|
||||||
|
* @author Administrator
|
||||||
|
*/
|
||||||
|
public class SharePreUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除键值对
|
||||||
|
*/
|
||||||
|
public static void removeKey(String preName, Context context, String key) {
|
||||||
|
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
|
||||||
|
Editor editor = pre.edit();
|
||||||
|
editor.remove(key);
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从配置文件读取字符串
|
||||||
|
*
|
||||||
|
* @param preName 配置文件名
|
||||||
|
* @param key 字符串键值
|
||||||
|
* @return 键值对应的字符串, 默认返回""
|
||||||
|
*/
|
||||||
|
public static String getString(String preName, Context context, String key) {
|
||||||
|
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
|
||||||
|
return pre.getString(key, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从配置文件读取int数据
|
||||||
|
*
|
||||||
|
* @param preName 配置文件名
|
||||||
|
* @param key int的键值
|
||||||
|
* @return 键值对应的int, 默认返回-1
|
||||||
|
*/
|
||||||
|
public static int getInt(String preName, Context context, String key) {
|
||||||
|
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
|
||||||
|
return pre.getInt(key, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从配置文件读取Boolean值
|
||||||
|
*
|
||||||
|
* @return 如果没有,默认返回false
|
||||||
|
*/
|
||||||
|
public static Boolean getBoolean(String preName, Context context, String key) {
|
||||||
|
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
|
||||||
|
return pre.getBoolean(key, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从配置文件获取float数据
|
||||||
|
*
|
||||||
|
* @return 默认返回0.0f
|
||||||
|
*/
|
||||||
|
public static float getFloat(String preName, Context context, String key) {
|
||||||
|
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
|
||||||
|
return pre.getFloat(key, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从配置文件获取对象
|
||||||
|
*/
|
||||||
|
public static <T> T getObject(String preName, Context context, String key, Class<T> clazz) {
|
||||||
|
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
|
||||||
|
String str = pre.getString(key, "");
|
||||||
|
return TextUtils.isEmpty(str) ? null : new Gson().fromJson(str, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储字符串到配置文件
|
||||||
|
*
|
||||||
|
* @param preName 配置文件名
|
||||||
|
* @param key 存储的键值
|
||||||
|
* @param value 需要存储的字符串
|
||||||
|
* @return 成功标志
|
||||||
|
*/
|
||||||
|
public static Boolean putString(String preName, Context context, String key, String value) {
|
||||||
|
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
|
||||||
|
Editor editor = pre.edit();
|
||||||
|
editor.putString(key, value);
|
||||||
|
return editor.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存Float数据到配置文件
|
||||||
|
*/
|
||||||
|
public static Boolean putFloat(String preName, Context context, String key, float value) {
|
||||||
|
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
|
||||||
|
Editor editor = pre.edit();
|
||||||
|
editor.putFloat(key, value);
|
||||||
|
return editor.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储数字到配置文件
|
||||||
|
*
|
||||||
|
* @param preName 配置文件名
|
||||||
|
* @param key 存储的键值
|
||||||
|
* @param value 需要存储的数字
|
||||||
|
* @return 成功标志
|
||||||
|
*/
|
||||||
|
public static Boolean putInt(String preName, Context context, String key, int value) {
|
||||||
|
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
|
||||||
|
Editor editor = pre.edit();
|
||||||
|
editor.putInt(key, value);
|
||||||
|
return editor.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储Boolean值到配置文件
|
||||||
|
*
|
||||||
|
* @param preName 配置文件名
|
||||||
|
* @param key 键值
|
||||||
|
* @param value 需要存储的boolean值
|
||||||
|
*/
|
||||||
|
public static Boolean putBoolean(String preName, Context context, String key, Boolean value) {
|
||||||
|
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
|
||||||
|
Editor editor = pre.edit();
|
||||||
|
editor.putBoolean(key, value);
|
||||||
|
return editor.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存放对象
|
||||||
|
*/
|
||||||
|
public static Boolean putObject(String preName, Context context, String key, Class<?> clazz,
|
||||||
|
Object obj) {
|
||||||
|
String str = new Gson().toJson(obj, clazz);
|
||||||
|
SharedPreferences pre = context.getSharedPreferences(preName, Context.MODE_PRIVATE);
|
||||||
|
Editor editor = pre.edit();
|
||||||
|
editor.putString(key, str);
|
||||||
|
return editor.commit();
|
||||||
|
}
|
||||||
|
}
|
213
AppFrame/src/main/java/com/arialyy/frame/util/ShellUtils.java
Normal file
213
AppFrame/src/main/java/com/arialyy/frame/util/ShellUtils.java
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ShellUtils
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link ShellUtils#checkRootPermission()}</li>
|
||||||
|
* </ul>
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link ShellUtils#execCommand(String, boolean)}</li>
|
||||||
|
* <li>{@link ShellUtils#execCommand(String, boolean, boolean)}</li>
|
||||||
|
* <li>{@link ShellUtils#execCommand(List, boolean)}</li>
|
||||||
|
* <li>{@link ShellUtils#execCommand(List, boolean, boolean)}</li>
|
||||||
|
* <li>{@link ShellUtils#execCommand(String[], boolean)}</li>
|
||||||
|
* <li>{@link ShellUtils#execCommand(String[], boolean, boolean)}</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16
|
||||||
|
*/
|
||||||
|
public class ShellUtils {
|
||||||
|
public static final String COMMAND_SU = "su";
|
||||||
|
public static final String COMMAND_SH = "sh";
|
||||||
|
public static final String COMMAND_EXIT = "exit\n";
|
||||||
|
public static final String COMMAND_LINE_END = "\n";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check whether has root permission
|
||||||
|
*/
|
||||||
|
public static boolean checkRootPermission() {
|
||||||
|
return execCommand("echo root", true, false).result == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute shell command, default return result msg
|
||||||
|
*
|
||||||
|
* @param command command
|
||||||
|
* @param isRoot whether need to run with root
|
||||||
|
* @see ShellUtils#execCommand(String[], boolean, boolean)
|
||||||
|
*/
|
||||||
|
public static CommandResult execCommand(String command, boolean isRoot) {
|
||||||
|
return execCommand(new String[] { command }, isRoot, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute shell commands, default return result msg
|
||||||
|
*
|
||||||
|
* @param commands command list
|
||||||
|
* @param isRoot whether need to run with root
|
||||||
|
* @see ShellUtils#execCommand(String[], boolean, boolean)
|
||||||
|
*/
|
||||||
|
public static CommandResult execCommand(List<String> commands, boolean isRoot) {
|
||||||
|
return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute shell commands, default return result msg
|
||||||
|
*
|
||||||
|
* @param commands command array
|
||||||
|
* @param isRoot whether need to run with root
|
||||||
|
* @see ShellUtils#execCommand(String[], boolean, boolean)
|
||||||
|
*/
|
||||||
|
public static CommandResult execCommand(String[] commands, boolean isRoot) {
|
||||||
|
return execCommand(commands, isRoot, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute shell command
|
||||||
|
*
|
||||||
|
* @param command command
|
||||||
|
* @param isRoot whether need to run with root
|
||||||
|
* @param isNeedResultMsg whether need result msg
|
||||||
|
* @see ShellUtils#execCommand(String[], boolean, boolean)
|
||||||
|
*/
|
||||||
|
public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) {
|
||||||
|
return execCommand(new String[] { command }, isRoot, isNeedResultMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute shell commands
|
||||||
|
*
|
||||||
|
* @param commands command list
|
||||||
|
* @param isRoot whether need to run with root
|
||||||
|
* @param isNeedResultMsg whether need result msg
|
||||||
|
* @see ShellUtils#execCommand(String[], boolean, boolean)
|
||||||
|
*/
|
||||||
|
public static CommandResult execCommand(List<String> commands, boolean isRoot,
|
||||||
|
boolean isNeedResultMsg) {
|
||||||
|
return execCommand(commands == null ? null : commands.toArray(new String[] {}), isRoot,
|
||||||
|
isNeedResultMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* execute shell commands
|
||||||
|
*
|
||||||
|
* @param commands command array
|
||||||
|
* @param isRoot whether need to run with root
|
||||||
|
* @param isNeedResultMsg whether need result msg
|
||||||
|
* @return <ul>
|
||||||
|
* <li>if isNeedResultMsg is false, {@link CommandResult#successMsg} is null and
|
||||||
|
* {@link CommandResult#errorMsg} is null.</li>
|
||||||
|
* <li>if {@link CommandResult#result} is -1, there maybe some excepiton.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public static CommandResult execCommand(String[] commands, boolean isRoot,
|
||||||
|
boolean isNeedResultMsg) {
|
||||||
|
int result = -1;
|
||||||
|
if (commands == null || commands.length == 0) {
|
||||||
|
return new CommandResult(result, null, null);
|
||||||
|
}
|
||||||
|
Process process = null;
|
||||||
|
BufferedReader successResult = null;
|
||||||
|
BufferedReader errorResult = null;
|
||||||
|
StringBuilder successMsg = null;
|
||||||
|
StringBuilder errorMsg = null;
|
||||||
|
DataOutputStream os = null;
|
||||||
|
try {
|
||||||
|
process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
|
||||||
|
os = new DataOutputStream(process.getOutputStream());
|
||||||
|
for (String command : commands) {
|
||||||
|
if (command == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// donnot use os.writeBytes(commmand), avoid chinese charset error
|
||||||
|
os.write(command.getBytes());
|
||||||
|
os.writeBytes(COMMAND_LINE_END);
|
||||||
|
os.flush();
|
||||||
|
}
|
||||||
|
os.writeBytes(COMMAND_EXIT);
|
||||||
|
os.flush();
|
||||||
|
result = process.waitFor();
|
||||||
|
// get command result
|
||||||
|
if (isNeedResultMsg) {
|
||||||
|
successMsg = new StringBuilder();
|
||||||
|
errorMsg = new StringBuilder();
|
||||||
|
successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||||
|
errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
|
||||||
|
String s;
|
||||||
|
while ((s = successResult.readLine()) != null) {
|
||||||
|
successMsg.append(s);
|
||||||
|
}
|
||||||
|
while ((s = errorResult.readLine()) != null) {
|
||||||
|
errorMsg.append(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (os != null) {
|
||||||
|
os.close();
|
||||||
|
}
|
||||||
|
if (successResult != null) {
|
||||||
|
successResult.close();
|
||||||
|
}
|
||||||
|
if (errorResult != null) {
|
||||||
|
errorResult.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (process != null) {
|
||||||
|
process.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new CommandResult(result, successMsg == null ? null : successMsg.toString(),
|
||||||
|
errorMsg == null ? null
|
||||||
|
: errorMsg.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* result of command
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link CommandResult#result} means result of command, 0 means normal, else means error,
|
||||||
|
* same to excute in
|
||||||
|
* linux shell</li>
|
||||||
|
* <li>{@link CommandResult#successMsg} means success message of command result</li>
|
||||||
|
* <li>{@link CommandResult#errorMsg} means error message of command result</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author <a href="http://www.trinea.cn" target="_blank">Trinea</a> 2013-5-16
|
||||||
|
*/
|
||||||
|
public static class CommandResult {
|
||||||
|
/**
|
||||||
|
* result of command
|
||||||
|
**/
|
||||||
|
public int result;
|
||||||
|
/**
|
||||||
|
* success message of command result
|
||||||
|
**/
|
||||||
|
public String successMsg;
|
||||||
|
/**
|
||||||
|
* error message of command result
|
||||||
|
**/
|
||||||
|
public String errorMsg;
|
||||||
|
|
||||||
|
public CommandResult(int result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandResult(int result, String successMsg, String errorMsg) {
|
||||||
|
this.result = result;
|
||||||
|
this.successMsg = successMsg;
|
||||||
|
this.errorMsg = errorMsg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaLyy on 2015/4/10.
|
||||||
|
*/
|
||||||
|
public class StreamUtil {
|
||||||
|
/**
|
||||||
|
* 得到图片字节流 数组大小
|
||||||
|
*/
|
||||||
|
public static byte[] readStream(InputStream inStream) throws Exception {
|
||||||
|
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int len = 0;
|
||||||
|
while ((len = inStream.read(buffer)) != -1) {
|
||||||
|
outStream.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
outStream.close();
|
||||||
|
return outStream.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
328
AppFrame/src/main/java/com/arialyy/frame/util/StringUtil.java
Normal file
328
AppFrame/src/main/java/com/arialyy/frame/util/StringUtil.java
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.text.Layout;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.text.TextPaint;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
import android.text.style.URLSpan;
|
||||||
|
import android.text.style.UnderlineSpan;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串工具类
|
||||||
|
*
|
||||||
|
* @author lyy
|
||||||
|
*/
|
||||||
|
public class StringUtil {
|
||||||
|
public static final int APPLICATION = 0;
|
||||||
|
public static final int BROADCAST = 1;
|
||||||
|
public static final int SERVICE = 2;
|
||||||
|
public static final int ACTIVITY = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取字体长度
|
||||||
|
*/
|
||||||
|
public static int getTextLen(TextView textView) {
|
||||||
|
TextPaint paint = textView.getPaint();
|
||||||
|
return (int) Layout.getDesiredWidth(textView.getText().toString(), 0,
|
||||||
|
textView.getText().length(), paint);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 给某段支付设置下划线
|
||||||
|
*/
|
||||||
|
public static SpannableString underLineHight(String str, String underLineStr) {
|
||||||
|
if (!str.contains(underLineStr)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 创建一个 SpannableString对象
|
||||||
|
SpannableString sp = new SpannableString(str);
|
||||||
|
int index = str.indexOf(underLineStr);
|
||||||
|
//设置背景颜色, StrikethroughSpan()是设置中划线
|
||||||
|
sp.setSpan(new UnderlineSpan(), index, index + underLineStr.length(),
|
||||||
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高亮所有关键字
|
||||||
|
*
|
||||||
|
* @param str 这个字符串
|
||||||
|
* @param key 关键字
|
||||||
|
*/
|
||||||
|
public static SpannableString highlightKeyword(String str, String key, int highlightColor) {
|
||||||
|
if (!str.contains(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
SpannableString sp = new SpannableString(str);
|
||||||
|
key = Pattern.quote(key);
|
||||||
|
Pattern p = Pattern.compile(key);
|
||||||
|
Matcher m = p.matcher(str);
|
||||||
|
|
||||||
|
while (m.find()) { //通过正则查找,逐个高亮
|
||||||
|
int start = m.start();
|
||||||
|
int end = m.end();
|
||||||
|
sp.setSpan(new ForegroundColorSpan(highlightColor), start, end,
|
||||||
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个含有超链接的字符串
|
||||||
|
*
|
||||||
|
* @param text 整段字符串
|
||||||
|
* @param clickText 含有超链接的字符
|
||||||
|
* @param url 超链接
|
||||||
|
*/
|
||||||
|
public static SpannableString createLinkText(String text, String clickText, String url) {
|
||||||
|
if (!text.contains(clickText)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
SpannableString sp = new SpannableString(text);
|
||||||
|
int index = text.indexOf(clickText);
|
||||||
|
// 设置超链接
|
||||||
|
sp.setSpan(new URLSpan(url), index, index + clickText.length(),
|
||||||
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
return sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将缓存的key转换为hash码
|
||||||
|
*
|
||||||
|
* @param key 缓存的key
|
||||||
|
* @return 转换后的key的值, 系统便是通过该key来读写缓存
|
||||||
|
*/
|
||||||
|
public static String keyToHashKey(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取Activity节点的meta-data
|
||||||
|
*/
|
||||||
|
public static String getActivityMetaData(Activity activity, String key) {
|
||||||
|
try {
|
||||||
|
return activity.getPackageManager()
|
||||||
|
.getActivityInfo(activity.getComponentName(),
|
||||||
|
PackageManager.GET_META_DATA).metaData.getString(key);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取Service节点的meta-data
|
||||||
|
*
|
||||||
|
* @param serviceClazz 服务的class
|
||||||
|
*/
|
||||||
|
public static String getServiceMetaData(Context context, Class<? extends Service> serviceClazz,
|
||||||
|
String key) {
|
||||||
|
try {
|
||||||
|
return context.getPackageManager()
|
||||||
|
.getServiceInfo(new ComponentName(context, serviceClazz),
|
||||||
|
PackageManager.GET_META_DATA).metaData.getString(key);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取BroadCast节点meta-data数据
|
||||||
|
*
|
||||||
|
* @param receiverClazz 广播接收器的class
|
||||||
|
*/
|
||||||
|
public static String getBroadCasetMetaData(Context context,
|
||||||
|
Class<? extends BroadcastReceiver> receiverClazz, String key) {
|
||||||
|
try {
|
||||||
|
return context.getPackageManager()
|
||||||
|
.getReceiverInfo(new ComponentName(context, receiverClazz),
|
||||||
|
PackageManager.GET_META_DATA).metaData.getString(key);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 读取Application节点的meta-data数据
|
||||||
|
*/
|
||||||
|
public static String getApplicationMetaData(Context context, String key) {
|
||||||
|
try {
|
||||||
|
return context.getPackageManager()
|
||||||
|
.getApplicationInfo(context.getPackageName(),
|
||||||
|
PackageManager.GET_META_DATA).metaData.getString(key);
|
||||||
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用AES算法解密加密的密码
|
||||||
|
*
|
||||||
|
* @param seed 密钥
|
||||||
|
* @param password 加密的密码
|
||||||
|
* @return 解密后的密码, 默认返回""
|
||||||
|
*/
|
||||||
|
public static String decryptPassword(String seed, String password) {
|
||||||
|
try {
|
||||||
|
return AESEncryption.decryptString(seed, password);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从XML读取字符串
|
||||||
|
*
|
||||||
|
* @param id 字符串id
|
||||||
|
*/
|
||||||
|
public static String getStringFromXML(Context context, int id) {
|
||||||
|
return context.getResources().getString(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从xml读取字符串数组
|
||||||
|
*/
|
||||||
|
public static String[] getStringArrayFromXML(Context context, int id) {
|
||||||
|
return context.getResources().getStringArray(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将字符串数组转换为list
|
||||||
|
*/
|
||||||
|
public static List<String> stringArray2List(String[] strArray) {
|
||||||
|
List<String> list = new ArrayList<String>();
|
||||||
|
Collections.addAll(list, strArray);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高亮整段字符串
|
||||||
|
*/
|
||||||
|
public static SpannableStringBuilder highLightStr(String str, int color) {
|
||||||
|
SpannableStringBuilder style = new SpannableStringBuilder(str);
|
||||||
|
style.setSpan(new ForegroundColorSpan(color), 0, str.length(),
|
||||||
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高亮代码片段
|
||||||
|
*
|
||||||
|
* @param str 整段字符串
|
||||||
|
* @param highLightStr 要高亮的代码段
|
||||||
|
* @param color 高亮颜色
|
||||||
|
*/
|
||||||
|
public static SpannableStringBuilder highLightStr(String str, String highLightStr, int color) {
|
||||||
|
int start = str.indexOf(highLightStr);
|
||||||
|
if (start == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
SpannableStringBuilder style = new SpannableStringBuilder(str);
|
||||||
|
// new BackgroundColorSpan(Color.RED)背景高亮
|
||||||
|
// ForegroundColorSpan(Color.RED) 字体高亮
|
||||||
|
style.setSpan(new ForegroundColorSpan(color), start, start + highLightStr.length(),
|
||||||
|
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串转hashcode
|
||||||
|
*/
|
||||||
|
public static int keyToHashCode(String str) {
|
||||||
|
int total = 0;
|
||||||
|
for (int i = 0; i < str.length(); i++) {
|
||||||
|
char ch = str.charAt(i);
|
||||||
|
if (ch == '-') ch = (char) 28; // does not contain the same last 5 bits as any letter
|
||||||
|
if (ch == '\'') ch = (char) 29; // nor this
|
||||||
|
total = (total * 33) + (ch & 0x1F);
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 字符串转dbouble
|
||||||
|
*/
|
||||||
|
public static double strToDouble(String str) {
|
||||||
|
// double d = Double.parseDouble(str);
|
||||||
|
|
||||||
|
/* 以下代码处理精度问题 */
|
||||||
|
BigDecimal bDeci = new BigDecimal(str);
|
||||||
|
// BigDecimal chushu =new BigDecimal(100000000);
|
||||||
|
// BigDecimal result =bDeci.divide(chushu,new
|
||||||
|
// MathContext(4));//MathConText(4)表示结果精确4位!
|
||||||
|
// return result.doubleValue() * 100000000;
|
||||||
|
return bDeci.doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将普通字符串转换为16位进制字符串
|
||||||
|
*/
|
||||||
|
public static String bytesToHexString(byte[] src) {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder("0x");
|
||||||
|
if (src == null || src.length <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
char[] buffer = new char[2];
|
||||||
|
for (byte aSrc : src) {
|
||||||
|
buffer[0] = Character.forDigit((aSrc >>> 4) & 0x0F, 16);
|
||||||
|
buffer[1] = Character.forDigit(aSrc & 0x0F, 16);
|
||||||
|
stringBuilder.append(buffer);
|
||||||
|
}
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把字符串长度加满16位
|
||||||
|
*
|
||||||
|
* @return 16位长度的字符串
|
||||||
|
*/
|
||||||
|
public static String addStrLenTo16(String str) {
|
||||||
|
//由于汉字的特殊性,长度要用byte来判断
|
||||||
|
for (int i = str.getBytes().length; i < 16; i++) {
|
||||||
|
str += '\0';
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取对象名
|
||||||
|
*
|
||||||
|
* @param obj 对象
|
||||||
|
* @return 对象名
|
||||||
|
*/
|
||||||
|
public static String getClassName(Object obj) {
|
||||||
|
String arrays[] = obj.getClass().getName().split("\\.");
|
||||||
|
return arrays[arrays.length - 1];
|
||||||
|
}
|
||||||
|
}
|
245
AppFrame/src/main/java/com/arialyy/frame/util/TextUtil.java
Normal file
245
AppFrame/src/main/java/com/arialyy/frame/util/TextUtil.java
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
package com.arialyy.frame.util;
|
||||||
|
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本处理工具
|
||||||
|
*/
|
||||||
|
public class TextUtil {
|
||||||
|
private TextUtil() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化字符
|
||||||
|
*/
|
||||||
|
public static String decimalFormat(Number scr, String format) {
|
||||||
|
return new DecimalFormat(format).format(scr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换字符号(不带空格)
|
||||||
|
*/
|
||||||
|
public static String replaceSymbol(String str) {
|
||||||
|
String dest = "";
|
||||||
|
if (str != null) {
|
||||||
|
// Pattern p = Pattern.compile("\\s*|\t|\r|\n");
|
||||||
|
Pattern p = Pattern.compile("\t|\r|\n");
|
||||||
|
Matcher m = p.matcher(str);
|
||||||
|
dest = m.replaceAll("");
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 首字母大写
|
||||||
|
*/
|
||||||
|
public static String firstUpperCase(String str) {
|
||||||
|
if (android.text.TextUtils.isEmpty(str)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return str.replaceFirst(str.substring(0, 1), str.substring(0, 1).toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从文本中读取数据,返回成List对象
|
||||||
|
*/
|
||||||
|
public static List<String> getTextToList(File file) {
|
||||||
|
FileInputStream fileInputStream = null;
|
||||||
|
InputStreamReader inputStreamReader = null;
|
||||||
|
BufferedReader bufferedReader = null;
|
||||||
|
List<String> list = new ArrayList<String>();
|
||||||
|
try {
|
||||||
|
fileInputStream = new FileInputStream(file);
|
||||||
|
inputStreamReader = new InputStreamReader(fileInputStream);
|
||||||
|
bufferedReader = new BufferedReader(inputStreamReader);
|
||||||
|
String text;
|
||||||
|
while ((text = bufferedReader.readLine()) != null) {
|
||||||
|
list.add(text);
|
||||||
|
}
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (fileInputStream != null) {
|
||||||
|
fileInputStream.close();
|
||||||
|
}
|
||||||
|
if (inputStreamReader != null) {
|
||||||
|
inputStreamReader.close();
|
||||||
|
}
|
||||||
|
if (bufferedReader != null) {
|
||||||
|
bufferedReader.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从文本中读取数据,返回成List对象
|
||||||
|
*/
|
||||||
|
public static List<String> getTextToList(InputStream inputStream) {
|
||||||
|
InputStreamReader inputStreamReader = null;
|
||||||
|
BufferedReader bufferedReader = null;
|
||||||
|
List<String> list = new ArrayList<String>();
|
||||||
|
try {
|
||||||
|
inputStreamReader = new InputStreamReader(inputStream);
|
||||||
|
bufferedReader = new BufferedReader(inputStreamReader);
|
||||||
|
String text;
|
||||||
|
while ((text = bufferedReader.readLine()) != null) {
|
||||||
|
list.add(text);
|
||||||
|
}
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (inputStreamReader != null) {
|
||||||
|
inputStreamReader.close();
|
||||||
|
}
|
||||||
|
if (bufferedReader != null) {
|
||||||
|
bufferedReader.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断一个数是否是整数
|
||||||
|
*/
|
||||||
|
public static boolean isInteger(String numStr) {
|
||||||
|
try {
|
||||||
|
double parseDouble = Double.parseDouble(numStr);
|
||||||
|
return parseDouble % 1 == 0;
|
||||||
|
} catch (Exception exception) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断一个数是否是大于0的数
|
||||||
|
*/
|
||||||
|
public static boolean isPositiveInteger(String numStr) {
|
||||||
|
if (isInteger(numStr)) {
|
||||||
|
double parseDouble = Double.parseDouble(numStr);
|
||||||
|
if (parseDouble > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化数据
|
||||||
|
*
|
||||||
|
* @param value 需要转换的值
|
||||||
|
* @param pattern 小数位数
|
||||||
|
*/
|
||||||
|
public static String decimalFormat(double value, String pattern) {
|
||||||
|
DecimalFormat df = new DecimalFormat(pattern);
|
||||||
|
return df.format(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化数据
|
||||||
|
*
|
||||||
|
* @param value 需要转换的值
|
||||||
|
* @param pattern 小数位数
|
||||||
|
*/
|
||||||
|
public static String decimalFormat(String value, String pattern) {
|
||||||
|
DecimalFormat df = new DecimalFormat(pattern);
|
||||||
|
return df.format(Double.parseDouble(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化数据
|
||||||
|
*/
|
||||||
|
public static String decimalFormat(double value, int scale) {
|
||||||
|
return decimalFormat(value, getScalePattern(scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化数据
|
||||||
|
*/
|
||||||
|
public static String decimalFormat(String value, int scale) {
|
||||||
|
return decimalFormat(value, getScalePattern(scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回小数位数的匹配
|
||||||
|
*/
|
||||||
|
private static String getScalePattern(int scale) {
|
||||||
|
StringBuffer sb = new StringBuffer("#0.");
|
||||||
|
if (scale <= 0) {
|
||||||
|
sb = new StringBuffer("#");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < scale; ++i) {
|
||||||
|
sb.append("0");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回TextView的值,没有或者null返回0
|
||||||
|
*/
|
||||||
|
public static String getViewText(TextView view) {
|
||||||
|
if (view == null) {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
boolean empty = android.text.TextUtils.isEmpty(view.getText().toString());
|
||||||
|
return empty ? "0" : view.getText().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换字符串
|
||||||
|
*/
|
||||||
|
public static String replace(String source, int index, String before, String after) {
|
||||||
|
Matcher matcher = Pattern.compile(before).matcher(source);
|
||||||
|
for (int counter = 0; matcher.find(); counter++) {
|
||||||
|
if (counter == index) {
|
||||||
|
return source.substring(0, matcher.start()) + after + source.substring(matcher.end(),
|
||||||
|
source.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String JsonToString(String src) {
|
||||||
|
if ("{}".equals(src) || "[]".equals(src)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 去掉空格和特殊字符
|
||||||
|
*/
|
||||||
|
public static String trimString(String str) {
|
||||||
|
if (android.text.TextUtils.isEmpty(str)) {
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
return str.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
204
AppFrame/src/main/java/com/arialyy/frame/util/show/FL.java
Normal file
204
AppFrame/src/main/java/com/arialyy/frame/util/show/FL.java
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
package com.arialyy.frame.util.show;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.arialyy.frame.util.CalendarUtils;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Lyy on 2015/4/1.
|
||||||
|
* 写入文件的log,由于使用到反射和文件流的操作,建议在需要的地方才去使用
|
||||||
|
*/
|
||||||
|
public class FL {
|
||||||
|
static String LINE_SEPARATOR = System.getProperty("line.separator"); //等价于"\n\r",唯一的作用是能装逼
|
||||||
|
static int JSON_INDENT = 4;
|
||||||
|
public static boolean isDebug = true;// 是否需要打印bug,可以在application的onCreate函数里面初始化
|
||||||
|
public static String NAME = "AriaFrame"; //log路径
|
||||||
|
|
||||||
|
private static String printLine(String tag, boolean isTop) {
|
||||||
|
String top =
|
||||||
|
"╔══════════════════════════════════════════ JSON ═══════════════════════════════════════";
|
||||||
|
String bottom =
|
||||||
|
"╚═══════════════════════════════════════════════════════════════════════════════════════";
|
||||||
|
if (isTop) {
|
||||||
|
Log.d(tag, top);
|
||||||
|
return top;
|
||||||
|
} else {
|
||||||
|
Log.d(tag, bottom);
|
||||||
|
return bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印JSON
|
||||||
|
*/
|
||||||
|
public static void j(String tag, String jsonStr) {
|
||||||
|
if (isDebug) {
|
||||||
|
String message;
|
||||||
|
try {
|
||||||
|
if (jsonStr.startsWith("{")) {
|
||||||
|
JSONObject jsonObject = new JSONObject(jsonStr);
|
||||||
|
message = jsonObject.toString(JSON_INDENT); //这个是核心方法
|
||||||
|
} else if (jsonStr.startsWith("[")) {
|
||||||
|
JSONArray jsonArray = new JSONArray(jsonStr);
|
||||||
|
message = jsonArray.toString(JSON_INDENT);
|
||||||
|
} else {
|
||||||
|
message = jsonStr;
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
message = jsonStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeLogToFile(tag, printLine(tag, true));
|
||||||
|
message = LINE_SEPARATOR + message;
|
||||||
|
String temp = "";
|
||||||
|
String[] lines = message.split(LINE_SEPARATOR);
|
||||||
|
for (String line : lines) {
|
||||||
|
temp += "║ " + line;
|
||||||
|
Log.d(tag, "║ " + line);
|
||||||
|
}
|
||||||
|
writeLogToFile(tag, temp);
|
||||||
|
writeLogToFile(tag, printLine(tag, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下面四个是默认tag的函数
|
||||||
|
public static void i(Object obj, String msg) {
|
||||||
|
String TAG = getTag(obj);
|
||||||
|
if (isDebug) {
|
||||||
|
Log.i(TAG, msg);
|
||||||
|
writeLogToFile(TAG, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void d(Object obj, String msg) {
|
||||||
|
String TAG = getTag(obj);
|
||||||
|
if (isDebug) {
|
||||||
|
Log.d(TAG, msg);
|
||||||
|
writeLogToFile(TAG, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void e(Object obj, String msg) {
|
||||||
|
String TAG = getTag(obj);
|
||||||
|
if (isDebug) {
|
||||||
|
Log.e(TAG, msg);
|
||||||
|
writeLogToFile(TAG, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void v(Object obj, String msg) {
|
||||||
|
String TAG = getTag(obj);
|
||||||
|
if (isDebug) {
|
||||||
|
Log.v(TAG, msg);
|
||||||
|
writeLogToFile(TAG, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void i(String TAG, String msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.i(TAG, msg);
|
||||||
|
writeLogToFile(TAG, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void d(String TAG, String msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.d(TAG, msg);
|
||||||
|
writeLogToFile(TAG, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void e(String TAG, String msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.e(TAG, msg);
|
||||||
|
writeLogToFile(TAG, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void v(String TAG, String msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.v(TAG, msg);
|
||||||
|
writeLogToFile(TAG, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取类名
|
||||||
|
*/
|
||||||
|
private static String getTag(Object object) {
|
||||||
|
Class<?> cls = object.getClass();
|
||||||
|
String tag = cls.getName();
|
||||||
|
String arrays[] = tag.split("\\.");
|
||||||
|
tag = arrays[arrays.length - 1];
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回日志路径
|
||||||
|
*/
|
||||||
|
public static String getLogPath() {
|
||||||
|
String name = NAME + "_" + CalendarUtils.getData() + ".log";
|
||||||
|
return android.os.Environment.getExternalStorageDirectory().getPath() + File.separator + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把日志记录到文件
|
||||||
|
*/
|
||||||
|
private static int writeLogToFile(String tag, String message) {
|
||||||
|
StringBuffer stringBuffer = new StringBuffer();
|
||||||
|
stringBuffer.append(CalendarUtils.getNowDataTime());
|
||||||
|
stringBuffer.append(" ");
|
||||||
|
stringBuffer.append(tag);
|
||||||
|
stringBuffer.append(" ");
|
||||||
|
stringBuffer.append(message);
|
||||||
|
stringBuffer.append("\n");
|
||||||
|
PrintWriter writer = null;
|
||||||
|
try {
|
||||||
|
writer = new PrintWriter(new FileWriter(getLogPath(), true));
|
||||||
|
writer.append(stringBuffer);
|
||||||
|
writer.flush();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
if (writer != null) {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将异常信息转换为字符串
|
||||||
|
*/
|
||||||
|
public static String getExceptionString(Throwable ex) {
|
||||||
|
StringBuilder err = new StringBuilder();
|
||||||
|
err.append("ExceptionDetailed:\n");
|
||||||
|
err.append("====================Exception Info====================\n");
|
||||||
|
err.append(ex.toString());
|
||||||
|
err.append("\n");
|
||||||
|
StackTraceElement[] stack = ex.getStackTrace();
|
||||||
|
for (StackTraceElement stackTraceElement : stack) {
|
||||||
|
err.append(stackTraceElement.toString()).append("\n");
|
||||||
|
}
|
||||||
|
Throwable cause = ex.getCause();
|
||||||
|
if (cause != null) {
|
||||||
|
err.append("【Caused by】: ");
|
||||||
|
err.append(cause.toString());
|
||||||
|
err.append("\n");
|
||||||
|
StackTraceElement[] stackTrace = cause.getStackTrace();
|
||||||
|
for (StackTraceElement stackTraceElement : stackTrace) {
|
||||||
|
err.append(stackTraceElement.toString()).append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err.append("===================================================");
|
||||||
|
return err.toString();
|
||||||
|
}
|
||||||
|
}
|
291
AppFrame/src/main/java/com/arialyy/frame/util/show/L.java
Normal file
291
AppFrame/src/main/java/com/arialyy/frame/util/show/L.java
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
package com.arialyy.frame.util.show;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Lyy on 2015/4/1.
|
||||||
|
* 普通的Log管理类
|
||||||
|
*/
|
||||||
|
public class L {
|
||||||
|
/**
|
||||||
|
* Drawing toolbox
|
||||||
|
*/
|
||||||
|
private static final char TOP_LEFT_CORNER = '╔';
|
||||||
|
private static final char BOTTOM_LEFT_CORNER = '╚';
|
||||||
|
private static final char MIDDLE_CORNER = '╟';
|
||||||
|
private static final char HORIZONTAL_DOUBLE_LINE = '║';
|
||||||
|
private static final String DOUBLE_DIVIDER = "════════════════════════════════════════════";
|
||||||
|
private static final String SINGLE_DIVIDER = "────────────────────────────────────────────";
|
||||||
|
private static final String TOP_BORDER = TOP_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER;
|
||||||
|
private static final String BOTTOM_BORDER = BOTTOM_LEFT_CORNER + DOUBLE_DIVIDER + DOUBLE_DIVIDER;
|
||||||
|
private static final String MIDDLE_BORDER = MIDDLE_CORNER + SINGLE_DIVIDER + SINGLE_DIVIDER;
|
||||||
|
private static final char I = 'I', W = 'W', D = 'D', E = 'E', V = 'V', A = 'A', M = 'M';
|
||||||
|
|
||||||
|
static String LINE_SEPARATOR = System.getProperty("line.separator"); //等价于"\n\r",唯一的作用是能装逼
|
||||||
|
static int JSON_INDENT = 4;
|
||||||
|
|
||||||
|
private L() {
|
||||||
|
/* cannot be instantiated */
|
||||||
|
throw new UnsupportedOperationException("cannot be instantiated");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isDebug = true;// 是否需要打印bug,可以在application的onCreate函数里面初始化
|
||||||
|
private static final String TAG = "lyy";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* map to str
|
||||||
|
*/
|
||||||
|
public static String m2s(Map map) {
|
||||||
|
if (isDebug) {
|
||||||
|
if (map == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
Set set = map.entrySet();
|
||||||
|
for (Object aSet : set) {
|
||||||
|
Map.Entry entry = (Map.Entry) aSet;
|
||||||
|
sb.append(entry.getValue());
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印MAp
|
||||||
|
*/
|
||||||
|
public static void m(Map map) {
|
||||||
|
if (isDebug) {
|
||||||
|
Set set = map.entrySet();
|
||||||
|
if (set.size() < 1) {
|
||||||
|
printLog(D, "[]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
String[] s = new String[set.size()];
|
||||||
|
for (Object aSet : set) {
|
||||||
|
Map.Entry entry = (Map.Entry) aSet;
|
||||||
|
s[i] = entry.getKey() + " = " + entry.getValue() + ",\n";
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
printLog(V, s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印JSON
|
||||||
|
*/
|
||||||
|
public static void j(String jsonStr) {
|
||||||
|
if (isDebug) {
|
||||||
|
String message;
|
||||||
|
try {
|
||||||
|
if (jsonStr.startsWith("{")) {
|
||||||
|
JSONObject jsonObject = new JSONObject(jsonStr);
|
||||||
|
message = jsonObject.toString(JSON_INDENT); //这个是核心方法
|
||||||
|
} else if (jsonStr.startsWith("[")) {
|
||||||
|
JSONArray jsonArray = new JSONArray(jsonStr);
|
||||||
|
message = jsonArray.toString(JSON_INDENT);
|
||||||
|
} else {
|
||||||
|
message = jsonStr;
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
message = jsonStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
message = LINE_SEPARATOR + message;
|
||||||
|
String[] lines = message.split(LINE_SEPARATOR);
|
||||||
|
printLog(D, lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下面四个是默认tag的函数
|
||||||
|
public static void i(String... msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
printLog(I, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void d(String... msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
printLog(D, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void w(String... msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
printLog(W, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void e(String... msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
printLog(E, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void v(String... msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
printLog(V, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下面是传入自定义tag的函数
|
||||||
|
public static void i(String tag, String msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.i(tag, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void d(String tag, String msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.d(tag, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void w(String tag, String msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.w(tag, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void e(String tag, String msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.e(tag, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void v(String tag, String msg) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.v(tag, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//带异常的
|
||||||
|
public static void i(String tag, String msg, Throwable tr) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.i(tag, msg, tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void d(String tag, String msg, Throwable tr) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.d(tag, msg, tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void w(String tag, String msg, Throwable tr) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.w(tag, msg, tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void e(String tag, String msg, Throwable tr) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.e(tag, msg, tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void v(String tag, String msg, Throwable tr) {
|
||||||
|
if (isDebug) {
|
||||||
|
Log.v(tag, msg, tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同意打印
|
||||||
|
*/
|
||||||
|
private static void printHunk(char type, String str) {
|
||||||
|
switch (type) {
|
||||||
|
case I:
|
||||||
|
Log.i(TAG, str);
|
||||||
|
break;
|
||||||
|
case D:
|
||||||
|
Log.d(TAG, str);
|
||||||
|
break;
|
||||||
|
case E:
|
||||||
|
Log.e(TAG, str);
|
||||||
|
break;
|
||||||
|
case V:
|
||||||
|
Log.v(TAG, str);
|
||||||
|
break;
|
||||||
|
case A:
|
||||||
|
Log.wtf(TAG, str);
|
||||||
|
break;
|
||||||
|
case W:
|
||||||
|
Log.w(TAG, str);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印头部信息
|
||||||
|
*/
|
||||||
|
private static void printHead(char type) {
|
||||||
|
printHunk(type, TOP_BORDER);
|
||||||
|
printHunk(type, HORIZONTAL_DOUBLE_LINE + " Thread:");
|
||||||
|
printHunk(type, HORIZONTAL_DOUBLE_LINE + " " + Thread.currentThread().getName());
|
||||||
|
printHunk(type, MIDDLE_BORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印Log被调用的位置
|
||||||
|
*/
|
||||||
|
private static void printLocation(char type, String... msg) {
|
||||||
|
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
|
||||||
|
int i = 0;
|
||||||
|
for (StackTraceElement e : stack) {
|
||||||
|
String name = e.getClassName();
|
||||||
|
if (!name.equals(L.class.getName())) {
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += 3;
|
||||||
|
String className = stack[i].getFileName();
|
||||||
|
String methodName = stack[i].getMethodName();
|
||||||
|
int lineNumber = stack[i].getLineNumber();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
printHunk(type, HORIZONTAL_DOUBLE_LINE + " Location:");
|
||||||
|
sb.append(HORIZONTAL_DOUBLE_LINE)
|
||||||
|
.append(" (")
|
||||||
|
.append(className)
|
||||||
|
.append(":")
|
||||||
|
.append(lineNumber)
|
||||||
|
.append(")# ")
|
||||||
|
.append(methodName);
|
||||||
|
printHunk(type, sb.toString());
|
||||||
|
printHunk(type, msg == null || msg.length == 0 ? BOTTOM_BORDER : MIDDLE_BORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印消息
|
||||||
|
*/
|
||||||
|
private static void printMsg(char type, String... msg) {
|
||||||
|
printHunk(type, HORIZONTAL_DOUBLE_LINE + " msg:");
|
||||||
|
for (String str : msg) {
|
||||||
|
printHunk(type, HORIZONTAL_DOUBLE_LINE + " " + str);
|
||||||
|
}
|
||||||
|
printHunk(type, BOTTOM_BORDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印log
|
||||||
|
*/
|
||||||
|
private static void printLog(char type, String... msg) {
|
||||||
|
printHead(type);
|
||||||
|
printLocation(type, msg);
|
||||||
|
if (msg == null || msg.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printMsg(type, msg);
|
||||||
|
}
|
||||||
|
}
|
74
AppFrame/src/main/java/com/arialyy/frame/util/show/T.java
Normal file
74
AppFrame/src/main/java/com/arialyy/frame/util/show/T.java
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package com.arialyy.frame.util.show;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Lyy on 2015/4/1.
|
||||||
|
* Toast统一管理类
|
||||||
|
*/
|
||||||
|
public class T {
|
||||||
|
|
||||||
|
private T() {
|
||||||
|
throw new UnsupportedOperationException("cannot be instantiated");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否显示Tost
|
||||||
|
*/
|
||||||
|
public static boolean isShow = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短时间显示Toast
|
||||||
|
*/
|
||||||
|
public static void showShort(Context context, CharSequence message) {
|
||||||
|
if (isShow) {
|
||||||
|
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 短时间显示Toast
|
||||||
|
*/
|
||||||
|
public static void showShort(Context context, int message) {
|
||||||
|
if (isShow) {
|
||||||
|
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 长时间显示Toast
|
||||||
|
*/
|
||||||
|
public static void showLong(Context context, CharSequence message) {
|
||||||
|
if (isShow) {
|
||||||
|
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 长时间显示Toast
|
||||||
|
*/
|
||||||
|
public static void showLong(Context context, int message) {
|
||||||
|
if (isShow) {
|
||||||
|
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义显示Toast时间
|
||||||
|
*/
|
||||||
|
public static void show(Context context, CharSequence message, int duration) {
|
||||||
|
if (isShow) {
|
||||||
|
Toast.makeText(context, message, duration).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义显示Toast时间
|
||||||
|
*/
|
||||||
|
public static void show(Context context, int message, int duration) {
|
||||||
|
if (isShow) {
|
||||||
|
Toast.makeText(context, message, duration).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
AppFrame/src/main/res/drawable/selector_green_bt.xml
Normal file
15
AppFrame/src/main/res/drawable/selector_green_bt.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:state_pressed="true">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#005bab"/>
|
||||||
|
<corners android:radius="30dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:state_pressed="false">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<solid android:color="#095389"/>
|
||||||
|
<corners android:radius="30dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</selector>
|
62
AppFrame/src/main/res/layout/layout_error_temp.xml
Normal file
62
AppFrame/src/main/res/layout/layout_error_temp.xml
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/background_color"
|
||||||
|
>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/temp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:orientation="vertical"
|
||||||
|
>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/pb"
|
||||||
|
android:layout_width="80dp"
|
||||||
|
android:layout_height="80dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/error"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/hint"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="网络错误"
|
||||||
|
android:textColor="@android:color/black"
|
||||||
|
android:textSize="20sp"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/bt"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_below="@+id/hint"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:background="@drawable/selector_green_bt"
|
||||||
|
android:text="刷新"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="16sp"
|
||||||
|
/>
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
6
AppFrame/src/main/res/values/color.xml
Normal file
6
AppFrame/src/main/res/values/color.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="background_color">#E5E5E5</color>
|
||||||
|
<color name="white">#fff</color>
|
||||||
|
<color name="bg_line">#757575</color>
|
||||||
|
</resources>
|
3
AppFrame/src/main/res/values/strings.xml
Normal file
3
AppFrame/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">Frame</string>
|
||||||
|
</resources>
|
15
AppFrame/src/main/res/values/style.xml
Normal file
15
AppFrame/src/main/res/values/style.xml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="AppTheme" parent="Theme.AppCompat.Light.Dialog.Alert">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
</style>
|
||||||
|
<!-- <item name="android:windowBackground">@drawable/white_pop_normal_background</item>
|
||||||
|
-->
|
||||||
|
<style name="MyDialog" parent="AppTheme">
|
||||||
|
<item name="android:windowFrame">@null</item>
|
||||||
|
<item name="android:windowNoTitle">true</item>
|
||||||
|
<item name="android:windowIsFloating">true</item>
|
||||||
|
<item name="android:windowContentOverlay">@null</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
3
Aria/.gitignore
vendored
Normal file
3
Aria/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
/build
|
||||||
|
gradle.properties
|
||||||
|
downloadutil.iml
|
13
Aria/bintray-release.gradle
Normal file
13
Aria/bintray-release.gradle
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
apply plugin: 'com.novoda.bintray-release'
|
||||||
|
publish {
|
||||||
|
// artifactId = 'aria-core'
|
||||||
|
// uploadName = 'AriaApi'
|
||||||
|
artifactId = 'core'
|
||||||
|
uploadName = 'Core'
|
||||||
|
userOrg = rootProject.ext.userOrg
|
||||||
|
groupId = rootProject.ext.groupId
|
||||||
|
publishVersion = rootProject.ext.publishVersion
|
||||||
|
desc = rootProject.ext.desc
|
||||||
|
website = rootProject.ext.website
|
||||||
|
licences = rootProject.ext.licences
|
||||||
|
}
|
39
Aria/build.gradle
Normal file
39
Aria/build.gradle
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion rootProject.ext.compileSdkVersion
|
||||||
|
buildToolsVersion rootProject.ext.buildToolsVersion
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
|
versionCode rootProject.ext.versionCode
|
||||||
|
versionName rootProject.ext.versionName
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
debug{
|
||||||
|
debuggable true
|
||||||
|
}
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lintOptions {
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
|
testImplementation 'junit:junit:4.12'
|
||||||
|
// implementation "androidx.appcompat:appcompat:${rootProject.ext.XAppcompatVersion}"
|
||||||
|
api project(path: ':AriaAnnotations')
|
||||||
|
api project(path: ':PublicComponent')
|
||||||
|
api project(path: ':HttpComponent')
|
||||||
|
}
|
||||||
|
|
||||||
|
//apply from: 'bintray-release.gradle'
|
||||||
|
ext{
|
||||||
|
PUBLISH_ARTIFACT_ID = 'core'
|
||||||
|
}
|
||||||
|
apply from: '../gradle/mavenCentral-release.gradle'
|
143
Aria/jcenter.gradle
Normal file
143
Aria/jcenter.gradle
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
group = PROJ_GROUP_ID
|
||||||
|
version = PROJ_VERSION
|
||||||
|
project.archivesBaseName = PROJ_ARTIFACT_ID
|
||||||
|
apply plugin: 'com.jfrog.bintray'
|
||||||
|
apply plugin: 'com.github.dcendents.android-maven'
|
||||||
|
//输入:gradlew bintray 执行
|
||||||
|
|
||||||
|
//############################## jar、sources、doc 打包 create #######################################
|
||||||
|
task sourcesJar(type: Jar) {
|
||||||
|
from android.sourceSets.main.java.srcDirs
|
||||||
|
classifier = 'sources'
|
||||||
|
}
|
||||||
|
|
||||||
|
task javadoc(type: Javadoc) {
|
||||||
|
source = android.sourceSets.main.java.srcDirs
|
||||||
|
classpath += configurations.compile
|
||||||
|
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
|
||||||
|
}
|
||||||
|
|
||||||
|
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||||
|
classifier = 'javadoc'
|
||||||
|
from javadoc.destinationDir
|
||||||
|
}
|
||||||
|
|
||||||
|
javadoc {
|
||||||
|
options {
|
||||||
|
encoding "UTF-8"
|
||||||
|
charSet 'UTF-8'
|
||||||
|
author true
|
||||||
|
version true
|
||||||
|
links "http://docs.oracle.com/javase/7/docs/api"
|
||||||
|
title PROJ_ARTIFACT_ID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//添加以下信息避免JAVADOC打包时引用其它类库而出现问题,比如出现以下错误
|
||||||
|
// xxxx.java:20: 错误: 找不到符号
|
||||||
|
// public static <T> T create(JsonElement json, Class<T> classOfModel) {
|
||||||
|
// ^
|
||||||
|
// 符号: 类 JsonElement
|
||||||
|
// 位置: 类 xxxx
|
||||||
|
android.libraryVariants.all { variant ->
|
||||||
|
println variant.javaCompile.classpath.files
|
||||||
|
if (variant.name == 'release') {
|
||||||
|
//我们只需 release 的 javadoc
|
||||||
|
task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) {
|
||||||
|
// title = ''
|
||||||
|
// description = ''
|
||||||
|
source = variant.javaCompile.source
|
||||||
|
classpath = files(variant.javaCompile.classpath.files, project.android.getBootClasspath())
|
||||||
|
options {
|
||||||
|
encoding "utf-8"
|
||||||
|
links "http://docs.oracle.com/javase/7/docs/api/"
|
||||||
|
linksOffline "http://d.android.com/reference", "${android.sdkDirectory}/docs/reference"
|
||||||
|
}
|
||||||
|
exclude '**/BuildConfig.java'
|
||||||
|
exclude '**/R.java'
|
||||||
|
}
|
||||||
|
task("javadoc${variant.name.capitalize()}Jar", type: Jar,
|
||||||
|
dependsOn: "generate${variant.name.capitalize()}Javadoc") {
|
||||||
|
classifier = 'javadoc'
|
||||||
|
from tasks.getByName("generate${variant.name.capitalize()}Javadoc").destinationDir
|
||||||
|
}
|
||||||
|
artifacts {
|
||||||
|
archives tasks.getByName("javadoc${variant.name.capitalize()}Jar")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
artifacts {
|
||||||
|
archives javadocJar
|
||||||
|
archives sourcesJar
|
||||||
|
}
|
||||||
|
//############################## jar、sources、doc 打包 end #######################################
|
||||||
|
|
||||||
|
//################################# jcenter 上传配置 create #########################################
|
||||||
|
bintray {
|
||||||
|
// user = hasProperty("bintrayUser") ? getProperty("bintrayUser") : getProperty("BINTRAY_USER")
|
||||||
|
// groupHash = hasProperty("bintrayKey") ? getProperty("bintrayKey") : getProperty("BINTRAY_KEY")
|
||||||
|
user = BINTRAY_USER
|
||||||
|
key = BINTRAY_KEY
|
||||||
|
configurations = ['archives']
|
||||||
|
|
||||||
|
pkg {
|
||||||
|
repo = PROJ_REPO
|
||||||
|
name = PROJ_NAME
|
||||||
|
desc = PROJ_DESCRIPTION
|
||||||
|
websiteUrl = PROJ_WEB_SITE_URL
|
||||||
|
issueTrackerUrl = PROJ_ISSUE_TRACKER_URL
|
||||||
|
vcsUrl = PROJ_VCS_URL
|
||||||
|
publish = true
|
||||||
|
publicDownloadNumbers = true
|
||||||
|
licenses = LICENSES
|
||||||
|
// version {
|
||||||
|
// desc = libraryDescription
|
||||||
|
// gpg {
|
||||||
|
// sign = true //Determines whether to GPG sign the files. The default is false
|
||||||
|
// passphrase = properties.getProperty("bintray.gpg.password")
|
||||||
|
// //Optional. The passphrase for GPG signing'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//install
|
||||||
|
install {
|
||||||
|
repositories.mavenInstaller {
|
||||||
|
// This generates POM.xml with proper parameters
|
||||||
|
pom {
|
||||||
|
project {
|
||||||
|
packaging 'aar'
|
||||||
|
groupId PROJ_GROUP_ID
|
||||||
|
artifactId PROJ_ARTIFACT_ID
|
||||||
|
|
||||||
|
// Add your description here
|
||||||
|
name PROJ_NAME
|
||||||
|
description PROJ_DESCRIPTION
|
||||||
|
url PROJ_WEB_SITE_URL
|
||||||
|
|
||||||
|
// Set your license
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name LICENSE_NAME
|
||||||
|
url LICENSE_URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id DEVELOPER_ID
|
||||||
|
name DEVELOPER_NAME
|
||||||
|
email DEVELOPER_EMAIL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scm {
|
||||||
|
connection PROJ_WEB_SITE_URL
|
||||||
|
developerConnection PROJ_WEB_SITE_URL
|
||||||
|
url PROJ_VCS_URL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//################################# jcenter 上传配置 end #########################################
|
17
Aria/proguard-rules.pro
vendored
Normal file
17
Aria/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# By default, the flags in this file are appended to flags specified
|
||||||
|
# in D:\sdk/tools/proguard/proguard-android.txt
|
||||||
|
# You can edit the include path and order by changing the proguardFiles
|
||||||
|
# directive in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# Add any project specific keep options here:
|
||||||
|
|
||||||
|
# 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 *;
|
||||||
|
#}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package com.arialyy.downloadutil;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.test.ApplicationTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
|
||||||
|
*/
|
||||||
|
public class ApplicationTest extends ApplicationTestCase<Application> {
|
||||||
|
public ApplicationTest() {
|
||||||
|
super(Application.class);
|
||||||
|
}
|
||||||
|
}
|
11
Aria/src/main/AndroidManifest.xml
Normal file
11
Aria/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.arialyy.aria">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:supportsRtl="true">
|
||||||
|
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
153
Aria/src/main/java/com/arialyy/aria/core/Aria.java
Normal file
153
Aria/src/main/java/com/arialyy/aria/core/Aria.java
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.arialyy.aria.core;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.Application;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.widget.PopupWindow;
|
||||||
|
import com.arialyy.aria.core.download.DownloadReceiver;
|
||||||
|
import com.arialyy.aria.core.upload.UploadReceiver;
|
||||||
|
import com.arialyy.aria.util.ALog;
|
||||||
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/12/1.
|
||||||
|
*
|
||||||
|
* @see <a href="https://github.com/AriaLyy/Aria">Aria</a>
|
||||||
|
* @see <a href="https://aria.laoyuyu.me/aria_doc/">Aria doc</a>
|
||||||
|
* Aria启动,管理全局任务
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* //下载
|
||||||
|
* Aria.download(this)
|
||||||
|
* .load(URL) //下载地址,必填
|
||||||
|
* //文件保存路径,必填
|
||||||
|
* .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk")
|
||||||
|
* .create();
|
||||||
|
* </code>
|
||||||
|
* <code>
|
||||||
|
* //上传
|
||||||
|
* Aria.upload(this)
|
||||||
|
* .load(filePath) //文件路径,必填
|
||||||
|
* .setTempUrl(uploadUrl) //上传路径,必填
|
||||||
|
* .setAttachment(fileKey) //服务器读取文件的key,必填
|
||||||
|
* .create();
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* 如果你需要在【Activity、Service、Application、DialogFragment、Fragment、PopupWindow、Dialog】
|
||||||
|
* 之外的java中使用Aria,那么你应该在Application或Activity初始化的时候调用{@link #init(Context)}对Aria进行初始化
|
||||||
|
* 然后才能使用{@link #download(Object)}、{@link #upload(Object)}
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* Aria.init(this);
|
||||||
|
*
|
||||||
|
* Aria.download(this)
|
||||||
|
* .load(URL) //下载地址,必填
|
||||||
|
* //文件保存路径,必填
|
||||||
|
* .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk")
|
||||||
|
* .create();
|
||||||
|
*
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) public class Aria {
|
||||||
|
|
||||||
|
private Aria() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载,在当前类中调用Aria方法,参数需要使用this,否则将
|
||||||
|
* 如果不是【Activity、Service、Application、DialogFragment、Fragment、PopupWindow、Dialog】对象,那么你
|
||||||
|
* 需要在对象中初始化下载前,在Application或Activity初始化的时候调用{@link #init(Context)}对Aria进行初始化
|
||||||
|
*
|
||||||
|
* @param obj 观察者对象,为本类对象,使用{@code this}
|
||||||
|
*/
|
||||||
|
public static DownloadReceiver download(Object obj) {
|
||||||
|
if (AriaManager.getInstance() != null) {
|
||||||
|
return AriaManager.getInstance().download(obj);
|
||||||
|
}
|
||||||
|
return get(convertContext(obj)).download(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传
|
||||||
|
* 如果不是【Activity、Service、Application、DialogFragment、Fragment、PopupWindow、Dialog】对象,那么你
|
||||||
|
* 需要在对象中初始化下载前,在Application或Activity初始化的时候调用{@link #init(Context)}对Aria进行初始化
|
||||||
|
*
|
||||||
|
* @param obj 观察者对象,为本类对象,使用{@code this}
|
||||||
|
*/
|
||||||
|
public static UploadReceiver upload(Object obj) {
|
||||||
|
if (AriaManager.getInstance() != null) {
|
||||||
|
return AriaManager.getInstance().upload(obj);
|
||||||
|
}
|
||||||
|
return get(convertContext(obj)).upload(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理通用事件
|
||||||
|
*/
|
||||||
|
public static AriaManager get(Context context) {
|
||||||
|
if (context == null) {
|
||||||
|
throw new NullPointerException(
|
||||||
|
"context 无效,在非【Activity、Service、Application、DialogFragment、Fragment、PopupWindow、Dialog】,"
|
||||||
|
+ "请参考【https://aria.laoyuyu.me/aria_doc/create/any_java.html】,参数请使用 download(this) 或 upload(this);"
|
||||||
|
+ "不要使用 download(getContext()) 或 upload(getContext())");
|
||||||
|
}
|
||||||
|
return AriaManager.init(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化Aria,如果你需要在【Activity、Service、Application、DialogFragment、Fragment、PopupWindow、Dialog】
|
||||||
|
* 之外的java中使用Aria,那么你应该在Application或Activity初始化的时候调用本方法对Aria进行初始化
|
||||||
|
* 只需要初始化一次就可以
|
||||||
|
* {@link #download(Object)}、{@link #upload(Object)}
|
||||||
|
*/
|
||||||
|
public static AriaManager init(Context context) {
|
||||||
|
return get(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Context convertContext(Object obj) {
|
||||||
|
if (obj instanceof Application) {
|
||||||
|
return (Application) obj;
|
||||||
|
}
|
||||||
|
if (obj instanceof Service) {
|
||||||
|
return (Service) obj;
|
||||||
|
}
|
||||||
|
if (obj instanceof Activity) {
|
||||||
|
return (Activity) obj;
|
||||||
|
}
|
||||||
|
if (CommonUtil.isFragment(obj.getClass())) {
|
||||||
|
return CommonUtil.getFragmentActivity(obj);
|
||||||
|
}
|
||||||
|
if (obj instanceof Dialog) {
|
||||||
|
return ((Dialog) obj).getContext();
|
||||||
|
}
|
||||||
|
if (obj instanceof PopupWindow) {
|
||||||
|
return ((PopupWindow) obj).getContentView().getContext();
|
||||||
|
}
|
||||||
|
ALog.e("Aria", "请使用download(this)或upload(this)");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
389
Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
Normal file
389
Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
Normal file
@ -0,0 +1,389 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.arialyy.aria.core;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import com.arialyy.aria.core.command.CommandManager;
|
||||||
|
import com.arialyy.aria.core.common.QueueMod;
|
||||||
|
import com.arialyy.aria.core.config.AppConfig;
|
||||||
|
import com.arialyy.aria.core.config.DGroupConfig;
|
||||||
|
import com.arialyy.aria.core.config.DownloadConfig;
|
||||||
|
import com.arialyy.aria.core.config.UploadConfig;
|
||||||
|
import com.arialyy.aria.core.download.DownloadEntity;
|
||||||
|
import com.arialyy.aria.core.download.DownloadGroupEntity;
|
||||||
|
import com.arialyy.aria.core.download.DownloadReceiver;
|
||||||
|
import com.arialyy.aria.core.inf.AbsReceiver;
|
||||||
|
import com.arialyy.aria.core.inf.IReceiver;
|
||||||
|
import com.arialyy.aria.core.inf.ReceiverType;
|
||||||
|
import com.arialyy.aria.core.loader.IRecordHandler;
|
||||||
|
import com.arialyy.aria.core.upload.UploadEntity;
|
||||||
|
import com.arialyy.aria.core.upload.UploadReceiver;
|
||||||
|
import com.arialyy.aria.orm.DbEntity;
|
||||||
|
import com.arialyy.aria.orm.DelegateWrapper;
|
||||||
|
import com.arialyy.aria.util.ALog;
|
||||||
|
import com.arialyy.aria.util.AriaCrashHandler;
|
||||||
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
|
import com.arialyy.aria.util.DeleteURecord;
|
||||||
|
import com.arialyy.aria.util.RecordUtil;
|
||||||
|
import java.io.File;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2016/12/1. https://github.com/AriaLyy/Aria
|
||||||
|
* Aria管理器,任务操作在这里执行
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public class AriaManager {
|
||||||
|
private static final String TAG = "AriaManager";
|
||||||
|
private static final Object LOCK = new Object();
|
||||||
|
|
||||||
|
@SuppressLint("StaticFieldLeak") private static volatile AriaManager INSTANCE = null;
|
||||||
|
private Map<String, AbsReceiver> mReceivers = new ConcurrentHashMap<>();
|
||||||
|
private static Context APP;
|
||||||
|
private DelegateWrapper mDbWrapper;
|
||||||
|
private AriaConfig mConfig;
|
||||||
|
|
||||||
|
private AriaManager(Context context) {
|
||||||
|
APP = context.getApplicationContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AriaManager getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AriaManager init(Context context) {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
synchronized (LOCK) {
|
||||||
|
if (INSTANCE == null) {
|
||||||
|
INSTANCE = new AriaManager(context);
|
||||||
|
INSTANCE.initData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initData() {
|
||||||
|
mConfig = AriaConfig.init(APP);
|
||||||
|
initDb(APP);
|
||||||
|
regAppLifeCallback(APP);
|
||||||
|
initAria();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Context getAPP() {
|
||||||
|
return APP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化数据库
|
||||||
|
*/
|
||||||
|
private void initDb(Context context) {
|
||||||
|
String oldDbName = "AriaLyyDb";
|
||||||
|
File oldDbFile = context.getDatabasePath(oldDbName);
|
||||||
|
if (oldDbFile != null && oldDbFile.exists()) {
|
||||||
|
File dbConfig = new File(String.format("%s/%s", oldDbFile.getParent(), "AriaLyyDb-journal"));
|
||||||
|
oldDbFile.renameTo(new File(String.format("%s/%s", oldDbFile.getParent(), "AndroidAria.db")));
|
||||||
|
// 如果数据库是在/data/data/{packagename}/databases/下面,journal文件因权限问题将无法删除和重命名
|
||||||
|
if (dbConfig.exists()) {
|
||||||
|
dbConfig.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mDbWrapper = DelegateWrapper.init(context.getApplicationContext());
|
||||||
|
amendTaskState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initAria() {
|
||||||
|
AppConfig appConfig = mConfig.getAConfig();
|
||||||
|
if (appConfig.getUseAriaCrashHandler()) {
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler(new AriaCrashHandler());
|
||||||
|
}
|
||||||
|
appConfig.setLogLevel(appConfig.getLogLevel());
|
||||||
|
CommandManager.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修正任务状态
|
||||||
|
*/
|
||||||
|
private void amendTaskState() {
|
||||||
|
Class[] clazzs = new Class[] {
|
||||||
|
DownloadEntity.class, UploadEntity.class, DownloadGroupEntity.class
|
||||||
|
};
|
||||||
|
String sql = "UPDATE %s SET state=2 WHERE state IN (4,5,6)";
|
||||||
|
for (Class clazz : clazzs) {
|
||||||
|
if (!mDbWrapper.tableExists(clazz)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String temp = String.format(sql, clazz.getSimpleName());
|
||||||
|
DbEntity.exeSql(temp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, AbsReceiver> getReceiver() {
|
||||||
|
return mReceivers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置上传任务的执行队列类型,后续版本会删除该api,请使用:
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* Aria.get(this).getUploadConfig().setQueueMod(mod.tag)
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param mod {@link QueueMod}
|
||||||
|
* @deprecated 后续版本会删除该api
|
||||||
|
*/
|
||||||
|
@Deprecated public AriaManager setUploadQueueMod(QueueMod mod) {
|
||||||
|
mConfig.getUConfig().setQueueMod(mod.tag);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置下载任务的执行队列类型,后续版本会删除该api,请使用:
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* Aria.get(this).getDownloadConfig().setQueueMod(mod.tag)
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param mod {@link QueueMod}
|
||||||
|
* @deprecated 后续版本会删除该api
|
||||||
|
*/
|
||||||
|
@Deprecated public AriaManager setDownloadQueueMod(QueueMod mod) {
|
||||||
|
mConfig.getDConfig().setQueueMod(mod.tag);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果需要在代码中修改下载配置,请使用以下方法
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* //修改最大任务队列数
|
||||||
|
* Aria.get(this).getDownloadConfig().setMaxTaskNum(3);
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public DownloadConfig getDownloadConfig() {
|
||||||
|
return mConfig.getDConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果需要在代码中修改下载配置,请使用以下方法
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* //修改最大任务队列数
|
||||||
|
* Aria.get(this).getUploadConfig().setMaxTaskNum(3);
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public UploadConfig getUploadConfig() {
|
||||||
|
return mConfig.getUConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取APP配置
|
||||||
|
*/
|
||||||
|
public AppConfig getAppConfig() {
|
||||||
|
return mConfig.getAConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果需要在代码中修改下载类型的组合任务的配置,请使用以下方法
|
||||||
|
* <pre>
|
||||||
|
* <code>
|
||||||
|
* //修改最大任务队列数
|
||||||
|
* Aria.get(this).getDownloadConfig().setMaxTaskNum(3);
|
||||||
|
* </code>
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
public DGroupConfig getDGroupConfig() {
|
||||||
|
return mConfig.getDGConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理下载操作
|
||||||
|
*/
|
||||||
|
DownloadReceiver download(Object obj) {
|
||||||
|
|
||||||
|
IReceiver receiver = mReceivers.get(getKey(ReceiverType.DOWNLOAD, obj));
|
||||||
|
if (receiver == null) {
|
||||||
|
receiver = putReceiver(ReceiverType.DOWNLOAD, obj);
|
||||||
|
}
|
||||||
|
return (receiver instanceof DownloadReceiver) ? (DownloadReceiver) receiver : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理上传操作
|
||||||
|
*/
|
||||||
|
UploadReceiver upload(Object obj) {
|
||||||
|
IReceiver receiver = mReceivers.get(getKey(ReceiverType.UPLOAD, obj));
|
||||||
|
if (receiver == null) {
|
||||||
|
receiver = putReceiver(ReceiverType.UPLOAD, obj);
|
||||||
|
}
|
||||||
|
return (receiver instanceof UploadReceiver) ? (UploadReceiver) receiver : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除任务记录
|
||||||
|
*
|
||||||
|
* @param type 需要删除的任务类型,1、普通下载任务;2、组合任务;3、普通上传任务。
|
||||||
|
* @param key type为1时,key为保存路径;type为2时,key为组合任务hash;type为3时,key为文件上传路径。
|
||||||
|
* @param removeFile {@code true} 不仅删除任务数据库记录,还会删除已经删除完成的文件;{@code false}如果任务已经完成,只删除任务数据库记录。
|
||||||
|
*/
|
||||||
|
public void delRecord(int type, String key, boolean removeFile) {
|
||||||
|
switch (type) {
|
||||||
|
case 1: // 删除普通任务记录
|
||||||
|
RecordUtil.delTaskRecord(key, IRecordHandler.TYPE_DOWNLOAD, removeFile, true);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
RecordUtil.delGroupTaskRecordByHash(key, removeFile);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
DeleteURecord.getInstance().deleteRecord(key, removeFile, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IReceiver putReceiver(ReceiverType type, Object obj) {
|
||||||
|
final String key = getKey(type, obj);
|
||||||
|
IReceiver receiver = mReceivers.get(key);
|
||||||
|
|
||||||
|
if (receiver == null) {
|
||||||
|
AbsReceiver absReceiver =
|
||||||
|
type.equals(ReceiverType.DOWNLOAD) ? new DownloadReceiver(obj) : new UploadReceiver(obj);
|
||||||
|
mReceivers.put(key, absReceiver);
|
||||||
|
receiver = absReceiver;
|
||||||
|
}
|
||||||
|
return receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据功能类型和控件类型获取对应的key
|
||||||
|
*
|
||||||
|
* @param type {@link ReceiverType}
|
||||||
|
* @param obj 观察者对象
|
||||||
|
* @return key的格式为:{@code String.format("%s_%s_%s", obj.getClass().getName(), type,
|
||||||
|
* obj.hashCode());}
|
||||||
|
*/
|
||||||
|
private String getKey(ReceiverType type, Object obj) {
|
||||||
|
return String.format("%s_%s_%s", CommonUtil.getTargetName(obj), type.name(), obj.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册APP生命周期回调
|
||||||
|
*/
|
||||||
|
private void regAppLifeCallback(Context context) {
|
||||||
|
Context app = context.getApplicationContext();
|
||||||
|
if (app instanceof Application) {
|
||||||
|
LifeCallback lifeCallback = new LifeCallback();
|
||||||
|
((Application) app).registerActivityLifecycleCallbacks(lifeCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除指定对象的receiver
|
||||||
|
*/
|
||||||
|
public void removeReceiver(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
ALog.e(TAG, "target obj is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 移除寄主的receiver
|
||||||
|
for (Iterator<Map.Entry<String, AbsReceiver>> iter = mReceivers.entrySet().iterator();
|
||||||
|
iter.hasNext(); ) {
|
||||||
|
Map.Entry<String, AbsReceiver> entry = iter.next();
|
||||||
|
String key = entry.getKey();
|
||||||
|
AbsReceiver receiver = entry.getValue();
|
||||||
|
|
||||||
|
if (receiver.isFragment()){
|
||||||
|
Method method = CommonUtil.getMethod(receiver.obj.getClass(), "getActivity");
|
||||||
|
if (method != null){
|
||||||
|
try {
|
||||||
|
Activity ac = (Activity) method.invoke(receiver.obj);
|
||||||
|
if (ac == obj){
|
||||||
|
receiver.destroy();
|
||||||
|
iter.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理内部类的
|
||||||
|
String objClsName = obj.getClass().getName();
|
||||||
|
if (receiver.isLocalOrAnonymousClass && key.startsWith(objClsName)) {
|
||||||
|
receiver.destroy();
|
||||||
|
iter.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.equals(getKey(ReceiverType.DOWNLOAD, obj))
|
||||||
|
|| key.equals(getKey(ReceiverType.UPLOAD, obj))
|
||||||
|
) {
|
||||||
|
receiver.destroy();
|
||||||
|
iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.d(TAG, "debug");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activity生命周期
|
||||||
|
*/
|
||||||
|
private class LifeCallback implements Application.ActivityLifecycleCallbacks {
|
||||||
|
|
||||||
|
@Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onActivityStarted(Activity activity) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onActivityResumed(Activity activity) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onActivityPaused(Activity activity) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onActivityStopped(Activity activity) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onActivityDestroyed(Activity activity) {
|
||||||
|
removeReceiver(activity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
133
Aria/src/main/java/com/arialyy/aria/core/WidgetLiftManager.java
Normal file
133
Aria/src/main/java/com/arialyy/aria/core/WidgetLiftManager.java
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.arialyy.aria.core;
|
||||||
|
|
||||||
|
import android.annotation.TargetApi;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.widget.PopupWindow;
|
||||||
|
import com.arialyy.aria.util.ALog;
|
||||||
|
import com.arialyy.aria.util.CommonUtil;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by lyy on 2017/2/7.
|
||||||
|
* 为组件添加生命周期
|
||||||
|
*/
|
||||||
|
public final class WidgetLiftManager {
|
||||||
|
private final String TAG = "WidgetLiftManager";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理DialogFragment事件
|
||||||
|
*/
|
||||||
|
@TargetApi(Build.VERSION_CODES.HONEYCOMB) public boolean handleDialogFragmentLift(Dialog dialog) {
|
||||||
|
return handleDialogLift(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理悬浮框取消或dismiss事件
|
||||||
|
*/
|
||||||
|
public boolean handlePopupWindowLift(PopupWindow popupWindow) {
|
||||||
|
try {
|
||||||
|
Field dismissField = CommonUtil.getField(popupWindow.getClass(), "mOnDismissListener");
|
||||||
|
PopupWindow.OnDismissListener listener =
|
||||||
|
(PopupWindow.OnDismissListener) dismissField.get(popupWindow);
|
||||||
|
if (listener != null) {
|
||||||
|
ALog.e(TAG, "你已经对PopupWindow设置了Dismiss事件。为了防止内存泄露,"
|
||||||
|
+ "请在dismiss方法中调用Aria.download(this).unRegister();来注销事件");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
popupWindow.setOnDismissListener(createPopupWindowListener(popupWindow));
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建popupWindow dismiss事件
|
||||||
|
*/
|
||||||
|
private PopupWindow.OnDismissListener createPopupWindowListener(final PopupWindow popupWindow) {
|
||||||
|
return new PopupWindow.OnDismissListener() {
|
||||||
|
@Override public void onDismiss() {
|
||||||
|
AriaManager.getInstance().removeReceiver(popupWindow);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理对话框取消或dismiss
|
||||||
|
*
|
||||||
|
* @return true 设置了dialog的销毁事件。false 没有设置dialog的销毁事件
|
||||||
|
*/
|
||||||
|
public boolean handleDialogLift(Dialog dialog) {
|
||||||
|
if (dialog == null) {
|
||||||
|
ALog.w(TAG,
|
||||||
|
"dialog 为空,没有设置自动销毁事件,为了防止内存泄露,请在dismiss方法中调用Aria.download(this).unRegister();来注销事件\n"
|
||||||
|
+ "如果你使用的是DialogFragment,那么你需要在onDestroy()中进行销毁Aria事件操作");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Field dismissField = CommonUtil.getField(dialog.getClass(), "mDismissMessage");
|
||||||
|
Message dismissMsg = (Message) dismissField.get(dialog);
|
||||||
|
//如果Dialog已经设置Dismiss事件,则查找cancel事件
|
||||||
|
if (dismissMsg != null) {
|
||||||
|
Field cancelField = CommonUtil.getField(dialog.getClass(), "mCancelMessage");
|
||||||
|
Message cancelMsg = (Message) cancelField.get(dialog);
|
||||||
|
if (cancelMsg != null) {
|
||||||
|
ALog.e(TAG, "你已经对Dialog设置了Dismiss和cancel事件。"
|
||||||
|
+ "为了防止内存泄露,请在dismiss方法中调用Aria.download(this).unRegister();来注销事件\n"
|
||||||
|
+ "如果你使用的是DialogFragment,那么你需要在onDestroy()中进行销毁Aria事件操作");
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
dialog.setOnCancelListener(createCancelListener());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dialog.setOnDismissListener(createDismissListener());
|
||||||
|
}
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建Dialog取消事件
|
||||||
|
*/
|
||||||
|
private Dialog.OnCancelListener createCancelListener() {
|
||||||
|
return new Dialog.OnCancelListener() {
|
||||||
|
|
||||||
|
@Override public void onCancel(DialogInterface dialog) {
|
||||||
|
AriaManager.getInstance().removeReceiver(dialog);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建Dialog dismiss取消事件
|
||||||
|
*/
|
||||||
|
private Dialog.OnDismissListener createDismissListener() {
|
||||||
|
return new Dialog.OnDismissListener() {
|
||||||
|
|
||||||
|
@Override public void onDismiss(DialogInterface dialog) {
|
||||||
|
AriaManager.getInstance().removeReceiver(dialog);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
35
Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
Normal file
35
Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.arialyy.aria.core.command;
|
||||||
|
|
||||||
|
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||||
|
import com.arialyy.aria.core.queue.AbsTaskQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaL on 2017/6/29.
|
||||||
|
*/
|
||||||
|
public abstract class AbsCmd<T extends AbsTaskWrapper> implements ICmd {
|
||||||
|
protected AbsTaskQueue mQueue;
|
||||||
|
protected T mTaskWrapper;
|
||||||
|
protected String TAG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否是下载任务的命令
|
||||||
|
* {@code true} 下载任务的命令,{@code false} 上传任务的命令
|
||||||
|
*/
|
||||||
|
protected boolean isDownloadCmd = true;
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.arialyy.aria.core.command;
|
||||||
|
|
||||||
|
import com.arialyy.aria.core.task.ITask;
|
||||||
|
import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaL on 2017/6/29.
|
||||||
|
* 抽象命令工厂
|
||||||
|
*/
|
||||||
|
public abstract class AbsCmdFactory<TASK_ENTITY extends AbsTaskWrapper, CMD extends AbsCmd> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param entity 下载实体
|
||||||
|
* {@link ITask#DOWNLOAD}、{@link ITask#DOWNLOAD_GROUP}、{@link ITask#UPLOAD}
|
||||||
|
*/
|
||||||
|
public abstract CMD createCmd(TASK_ENTITY entity, int type, int taskType);
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user