cachedView;
23 | public static boolean showDebugLog = true;
24 |
25 | private static void preCreateActivityLayoutCache(Context context, String baseActivityName, int layoutId) {
26 | if (layoutId == 0 || isNull(baseActivityName)) {
27 | return;
28 | }
29 | if (cachedView == null) {
30 | cachedView = new HashMap<>();
31 | }
32 | new AsyncLayoutInflater(context).inflate(layoutId, null, new AsyncLayoutInflater.OnInflateFinishedListener() {
33 | @Override
34 | public void onInflateFinished(@NonNull View view, int resId, @Nullable ViewGroup parent) {
35 | cachedView.put(baseActivityName, new ViewWrapper(view, resId));
36 | if (showDebugLog)
37 | Log.w(">>>", "AsyncActivityLayoutLoader: " + baseActivityName + " is already cached");
38 | }
39 | });
40 | }
41 |
42 | public static void preCreateActivityLayoutCache(Context context, Class baseActivityClass) {
43 | String baseActivityName = baseActivityClass.getName();
44 | Layout layout = (Layout) baseActivityClass.getAnnotation(Layout.class);
45 | if (layout != null) {
46 | if (layout.value() != -1) {
47 | preCreateActivityLayoutCache(context, baseActivityName, layout.value());
48 | }
49 | }
50 | }
51 |
52 | public static void preCreateActivityLayoutCache(Class baseActivityClass) {
53 | String baseActivityName = baseActivityClass.getName();
54 | Layout layout = (Layout) baseActivityClass.getAnnotation(Layout.class);
55 | if (layout != null) {
56 | if (layout.value() != -1) {
57 | preCreateActivityLayoutCache(new MutableContextWrapper(BaseApp.getPrivateInstance()), baseActivityName, layout.value());
58 | }
59 | }
60 | }
61 |
62 | public static View getActivityLayout(Context context, String baseActivityName) {
63 | if (cachedView == null) {
64 | return null;
65 | }
66 | ViewWrapper pkg = cachedView.get(baseActivityName);
67 | if (pkg != null && pkg.getView() != null) {
68 | View view = pkg.getView();
69 | if (view.getContext() instanceof MutableContextWrapper) {
70 | MutableContextWrapper contextWrapper = (MutableContextWrapper) view.getContext();
71 | contextWrapper.setBaseContext(context);
72 | }
73 | if (showDebugLog)
74 | Log.w(">>>", "AsyncActivityLayoutLoader: " + baseActivityName + " is used from cache");
75 | cachedView.remove(baseActivityName);
76 | preCreateActivityLayoutCache(context, baseActivityName, pkg.resId);
77 | pkg.cleanAll();
78 | return view;
79 | }
80 | return null;
81 | }
82 |
83 | public static void clearActivityLayoutCache() {
84 | cachedView.clear();
85 | cachedView = null;
86 | }
87 |
88 | static class ViewWrapper {
89 | View view;
90 | int resId;
91 |
92 | ViewWrapper(View view, int resId) {
93 | this.view = view;
94 | this.resId = resId;
95 | }
96 |
97 | View getView() {
98 | return view;
99 | }
100 |
101 | void cleanAll() {
102 | view = null;
103 | resId = 0;
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/publish-mavencentral.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'maven-publish'
2 | apply plugin: 'signing'
3 |
4 | task androidSourcesJar(type: Jar) {
5 | classifier = 'sources'
6 | from android.sourceSets.main.java.source
7 | }
8 |
9 | ext["signing.keyId"] = ''
10 | ext["signing.password"] = ''
11 | ext["signing.secretKeyRingFile"] = ''
12 | ext["ossrhUsername"] = ''
13 | ext["ossrhPassword"] = ''
14 |
15 | File secretPropsFile = project.rootProject.file('local.properties')
16 | if (secretPropsFile.exists()) {
17 | println "Found secret props file, loading props"
18 | Properties p = new Properties()
19 | p.load(new FileInputStream(secretPropsFile))
20 | p.each { name, value ->
21 | ext[name] = value
22 | }
23 | } else {
24 | println "No props file, loading env vars"
25 | }
26 | publishing {
27 | publications {
28 | release(MavenPublication) {
29 | // The coordinates of the library, being set from variables that
30 | // we'll set up in a moment
31 | groupId PUBLISH_GROUP_ID
32 | artifactId PUBLISH_ARTIFACT_ID
33 | version PUBLISH_VERSION
34 |
35 | // Two artifacts, the `aar` and the sources
36 | artifact("$buildDir/outputs/aar/${project.getName()}-release.aar")
37 | artifact androidSourcesJar
38 |
39 | // Self-explanatory metadata for the most part
40 | pom {
41 | name = PUBLISH_ARTIFACT_ID
42 | description = 'Kongzue BaseFramework'
43 | // If your project has a dedicated site, use its URL here
44 | url = 'https://github.com/kongzue/BaseFramework/'
45 | licenses {
46 | license {
47 | //协议类型,一般默认Apache License2.0的话不用改:
48 | name = 'The Apache License, Version 2.0'
49 | url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
50 | }
51 | }
52 | developers {
53 | developer {
54 | id = 'kongzue'
55 | name = 'kongzue'
56 | email = 'myzcxhh@live.cn'
57 | }
58 | }
59 | // Version control info, if you're using GitHub, follow the format as seen here
60 | scm {
61 | //修改成你的Git地址:
62 | connection = 'scm:git:github.com/kongzue/BaseFramework.git'
63 | developerConnection = 'scm:git:ssh://github.com/kongzue/BaseFramework.git'
64 | //分支地址:
65 | url = 'https://github.com/kongzue/BaseFramework/tree/master'
66 | }
67 | // A slightly hacky fix so that your POM will include any transitive dependencies
68 | // that your library builds upon
69 | withXml {
70 | def dependenciesNode = asNode().appendNode('dependencies')
71 |
72 | project.configurations.implementation.allDependencies.each {
73 | def dependencyNode = dependenciesNode.appendNode('dependency')
74 | dependencyNode.appendNode('groupId', it.group)
75 | dependencyNode.appendNode('artifactId', it.name)
76 | dependencyNode.appendNode('version', it.version)
77 | }
78 | }
79 | }
80 | }
81 | }
82 | repositories {
83 | // The repository to publish to, Sonatype/MavenCentral
84 | maven {
85 | // This is an arbitrary name, you may also use "mavencentral" or
86 | // any other name that's descriptive for you
87 | name = "BaseFramework"
88 |
89 | def releasesRepoUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
90 | def snapshotsRepoUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
91 | // You only need this if you want to publish snapshots, otherwise just set the URL
92 | // to the release repo directly
93 | url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
94 |
95 | // The username and password we've fetched earlier
96 | credentials {
97 | username ossrhUsername
98 | password ossrhPassword
99 | }
100 | }
101 | }
102 | }
103 | signing {
104 | sign publishing.publications
105 | }
--------------------------------------------------------------------------------
/baseframework/src/main/java/com/kongzue/baseframework/util/swipeback/util/SwipeBackUtil.java:
--------------------------------------------------------------------------------
1 | package com.kongzue.baseframework.util.swipeback.util;
2 |
3 | import android.app.Activity;
4 | import android.app.ActivityOptions;
5 | import android.os.Build;
6 |
7 | import java.lang.reflect.Method;
8 |
9 | /**
10 | * Created by Chaojun Wang on 6/9/14.
11 | */
12 | public class SwipeBackUtil {
13 | private SwipeBackUtil() {
14 | }
15 |
16 | /**
17 | * Convert a translucent themed Activity
18 | * {@link android.R.attr#windowIsTranslucent} to a fullscreen opaque
19 | * Activity.
20 | *
21 | * Call this whenever the background of a translucent Activity has changed
22 | * to become opaque. Doing so will allow the {@link android.view.Surface} of
23 | * the Activity behind to be released.
24 | *
25 | * This call has no effect on non-translucent activities or on activities
26 | * with the {@link android.R.attr#windowIsFloating} attribute.
27 | */
28 | public static void convertActivityFromTranslucent(Activity activity) {
29 | try {
30 | Method method = Activity.class.getDeclaredMethod("convertFromTranslucent");
31 | method.setAccessible(true);
32 | method.invoke(activity);
33 | } catch (Throwable t) {
34 | }
35 | }
36 |
37 | /**
38 | * Convert a translucent themed Activity
39 | * {@link android.R.attr#windowIsTranslucent} back from opaque to
40 | * translucent following a call to
41 | * {@link #convertActivityFromTranslucent(android.app.Activity)} .
42 | *
43 | * Calling this allows the Activity behind this one to be seen again. Once
44 | * all such Activities have been redrawn
45 | *
46 | * This call has no effect on non-translucent activities or on activities
47 | * with the {@link android.R.attr#windowIsFloating} attribute.
48 | */
49 | public static void convertActivityToTranslucent(Activity activity) {
50 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
51 | convertActivityToTranslucentAfterL(activity);
52 | } else {
53 | convertActivityToTranslucentBeforeL(activity);
54 | }
55 | }
56 |
57 | /**
58 | * Calling the convertToTranslucent method on platforms before Android 5.0
59 | */
60 | public static void convertActivityToTranslucentBeforeL(Activity activity) {
61 | try {
62 | Class>[] classes = Activity.class.getDeclaredClasses();
63 | Class> translucentConversionListenerClazz = null;
64 | for (Class clazz : classes) {
65 | if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
66 | translucentConversionListenerClazz = clazz;
67 | }
68 | }
69 | Method method = Activity.class.getDeclaredMethod(
70 | "convertToTranslucent",
71 | translucentConversionListenerClazz
72 | );
73 | method.setAccessible(true);
74 | method.invoke(activity, new Object[]{
75 | null
76 | });
77 | } catch (Throwable t) {
78 | }
79 | }
80 |
81 | /**
82 | * Calling the convertToTranslucent method on platforms after Android 5.0
83 | */
84 | private static void convertActivityToTranslucentAfterL(Activity activity) {
85 | try {
86 | Method getActivityOptions = Activity.class.getDeclaredMethod("getActivityOptions");
87 | getActivityOptions.setAccessible(true);
88 | Object options = getActivityOptions.invoke(activity);
89 |
90 | Class>[] classes = Activity.class.getDeclaredClasses();
91 | Class> translucentConversionListenerClazz = null;
92 | for (Class clazz : classes) {
93 | if (clazz.getSimpleName().contains("TranslucentConversionListener")) {
94 | translucentConversionListenerClazz = clazz;
95 | }
96 | }
97 | Method convertToTranslucent = Activity.class.getDeclaredMethod("convertToTranslucent",
98 | translucentConversionListenerClazz, ActivityOptions.class
99 | );
100 | convertToTranslucent.setAccessible(true);
101 | convertToTranslucent.invoke(activity, null, options);
102 | } catch (Throwable t) {
103 | }
104 | }
105 | }
106 |
107 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_introduction.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
12 |
21 |
22 |
26 |
27 |
33 |
34 |
40 |
41 |
48 |
49 |
57 |
58 |
65 |
66 |
74 |
75 |
82 |
83 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
107 |
108 |
--------------------------------------------------------------------------------
/app/src/main/java/com/kongzue/baseframeworkdemo/activity/DemoActivity.java:
--------------------------------------------------------------------------------
1 | package com.kongzue.baseframeworkdemo.activity;
2 |
3 | import android.view.View;
4 |
5 | import androidx.fragment.app.Fragment;
6 |
7 | import com.kongzue.baseframework.BaseActivity;
8 | import com.kongzue.baseframework.BaseFragment;
9 | import com.kongzue.baseframework.interfaces.BindView;
10 | import com.kongzue.baseframework.interfaces.DarkNavigationBarTheme;
11 | import com.kongzue.baseframework.interfaces.DarkStatusBarTheme;
12 | import com.kongzue.baseframework.interfaces.EnterAnim;
13 | import com.kongzue.baseframework.interfaces.ExitAnim;
14 | import com.kongzue.baseframework.interfaces.FragmentLayout;
15 | import com.kongzue.baseframework.interfaces.FullScreen;
16 | import com.kongzue.baseframework.interfaces.Layout;
17 | import com.kongzue.baseframework.interfaces.LayoutName;
18 | import com.kongzue.baseframework.interfaces.NavigationBarBackgroundColorRes;
19 | import com.kongzue.baseframework.interfaces.OnFragmentChangeListener;
20 | import com.kongzue.baseframework.util.FragmentChangeUtil;
21 | import com.kongzue.baseframework.util.JumpParameter;
22 | import com.kongzue.baseframeworkdemo.R;
23 | import com.kongzue.baseframeworkdemo.fragment.AboutFragment;
24 | import com.kongzue.baseframeworkdemo.fragment.FunctionFragment;
25 | import com.kongzue.baseframeworkdemo.fragment.IntroductionFragment;
26 | import com.kongzue.tabbar.Tab;
27 | import com.kongzue.tabbar.TabBarView;
28 | import com.kongzue.tabbar.interfaces.OnTabChangeListener;
29 |
30 | import java.util.ArrayList;
31 | import java.util.List;
32 |
33 | //使用 @Layout 注解直接绑定要显示的布局
34 | //@Layout(R.layout.activity_demo)
35 | //使用 @LayoutName 注解按照布局名称绑定布局
36 | @LayoutName("activity_demo")
37 | //设置不使用状态栏暗色文字图标样式
38 | @DarkStatusBarTheme(false)
39 | //设置底部导航栏背景颜色,此外还可以使用 @NavigationBarBackgroundColor 来指定 argb 颜色
40 | @NavigationBarBackgroundColorRes(R.color.colorWhite)
41 | //设置使用底部导航栏暗色图标样式
42 | @DarkNavigationBarTheme(true)
43 | //绑定子 Fragment 要显示的容器布局
44 | @FragmentLayout(R.id.viewPager)
45 | //入场动画
46 | @EnterAnim(enterAnimResId = R.anim.fade, holdAnimResId = R.anim.hold)
47 | //出场动画
48 | @ExitAnim(holdAnimResId = R.anim.hold, exitAnimResId = R.anim.back)
49 | public class DemoActivity extends BaseActivity {
50 |
51 | // public DemoActivity() {
52 | // setLayout(R.layout.activity_demo);
53 | // setFragmentLayout(R.id.viewPager);
54 | // setDarkStatusAndNavBarTheme(true);
55 | // setNavigationBarBackgroundRes(R.color.colorWhite);
56 | // setEnterAnim(R.anim.fade,R.anim.hold);
57 | // setExitAnim(R.anim.hold,R.anim.back);
58 | // }
59 |
60 | //三个子 Fragment 布局(简介界面、功能界面、Github关于界面)
61 | private IntroductionFragment introductionFragment = new IntroductionFragment();
62 | private FunctionFragment functionFragment = new FunctionFragment();
63 | private AboutFragment aboutFragment = new AboutFragment();
64 |
65 | //使用 @BindView(resId) 来初始化组件
66 | @BindView(R.id.tabbar)
67 | private TabBarView tabbar;
68 |
69 | @Override
70 | //此处用于绑定布局组件,你也可以使用 @BindView(resId) 来初始化组件
71 | public void initViews() {
72 | tabbar = findViewById(R.id.tabbar);
73 | }
74 |
75 | @Override
76 | //请在此编写初始化操作,例如读取数据等,以及对 UI 组件进行赋值
77 | public void initDatas(JumpParameter parameter) {
78 | List tabs = new ArrayList<>();
79 | tabs.add(new Tab(this, getString(R.string.introduction), R.mipmap.img_tab_introduction));
80 | tabs.add(new Tab(this, getString(R.string.function), R.mipmap.img_maintab_function));
81 | tabs.add(new Tab(this, getString(R.string.github), R.mipmap.img_maintab_me));
82 | tabbar.setTab(tabs);
83 | }
84 |
85 | @Override
86 | protected void lazyInit(JumpParameter parameter) {
87 |
88 | }
89 |
90 | private void doTestError() throws NullPointerException {
91 | throw new NullPointerException("This is a exception for test");
92 | }
93 |
94 | @Override
95 | //此处为添加子布局逻辑
96 | public void initFragment(FragmentChangeUtil fragmentChangeUtil) {
97 | fragmentChangeUtil.addFragment(introductionFragment);
98 | fragmentChangeUtil.addFragment(functionFragment);
99 | fragmentChangeUtil.addFragment(aboutFragment);
100 |
101 | //默认切换至第一个界面
102 | changeFragment(0);
103 | }
104 |
105 | @Override
106 | //此处为组件绑定功能事件、回调等方法
107 | public void setEvents() {
108 | tabbar.setOnTabChangeListener(new OnTabChangeListener() {
109 | @Override
110 | public boolean onTabChanged(View v, int index) {
111 | changeFragment(index);
112 | return false;
113 | }
114 | });
115 |
116 | getFragmentChangeUtil().setOnFragmentChangeListener(new OnFragmentChangeListener() {
117 | @Override
118 | public void onChange(int index, BaseFragment fragment) {
119 | tabbar.setNormalFocusIndex(index);
120 | }
121 | });
122 | }
123 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/kongzue/baseframeworkdemo/App.java:
--------------------------------------------------------------------------------
1 | package com.kongzue.baseframeworkdemo;
2 |
3 | import android.content.DialogInterface;
4 | import android.widget.Toast;
5 |
6 | import androidx.appcompat.app.AlertDialog;
7 |
8 | import com.kongzue.baseframework.BaseApp;
9 | import com.kongzue.baseframework.BaseFrameworkSettings;
10 | import com.kongzue.baseframework.interfaces.OnBugReportListener;
11 | import com.kongzue.baseframework.interfaces.OnSDKInitializedCallBack;
12 | import com.kongzue.baseframework.util.AppManager;
13 | import com.kongzue.baseframework.util.AsyncActivityLayoutLoader;
14 | import com.kongzue.baseframework.util.SettingsUtil;
15 | import com.kongzue.baseframeworkdemo.activity.AdapterTestActivity;
16 | import com.kongzue.baseframeworkdemo.activity.DemoActivity;
17 | import com.kongzue.baseframeworkdemo.activity.JumpActivity;
18 | import com.kongzue.baseframeworkdemo.activity.ResponseActivity;
19 | import com.kongzue.baseframeworkdemo.activity.TransitionActivity;
20 | import com.kongzue.baseframeworkdemo.fragment.AboutFragment;
21 | import com.kongzue.baseframeworkdemo.fragment.FunctionFragment;
22 | import com.kongzue.baseframeworkdemo.fragment.IntroductionFragment;
23 | import com.kongzue.baseframeworkdemo.util.User;
24 |
25 | import java.io.File;
26 |
27 | /**
28 | * Author: @Kongzue
29 | * Github: https://github.com/kongzue/
30 | * Homepage: http://kongzue.com/
31 | * Mail: myzcxhh@live.cn
32 | * CreateTime: 2018/9/30 04:12
33 | */
34 | public class App extends BaseApp {
35 |
36 | @Override
37 | public void init() {
38 | // AsyncActivityLayoutLoader.preCreateActivityLayoutCache(AdapterTestActivity.class);
39 | // AsyncActivityLayoutLoader.preCreateActivityLayoutCache(DemoActivity.class);
40 | // AsyncActivityLayoutLoader.preCreateActivityLayoutCache(JumpActivity.class);
41 | // AsyncActivityLayoutLoader.preCreateActivityLayoutCache(ResponseActivity.class);
42 | // AsyncActivityLayoutLoader.preCreateActivityLayoutCache(TransitionActivity.class);
43 | // AsyncActivityLayoutLoader.preCreateActivityLayoutCache(AboutFragment.class);
44 | // AsyncActivityLayoutLoader.preCreateActivityLayoutCache(FunctionFragment.class);
45 | // AsyncActivityLayoutLoader.preCreateActivityLayoutCache(IntroductionFragment.class);
46 |
47 | // try {
48 | // Thread.sleep(2000);
49 | // } catch (InterruptedException e) {
50 | // throw new RuntimeException(e);
51 | // }
52 |
53 | setOnSDKInitializedCallBack(new OnSDKInitializedCallBack() {
54 | @Override
55 | public void onInitialized() {
56 | log("onInitialized: ");
57 | Toast.makeText(me, "SDK已加载完毕", Toast.LENGTH_LONG).show();
58 | }
59 | });
60 |
61 | setOnCrashListener(new OnBugReportListener() {
62 | @Override
63 | public boolean onCrash(Exception e, final File crashLogFile) {
64 | if (AppManager.getInstance().getActiveActivity() == null || !AppManager.getInstance().getActiveActivity().isActive) {
65 | return false;
66 | }
67 | AlertDialog.Builder builder = new AlertDialog.Builder(AppManager.getInstance().getActiveActivity());
68 | builder.setTitle("Ops!发生了一次崩溃!");
69 | builder.setMessage("您是否愿意帮助我们改进程序以修复此Bug?");
70 | builder.setPositiveButton("愿意", new DialogInterface.OnClickListener() {
71 | @Override
72 | public void onClick(DialogInterface dialog, int which) {
73 | toast("请对file进行处理:" + crashLogFile.getAbsolutePath());
74 | }
75 | });
76 | builder.setNegativeButton("不了", new DialogInterface.OnClickListener() {
77 | @Override
78 | public void onClick(DialogInterface dialog, int which) {
79 |
80 | }
81 | });
82 | builder.setCancelable(false);
83 | AlertDialog dialog = builder.create();
84 | dialog.show();
85 |
86 | return false;
87 | }
88 | });
89 |
90 | // Bitmap bm = null; //随便写的 Demo
91 | // App.cache.set("key","value");
92 | // App.cache.set("bitmap",bm);
93 | // App.cache.clean();
94 |
95 | User user = new User("张三", 18, "192.168.1.1");
96 | App.user.set("userInfo", user);
97 | }
98 |
99 | public static USER user = new USER();
100 |
101 | public static class USER extends SettingsUtil {
102 |
103 | public USER() {
104 | super("user");
105 | }
106 | }
107 |
108 | public static CACHE cache;
109 |
110 | public static class CACHE extends SettingsUtil {
111 |
112 | public CACHE() {
113 | super("cache");
114 | }
115 | }
116 |
117 | @Override
118 | public void initSDKs() {
119 | BaseFrameworkSettings.DEBUGMODE = true;
120 | BaseFrameworkSettings.BETA_PLAN = true;
121 | try {
122 | Thread.sleep(8000);
123 | } catch (Exception e) {
124 | }
125 | }
126 | }
--------------------------------------------------------------------------------
/baseframework/src/main/java/com/kongzue/baseframework/util/JumpParameter.java:
--------------------------------------------------------------------------------
1 | package com.kongzue.baseframework.util;
2 |
3 | import android.util.Log;
4 |
5 | import com.kongzue.baseframework.BaseFrameworkSettings;
6 |
7 | import org.json.JSONObject;
8 |
9 | import java.util.HashMap;
10 | import java.util.Iterator;
11 | import java.util.Map;
12 |
13 | /**
14 | * @Version: 6.7.0
15 | * @Author: Kongzue
16 | * @github: https://github.com/kongzue/BaseFramework
17 | * @link: http://kongzue.com/
18 | */
19 |
20 | public class JumpParameter {
21 |
22 | private Map dataMap;
23 |
24 | public JumpParameter(Map dataMap) {
25 | this.dataMap = dataMap;
26 | }
27 |
28 | public JumpParameter() {
29 | }
30 |
31 | public JumpParameter(String jsonStr) {
32 | try {
33 | JSONObject jsonObject = new JSONObject(jsonStr);
34 | Iterator keys = jsonObject.keys();
35 | while (keys.hasNext()) {
36 | String key = keys.next() + "";
37 | String value = jsonObject.optString(key);
38 | put(key, value);
39 | }
40 | } catch (Exception e) {
41 | if (BaseFrameworkSettings.DEBUGMODE) {
42 | Log.e(">>>", "JumpParameter.create: Error json: " + jsonStr);
43 | }
44 | }
45 | }
46 |
47 | public JumpParameter put(String key, Object value) {
48 | if (dataMap == null) {
49 | dataMap = new HashMap<>();
50 | }
51 | dataMap.put(key, value);
52 | return this;
53 | }
54 |
55 | public JumpParameter set(String key, Object value) {
56 | if (dataMap == null) {
57 | dataMap = new HashMap<>();
58 | }
59 | dataMap.put(key, value);
60 | return this;
61 | }
62 |
63 | public JumpParameter cleanAll() {
64 | dataMap = new HashMap<>();
65 | return this;
66 | }
67 |
68 | public T get(String key) {
69 | if (dataMap == null) {
70 | return null;
71 | }
72 | return (T) dataMap.get(key);
73 | }
74 |
75 | public boolean getBoolean(String key) {
76 | if (dataMap == null || dataMap.get(key) == null) {
77 | return false;
78 | }
79 | return (boolean) dataMap.get(key);
80 | }
81 |
82 | public boolean getBoolean(String key, boolean defaultValue) {
83 | if (dataMap == null || dataMap.get(key) == null) {
84 | return defaultValue;
85 | }
86 | return (boolean) dataMap.get(key);
87 | }
88 |
89 | public int getInt(String key) {
90 | if (dataMap == null || dataMap.get(key) == null) {
91 | return 0;
92 | }
93 | return (int) dataMap.get(key);
94 | }
95 |
96 | public int getInt(String key, int defaultValue) {
97 | if (dataMap == null || dataMap.get(key) == null) {
98 | return defaultValue;
99 | }
100 | return (int) dataMap.get(key);
101 | }
102 |
103 | public String getString(String key) {
104 | if (dataMap == null || dataMap.get(key) == null) {
105 | return "";
106 | }
107 | return (String) dataMap.get(key);
108 | }
109 |
110 | public String getString(String key, String defaultValue) {
111 | if (dataMap == null || dataMap.get(key) == null) {
112 | return defaultValue;
113 | }
114 | return (String) dataMap.get(key);
115 | }
116 |
117 | public double getDouble(String key) {
118 | if (dataMap == null || dataMap.get(key) == null) {
119 | return 0;
120 | }
121 | return (double) dataMap.get(key);
122 | }
123 |
124 | public double getDouble(String key, double defaultValue) {
125 | if (dataMap == null || dataMap.get(key) == null) {
126 | return defaultValue;
127 | }
128 | return (double) dataMap.get(key);
129 | }
130 |
131 | public long getLong(String key) {
132 | if (dataMap == null || dataMap.get(key) == null) {
133 | return 0;
134 | }
135 | return (long) dataMap.get(key);
136 | }
137 |
138 | public long getLong(String key, long defaultValue) {
139 | if (dataMap == null || dataMap.get(key) == null) {
140 | return defaultValue;
141 | }
142 | return (long) dataMap.get(key);
143 | }
144 |
145 | public short getShort(String key) {
146 | if (dataMap == null || dataMap.get(key) == null) {
147 | return 0;
148 | }
149 | return (short) dataMap.get(key);
150 | }
151 |
152 | public short getShort(String key, short defaultValue) {
153 | if (dataMap == null || dataMap.get(key) == null) {
154 | return defaultValue;
155 | }
156 | return (short) dataMap.get(key);
157 | }
158 |
159 | public float getFloat(String key) {
160 | if (dataMap == null || dataMap.get(key) == null) {
161 | return 0;
162 | }
163 | return (float) dataMap.get(key);
164 | }
165 |
166 | public float getFloat(String key, float defaultValue) {
167 | if (dataMap == null || dataMap.get(key) == null) {
168 | return defaultValue;
169 | }
170 | return (float) dataMap.get(key);
171 | }
172 |
173 | public Map getAll() {
174 | return dataMap;
175 | }
176 |
177 | public String toJsonString() {
178 | return new JSONObject(dataMap).toString();
179 | }
180 | }
--------------------------------------------------------------------------------
/baseframework/src/main/java/com/kongzue/baseframework/util/toast/CompatToast.java:
--------------------------------------------------------------------------------
1 | package com.kongzue.baseframework.util.toast;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.res.Resources;
6 | import android.graphics.drawable.ColorDrawable;
7 | import android.util.Log;
8 | import android.view.Gravity;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.PopupWindow;
13 | import android.widget.TextView;
14 | import android.widget.Toast;
15 |
16 | import com.kongzue.baseframework.R;
17 |
18 | import java.util.Timer;
19 | import java.util.TimerTask;
20 |
21 | import static com.kongzue.baseframework.util.toast.Toaster.DURATION;
22 |
23 | public class CompatToast extends BaseToast {
24 |
25 | private Context context;
26 | private View contentView;
27 | private PopupWindow popupWindow;
28 | private Timer timer;
29 |
30 | private int animation = android.R.style.Animation_Toast;
31 | private int gravity = Gravity.BOTTOM | Gravity.CENTER;
32 |
33 | private int xOffset;
34 | private int yOffset = dip2px(80);
35 |
36 | public CompatToast(Context context) {
37 | this.context = context;
38 | }
39 |
40 | @Override
41 | public BaseToast show(String msg) {
42 | Toaster.cancel();
43 | popupWindow = new PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
44 |
45 | LayoutInflater inflate = (LayoutInflater)
46 | context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
47 | View v = inflate.inflate(R.layout.layout_system_toast, null);
48 | TextView tv = v.findViewById(R.id.message);
49 | tv.setText(msg);
50 |
51 | popupWindow.setContentView(v);
52 | popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));
53 | popupWindow.setOutsideTouchable(false);
54 | popupWindow.setClippingEnabled(false);
55 | popupWindow.setFocusable(false);
56 |
57 | popupWindow.setAnimationStyle(animation);
58 |
59 | popupWindow.showAtLocation(((Activity) context).getWindow().getDecorView(), Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, xOffset, yOffset);
60 |
61 | timer = new Timer();
62 | timer.schedule(new TimerTask() {
63 | @Override
64 | public void run() {
65 | ((Activity) context).runOnUiThread(new Runnable() {
66 | @Override
67 | public void run() {
68 | Toaster.cancel();
69 | }
70 | });
71 | }
72 | }, DURATION == Toast.LENGTH_SHORT ? 2000 : 3500);
73 |
74 | Toaster.nowToast = this;
75 | return this;
76 | }
77 |
78 | @Override
79 | public BaseToast show(int layoutResId) {
80 | Toaster.cancel();
81 | popupWindow = new PopupWindow(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
82 |
83 | LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
84 | this.contentView = layoutInflater.inflate(layoutResId, null);
85 |
86 | popupWindow.setContentView(contentView);
87 | popupWindow.setBackgroundDrawable(new ColorDrawable(0x00000000));
88 | popupWindow.setOutsideTouchable(false);
89 | popupWindow.setClippingEnabled(false);
90 | popupWindow.setFocusable(false);
91 |
92 | popupWindow.setAnimationStyle(animation);
93 |
94 | popupWindow.showAtLocation(((Activity) context).getWindow().getDecorView(), Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, xOffset, yOffset);
95 |
96 | timer = new Timer();
97 | timer.schedule(new TimerTask() {
98 | @Override
99 | public void run() {
100 | ((Activity) context).runOnUiThread(new Runnable() {
101 | @Override
102 | public void run() {
103 | Toaster.cancel();
104 | }
105 | });
106 | }
107 | }, DURATION == Toast.LENGTH_SHORT ? 2000 : 3500);
108 |
109 | Toaster.nowToast = this;
110 | return this;
111 | }
112 |
113 | @Override
114 | public BaseToast cancel() {
115 | Log.i(".>>", "cancel: ");
116 | if (popupWindow != null) {
117 | popupWindow.dismiss();
118 | }
119 | return this;
120 | }
121 |
122 | public int dip2px(float dpValue) {
123 | return (int) (0.5f + dpValue * Resources.getSystem().getDisplayMetrics().density);
124 | }
125 |
126 | public int getAnimation() {
127 | return animation;
128 | }
129 |
130 | public BaseToast setAnimation(int animation) {
131 | this.animation = animation;
132 | return this;
133 | }
134 |
135 | public int getGravity() {
136 | return gravity;
137 | }
138 |
139 | public BaseToast setGravity(int gravity) {
140 | this.gravity = gravity;
141 | return this;
142 | }
143 |
144 | public int getxOffset() {
145 | return xOffset;
146 | }
147 |
148 | public BaseToast setxOffset(int xOffset) {
149 | this.xOffset = xOffset;
150 | return this;
151 | }
152 |
153 | public int getyOffset() {
154 | return yOffset;
155 | }
156 |
157 | public BaseToast setyOffset(int yOffset) {
158 | this.yOffset = yOffset;
159 | return this;
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_function.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
17 |
18 |
22 |
23 |
29 |
30 |
36 |
37 |
42 |
43 |
48 |
49 |
55 |
56 |
61 |
62 |
67 |
68 |
72 |
73 |
77 |
78 |
83 |
84 |
89 |
90 |
95 |
96 |
97 |
98 |
103 |
104 |
109 |
110 |
115 |
116 |
121 |
122 |
123 |
128 |
129 |
135 |
136 |
137 |
138 |
139 |
--------------------------------------------------------------------------------
/baseframework/src/main/java/com/kongzue/baseframework/util/Permission.java:
--------------------------------------------------------------------------------
1 | package com.kongzue.baseframework.util;
2 |
3 | import android.Manifest;
4 |
5 | import com.kongzue.baseframework.BaseActivity;
6 |
7 | import java.lang.reflect.ParameterizedType;
8 | import java.lang.reflect.Type;
9 | import java.util.ArrayList;
10 | import java.util.Arrays;
11 | import java.util.List;
12 |
13 | /**
14 | * @author: Kongzue
15 | * @github: https://github.com/kongzue/
16 | * @homepage: http://kongzue.com/
17 | * @mail: myzcxhh@live.cn
18 | * @createTime: 2022/11/2 2:13
19 | */
20 | public class Permission {
21 |
22 | public static Permission build() {
23 | return new Permission();
24 | }
25 |
26 | private List permissions = new ArrayList<>();
27 |
28 | public void get() {
29 | BaseActivity activity = AppManager.getInstance().getActiveActivity();
30 | if (activity != null) {
31 | activity.requestPermission(permissions.toArray(new String[permissions.size()]), null);
32 | }
33 | }
34 |
35 | public void get(OnPermissionResponseListener onPermissionResponseListener) {
36 | if (onPermissionResponseListener instanceof OnActivityPermissionCallBack) {
37 | try {
38 | Class> parameterizedTypeReferenceSubclass = onPermissionResponseListener.getClass();
39 | Type type = parameterizedTypeReferenceSubclass.getGenericSuperclass();
40 | ParameterizedType parameterizedType = (ParameterizedType) type;
41 | Class typeClass = (Class>) parameterizedType.getActualTypeArguments()[0];
42 | BaseActivity activity = AppManager.getInstance().getActivityInstance(typeClass);
43 | if (activity != null) {
44 | activity.requestPermission(permissions.toArray(new String[permissions.size()]), onPermissionResponseListener);
45 | return;
46 | }
47 | } catch (Exception e) {
48 | }
49 | }
50 | BaseActivity activity = AppManager.getInstance().getActiveActivity();
51 | if (activity != null) {
52 | activity.requestPermission(permissions.toArray(new String[permissions.size()]), onPermissionResponseListener);
53 | }
54 |
55 | }
56 |
57 | public Permission CALENDAR() {
58 | permissions.add(Manifest.permission.READ_CALENDAR);
59 | permissions.add(Manifest.permission.WRITE_CALENDAR);
60 | return this;
61 | }
62 |
63 | public Permission EXTERNAL_STORAGE() {
64 | permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
65 | permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
66 | return this;
67 | }
68 |
69 | public Permission STORAGE() {
70 | permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
71 | permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
72 | return this;
73 | }
74 |
75 | public Permission MEDIA() {
76 | permissions.add(Manifest.permission.READ_MEDIA_IMAGES);
77 | permissions.add(Manifest.permission.READ_MEDIA_VIDEO);
78 | return this;
79 | }
80 |
81 | public Permission CAMERA() {
82 | permissions.add(Manifest.permission.CAMERA);
83 | return this;
84 | }
85 |
86 | public Permission CONTACTS() {
87 | permissions.add(Manifest.permission.READ_CONTACTS);
88 | permissions.add(Manifest.permission.WRITE_CONTACTS);
89 | permissions.add(Manifest.permission.GET_ACCOUNTS);
90 | return this;
91 | }
92 |
93 | public Permission LOCATION() {
94 | permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
95 | permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
96 | return this;
97 | }
98 |
99 | public Permission MICROPHONE() {
100 | permissions.add(Manifest.permission.RECORD_AUDIO);
101 | return this;
102 | }
103 |
104 | public Permission PHONE_STATE() {
105 | permissions.add(Manifest.permission.READ_PHONE_STATE);
106 | return this;
107 | }
108 |
109 | public Permission CALL() {
110 | permissions.add(Manifest.permission.CALL_PHONE);
111 | return this;
112 | }
113 |
114 | public Permission CALL_LOG() {
115 | permissions.add(Manifest.permission.READ_CALL_LOG);
116 | permissions.add(Manifest.permission.WRITE_CALL_LOG);
117 | return this;
118 | }
119 |
120 | public Permission VOICEMAIL() {
121 | permissions.add(Manifest.permission.ADD_VOICEMAIL);
122 | return this;
123 | }
124 |
125 | public Permission SIP() {
126 | permissions.add(Manifest.permission.USE_SIP);
127 | return this;
128 | }
129 |
130 | public Permission OUTGOING_CALLS() {
131 | permissions.add(Manifest.permission.PROCESS_OUTGOING_CALLS);
132 | return this;
133 | }
134 |
135 | public Permission SENSORS() {
136 | permissions.add(Manifest.permission.BODY_SENSORS);
137 | return this;
138 | }
139 |
140 | public Permission SMS() {
141 | permissions.add(Manifest.permission.SEND_SMS);
142 | return this;
143 | }
144 |
145 | public Permission SMS_RECEIVE() {
146 | permissions.add(Manifest.permission.RECEIVE_SMS);
147 | return this;
148 | }
149 |
150 | public Permission RECEIVE_SMS() {
151 | permissions.add(Manifest.permission.RECEIVE_SMS);
152 | return this;
153 | }
154 |
155 | public Permission SMS_READ() {
156 | permissions.add(Manifest.permission.READ_SMS);
157 | return this;
158 | }
159 |
160 | public Permission READ_SMS() {
161 | permissions.add(Manifest.permission.READ_SMS);
162 | return this;
163 | }
164 |
165 | public Permission RECEIVE_WAP_PUSH() {
166 | permissions.add(Manifest.permission.RECEIVE_WAP_PUSH);
167 | return this;
168 | }
169 |
170 | public Permission RECEIVE_MMS() {
171 | permissions.add(Manifest.permission.RECEIVE_MMS);
172 | return this;
173 | }
174 |
175 | public Permission add(String... p) {
176 | permissions.addAll(Arrays.asList(p));
177 | return this;
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/baseframework/src/main/java/com/kongzue/baseframework/view/TableLayout.java:
--------------------------------------------------------------------------------
1 | package com.kongzue.baseframework.view;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.content.res.TypedArray;
6 | import android.graphics.Canvas;
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 |
11 | import com.kongzue.baseframework.R;
12 |
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | /**
17 | * TableLayout 2.0
18 | * Author: @Kongzue
19 | * Github: https://github.com/kongzue/
20 | * Homepage: http://kongzue.com/
21 | * Mail: myzcxhh@live.cn
22 | * CreateTime: 2019/4/24 15:51
23 | */
24 | public class TableLayout extends ViewGroup {
25 |
26 | private int maxColumn = 2;
27 | private int itemMargin = 0;
28 | private int setChildHeight = dp2px(150);
29 |
30 | private Context context;
31 |
32 | public TableLayout(Context context) {
33 | super(context);
34 | this.context = context;
35 | loadAttrs(context, null);
36 | }
37 |
38 | public TableLayout(Context context, AttributeSet attrs) {
39 | super(context, attrs);
40 | this.context = context;
41 |
42 | loadAttrs(context, attrs);
43 | }
44 |
45 | public TableLayout(Context context, AttributeSet attrs, int defStyleAttr) {
46 | super(context, attrs, defStyleAttr);
47 | this.context = context;
48 |
49 | loadAttrs(context, attrs);
50 | }
51 |
52 | private void loadAttrs(Context context, AttributeSet attrs) {
53 | TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TableLayout);
54 |
55 | itemMargin = typedArray.getDimensionPixelOffset(R.styleable.TableLayout_marginDp, 0);
56 | setChildHeight = typedArray.getDimensionPixelOffset(R.styleable.TableLayout_itemHeight, dp2px(150));
57 | maxColumn = typedArray.getInteger(R.styleable.TableLayout_column, 2);
58 |
59 | typedArray.recycle();
60 | }
61 |
62 | private List items;
63 | private int newHeight = 0;
64 |
65 | private int[] childTop, childLeft, childRight, childBottom;
66 |
67 | @Override
68 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
69 | int maxWidth = resolveSize(Integer.MAX_VALUE, widthMeasureSpec) + itemMargin;
70 | int itemWidth = maxWidth / maxColumn - itemMargin;
71 | int itemHeight = resolveSize(setChildHeight, heightMeasureSpec);
72 |
73 | childTop = new int[getChildCount()];
74 | childLeft = new int[getChildCount()];
75 | childRight = new int[getChildCount()];
76 | childBottom = new int[getChildCount()];
77 |
78 | int l = 0, t = 0, r = 0, b = 0;
79 |
80 | items = new ArrayList<>();
81 | for (int i = 0; i < getChildCount(); i++) {
82 | View child = getChildAt(i);
83 | if (child.getVisibility() == VISIBLE) {
84 | items.add(getChildAt(i));
85 | }
86 | }
87 |
88 | //调用每个子view的onMeasure测量子view
89 | for (int i = 0; i < items.size(); i++) {
90 | View child = items.get(i);
91 | //LayoutParams lp = child.getLayoutParams();
92 |
93 | int childWidthSpec = MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY);
94 | int childHeightSpec = MeasureSpec.makeMeasureSpec(itemHeight, MeasureSpec.EXACTLY);
95 |
96 | if (i != 0 && i % maxColumn == 0) {
97 | l = 0;
98 | t = t + itemHeight + itemMargin;
99 | }
100 | r = l + itemWidth;
101 | b = t + itemHeight;
102 |
103 | childLeft[i] = l;
104 | childTop[i] = t;
105 | childRight[i] = r;
106 | childBottom[i] = b;
107 |
108 | l = l + itemWidth + itemMargin;
109 | newHeight = t + itemHeight;
110 |
111 | child.measure(childWidthSpec, childHeightSpec);
112 | }
113 |
114 | int mWidth = resolveSize(itemWidth, widthMeasureSpec);
115 | int mHeight = resolveSize(itemHeight, heightMeasureSpec);
116 |
117 | //setMeasuredDimension(mWidth, mHeight);
118 |
119 | //refreshViews(widthMeasureSpec, heightMeasureSpec);
120 |
121 | setMeasuredDimension(mWidth, newHeight);//设置宽高
122 | }
123 |
124 | @Override
125 | protected void onLayout(boolean changed, int l, int t, int r, int b) {
126 | if (items != null) {
127 | for (int i = 0; i < items.size(); i++) {
128 | View child = items.get(i);
129 | child.layout(childLeft[i], childTop[i], childRight[i], childBottom[i]);
130 | }
131 | }
132 | }
133 |
134 | @Override
135 | public void addView(View child) {
136 | super.addView(child);
137 | }
138 |
139 | @Override
140 | public void addView(View child, int index) {
141 | super.addView(child, index);
142 | }
143 |
144 | @Override
145 | public void addView(View child, int width, int height) {
146 | super.addView(child, width, height);
147 | }
148 |
149 | @Override
150 | public void addView(View child, LayoutParams params) {
151 | super.addView(child, params);
152 | }
153 |
154 | @Override
155 | public void addView(View child, int index, LayoutParams params) {
156 | super.addView(child, index, params);
157 | }
158 |
159 | @Override
160 | protected void onDraw(Canvas canvas) {
161 | super.onDraw(canvas);
162 | }
163 |
164 | private int dp2px(float dpValue) {
165 | return (int) (0.5f + dpValue * Resources.getSystem().getDisplayMetrics().density);
166 | }
167 |
168 | public int getMaxColumn() {
169 | return maxColumn;
170 | }
171 |
172 | public TableLayout setMaxColumn(int maxColumn) {
173 | this.maxColumn = maxColumn;
174 | return this;
175 | }
176 |
177 | public int getItemMargin() {
178 | return itemMargin;
179 | }
180 |
181 | public TableLayout setItemMargin(int itemMargin) {
182 | this.itemMargin = itemMargin;
183 | return this;
184 | }
185 |
186 | public int getItemHeight() {
187 | return setChildHeight;
188 | }
189 |
190 | public TableLayout setItemHeight(int itemHeight) {
191 | this.setChildHeight = itemHeight;
192 | return this;
193 | }
194 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_response.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
18 |
19 |
20 |
21 |
25 |
26 |
31 |
32 |
33 |
34 |
40 |
41 |
51 |
52 |
53 |
60 |
61 |
68 |
69 |
74 |
75 |
80 |
81 |
87 |
88 |
91 |
92 |
103 |
104 |
105 |
106 |
112 |
113 |
119 |
120 |
124 |
125 |
136 |
137 |
138 |
139 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_adapter_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
26 |
27 |
32 |
33 |
34 |
35 |
46 |
47 |
48 |
51 |
52 |
56 |
57 |
61 |
62 |
68 |
69 |
75 |
76 |
77 |
78 |
82 |
83 |
89 |
90 |
96 |
97 |
98 |
99 |
107 |
108 |
111 |
112 |
124 |
125 |
126 |
127 |
136 |
137 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_jump.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
18 |
19 |
20 |
21 |
25 |
26 |
31 |
32 |
33 |
34 |
40 |
41 |
51 |
52 |
53 |
57 |
58 |
63 |
64 |
72 |
73 |
80 |
81 |
85 |
86 |
93 |
94 |
97 |
98 |
109 |
110 |
111 |
112 |
119 |
120 |
123 |
124 |
136 |
137 |
138 |
143 |
144 |
145 |
146 |
147 |
148 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
--------------------------------------------------------------------------------
/baseframework/src/main/java/com/kongzue/baseframework/BaseFrameworkSettings.java:
--------------------------------------------------------------------------------
1 | package com.kongzue.baseframework;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.os.Looper;
6 | import android.util.Log;
7 |
8 | import com.kongzue.baseframework.interfaces.OnBugReportListener;
9 | import com.kongzue.baseframework.util.DebugLogG;
10 | import com.kongzue.baseframework.util.JsonFormat;
11 | import com.kongzue.baseframework.util.Preferences;
12 |
13 | import java.io.File;
14 | import java.util.Locale;
15 | import java.util.UUID;
16 |
17 | /**
18 | * Author: @Kongzue
19 | * Github: https://github.com/kongzue/
20 | * Homepage: http://kongzue.com/
21 | * Mail: myzcxhh@live.cn
22 | * CreateTime: 2018/9/30 03:22
23 | */
24 | public class BaseFrameworkSettings {
25 |
26 | private static OnBugReportListener onBugReportListener;
27 |
28 | //是否开启debug模式,此开关影响打印Log日志等行为
29 | public static boolean DEBUGMODE = true;
30 |
31 | //Debug模式详细版,会打印日志位置
32 | public static boolean DEBUG_DETAILS = true;
33 |
34 | //是否开启beta计划,详情请参阅 https://github.com/kongzue/BaseFramework
35 | public static boolean BETA_PLAN = false;
36 |
37 | //语言设置
38 | public static Locale selectLocale;
39 |
40 | private static boolean running = true;
41 |
42 | //隐私权限设置
43 | public static boolean PRIVACY_ALLOWED = true;
44 |
45 | //设置开启崩溃监听
46 | public static void turnOnReadErrorInfoPermissions(Context context, OnBugReportListener listener) {
47 | onBugReportListener = listener;
48 | final String reporterFile = Preferences.getInstance().getString(context, "cache", "bugReporterFile");
49 | if (reporterFile != null && !reporterFile.isEmpty()) {
50 | onBugReportListener.onReporter(new File(reporterFile));
51 | Preferences.getInstance().commit(context, "cache", "bugReporterFile", "");
52 | }
53 |
54 | new Handler(Looper.getMainLooper()).post(new Runnable() {
55 | @Override
56 | public void run() {
57 | while (running) {
58 | try {
59 | Looper.loop();
60 | } catch (Throwable e) {
61 | DebugLogG.catchException(e);
62 | if (onBugReportListener != null) {
63 | onBugReportListener.onReporter(new File(reporterFile));
64 | if (onBugReportListener.onCrash(new Exception(e), new File(reporterFile))) {
65 | exitApp();
66 | }
67 | }
68 | }
69 | }
70 | }
71 | });
72 |
73 | Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
74 | @Override
75 | public void uncaughtException(Thread t, final Throwable e) {
76 | new Thread() {
77 | @Override
78 | public void run() {
79 | DebugLogG.catchException(e);
80 |
81 | if (onBugReportListener != null) {
82 | Looper.prepare();
83 | onBugReportListener.onReporter(new File(reporterFile));
84 | if (onBugReportListener.onCrash(new Exception(e), new File(reporterFile))) {
85 | exitApp();
86 | }
87 | Looper.loop();
88 | }
89 | try {
90 | Thread.sleep(3000);
91 | } catch (InterruptedException ae) {
92 | ae.printStackTrace();
93 | }
94 | super.run();
95 | }
96 | }.start();
97 | }
98 | });
99 | }
100 |
101 | public static boolean setNavigationBarHeightZero = false;
102 |
103 | public static void log(Object s) {
104 | if (DEBUGMODE) {
105 | String logStr = String.valueOf(s);
106 | if (logStr.length() > 2048) {
107 | bigLog(logStr);
108 | } else {
109 | if (!JsonFormat.formatJson(logStr)) {
110 | Log.v(">>>>>>", logStr);
111 | }
112 | }
113 | }
114 | }
115 |
116 | public static void bigLog(String msg) {
117 | Log.i(">>>bigLog", "BIGLOG.start=================================");
118 | if (isNull(msg)) {
119 | return;
120 | }
121 | int strLength = msg.length();
122 | int start = 0;
123 | int end = 2000;
124 | for (int i = 0; i < 100; i++) {
125 | //剩下的文本还是大于规定长度则继续重复截取并输出
126 | if (strLength > end) {
127 | Log.v(">>>", msg.substring(start, end));
128 | start = end;
129 | end = end + 2000;
130 | } else {
131 | Log.v(">>>", msg.substring(start, strLength));
132 | break;
133 | }
134 | }
135 | Log.i(">>>bigLog", "BIGLOG.end=================================");
136 | }
137 |
138 | private static boolean isNull(String s) {
139 | if (s == null || s.trim().isEmpty() || "null".equals(s) || "(null)".equals(s)) {
140 | return true;
141 | }
142 | return false;
143 | }
144 |
145 | public static void exitApp() {
146 | android.os.Process.killProcess(android.os.Process.myPid());
147 | }
148 |
149 | private static String androidId;
150 |
151 | public static void setAndroidId(String androidId) {
152 | BaseFrameworkSettings.androidId = androidId;
153 | }
154 |
155 | public static String getAndroidId() {
156 | if (PRIVACY_ALLOWED) {
157 | if (!isNull(androidId)) {
158 | return androidId;
159 | }
160 | try {
161 | androidId = BaseApp.Settings.getString("device", "androidId",
162 | getSystemAndroidId()
163 | );
164 | } catch (Exception e) {
165 | return createDeviceId();
166 | }
167 | if (!isNull(androidId)) {
168 | BaseApp.Settings("device").set("androidId", androidId);
169 | return androidId;
170 | } else {
171 | return createDeviceId();
172 | }
173 | } else {
174 | if (!isNull(androidId)) {
175 | return androidId;
176 | }
177 | return createDeviceId();
178 | }
179 | }
180 |
181 | private static String getSystemAndroidId() {
182 | return android.provider.Settings.Secure.getString(BaseApp.getPrivateInstance().getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
183 | }
184 |
185 | private static String createDeviceId() {
186 | String id = BaseApp.Settings("device").getString("id");
187 | if (isNull(id)) {
188 | id = UUID.randomUUID().toString();
189 | BaseApp.Settings("device").set("id", id);
190 | }
191 | return id;
192 | }
193 |
194 | //全局 Activity 默认入场动画
195 | public static int defaultActivityEnterInAnimRes = 0;
196 | public static int defaultActivityEnterOutAnimRes = 0;
197 |
198 | //全局 Activity 默认退出动画
199 | public static int defaultActivityExitInAnimRes = 0;
200 | public static int defaultActivityExitOutAnimRes = 0;
201 |
202 | //使用DataBinding
203 | @Deprecated
204 | public static boolean useDataBinding = false;
205 |
206 | //使用overrideActivityTransition而不是overridePendingTransition,警告,该 API 在某些情况下不生效,原因不明
207 | public static boolean supportOverrideActivityTransition = false;
208 | }
--------------------------------------------------------------------------------
/baseframework/src/main/java/com/kongzue/baseframework/util/AsyncLayoutInflater.java:
--------------------------------------------------------------------------------
1 | package com.kongzue.baseframework.util;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.os.Message;
6 | import android.util.AttributeSet;
7 | import android.util.Log;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 |
12 | import androidx.annotation.LayoutRes;
13 | import androidx.annotation.NonNull;
14 | import androidx.annotation.Nullable;
15 | import androidx.annotation.UiThread;
16 | import androidx.appcompat.app.AppCompatActivity;
17 | import androidx.appcompat.app.AppCompatDelegate;
18 | import androidx.core.util.Pools;
19 | import androidx.core.view.LayoutInflaterCompat;
20 |
21 | import java.util.concurrent.BlockingQueue;
22 | import java.util.concurrent.LinkedBlockingQueue;
23 | import java.util.concurrent.ThreadFactory;
24 | import java.util.concurrent.ThreadPoolExecutor;
25 | import java.util.concurrent.TimeUnit;
26 | import java.util.concurrent.atomic.AtomicInteger;
27 |
28 | public class AsyncLayoutInflater {
29 |
30 | private static final String TAG = "AsyncLayoutInflater";
31 |
32 | private Pools.SynchronizedPool mRequestPool = new Pools.SynchronizedPool<>(10);
33 |
34 | LayoutInflater mInflater;
35 | Handler mHandler;
36 | Dispather mDispatcher;
37 |
38 |
39 | public AsyncLayoutInflater(@NonNull Context context) {
40 | mInflater = new BasicInflater(context);
41 | mHandler = new Handler(mHandlerCallback);
42 | mDispatcher = new Dispather();
43 | }
44 |
45 | @UiThread
46 | public void inflate(@LayoutRes int resid, @Nullable ViewGroup parent,
47 | @NonNull OnInflateFinishedListener callback) {
48 | if (callback == null) {
49 | throw new NullPointerException("callback argument may not be null!");
50 | }
51 | InflateRequest request = obtainRequest();
52 | request.inflater = this;
53 | request.resid = resid;
54 | request.parent = parent;
55 | request.callback = callback;
56 | mDispatcher.enqueue(request);
57 | }
58 |
59 | private Handler.Callback mHandlerCallback = new Handler.Callback() {
60 | @Override
61 | public boolean handleMessage(Message msg) {
62 | InflateRequest request = (InflateRequest) msg.obj;
63 | if (request.view == null) {
64 | request.view = mInflater.inflate(
65 | request.resid, request.parent, false);
66 | }
67 | request.callback.onInflateFinished(
68 | request.view, request.resid, request.parent);
69 | releaseRequest(request);
70 | return true;
71 | }
72 | };
73 |
74 | public interface OnInflateFinishedListener {
75 | void onInflateFinished(@NonNull View view, @LayoutRes int resid,
76 | @Nullable ViewGroup parent);
77 | }
78 |
79 | private static class InflateRequest {
80 | AsyncLayoutInflater inflater;
81 | ViewGroup parent;
82 | int resid;
83 | View view;
84 | OnInflateFinishedListener callback;
85 |
86 | InflateRequest() {
87 | }
88 | }
89 |
90 |
91 | private static class Dispather {
92 |
93 | //获得当前CPU的核心数
94 | private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
95 | //设置线程池的核心线程数2-4之间,但是取决于CPU核数
96 | private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
97 | //设置线程池的最大线程数为 CPU核数 * 2 + 1
98 | private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
99 | //设置线程池空闲线程存活时间30s
100 | private static final int KEEP_ALIVE_SECONDS = 30;
101 |
102 | private static final ThreadFactory sThreadFactory = new ThreadFactory() {
103 | private final AtomicInteger mCount = new AtomicInteger(1);
104 |
105 | public Thread newThread(Runnable r) {
106 | return new Thread(r, "AsyncLayoutInflate" + mCount.getAndIncrement());
107 | }
108 | };
109 |
110 | //LinkedBlockingQueue 默认构造器,队列容量是Integer.MAX_VALUE
111 | private static final BlockingQueue sPoolWorkQueue =
112 | new LinkedBlockingQueue();
113 |
114 | public static final ThreadPoolExecutor THREAD_POOL_EXECUTOR;
115 |
116 | static {
117 | Log.i(TAG, "static initializer: " + " CPU_COUNT = " + CPU_COUNT + " CORE_POOL_SIZE = " + CORE_POOL_SIZE + " MAXIMUM_POOL_SIZE = " + MAXIMUM_POOL_SIZE);
118 | ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
119 | CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
120 | sPoolWorkQueue, sThreadFactory);
121 | threadPoolExecutor.allowCoreThreadTimeOut(true);
122 | THREAD_POOL_EXECUTOR = threadPoolExecutor;
123 | }
124 |
125 | public void enqueue(InflateRequest request) {
126 | THREAD_POOL_EXECUTOR.execute((new InflateRunnable(request)));
127 |
128 | }
129 |
130 | }
131 |
132 | private static class BasicInflater extends LayoutInflater {
133 | private static final String[] sClassPrefixList = {
134 | "android.widget.",
135 | "android.webkit.",
136 | "android.app."
137 | };
138 |
139 | BasicInflater(Context context) {
140 | super(context);
141 | if (context instanceof AppCompatActivity) {
142 | AppCompatDelegate appCompatDelegate = ((AppCompatActivity) context).getDelegate();
143 | if (appCompatDelegate instanceof LayoutInflater.Factory2) {
144 | LayoutInflaterCompat.setFactory2(this, (LayoutInflater.Factory2) appCompatDelegate);
145 | }
146 | }
147 | }
148 |
149 | @Override
150 | public LayoutInflater cloneInContext(Context newContext) {
151 | return new BasicInflater(newContext);
152 | }
153 |
154 | @Override
155 | protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
156 | for (String prefix : sClassPrefixList) {
157 | try {
158 | View view = createView(name, prefix, attrs);
159 | if (view != null) {
160 | return view;
161 | }
162 | } catch (ClassNotFoundException e) {
163 | // In this case we want to let the base class take a crack
164 | // at it.
165 | }
166 | }
167 |
168 | return super.onCreateView(name, attrs);
169 | }
170 | }
171 |
172 |
173 | private static class InflateRunnable implements Runnable {
174 | private InflateRequest request;
175 | private boolean isRunning;
176 |
177 | public InflateRunnable(InflateRequest request) {
178 | this.request = request;
179 | }
180 |
181 | @Override
182 | public void run() {
183 | isRunning = true;
184 | try {
185 | request.view = request.inflater.mInflater.inflate(
186 | request.resid, request.parent, false);
187 | } catch (RuntimeException ex) {
188 | // Probably a Looper failure, retry on the UI thread
189 | Log.w(TAG, "Failed to inflate resource in the background! Retrying on the UI"
190 | + " thread", ex);
191 | }
192 | Message.obtain(request.inflater.mHandler, 0, request)
193 | .sendToTarget();
194 | }
195 |
196 | public boolean isRunning() {
197 | return isRunning;
198 | }
199 | }
200 |
201 |
202 | public InflateRequest obtainRequest() {
203 | InflateRequest obj = mRequestPool.acquire();
204 | if (obj == null) {
205 | obj = new InflateRequest();
206 | }
207 | return obj;
208 | }
209 |
210 | public void releaseRequest(InflateRequest obj) {
211 | obj.callback = null;
212 | obj.inflater = null;
213 | obj.parent = null;
214 | obj.resid = 0;
215 | obj.view = null;
216 | mRequestPool.release(obj);
217 | }
218 |
219 |
220 | public void cancel() {
221 | mHandler.removeCallbacksAndMessages(null);
222 | mHandlerCallback = null;
223 | }
224 | }
225 |
--------------------------------------------------------------------------------