├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ └── strings.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ ├── menu
│ │ │ └── menu_main_activity_bottom_navigation_view.xml
│ │ ├── layout
│ │ │ └── layout_main_activity.xml
│ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ └── drawable
│ │ │ └── ic_launcher_background.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── me
│ │ └── jiahuan
│ │ └── androidlearn
│ │ ├── App.java
│ │ └── MainActivity.java
├── build.gradle
└── proguard-rules.pro
├── clint
├── .gitignore
├── build.gradle
└── src
│ └── main
│ └── java
│ └── me
│ └── jiahuan
│ └── androidlearn
│ └── clint
│ ├── CIssueRegistry.java
│ ├── NewThreadDetector.java
│ └── LogDetector.java
├── README.md
├── clint-aar
├── .gitignore
├── src
│ └── main
│ │ └── AndroidManifest.xml
├── build.gradle
└── proguard-rules.pro
├── lib_base
├── .gitignore
├── src
│ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── res
│ │ ├── drawable
│ │ │ └── lib_base_drawable_item_decoration.xml
│ │ ├── values
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ │ └── layout
│ │ │ └── lib_base_layout_tool_bar.xml
│ │ └── java
│ │ └── me
│ │ └── jiahuan
│ │ └── androidlearn
│ │ └── base
│ │ ├── BaseFragment.java
│ │ ├── BaseActivity.java
│ │ ├── DividerItemDecoration.java
│ │ └── DividerGridItemDecoration.java
├── build.gradle
└── proguard-rules.pro
├── module_ui
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ └── layout
│ │ │ ├── module_ui_layout_recycler_view_activity_item.xml
│ │ │ ├── module_ui_layout_recycler_view_activity.xml
│ │ │ ├── module_ui_layout_ui_fragment.xml
│ │ │ └── module_ui_layout_view_pager_activity.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── me
│ │ └── jiahuan
│ │ └── androidlearn
│ │ └── ui
│ │ ├── UIFragment.java
│ │ ├── viewpager
│ │ ├── TabFragment.java
│ │ └── ViewPagerActivity.java
│ │ └── recyclerview
│ │ └── RecyclerViewActivity.java
├── build.gradle
└── proguard-rules.pro
├── module_function
├── .gitignore
├── src
│ └── main
│ │ ├── aidl
│ │ └── me
│ │ │ └── jiahuan
│ │ │ └── androidlearn
│ │ │ └── function
│ │ │ └── binder
│ │ │ ├── Book.aidl
│ │ │ └── IBookManager.aidl
│ │ ├── res
│ │ └── layout
│ │ │ ├── module_function_layout_lru_activity.xml
│ │ │ ├── module_function_layout_jni_activity.xml
│ │ │ ├── module_function_layout_hook_activity.xml
│ │ │ ├── module_function_layout_binder_activity.xml
│ │ │ ├── module_function_layout_permission_activity.xml
│ │ │ ├── module_function_layout_rxjava2_activity.xml
│ │ │ └── module_function_layout_function_fragment.xml
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── me
│ │ │ └── jiahuan
│ │ │ └── androidlearn
│ │ │ └── function
│ │ │ ├── jni
│ │ │ └── JNIActivity.java
│ │ │ ├── hook
│ │ │ ├── HookHelper.java
│ │ │ ├── HookActivity.java
│ │ │ └── ProxyInstrumentation.java
│ │ │ ├── binder
│ │ │ ├── Book.java
│ │ │ ├── BookRemoteService.java
│ │ │ └── BinderActivity.java
│ │ │ ├── lru
│ │ │ └── LruCacheActivity.java
│ │ │ ├── FunctionFragment.java
│ │ │ ├── rxjava2
│ │ │ └── RxJava2Activity.java
│ │ │ └── permission
│ │ │ └── PermissionActivity.java
│ │ └── cpp
│ │ └── native-lib.cpp
├── CMakeLists.txt
├── build.gradle
└── proguard-rules.pro
├── .gitignore
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── settings.gradle
├── gradle.properties
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/clint/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Android 代码实例库
2 |
--------------------------------------------------------------------------------
/clint-aar/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/lib_base/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/module_ui/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/module_function/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .gradle
3 | /local.properties
4 | .DS_Store
5 | /build
6 | *.iml
7 | .externalNativeBuild
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Only
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahuanyu/android-example-code/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahuanyu/android-example-code/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahuanyu/android-example-code/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahuanyu/android-example-code/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahuanyu/android-example-code/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahuanyu/android-example-code/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/clint-aar/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/lib_base/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahuanyu/android-example-code/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahuanyu/android-example-code/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahuanyu/android-example-code/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | println "setting.gradle start"
2 | include ':app', ':module_function', ':lib_base', ':clint', ':clint-aar', ':module_ui'
3 | println "setting.gradle end"
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahuanyu/android-example-code/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jiahuanyu/android-example-code/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/module_function/src/main/aidl/me/jiahuan/androidlearn/function/binder/Book.aidl:
--------------------------------------------------------------------------------
1 | // Book.aidl
2 | package me.jiahuan.androidlearn.function.binder;
3 |
4 | parcelable Book;
5 |
--------------------------------------------------------------------------------
/module_function/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.4.1)
2 |
3 | add_library(native-lib SHARED src/main/cpp/native-lib.cpp)
4 |
5 | find_library(log-lib log)
6 |
7 | target_link_libraries(native-lib ${log-lib})
8 |
--------------------------------------------------------------------------------
/lib_base/src/main/res/drawable/lib_base_drawable_item_decoration.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Dec 22 21:33:35 CST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
7 |
--------------------------------------------------------------------------------
/lib_base/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/module_function/src/main/aidl/me/jiahuan/androidlearn/function/binder/IBookManager.aidl:
--------------------------------------------------------------------------------
1 | // IBookManager.aidl
2 | package me.jiahuan.androidlearn.function.binder;
3 |
4 | import me.jiahuan.androidlearn.function.binder.Book;
5 |
6 | interface IBookManager {
7 | // 定义方法
8 | List getBookList();
9 | void addBook(in Book book);
10 | }
11 |
--------------------------------------------------------------------------------
/module_ui/src/main/res/layout/module_ui_layout_recycler_view_activity_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/clint/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java-library'
2 |
3 |
4 | sourceCompatibility = "1.7"
5 | targetCompatibility = "1.7"
6 |
7 |
8 | jar {
9 | manifest {
10 | attributes("Lint-Registry-v2": "me.jiahuan.androidlearn.clint.CIssueRegistry")
11 | }
12 | }
13 |
14 | dependencies {
15 | compileOnly "com.android.tools.lint:lint-api:26.1.2"
16 | compileOnly "com.android.tools.lint:lint-checks:26.1.2"
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main_activity_bottom_navigation_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/module_ui/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/clint/src/main/java/me/jiahuan/androidlearn/clint/CIssueRegistry.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.clint;
2 |
3 | import com.android.tools.lint.client.api.IssueRegistry;
4 | import com.android.tools.lint.detector.api.Issue;
5 |
6 | import java.util.ArrayList;
7 | import java.util.Arrays;
8 | import java.util.List;
9 |
10 |
11 | public class CIssueRegistry extends IssueRegistry {
12 | @Override
13 | public List getIssues() {
14 | return Arrays.asList(LogDetector.ISSUE, NewThreadDetector.ISSUE);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/lib_base/src/main/java/me/jiahuan/androidlearn/base/BaseFragment.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.base;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.v4.app.Fragment;
6 | import android.util.Log;
7 |
8 | public class BaseFragment extends Fragment {
9 | private static final String TAG = "BaseFragment";
10 | @Override
11 | public void onCreate(@Nullable Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | Log.d(TAG, "onCreate");
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/lib_base/src/main/res/layout/lib_base_layout_tool_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
--------------------------------------------------------------------------------
/lib_base/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/module_function/src/main/res/layout/module_function_layout_lru_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
14 |
--------------------------------------------------------------------------------
/module_function/src/main/res/layout/module_function_layout_jni_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/module_function/src/main/res/layout/module_function_layout_hook_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
--------------------------------------------------------------------------------
/clint-aar/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion config.compileSdkVersion
5 |
6 | defaultConfig {
7 | minSdkVersion config.minSdkVersion
8 | targetSdkVersion config.targetSdkVersion
9 | versionCode config.versionCode
10 | versionName config.versionName
11 | }
12 |
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 |
20 | }
21 |
22 | dependencies {
23 | lintChecks project(':clint')
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/lib_base/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 |
4 | android {
5 | compileSdkVersion config.compileSdkVersion
6 |
7 | defaultConfig {
8 | minSdkVersion config.minSdkVersion
9 | targetSdkVersion config.targetSdkVersion
10 | versionCode config.versionCode
11 | versionName config.versionName
12 |
13 | resourcePrefix 'lib_base_'
14 | }
15 | }
16 |
17 | dependencies {
18 | api 'com.android.support:appcompat-v7:' + config.supportVersion
19 | api 'com.android.support:design:' + config.supportVersion
20 | api 'io.reactivex.rxjava2:rxandroid:2.0.2'
21 | api 'com.orhanobut:logger:2.2.0'
22 | }
23 |
--------------------------------------------------------------------------------
/module_ui/src/main/res/layout/module_ui_layout_recycler_view_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/module_function/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion config.compileSdkVersion
5 |
6 | defaultConfig {
7 | minSdkVersion config.minSdkVersion
8 | targetSdkVersion config.targetSdkVersion
9 | versionCode config.versionCode
10 | versionName config.versionName
11 |
12 | resourcePrefix "module_function_"
13 |
14 |
15 | externalNativeBuild {
16 | cmake {
17 | cppFlags ""
18 | }
19 | }
20 |
21 | }
22 |
23 | externalNativeBuild {
24 | cmake {
25 | path "CMakeLists.txt"
26 | }
27 | }
28 | }
29 |
30 |
31 | dependencies {
32 |
33 | api project(':lib_base')
34 | }
35 |
--------------------------------------------------------------------------------
/module_ui/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion config.compileSdkVersion
5 |
6 | defaultConfig {
7 | minSdkVersion config.minSdkVersion
8 | targetSdkVersion config.targetSdkVersion
9 | versionCode config.versionCode
10 | versionName config.versionName
11 |
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 |
14 | resourcePrefix 'module_ui_'
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | api project(':lib_base')
27 | }
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion config.compileSdkVersion
5 | defaultConfig {
6 | applicationId "me.jiahuan.androidlearn"
7 | minSdkVersion config.minSdkVersion
8 | targetSdkVersion config.targetSdkVersion
9 | versionCode config.versionCode
10 | versionName config.versionName
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | api project(':module_function')
23 | api project(':module_ui')
24 | }
25 |
--------------------------------------------------------------------------------
/module_ui/src/main/res/layout/module_ui_layout_ui_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
19 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/clint-aar/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/lib_base/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/module_ui/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/module_function/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/module_ui/src/main/res/layout/module_ui_layout_view_pager_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
14 |
15 |
16 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/lib_base/src/main/java/me/jiahuan/androidlearn/base/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.base;
2 |
3 | import android.app.Activity;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.support.v7.widget.Toolbar;
6 | import android.view.MenuItem;
7 |
8 |
9 | public class BaseActivity extends AppCompatActivity {
10 |
11 | protected Activity mSelfActivity;
12 |
13 | protected void initializeActivity(int layoutId) {
14 | setContentView(layoutId);
15 | Toolbar toolbar = findViewById(R.id.id_layout_tool_bar_tool_bar);
16 | setSupportActionBar(toolbar);
17 | mSelfActivity = this;
18 | }
19 |
20 | @Override
21 | public boolean onOptionsItemSelected(MenuItem item) {
22 | if (item.getItemId() == android.R.id.home) {
23 | finish();
24 | }
25 | return true;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/module_function/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_main_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
15 |
16 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
12 |
13 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/module_function/src/main/java/me/jiahuan/androidlearn/function/jni/JNIActivity.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.function.jni;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.widget.TextView;
6 |
7 | import me.jiahuan.androidlearn.base.BaseActivity;
8 | import me.jiahuan.androidlearn.function.R;
9 |
10 | public class JNIActivity extends BaseActivity {
11 |
12 | static {
13 | System.loadLibrary("native-lib");
14 | }
15 |
16 |
17 | @Override
18 | protected void onCreate(@Nullable Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | initializeActivity(R.layout.module_function_layout_jni_activity);
21 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
22 | initialize();
23 | }
24 |
25 | private void initialize() {
26 | ((TextView) findViewById(R.id.id_module_function_layout_jni_activity_from_jni_text_view)).setText(stringFromJNI() + " " + stringFromJNI2());
27 | }
28 |
29 | public native String stringFromJNI();
30 |
31 | public native String stringFromJNI2();
32 | }
33 |
--------------------------------------------------------------------------------
/module_function/src/main/java/me/jiahuan/androidlearn/function/hook/HookHelper.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.function.hook;
2 |
3 | import android.app.Instrumentation;
4 |
5 | import java.lang.reflect.Field;
6 |
7 | public class HookHelper {
8 |
9 |
10 | public static void attachContext() throws Exception {
11 | Class activityThreadClass = Class.forName("android.app.ActivityThread");
12 | Field currentActivityThreadField = activityThreadClass.getDeclaredField("sCurrentActivityThread");
13 | currentActivityThreadField.setAccessible(true);
14 | Object currentActivityThread = currentActivityThreadField.get(null);
15 |
16 | Field mInstrumentationField = activityThreadClass.getDeclaredField("mInstrumentation");
17 | mInstrumentationField.setAccessible(true);
18 | Instrumentation instrumentation = (Instrumentation) mInstrumentationField.get(currentActivityThread);
19 |
20 |
21 | ProxyInstrumentation proxyInstrumentation = new ProxyInstrumentation(instrumentation);
22 | mInstrumentationField.set(currentActivityThread, proxyInstrumentation);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/module_function/src/main/java/me/jiahuan/androidlearn/function/binder/Book.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.function.binder;
2 |
3 | import android.os.Parcel;
4 | import android.os.Parcelable;
5 |
6 | public class Book implements Parcelable {
7 | int bookId;
8 | String bookName;
9 |
10 | public Book(int bookId, String bookName) {
11 | this.bookId = bookId;
12 | this.bookName = bookName;
13 | }
14 |
15 | protected Book(Parcel in) {
16 | bookId = in.readInt();
17 | bookName = in.readString();
18 | }
19 |
20 | public static final Creator CREATOR = new Creator() {
21 | @Override
22 | public Book createFromParcel(Parcel in) {
23 | return new Book(in);
24 | }
25 |
26 | @Override
27 | public Book[] newArray(int size) {
28 | return new Book[size];
29 | }
30 | };
31 |
32 | @Override
33 | public int describeContents() {
34 | return 0;
35 | }
36 |
37 | @Override
38 | public void writeToParcel(Parcel dest, int flags) {
39 | dest.writeInt(bookId);
40 | dest.writeString(bookName);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/module_function/src/main/java/me/jiahuan/androidlearn/function/hook/HookActivity.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.function.hook;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.annotation.Nullable;
7 | import android.view.View;
8 |
9 | import me.jiahuan.androidlearn.base.BaseActivity;
10 | import me.jiahuan.androidlearn.function.R;
11 |
12 | public class HookActivity extends BaseActivity {
13 |
14 | @Override
15 | protected void onCreate(@Nullable Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | initializeActivity(R.layout.module_function_layout_hook_activity);
18 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
19 | }
20 |
21 |
22 | public void onButtonClicked(View v) {
23 | getApplication().startActivity(new Intent(this, HookActivity.class));
24 | }
25 |
26 |
27 | @Override
28 | protected void attachBaseContext(Context newBase) {
29 | super.attachBaseContext(newBase);
30 | try {
31 | HookHelper.attachContext();
32 | } catch (Exception e) {
33 | e.printStackTrace();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/module_function/src/main/res/layout/module_function_layout_binder_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
17 |
22 |
23 |
28 |
29 |
34 |
35 |
--------------------------------------------------------------------------------
/module_function/src/main/res/layout/module_function_layout_permission_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
15 |
16 |
22 |
23 |
29 |
30 |
--------------------------------------------------------------------------------
/module_function/src/main/res/layout/module_function_layout_rxjava2_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
20 |
21 |
26 |
27 |
31 |
32 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/module_function/src/main/java/me/jiahuan/androidlearn/function/lru/LruCacheActivity.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.function.lru;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.util.LruCache;
6 | import android.view.View;
7 |
8 |
9 | import com.orhanobut.logger.Logger;
10 |
11 | import me.jiahuan.androidlearn.base.BaseActivity;
12 | import me.jiahuan.androidlearn.function.R;
13 |
14 | public class LruCacheActivity extends BaseActivity {
15 | private static final String TAG = "LruCacheActivity";
16 |
17 | private LruCache mLruCache = new LruCache(10) { // 10个字节
18 |
19 | @Override
20 | protected int sizeOf(String key, String value) {
21 | return value.getBytes().length;
22 | }
23 |
24 | @Override
25 | protected void entryRemoved(boolean evicted, String key, String oldValue, String newValue) {
26 | Logger.d("剔除或者替换,key = %s, oldValue = %s, newValue = %s", key, oldValue, newValue);
27 | }
28 | };
29 |
30 | @Override
31 | protected void onCreate(@Nullable Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | initializeActivity(R.layout.module_function_layout_lru_activity);
34 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
35 | }
36 |
37 | public void addItem(View v) {
38 | mLruCache.put(Math.random() + "", "test");
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/clint/src/main/java/me/jiahuan/androidlearn/clint/NewThreadDetector.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.clint;
2 |
3 |
4 | import com.android.tools.lint.detector.api.Category;
5 | import com.android.tools.lint.detector.api.Detector;
6 | import com.android.tools.lint.detector.api.Implementation;
7 | import com.android.tools.lint.detector.api.Issue;
8 | import com.android.tools.lint.detector.api.JavaContext;
9 | import com.android.tools.lint.detector.api.Scope;
10 | import com.android.tools.lint.detector.api.Severity;
11 | import com.intellij.psi.PsiMethod;
12 |
13 | import org.jetbrains.uast.UCallExpression;
14 |
15 | import java.util.Collections;
16 | import java.util.List;
17 |
18 | public class NewThreadDetector extends Detector implements Detector.UastScanner {
19 |
20 | private static final String ISSUE_DESCRIPTION = "避免自己创建Thread,使用同一线程管理";
21 |
22 | public static final Issue ISSUE = Issue.create(
23 | "NewThread",
24 | ISSUE_DESCRIPTION,
25 | "请勿直接调用new Thread(),建议使用AsyncTask或统一的线程管理工具类",
26 | Category.PERFORMANCE,
27 | 5,
28 | Severity.ERROR,
29 | new Implementation(NewThreadDetector.class, Scope.JAVA_FILE_SCOPE)
30 | );
31 |
32 | @Override
33 | public List getApplicableConstructorTypes() {
34 | return Collections.singletonList("java.lang.Thread");
35 | }
36 |
37 |
38 | @Override
39 | public void visitConstructor(JavaContext context, UCallExpression node, PsiMethod constructor) {
40 | context.report(ISSUE, node, context.getLocation(node), ISSUE_DESCRIPTION);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/module_function/src/main/res/layout/module_function_layout_function_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
19 |
24 |
25 |
30 |
31 |
36 |
41 |
42 |
--------------------------------------------------------------------------------
/module_ui/src/main/java/me/jiahuan/androidlearn/ui/UIFragment.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.ui;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import me.jiahuan.androidlearn.base.BaseFragment;
12 | import me.jiahuan.androidlearn.ui.recyclerview.RecyclerViewActivity;
13 | import me.jiahuan.androidlearn.ui.viewpager.ViewPagerActivity;
14 |
15 | public class UIFragment extends BaseFragment {
16 |
17 | public static final String TAG = "UIFragment";
18 |
19 | @Nullable
20 | @Override
21 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
22 | View view = inflater.inflate(R.layout.module_ui_layout_ui_fragment, container, false);
23 | initialize(view);
24 | return view;
25 | }
26 |
27 | private void initialize(View view) {
28 | view.findViewById(R.id.module_ui_layout_ui_fragment_recycler_view_button).setOnClickListener(new View.OnClickListener() {
29 | @Override
30 | public void onClick(View v) {
31 | startActivity(new Intent(getActivity(), RecyclerViewActivity.class));
32 | }
33 | });
34 |
35 | view.findViewById(R.id.module_ui_layout_ui_fragment_view_pager_button).setOnClickListener(new View.OnClickListener() {
36 | @Override
37 | public void onClick(View v) {
38 | startActivity(new Intent(getActivity(), ViewPagerActivity.class));
39 | }
40 | });
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/clint/src/main/java/me/jiahuan/androidlearn/clint/LogDetector.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.clint;
2 |
3 |
4 | import com.android.tools.lint.detector.api.Category;
5 | import com.android.tools.lint.detector.api.Detector;
6 | import com.android.tools.lint.detector.api.Implementation;
7 | import com.android.tools.lint.detector.api.Issue;
8 | import com.android.tools.lint.detector.api.JavaContext;
9 | import com.android.tools.lint.detector.api.Scope;
10 | import com.android.tools.lint.detector.api.Severity;
11 | import com.intellij.psi.JavaElementVisitor;
12 | import com.intellij.psi.PsiMethod;
13 | import com.intellij.psi.PsiMethodCallExpression;
14 |
15 | import org.jetbrains.annotations.Nullable;
16 | import org.jetbrains.uast.UCallExpression;
17 | import org.jetbrains.uast.UElement;
18 |
19 | import java.util.Arrays;
20 | import java.util.List;
21 |
22 | public class LogDetector extends Detector implements Detector.UastScanner {
23 |
24 | private static final String ISSUE_DESCRIPTION = "请勿直接调用android.util.Log,应该使用统一工具类";
25 |
26 | public static final Issue ISSUE = Issue.create(
27 | "LogUsage",
28 | ISSUE_DESCRIPTION,
29 | "...",
30 | Category.SECURITY,
31 | 6,
32 | Severity.ERROR,
33 | new Implementation(LogDetector.class, Scope.JAVA_FILE_SCOPE)
34 | );
35 |
36 | @Override
37 | public List getApplicableMethodNames() {
38 | return Arrays.asList("v", "d", "i", "w", "e");
39 | }
40 |
41 |
42 | @Override
43 | public void visitMethod(JavaContext context, UCallExpression node, PsiMethod method) {
44 | if (context.getEvaluator().isMemberInClass(method, "android.util.Log")) {
45 | context.report(ISSUE, node, context.getLocation(node), ISSUE_DESCRIPTION);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/module_function/src/main/java/me/jiahuan/androidlearn/function/hook/ProxyInstrumentation.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.function.hook;
2 |
3 | import android.app.Activity;
4 | import android.app.Instrumentation;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.os.Bundle;
8 | import android.os.IBinder;
9 | import android.util.Log;
10 |
11 | import java.lang.reflect.Method;
12 |
13 | public class ProxyInstrumentation extends Instrumentation {
14 |
15 | private static final String TAG = "ProxyInstrumentation";
16 |
17 | private Instrumentation mBase;
18 |
19 | public ProxyInstrumentation(Instrumentation base) {
20 | mBase = base;
21 | }
22 |
23 | public ActivityResult execStartActivity(
24 | Context who, IBinder contextThread, IBinder token, Activity target,
25 | Intent intent, int requestCode, Bundle options) {
26 |
27 | // Hook之前, XXX到此一游!
28 | Log.d(TAG, "\n执行了startActivity, 参数如下: \n" + "who = [" + who + "], " +
29 | "\ncontextThread = [" + contextThread + "], \ntoken = [" + token + "], " +
30 | "\ntarget = [" + target + "], \nintent = [" + intent +
31 | "], \nrequestCode = [" + requestCode + "], \noptions = [" + options + "]");
32 |
33 | try {
34 | Method execStartActivity = Instrumentation.class.getDeclaredMethod("execStartActivity", Context.class, IBinder.class, IBinder.class, Activity.class, Intent.class, int.class, Bundle.class);
35 | execStartActivity.setAccessible(true);
36 | return (ActivityResult) execStartActivity.invoke(mBase, who, contextThread, token, target, intent, requestCode, options);
37 | } catch (Exception e) {
38 | throw new RuntimeException("do not support!!! pls adapt it");
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/module_function/src/main/java/me/jiahuan/androidlearn/function/binder/BookRemoteService.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.function.binder;
2 |
3 | import android.app.Service;
4 | import android.content.Intent;
5 | import android.os.IBinder;
6 | import android.os.RemoteException;
7 | import android.support.annotation.Nullable;
8 | import android.util.Log;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | public class BookRemoteService extends Service {
14 |
15 | private static final String TAG = "BinderSample";
16 |
17 | private List mBooks = new ArrayList<>();
18 |
19 | private IBinder mBinder = new IBookManager.Stub() {
20 | @Override
21 | public List getBookList() throws RemoteException {
22 | return mBooks;
23 | }
24 |
25 | @Override
26 | public void addBook(Book book) throws RemoteException {
27 | mBooks.add(book);
28 | }
29 | };
30 |
31 | @Override
32 | public void onRebind(Intent intent) {
33 | Log.d(TAG, "onRebind");
34 | super.onRebind(intent);
35 | }
36 |
37 | @Override
38 | public void onCreate() {
39 | super.onCreate();
40 | Log.d(TAG, "onCreate");
41 | }
42 |
43 | @Nullable
44 | @Override
45 | public IBinder onBind(Intent intent) {
46 | Log.d(TAG, "onBind");
47 | return mBinder;
48 | }
49 |
50 | @Override
51 | public boolean onUnbind(Intent intent) {
52 | return super.onUnbind(intent);
53 | }
54 |
55 | @Override
56 | public void onDestroy() {
57 | super.onDestroy();
58 | Log.d(TAG, "onDestroy");
59 | }
60 |
61 | @Override
62 | public void onTaskRemoved(Intent rootIntent) {
63 | super.onTaskRemoved(rootIntent);
64 | Log.d(TAG, "onTaskRemoved");
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/module_function/src/main/cpp/native-lib.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #ifdef __cplusplus
6 | extern "C" {
7 | #endif
8 |
9 | #define LOG_TAG "NATIVE_LIB"
10 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
11 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
12 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
13 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
14 | #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG,__VA_ARGS__)
15 |
16 |
17 | jstring stringFromJNI2(JNIEnv *env, jobject obj);
18 |
19 |
20 | JNINativeMethod nativeMethods[] = {
21 | {"stringFromJNI2", "()Ljava/lang/String;", (jstring *) stringFromJNI2}
22 | };
23 |
24 | JNIEXPORT jstring
25 | Java_me_jiahuan_androidlearn_function_jni_JNIActivity_stringFromJNI(JNIEnv *env, jobject obj) {
26 | std::string hello = "Hello from C++";
27 | return env->NewStringUTF(hello.c_str());
28 | }
29 |
30 | jstring stringFromJNI2(JNIEnv *env, jobject obj) {
31 | std::string str = "动态注册";
32 | return env->NewStringUTF(str.c_str());
33 | }
34 |
35 | jint JNI_OnLoad(JavaVM *vm, void *reserved) {
36 | LOGI("JNI_OnLoad");
37 |
38 | JNIEnv *env = nullptr;
39 |
40 | jint result = vm->GetEnv((void **) &env, JNI_VERSION_1_6);
41 |
42 | if (result != JNI_OK) {
43 | LOGE("JNI GET ENV ERROR");
44 | return JNI_ERR;
45 | }
46 |
47 |
48 | jclass clazz = env->FindClass("me/jiahuan/androidlearn/function/jni/JNIActivity");
49 | if (clazz == nullptr) {
50 | LOGE("FIND JNIActivity Error");
51 | return JNI_ERR;
52 | }
53 |
54 | // 动态注册本地方法
55 | result = env->RegisterNatives(clazz, nativeMethods, sizeof(nativeMethods) / sizeof(nativeMethods[0]));
56 | if (result != JNI_OK) {
57 | LOGE("动态注册ERROR");
58 | return JNI_ERR;
59 | }
60 |
61 | return JNI_VERSION_1_6;
62 | }
63 |
64 | #ifdef __cplusplus
65 | }
66 | #endif
67 |
--------------------------------------------------------------------------------
/module_ui/src/main/java/me/jiahuan/androidlearn/ui/viewpager/TabFragment.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.ui.viewpager;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 | import android.support.v4.app.Fragment;
8 | import android.util.Log;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.webkit.WebView;
13 | import android.widget.TextView;
14 |
15 | public class TabFragment extends Fragment {
16 | private static final String TAG = "TabFragment";
17 | private static final String ARGUMENT_KET_TITLE = "ARGUMENT_KET_TITLE";
18 |
19 | private String mTitle = "";
20 |
21 | public static TabFragment newInstance(String title) {
22 | Bundle args = new Bundle();
23 | args.putString(ARGUMENT_KET_TITLE, title);
24 | TabFragment fragment = new TabFragment();
25 | fragment.setArguments(args);
26 | return fragment;
27 | }
28 |
29 | @Override
30 | public void onAttach(Context context) {
31 | super.onAttach(context);
32 | Log.d(TAG, "onAttach " + mTitle);
33 | }
34 |
35 | @Override
36 | public void onCreate(@Nullable Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | mTitle = getArguments().getString(ARGUMENT_KET_TITLE);
39 | Log.d(TAG, "onCreate " + mTitle);
40 | }
41 |
42 | @Nullable
43 | @Override
44 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
45 | Log.d(TAG, "onCreateView " + mTitle);
46 | TextView textView = new TextView(getActivity());
47 | textView.setText(mTitle);
48 | // WebView webView = new WebView(getActivity());
49 | // webView.loadUrl("http://www.baidu.com");
50 | return textView;
51 | }
52 |
53 | @Override
54 | public void setUserVisibleHint(boolean isVisibleToUser) {
55 | super.setUserVisibleHint(isVisibleToUser);
56 | Log.d(TAG, "setUserVisibleHint " + mTitle + " " + isVisibleToUser);
57 | }
58 |
59 | @Override
60 | public void onDestroyView() {
61 | super.onDestroyView();
62 | Log.d(TAG, "onDestroyView " + mTitle);
63 | }
64 |
65 | @Override
66 | public void onDestroy() {
67 | super.onDestroy();
68 | Log.d(TAG, "onDestroy " + mTitle);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/module_ui/src/main/java/me/jiahuan/androidlearn/ui/viewpager/ViewPagerActivity.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.ui.viewpager;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.support.design.widget.TabLayout;
6 | import android.support.v4.app.Fragment;
7 | import android.support.v4.app.FragmentManager;
8 | import android.support.v4.app.FragmentPagerAdapter;
9 | import android.support.v4.view.ViewPager;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | import me.jiahuan.androidlearn.base.BaseActivity;
15 | import me.jiahuan.androidlearn.ui.R;
16 |
17 | public class ViewPagerActivity extends BaseActivity {
18 |
19 | private ViewPager mViewPager;
20 | private TabLayout mTabLayout;
21 | private List mFragments = new ArrayList<>();
22 |
23 | @Override
24 | protected void onCreate(@Nullable Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | initializeActivity(R.layout.module_ui_layout_view_pager_activity);
27 | initialize();
28 | }
29 |
30 | private void initialize() {
31 | mViewPager = findViewById(R.id.module_ui_layout_view_pager_activity_view_pager);
32 | mTabLayout = findViewById(R.id.module_ui_layout_view_pager_activity_tab_layout);
33 | configData();
34 | configViewPager();
35 | configTabLayout();
36 | }
37 |
38 | private void configData() {
39 | for (int i = 0; i < 10; i++) {
40 | mFragments.add(TabFragment.newInstance(i + ""));
41 | }
42 | }
43 |
44 | private void configViewPager() {
45 | mViewPager.setAdapter(new MyPagerAdapter(getSupportFragmentManager()));
46 | mViewPager.setOffscreenPageLimit(2);
47 | }
48 |
49 | private void configTabLayout() {
50 | mTabLayout.setTabMode(TabLayout.MODE_SCROLLABLE);
51 | mTabLayout.setupWithViewPager(mViewPager);
52 | }
53 |
54 |
55 | class MyPagerAdapter extends FragmentPagerAdapter {
56 |
57 | public MyPagerAdapter(FragmentManager fm) {
58 | super(fm);
59 | }
60 |
61 | @Override
62 | public Fragment getItem(int position) {
63 | return mFragments.get(position);
64 | }
65 |
66 | @Override
67 | public int getCount() {
68 | return mFragments.size();
69 | }
70 |
71 | @Nullable
72 | @Override
73 | public CharSequence getPageTitle(int position) {
74 | return "Tab" + position;
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/me/jiahuan/androidlearn/App.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn;
2 |
3 | import android.app.Application;
4 | import android.content.pm.PackageInfo;
5 | import android.content.pm.PackageManager;
6 | import android.support.annotation.NonNull;
7 | import android.support.annotation.Nullable;
8 | import android.util.Log;
9 |
10 | import com.orhanobut.logger.AndroidLogAdapter;
11 | import com.orhanobut.logger.FormatStrategy;
12 | import com.orhanobut.logger.LogStrategy;
13 | import com.orhanobut.logger.Logger;
14 | import com.orhanobut.logger.PrettyFormatStrategy;
15 |
16 |
17 | public class App extends Application {
18 |
19 | private static final String TAG = "App";
20 |
21 | private String mAppName = null;
22 |
23 | @Override
24 | public void onCreate() {
25 | super.onCreate();
26 | Log.d("BinderSample", "application on create");
27 | // 初始化日志系统
28 | LogStrategy logStrategy = new LogStrategy() {
29 | private String[] prefix = {". ", " ."};
30 | private int index = 0;
31 |
32 | @Override
33 | public void log(int priority, @Nullable String tag, @NonNull String message) {
34 | index = index ^ 1;
35 | Log.println(priority, prefix[index] + tag, message);
36 | }
37 | };
38 | FormatStrategy logFormatStrategy = PrettyFormatStrategy.newBuilder()
39 | .logStrategy(logStrategy)
40 | .showThreadInfo(true)
41 | .methodCount(0)
42 | .methodOffset(0)
43 | .tag(getAppName())
44 | .build();
45 | Logger.addLogAdapter(new AndroidLogAdapter(logFormatStrategy) {
46 | @Override
47 | public boolean isLoggable(int priority, @Nullable String tag) {
48 | return BuildConfig.DEBUG;
49 | }
50 | });
51 | //
52 | // Router.initialize(new Configuration.Builder()
53 | // .setDebuggable(BuildConfig.DEBUG)
54 | // .registerModules("app", "module_function")
55 | // .build());
56 | }
57 |
58 | private String getAppName() {
59 | if (mAppName == null) {
60 | try {
61 | PackageManager packageManager = getPackageManager();
62 | PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(), 0);
63 | return getResources().getString(packageInfo.applicationInfo.labelRes);
64 | } catch (PackageManager.NameNotFoundException e) {
65 | e.printStackTrace();
66 | }
67 | mAppName = getResources().getResourceName(R.string.app_name);
68 | }
69 | return mAppName;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/module_function/src/main/java/me/jiahuan/androidlearn/function/binder/BinderActivity.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.function.binder;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Intent;
5 | import android.content.ServiceConnection;
6 | import android.os.Bundle;
7 | import android.os.IBinder;
8 | import android.os.RemoteException;
9 | import android.support.annotation.Nullable;
10 | import android.util.Log;
11 | import android.view.View;
12 |
13 | import java.util.List;
14 |
15 | import me.jiahuan.androidlearn.base.BaseActivity;
16 | import me.jiahuan.androidlearn.function.R;
17 |
18 | public class BinderActivity extends BaseActivity {
19 | private static final String TAG = "BinderSample";
20 |
21 | private IBookManager mBookManager;
22 |
23 | private ServiceConnection mServiceConnection = new ServiceConnection() {
24 | @Override
25 | public void onServiceConnected(ComponentName name, IBinder service) {
26 | Log.d(TAG, "onServiceConnected");
27 | mBookManager = IBookManager.Stub.asInterface(service);
28 | // service.linkToDeath();
29 | }
30 |
31 | @Override
32 | public void onServiceDisconnected(ComponentName name) {
33 | Log.d(TAG, "onServiceDisconnected");
34 | unbindService(this);
35 | mBookManager = null;
36 | }
37 | };
38 |
39 | @Override
40 | protected void onCreate(@Nullable Bundle savedInstanceState) {
41 | super.onCreate(savedInstanceState);
42 | initializeActivity(R.layout.module_function_layout_binder_activity);
43 | }
44 |
45 | public void onBindButtonClicked(View v) {
46 | Log.d(TAG, "onBindButtonClicked");
47 | Intent intent = new Intent(this, BookRemoteService.class);
48 | bindService(intent, mServiceConnection, BIND_AUTO_CREATE);
49 | }
50 |
51 |
52 | public void onGetBookListButtonClicked(View v) throws RemoteException {
53 | Log.d(TAG, "onGetBookListButtonClicked");
54 | if (mBookManager != null) {
55 | List books = mBookManager.getBookList();
56 | for (Book book : books) {
57 | Log.d(TAG, "bookId = " + book.bookId + ", bookName = " + book.bookName);
58 | }
59 | }
60 | }
61 |
62 | public void onAddBookButtonClicked(View v) throws RemoteException {
63 | Log.d(TAG, "onAddBookButtonClicked");
64 | if (mBookManager != null) {
65 | int id = (int) (Math.random() * 100);
66 | Book book = new Book(id, id + "");
67 | mBookManager.addBook(book);
68 | }
69 | }
70 |
71 | public void onUnbindButtonClicked(View v) {
72 | Log.d(TAG, "onUnbindButtonClicked");
73 | unbindService(mServiceConnection);
74 | }
75 |
76 | @Override
77 | protected void onDestroy() {
78 | super.onDestroy();
79 | // unbindService(mServiceConnection);
80 | }
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/module_function/src/main/java/me/jiahuan/androidlearn/function/FunctionFragment.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.function;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.NonNull;
6 | import android.support.annotation.Nullable;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import me.jiahuan.androidlearn.base.BaseFragment;
12 | import me.jiahuan.androidlearn.function.binder.BinderActivity;
13 | import me.jiahuan.androidlearn.function.hook.HookActivity;
14 | import me.jiahuan.androidlearn.function.jni.JNIActivity;
15 | import me.jiahuan.androidlearn.function.lru.LruCacheActivity;
16 | import me.jiahuan.androidlearn.function.permission.PermissionActivity;
17 | import me.jiahuan.androidlearn.function.rxjava2.RxJava2Activity;
18 |
19 | public class FunctionFragment extends BaseFragment {
20 | public static final String TAG = "FunctionFragment";
21 |
22 | @Override
23 | public void onCreate(@Nullable Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | }
26 |
27 |
28 | @Nullable
29 | @Override
30 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
31 | View view = inflater.inflate(R.layout.module_function_layout_function_fragment, null);
32 | initialize(view);
33 | return view;
34 | }
35 |
36 | private void initialize(View view) {
37 | view.findViewById(R.id.id_module_function_layout_fragment_lru_button).setOnClickListener(new View.OnClickListener() {
38 | @Override
39 | public void onClick(View v) {
40 | startActivity(new Intent(getActivity(), LruCacheActivity.class));
41 | }
42 | });
43 | view.findViewById(R.id.id_module_function_layout_fragment_rxjava2_button).setOnClickListener(new View.OnClickListener() {
44 | @Override
45 | public void onClick(View v) {
46 | startActivity(new Intent(getActivity(), RxJava2Activity.class));
47 | }
48 | });
49 | view.findViewById(R.id.id_module_function_layout_fragment_binder_button).setOnClickListener(new View.OnClickListener() {
50 | @Override
51 | public void onClick(View v) {
52 | startActivity(new Intent(getActivity(), BinderActivity.class));
53 | }
54 | });
55 | view.findViewById(R.id.id_module_function_layout_fragment_jni_button).setOnClickListener(new View.OnClickListener() {
56 | @Override
57 | public void onClick(View v) {
58 | startActivity(new Intent(getActivity(), JNIActivity.class));
59 | }
60 | });
61 | view.findViewById(R.id.id_module_function_layout_fragment_hook_button).setOnClickListener(new View.OnClickListener() {
62 | @Override
63 | public void onClick(View v) {
64 | startActivity(new Intent(getActivity(), HookActivity.class));
65 | }
66 | });
67 | view.findViewById(R.id.id_module_function_layout_fragment_permission_button).setOnClickListener(new View.OnClickListener() {
68 | @Override
69 | public void onClick(View v) {
70 | startActivity(new Intent(getActivity(), PermissionActivity.class));
71 | }
72 | });
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/lib_base/src/main/java/me/jiahuan/androidlearn/base/DividerItemDecoration.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.base;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Rect;
7 | import android.graphics.drawable.Drawable;
8 | import android.support.v7.widget.LinearLayoutManager;
9 | import android.support.v7.widget.RecyclerView;
10 | import android.view.View;
11 |
12 |
13 | public class DividerItemDecoration extends RecyclerView.ItemDecoration {
14 | private static final int[] ATTRS = new int[]{
15 | android.R.attr.listDivider
16 | };
17 |
18 | public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
19 |
20 | public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
21 |
22 | private Drawable mDivider;
23 |
24 | public DividerItemDecoration(Context context) {
25 | final TypedArray a = context.obtainStyledAttributes(ATTRS);
26 | mDivider = a.getDrawable(0);
27 | a.recycle();
28 | }
29 |
30 |
31 | private int getOrientation(RecyclerView parent) {
32 | LinearLayoutManager linearLayoutManager = (LinearLayoutManager) parent.getLayoutManager();
33 | return linearLayoutManager.getOrientation();
34 | }
35 |
36 | @Override
37 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
38 | if (getOrientation(parent) == VERTICAL_LIST) {
39 | drawVertical(c, parent, state);
40 | } else {
41 | drawHorizontal(c, parent, state);
42 | }
43 | }
44 |
45 | private void drawVertical(Canvas c, RecyclerView parent, RecyclerView.State state) {
46 | final int left = parent.getPaddingLeft();
47 | final int right = parent.getWidth() - parent.getPaddingRight();
48 | final int childCount = parent.getChildCount();
49 | for (int i = 0; i < childCount; i++) {
50 | final View child = parent.getChildAt(i);
51 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
52 | final int top = child.getBottom() + params.bottomMargin;
53 | final int bottom = top + mDivider.getIntrinsicHeight();
54 | mDivider.setBounds(left, top, right, bottom);
55 | mDivider.draw(c);
56 | }
57 | }
58 |
59 | private void drawHorizontal(Canvas c, RecyclerView parent, RecyclerView.State state) {
60 | final int top = parent.getPaddingTop();
61 | final int bottom = parent.getHeight() - parent.getPaddingBottom();
62 | final int childCount = parent.getChildCount();
63 | for (int i = 0; i < childCount; i++) {
64 | final View child = parent.getChildAt(i);
65 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
66 | final int left = child.getRight() + params.rightMargin;
67 | final int right = left + mDivider.getIntrinsicWidth();
68 | mDivider.setBounds(left, top, right, bottom);
69 | mDivider.draw(c);
70 | }
71 | }
72 |
73 |
74 | @Override
75 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
76 | if (getOrientation(parent) == HORIZONTAL_LIST) {
77 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
78 | } else {
79 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/app/src/main/java/me/jiahuan/androidlearn/MainActivity.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.NonNull;
5 | import android.support.annotation.Nullable;
6 | import android.support.design.widget.BottomNavigationView;
7 | import android.support.v4.app.Fragment;
8 | import android.support.v4.app.FragmentManager;
9 | import android.support.v4.app.FragmentTransaction;
10 | import android.util.Log;
11 | import android.view.MenuItem;
12 |
13 | import java.util.List;
14 |
15 | import me.jiahuan.androidlearn.base.BaseActivity;
16 | import me.jiahuan.androidlearn.function.FunctionFragment;
17 | import me.jiahuan.androidlearn.ui.UIFragment;
18 |
19 | public class MainActivity extends BaseActivity {
20 |
21 | private static final String TAG = "MainActivity";
22 |
23 | BottomNavigationView mBottomNavigationView;
24 |
25 | private FunctionFragment mFunctionFragment;
26 | private UIFragment mUIFragment;
27 |
28 | @Override
29 | protected void onCreate(@Nullable Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | Log.d(TAG, "onCreate");
32 | initializeActivity(R.layout.layout_main_activity);
33 | initialize();
34 | }
35 |
36 | private void initialize() {
37 | mBottomNavigationView = findViewById(R.id.id_layout_main_activity_bottom_navigation_view);
38 | mFunctionFragment = new FunctionFragment();
39 | mUIFragment = new UIFragment();
40 | mBottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
41 | @Override
42 | public boolean onNavigationItemSelected(@NonNull MenuItem item) {
43 | addOrShowFragment(item.getItemId());
44 | return true;
45 | }
46 | });
47 | addOrShowFragment(R.id.id_menu_main_activity_bottom_navigation_view_function);
48 | }
49 |
50 |
51 | private void hideAllFragments() {
52 | FragmentManager fragmentManager = getSupportFragmentManager();
53 | List fragments = fragmentManager.getFragments();
54 | FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
55 | for (Fragment fragment : fragments) {
56 | fragmentTransaction.hide(fragment);
57 | }
58 | fragmentTransaction.commit();
59 | }
60 |
61 | private void addOrShowFragment(int itemId) {
62 | hideAllFragments();
63 | FragmentManager fragmentManager = getSupportFragmentManager();
64 | List fragments = fragmentManager.getFragments();
65 | FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
66 | if (itemId == R.id.id_menu_main_activity_bottom_navigation_view_function) {
67 | if (fragments.contains(mFunctionFragment)) {
68 | fragmentTransaction.show(mFunctionFragment);
69 | } else {
70 | fragmentTransaction.add(R.id.id_layout_main_activity_fragment_container_view_group, mFunctionFragment, FunctionFragment.TAG);
71 | }
72 | getSupportActionBar().setTitle("功能");
73 | } else if (itemId == R.id.id_menu_main_activity_bottom_navigation_view_ui) {
74 | if (fragments.contains(mUIFragment)) {
75 | fragmentTransaction.show(mUIFragment);
76 | } else {
77 | fragmentTransaction.add(R.id.id_layout_main_activity_fragment_container_view_group, mUIFragment, UIFragment.TAG);
78 | }
79 | getSupportActionBar().setTitle("UI");
80 | }
81 | fragmentTransaction.commit();
82 | }
83 |
84 | @Override
85 | protected void onSaveInstanceState(Bundle outState) {
86 | super.onSaveInstanceState(outState);
87 | Log.d(TAG, "onSaveInstanceState");
88 | }
89 |
90 |
91 | @Override
92 | protected void onPause() {
93 | super.onPause();
94 | Log.d(TAG, "onPause");
95 | }
96 |
97 | @Override
98 | protected void onStop() {
99 | super.onStop();
100 | Log.d(TAG, "onStop");
101 | }
102 |
103 | @Override
104 | protected void onDestroy() {
105 | super.onDestroy();
106 | Log.d(TAG, "onDestroy");
107 | }
108 | }
109 |
110 |
--------------------------------------------------------------------------------
/module_function/src/main/java/me/jiahuan/androidlearn/function/rxjava2/RxJava2Activity.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.function.rxjava2;
2 |
3 | import android.os.Bundle;
4 | import android.support.annotation.Nullable;
5 | import android.util.Log;
6 | import android.view.View;
7 | import android.widget.TextView;
8 |
9 | import io.reactivex.Observable;
10 | import io.reactivex.ObservableEmitter;
11 | import io.reactivex.ObservableOnSubscribe;
12 | import io.reactivex.Observer;
13 | import io.reactivex.android.schedulers.AndroidSchedulers;
14 | import io.reactivex.disposables.Disposable;
15 | import io.reactivex.functions.Consumer;
16 | import io.reactivex.functions.Function;
17 | import io.reactivex.schedulers.Schedulers;
18 | import me.jiahuan.androidlearn.base.BaseActivity;
19 | import me.jiahuan.androidlearn.function.R;
20 |
21 | public class RxJava2Activity extends BaseActivity {
22 |
23 | private static final String TAG = "RxJava2Activity";
24 |
25 |
26 | private TextView mConsoleTextView;
27 |
28 | private Disposable mDisposable;
29 |
30 | @Override
31 | protected void onCreate(@Nullable Bundle savedInstanceState) {
32 | super.onCreate(savedInstanceState);
33 | initializeActivity(R.layout.module_function_layout_rxjava2_activity);
34 | mConsoleTextView = findViewById(R.id.id_module_function_layout_rxjava2_activity_console_text_view);
35 | rxjava();
36 | }
37 |
38 | private void rxjava() {
39 | Observable observable = Observable.create(new ObservableOnSubscribe() {
40 | @Override
41 | public void subscribe(ObservableEmitter emitter) throws Exception {
42 | Log.d(TAG, "Observable Current Thread = " + Thread.currentThread().getName() + "\n");
43 | mConsoleTextView.append("Observable Current Thread = " + Thread.currentThread().getName() + "\n");
44 |
45 | Log.d(TAG, "Observable emit 1\n");
46 | mConsoleTextView.append("Observable emit 1\n");
47 | emitter.onNext("Observable emit 1");
48 | // Thread.sleep(1000);
49 |
50 | mConsoleTextView.append("Observable emit 2\n");
51 | Log.d(TAG, "Observable emit 2\n");
52 | emitter.onNext("Observable emit 2");
53 | // Thread.sleep(1000);
54 |
55 |
56 | mConsoleTextView.append("Observable emit 3\n");
57 | Log.d(TAG, "Observable emit 3\n");
58 | emitter.onNext("Observable emit 3");
59 | // Thread.sleep(1000);
60 | }
61 | });
62 |
63 |
64 | Observer observer = new Observer() {
65 | @Override
66 | public void onSubscribe(Disposable d) {
67 | mDisposable = d;
68 | mConsoleTextView.append("observer onSubscribe\n");
69 | Log.d(TAG, "observer onSubscribe\n");
70 |
71 | Log.d(TAG, "observer Current Thread = " + Thread.currentThread().getName() + "\n");
72 | mConsoleTextView.append("observer Current Thread = " + Thread.currentThread().getName() + "\n");
73 | }
74 |
75 | @Override
76 | public void onNext(String str) {
77 | mConsoleTextView.append("observer onNext " + str + "\n");
78 | Log.d(TAG, "observer onNext " + str + "\n");
79 | }
80 |
81 | @Override
82 | public void onError(Throwable e) {
83 | mConsoleTextView.append("observer onError\n");
84 | Log.d(TAG, "observer onError\n");
85 | }
86 |
87 | @Override
88 | public void onComplete() {
89 | mConsoleTextView.append("observer onComplete\n");
90 | Log.d(TAG, "observer onComplete\n");
91 | }
92 | };
93 |
94 | mDisposable = observable
95 | // .subscribeOn(Schedulers.newThread())
96 | // .observeOn(AndroidSchedulers.mainThread())
97 | .map(new Function() {
98 |
99 | @Override
100 | public Integer apply(String s) throws Exception {
101 | return Integer.parseInt(s.substring(s.length() - 1));
102 | }
103 | })
104 | .subscribe(new Consumer() {
105 | @Override
106 | public void accept(Integer integer) throws Exception {
107 | mConsoleTextView.append("accept: " + integer + "\n");
108 | }
109 | });
110 | }
111 |
112 |
113 | public void onDisposeButtonClicked(View v) {
114 | if (mDisposable != null) {
115 | mDisposable.dispose();
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/module_function/src/main/java/me/jiahuan/androidlearn/function/permission/PermissionActivity.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.function.permission;
2 |
3 | import android.Manifest;
4 | import android.content.pm.PackageManager;
5 | import android.os.Bundle;
6 | import android.support.annotation.NonNull;
7 | import android.support.annotation.Nullable;
8 | import android.support.v4.app.ActivityCompat;
9 | import android.util.Log;
10 | import android.view.View;
11 |
12 | import java.io.File;
13 | import java.io.FileNotFoundException;
14 | import java.io.FileOutputStream;
15 | import java.io.IOException;
16 |
17 | import me.jiahuan.androidlearn.base.BaseActivity;
18 | import me.jiahuan.androidlearn.function.R;
19 |
20 | public class PermissionActivity extends BaseActivity {
21 | private static final String TAG = "PermissionActivity";
22 | private static final int REQUEST_READ_PHONE_STATE = 1000;
23 | private static final int REQUEST_READ_EXTERNAL_STORAGE = 1001;
24 | private static final int REQUEST_WRITE_EXTERNAL_STORAGE = 1002;
25 |
26 |
27 | @Override
28 | protected void onCreate(@Nullable Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | initializeActivity(R.layout.module_function_layout_permission_activity);
31 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
32 | }
33 |
34 | public void requestReadPhoneStatePermission(View v) {
35 | int hasPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE);
36 | if (hasPermission == PackageManager.PERMISSION_DENIED) {
37 | ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_READ_PHONE_STATE);
38 | } else {
39 | Log.d(TAG, "读手机状态权限已授权");
40 | }
41 | }
42 |
43 |
44 | public void requestReadExternalStoragePermission(View v) {
45 | int hasPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
46 | if (hasPermission == PackageManager.PERMISSION_DENIED) {
47 | ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_READ_EXTERNAL_STORAGE);
48 | } else {
49 | Log.d(TAG, "读外存权限已授权");
50 | }
51 | }
52 |
53 | public void requestWriteExternalStoragePermission(View v) {
54 | int hasPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
55 | if (hasPermission == PackageManager.PERMISSION_DENIED) {
56 | ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_EXTERNAL_STORAGE);
57 | } else {
58 | Log.d(TAG, "写外存权限已授权");
59 | }
60 | }
61 |
62 | @Override
63 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
64 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
65 | if (requestCode == REQUEST_READ_PHONE_STATE) {
66 | if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
67 | Log.d(TAG, "读取手机状态拒绝");
68 | } else {
69 | Log.d(TAG, "读取手机状态授权");
70 | }
71 | } else if (requestCode == REQUEST_READ_EXTERNAL_STORAGE) {
72 | if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
73 | Log.d(TAG, "读取外存拒绝");
74 | } else {
75 | Log.d(TAG, "读取外存授权");
76 |
77 | Log.d(TAG, "写外存权限" + ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE));
78 |
79 | File file = new File("/sdcard/1.txt");
80 | FileOutputStream fileOutputStream = null;
81 | try {
82 | fileOutputStream = new FileOutputStream(file, false);
83 | fileOutputStream.write(1);
84 | fileOutputStream.flush();
85 | } catch (FileNotFoundException e) {
86 | e.printStackTrace();
87 | } catch (IOException e) {
88 | e.printStackTrace();
89 | } finally {
90 | try {
91 | if (fileOutputStream != null) {
92 | fileOutputStream.close();
93 | }
94 | } catch (IOException e) {
95 | e.printStackTrace();
96 | }
97 | }
98 |
99 | }
100 | } else if(requestCode == REQUEST_WRITE_EXTERNAL_STORAGE) {
101 | if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
102 | Log.d(TAG, "写外存授权");
103 | } else {
104 | Log.d(TAG, "写外存授权");
105 | }
106 | }
107 | }
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
34 |
36 |
38 |
40 |
42 |
44 |
46 |
48 |
50 |
52 |
54 |
56 |
58 |
60 |
62 |
64 |
66 |
68 |
70 |
72 |
74 |
75 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/lib_base/src/main/java/me/jiahuan/androidlearn/base/DividerGridItemDecoration.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.base;
2 |
3 | import android.content.Context;
4 | import android.content.res.TypedArray;
5 | import android.graphics.Canvas;
6 | import android.graphics.Rect;
7 | import android.graphics.drawable.Drawable;
8 | import android.support.v7.widget.GridLayoutManager;
9 | import android.support.v7.widget.LinearLayoutManager;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.support.v7.widget.StaggeredGridLayoutManager;
12 | import android.view.View;
13 |
14 |
15 | public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {
16 |
17 | private static final int[] ATTRS = new int[]{
18 | android.R.attr.listDivider
19 | };
20 |
21 |
22 | private Drawable mDivider;
23 |
24 | public DividerGridItemDecoration(Context context) {
25 | final TypedArray a = context.obtainStyledAttributes(ATTRS);
26 | mDivider = a.getDrawable(0);
27 | a.recycle();
28 | }
29 |
30 |
31 | private int getSpanCount(RecyclerView parent) {
32 | // 列数
33 | int spanCount = -1;
34 | RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
35 | if (layoutManager instanceof GridLayoutManager) {
36 | spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
37 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
38 | spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
39 | }
40 | return spanCount;
41 | }
42 |
43 | private boolean isLastColumn(RecyclerView parent, int position, int spanCount, int childCount) {
44 | RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
45 | if (layoutManager instanceof GridLayoutManager) {
46 | if ((position + 1) % spanCount == 0) {
47 | return true;
48 | }
49 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
50 | StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
51 | if (staggeredGridLayoutManager.getOrientation() == StaggeredGridLayoutManager.VERTICAL) {
52 | if ((position + 1) % spanCount == 0) {
53 | return true;
54 | }
55 | } else if (staggeredGridLayoutManager.getOrientation() == StaggeredGridLayoutManager.HORIZONTAL) {
56 | if (position >= childCount - childCount % spanCount) {
57 | return true;
58 | }
59 | }
60 | }
61 | return false;
62 | }
63 |
64 | private boolean isLastRow(RecyclerView parent, int position, int spanCount, int childCount) {
65 | RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
66 | if (layoutManager instanceof GridLayoutManager) {
67 | if ((position + 1) % spanCount == 0) {
68 | return true;
69 | }
70 | } else if (layoutManager instanceof StaggeredGridLayoutManager) {
71 | StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
72 | if (staggeredGridLayoutManager.getOrientation() == StaggeredGridLayoutManager.VERTICAL) {
73 | if ((position + 1) % spanCount == 0) {
74 | return true;
75 | }
76 | } else if (staggeredGridLayoutManager.getOrientation() == StaggeredGridLayoutManager.HORIZONTAL) {
77 | if (position >= childCount - childCount % spanCount) {
78 | return true;
79 | }
80 | }
81 | }
82 | return false;
83 | }
84 |
85 | @Override
86 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
87 | drawVertical(c, parent, state);
88 | drawHorizontal(c, parent, state);
89 | }
90 |
91 | private void drawVertical(Canvas c, RecyclerView parent, RecyclerView.State state) {
92 | int childCount = parent.getChildCount();
93 | for (int i = 0; i < childCount; i++) {
94 | View child = parent.getChildAt(i);
95 | RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
96 | final int left = child.getRight();
97 | final int right = left + mDivider.getIntrinsicWidth();
98 | final int top = child.getTop();
99 | final int bottom = child.getBottom();
100 | mDivider.setBounds(left, top, right, bottom);
101 | mDivider.draw(c);
102 | }
103 | }
104 |
105 | private void drawHorizontal(Canvas c, RecyclerView parent, RecyclerView.State state) {
106 | int childCount = parent.getChildCount();
107 | for (int i = 0; i < childCount; i++) {
108 | View child = parent.getChildAt(i);
109 | RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
110 | final int left = child.getLeft();
111 | final int right = child.getRight();
112 | final int top = child.getBottom();
113 | final int bottom = top + mDivider.getIntrinsicHeight();
114 | mDivider.setBounds(left, top, right, bottom);
115 | mDivider.draw(c);
116 | }
117 | }
118 |
119 |
120 | @Override
121 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
122 | final int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
123 | final int spanCount = getSpanCount(parent);
124 | final int childCount = parent.getChildCount();
125 | if (isLastColumn(parent, position, spanCount, childCount)) {
126 | outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
127 | } else if (isLastRow(parent, position, spanCount, childCount)) {
128 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
129 | } else {
130 | outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight());
131 | }
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/module_ui/src/main/java/me/jiahuan/androidlearn/ui/recyclerview/RecyclerViewActivity.java:
--------------------------------------------------------------------------------
1 | package me.jiahuan.androidlearn.ui.recyclerview;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Color;
5 | import android.graphics.Paint;
6 | import android.graphics.Rect;
7 | import android.os.Bundle;
8 | import android.support.annotation.NonNull;
9 | import android.support.annotation.Nullable;
10 | import android.support.v7.widget.RecyclerView;
11 | import android.support.v7.widget.helper.ItemTouchHelper;
12 | import android.util.Log;
13 | import android.view.LayoutInflater;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 | import android.widget.TextView;
17 |
18 | import java.util.ArrayList;
19 | import java.util.Collections;
20 | import java.util.List;
21 |
22 | import me.jiahuan.androidlearn.base.BaseActivity;
23 | import me.jiahuan.androidlearn.ui.R;
24 |
25 | public class RecyclerViewActivity extends BaseActivity {
26 | private static final String TAG = "RecyclerViewActivity";
27 |
28 | private RecyclerView mRecyclerView;
29 |
30 | private List mStrings = new ArrayList<>();
31 |
32 |
33 | private static final int RECYCLE_THRESHOLD = 400;
34 |
35 | @Override
36 | protected void onCreate(@Nullable Bundle savedInstanceState) {
37 | super.onCreate(savedInstanceState);
38 | initializeActivity(R.layout.module_ui_layout_recycler_view_activity);
39 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
40 | mRecyclerView = findViewById(R.id.id_module_ui_layout_recycler_view_recycler_view);
41 | initialize();
42 | }
43 |
44 | private void initialize() {
45 | configData();
46 | configRecyclerView();
47 | }
48 |
49 | private void configData() {
50 | for (int i = 0; i < 100; i++) {
51 | mStrings.add("当前位置 " + i);
52 | }
53 | }
54 |
55 | private void configRecyclerView() {
56 | // mRecyclerView.setLayoutManager(new LinearLayoutManager(mSelfActivity));
57 | mRecyclerView.setLayoutManager(new MyLayoutManager());
58 | mRecyclerView.addItemDecoration(new MyItemDecoration());
59 | final MyAdapter adapter = new MyAdapter(mStrings);
60 | mRecyclerView.setAdapter(adapter);
61 | ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
62 | @Override
63 | public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
64 | int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
65 | int swipeFlags = ItemTouchHelper.LEFT;
66 | return makeMovementFlags(dragFlags, swipeFlags);
67 | }
68 |
69 | @Override
70 | public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
71 | adapter.itemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
72 | return true;
73 | }
74 |
75 | @Override
76 | public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
77 | adapter.itemRemove(viewHolder.getAdapterPosition());
78 | }
79 | });
80 | itemTouchHelper.attachToRecyclerView(mRecyclerView);
81 | // mRecyclerView.addItemDecoration(new DividerItemDecoration(this));
82 | // mRecyclerView.setViewCacheExtension();
83 | // mRecyclerView.setItemViewCacheSize();
84 | // mRecyclerView.getRecycledViewPool().setMaxRecycledViews();
85 | }
86 |
87 |
88 | static class MyAdapter extends RecyclerView.Adapter {
89 |
90 | private List mStrings = null;
91 |
92 | public MyAdapter(List strings) {
93 | mStrings = strings;
94 | }
95 |
96 |
97 | public void itemMove(int fromPosition, int toPosition) {
98 | Collections.swap(mStrings, fromPosition, toPosition);
99 | notifyItemMoved(fromPosition, toPosition);
100 | }
101 |
102 | public void itemRemove(int removePosition) {
103 | mStrings.remove(removePosition);
104 | notifyItemRemoved(removePosition);
105 | }
106 |
107 | @NonNull
108 | @Override
109 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
110 | // Log.d(TAG, "onCreateViewHolder");
111 | return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.module_ui_layout_recycler_view_activity_item, parent, false));
112 | }
113 |
114 | @Override
115 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
116 | // Log.d(TAG, "onBindViewHolder = " + position);
117 | ((MyViewHolder) holder).title.setText(mStrings.get(position));
118 | }
119 |
120 | @Override
121 | public int getItemCount() {
122 | return mStrings.size();
123 | }
124 |
125 | class MyViewHolder extends RecyclerView.ViewHolder {
126 |
127 | TextView title;
128 |
129 | public MyViewHolder(View itemView) {
130 | super(itemView);
131 | title = itemView.findViewById(R.id.module_ui_layout_recycler_view_activity_item_text_view);
132 | }
133 | }
134 | }
135 |
136 | static class MyLayoutManager extends RecyclerView.LayoutManager {
137 |
138 | private int mVerticalScrollOffset = 0; //
139 |
140 | private RecyclerView.Recycler mRecycler;
141 |
142 | @Override
143 | public RecyclerView.LayoutParams generateDefaultLayoutParams() {
144 | return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT);
145 | }
146 |
147 |
148 | @Override
149 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
150 | if (getItemCount() == 0) {
151 | return;
152 | }
153 | if (mRecycler == null) {
154 | mRecycler = recycler;
155 | }
156 | // 调用了两次
157 | Log.d(TAG, "onLayoutChildren");
158 | detachAndScrapAttachedViews(recycler);
159 | Log.d(TAG, "attached size = " + recycler.getScrapList().size());
160 | fill(recycler);
161 | }
162 |
163 |
164 | @Override
165 | public void onScrollStateChanged(int state) {
166 | super.onScrollStateChanged(state);
167 | if (state == RecyclerView.SCROLL_STATE_IDLE) {
168 | reFill(mRecycler);
169 | }
170 | }
171 |
172 | @Override
173 | public boolean canScrollVertically() {
174 | return true;
175 | }
176 |
177 | @Override
178 | public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
179 | if (getItemCount() == 0 || getChildCount() == 0 || dy == 0) {
180 | return 0;
181 | }
182 | int distance = dy;
183 |
184 | // 边界判断
185 | if (mVerticalScrollOffset + distance < 0) {
186 | distance = -mVerticalScrollOffset;
187 | } else {
188 | View lastChild = getChildAt(getChildCount() - 1);
189 | int lastPosition = getPosition(lastChild);
190 | int lastChildBottom = getDecoratedBottom(lastChild);
191 | if (lastPosition == getItemCount() - 1) {
192 | if (lastChildBottom - distance < getVerticalSpace()) {
193 | distance = lastChildBottom - getVerticalSpace();
194 | }
195 | }
196 | }
197 |
198 | mVerticalScrollOffset += distance;
199 |
200 | recycleViews(recycler);
201 | reFill(recycler);
202 | offsetChildrenVertical(-distance);
203 | Log.d(TAG, "child count = " + getChildCount());
204 | return distance;
205 | }
206 |
207 |
208 | private void recycleViews(RecyclerView.Recycler recycler) {
209 | int childCount = getChildCount();
210 | List recycleViews = new ArrayList<>();
211 | for (int i = 0; i < childCount; i++) {
212 | View child = getChildAt(i);
213 | int childTop = getDecoratedTop(child);
214 | int childBottom = getDecoratedBottom(child);
215 | if (childBottom <= 0 || childTop >= getVerticalSpace()) {
216 | recycleViews.add(child);
217 | }
218 | }
219 |
220 | for (View child : recycleViews) {
221 | removeAndRecycleView(child, recycler);
222 | Log.d(TAG, "removeAndRecycleView");
223 | }
224 | }
225 |
226 |
227 | private void reFill(RecyclerView.Recycler recycler) {
228 | // 取第一个
229 | View child = getChildAt(0);
230 | int currentFillItemPosition = getPosition(child) - 1;
231 | Log.d(TAG, "currentFillItemPosition = " + currentFillItemPosition);
232 | int currentFillItemBottom = getDecoratedTop(child);
233 | Log.d(TAG, "currentFillItemBottom = " + currentFillItemBottom);
234 | while (currentFillItemPosition >= 0 && currentFillItemBottom > -RECYCLE_THRESHOLD) {
235 | View view = recycler.getViewForPosition(currentFillItemPosition);
236 | addView(view, 0);
237 | measureChildWithMargins(view, 0, 0);
238 | int itemHeight = getDecoratedMeasuredHeight(view);
239 | layoutDecorated(view, 0, currentFillItemBottom - itemHeight, getHorizontalSpace(), currentFillItemBottom);
240 | currentFillItemBottom -= itemHeight;
241 | currentFillItemPosition--;
242 | }
243 |
244 | // 最后一个
245 | int itemCount = getItemCount();
246 | child = getChildAt(getChildCount() - 1);
247 | currentFillItemPosition = getPosition(child) + 1;
248 | int currentFillItemTop = getDecoratedBottom(child);
249 | while (currentFillItemPosition < itemCount && currentFillItemTop < getVerticalSpace() + RECYCLE_THRESHOLD) {
250 | View view = recycler.getViewForPosition(currentFillItemPosition);
251 | addView(view);
252 | measureChildWithMargins(view, 0, 0);
253 | int itemHeight = getDecoratedMeasuredHeight(view);
254 | layoutDecorated(view, 0, currentFillItemTop, getHorizontalSpace(), currentFillItemTop + itemHeight);
255 | currentFillItemTop += itemHeight;
256 | currentFillItemPosition++;
257 | }
258 | }
259 |
260 | private void fill(RecyclerView.Recycler recycler) {
261 | int itemCount = getItemCount();
262 | if (itemCount == 0) {
263 | return;
264 | }
265 | int currentFillItemPosition = 0;
266 | int currentFillItemTop = 0;
267 | while (currentFillItemPosition < itemCount && currentFillItemTop < getVerticalSpace() + RECYCLE_THRESHOLD) {
268 | View view = recycler.getViewForPosition(currentFillItemPosition);
269 | addView(view);
270 | measureChildWithMargins(view, 0, 0);
271 | int itemHeight = getDecoratedMeasuredHeight(view);
272 | layoutDecorated(view, 0, currentFillItemTop, getHorizontalSpace(), currentFillItemTop + itemHeight);
273 | currentFillItemTop += itemHeight;
274 | currentFillItemPosition++;
275 | }
276 | }
277 |
278 | private int getVerticalSpace() {
279 | return getHeight() - getPaddingTop() - getPaddingBottom();
280 | }
281 |
282 |
283 | private int getHorizontalSpace() {
284 | return getWidth() - getPaddingLeft() - getPaddingRight();
285 | }
286 | }
287 |
288 |
289 | class MyItemDecoration extends RecyclerView.ItemDecoration {
290 | private Paint mPaint;
291 |
292 | public MyItemDecoration() {
293 | mPaint = new Paint();
294 | mPaint.setStyle(Paint.Style.FILL);
295 | mPaint.setColor(Color.BLACK);
296 | }
297 |
298 | @Override
299 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
300 | // c.drawColor(Color.BLACK);
301 | final int left = parent.getPaddingLeft();
302 | final int right = parent.getWidth() - parent.getPaddingRight();
303 | final int childCount = parent.getChildCount();
304 | for (int i = 0; i < childCount; i++) {
305 | final View child = parent.getChildAt(i);
306 | final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
307 | final int top = child.getBottom() + params.bottomMargin;
308 | final int bottom = top + 20;
309 | c.drawRect(left, top, right, bottom, mPaint);
310 | }
311 | }
312 |
313 | @Override
314 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
315 | outRect.set(0, 0, 0, 20);
316 | }
317 | }
318 | }
319 |
--------------------------------------------------------------------------------