├── .gitignore
├── LICENSE
├── README.md
├── README_cn.md
├── blockframework
├── build.gradle
├── consumer-rules.pro
├── gradle.properties
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── bytedance
│ └── blockframework
│ ├── contract
│ ├── AbstractBlock.kt
│ ├── AbstractBlockManager.kt
│ ├── AbstractLifecycleBlock.kt
│ ├── AbstractViewBlock.kt
│ ├── BaseBlockLifeCycleAdapter.kt
│ └── IBlockLifeCycleAdapter.kt
│ ├── framework
│ ├── async
│ │ ├── AsyncBaseBlock.kt
│ │ ├── AsyncUIBlock.kt
│ │ └── IAsyncBlock.kt
│ ├── base
│ │ ├── BaseBlock.kt
│ │ ├── BlockBuilder.kt
│ │ ├── IUIBlock.kt
│ │ ├── NoBindBlock.kt
│ │ └── UIBlock.kt
│ ├── config
│ │ ├── BlockInit.kt
│ │ └── IBlockInitConfig.kt
│ ├── core
│ │ ├── BlockCoreManager.kt
│ │ ├── BlockGenerator.kt
│ │ ├── BlockLifeCycleDispatcher.kt
│ │ ├── BlockUnitHandler.kt
│ │ ├── IBlockModel.kt
│ │ └── message
│ │ │ ├── BlockContractManager.kt
│ │ │ └── TreeBlockMessageCenter.kt
│ ├── event
│ │ └── AllBlockViewCreatedEvent.kt
│ ├── join
│ │ ├── BlockContextImpl.kt
│ │ ├── IBlockAbility.kt
│ │ ├── IBlockDepend.kt
│ │ ├── IBlockJoin.kt
│ │ └── IBlockScene.kt
│ ├── monitor
│ │ ├── BlockLogger.kt
│ │ └── BlockMonitor.kt
│ ├── performance
│ │ ├── HandlerProcessor.kt
│ │ └── ThreadProcessor.kt
│ ├── task
│ │ ├── BlockLayoutInflater.kt
│ │ ├── BlockViewBuildTask.kt
│ │ ├── ITaskManager.kt
│ │ ├── ScheduleTask.kt
│ │ ├── Task.kt
│ │ └── TaskManager.kt
│ └── utils
│ │ ├── BlockDsl.kt
│ │ ├── BlockExt.kt
│ │ └── LifecycleUtil.kt
│ ├── interaction
│ ├── BaseBlockMessageCenter.kt
│ ├── CoreTreeLayerBlock.kt
│ ├── EventManager.kt
│ ├── IBlockMessageCenter.kt
│ ├── State.kt
│ ├── StateAndEventModel.kt
│ ├── TreeConstrainBlockMessageCenter.kt
│ └── TreeConstrainEventManager.kt
│ └── utils
│ └── Logger.kt
├── build.gradle
├── demo
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── bytedance
│ │ └── demo
│ │ ├── BlockScene.kt
│ │ ├── DemoActivity.kt
│ │ ├── DemoAdapter.kt
│ │ ├── DemoHolder.kt
│ │ ├── block
│ │ ├── BottomInfoBlock.kt
│ │ ├── DemoCardRootBlock.kt
│ │ ├── MainContentBlock.kt
│ │ └── RightInteractBlock.kt
│ │ ├── data
│ │ ├── DemoCardData.kt
│ │ └── DemoModel.kt
│ │ ├── depend
│ │ └── IHolderBlockDepend.kt
│ │ ├── event
│ │ └── ChangFontThemeEvent.kt
│ │ ├── service
│ │ └── IMainContentBlockService.kt
│ │ └── util
│ │ ├── DemoTestUtil.kt
│ │ └── FontType.kt
│ └── res
│ ├── drawable
│ ├── avatar_img1.xml
│ ├── avatar_img2.xml
│ ├── avatar_img3.xml
│ ├── avatar_img4.xml
│ ├── avatar_img5.xml
│ ├── avatar_img6.xml
│ ├── ic_collect_icon.xml
│ ├── ic_comment_icon.xml
│ ├── ic_digg_icon.xml
│ ├── ic_launcher.xml
│ └── ic_more_icon.xml
│ ├── layout
│ ├── demo_activity_layout.xml
│ ├── demo_bottom_info_block_layout.xml
│ ├── demo_card_holder_layout.xml
│ ├── demo_main_content_block_layout.xml
│ └── demo_right_interact_block_layout.xml
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── misc
├── jingxuan.png
├── ott.png
└── xigua.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
17 | # Eclipse
18 | .classpath
19 | .project
20 | .settings
21 | eclipsebin
22 |
23 | # IntelliJ IDEA
24 | .idea
25 | *.ipl
26 | *.iws
27 | classes/
28 | idea-classes/
29 | coverage-error.log
30 |
31 | # Android
32 | gen
33 | bin
34 | project.properties
35 | out
36 | captures
37 |
38 | lint-results.xml
39 |
40 | /blockframework/build
41 | /demo/build
42 | /blockframework/lint-results.xml
43 |
44 |
--------------------------------------------------------------------------------
/blockframework/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'kotlin-android'
4 | id 'kotlin-android-extensions'
5 | id 'maven-publish'
6 | }
7 |
8 | android {
9 | compileSdkVersion 30
10 | defaultConfig {
11 | minSdkVersion 24
12 | targetSdkVersion 30
13 | }
14 |
15 | buildTypes {
16 |
17 | }
18 |
19 | lintOptions {
20 | // Turns off checks for the issue IDs you specify.
21 | disable 'GradleCompatible', 'RequiredSize'// 暂时禁用RequiredSize,有bug https://issuetracker.google.com/issues/37138580
22 |
23 | // Turns on checks for the issue IDs you specify. These checks are in
24 | // addition to the default lint checks.
25 | // enable 'RtlHardcoded','RtlCompat', 'RtlEnabled'
26 |
27 | // To enable checks for only a subset of issue IDs and ignore all others,
28 | // list the issue IDs with the 'check' property instead. This property overrides
29 | // any issue IDs you enable or disable using the properties above.
30 | // check 'NewApi', 'InlinedApi'
31 |
32 | // If set to true, turns off analysis progress reporting by lint.
33 | quiet true
34 |
35 | // if set to true (default), stops the build if errors are found.
36 | abortOnError false
37 |
38 | // if true, only report errors.
39 | ignoreWarnings true
40 |
41 | // no check
42 | checkReleaseBuilds false
43 |
44 | // if true, don't include source code lines in the error output
45 | noLines false
46 |
47 | // if true, show all locations for an error, do not truncate lists, etc.
48 | showAll true
49 |
50 | // if true, generate a text report of issues (false by default)
51 | textReport true
52 |
53 | // location to write the output; can be a file or 'stdout'
54 | textOutput 'stdout'
55 |
56 | // if true, generate an HTML report for use by for example Jenkins
57 | // htmlReport true
58 | // file to write report to (if not specified, defaults to lint-results.html)
59 | // htmlOutput file("lint-results.html")
60 |
61 | xmlReport true
62 | xmlOutput file("lint-results.xml")
63 | }
64 | }
65 |
66 | dependencies {
67 |
68 | implementation LIFECYCLE_EXTENSIONS
69 | implementation LIFECYCLE_COMMON
70 | }
71 |
72 | afterEvaluate {
73 | publishing {
74 | publications {
75 | release(MavenPublication) {
76 | from components.release
77 | groupId 'com.github.bytedance'
78 | artifactId 'block-framework'
79 | version = '1.0.0'
80 | }
81 | }
82 | }
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/blockframework/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytedance/BlockFramework/d37e26ec8d28e95084ff5b7fb625d1a465fc43dd/blockframework/consumer-rules.pro
--------------------------------------------------------------------------------
/blockframework/gradle.properties:
--------------------------------------------------------------------------------
1 |
2 | android.useAndroidX=true
3 | android.enableJetifier=true
--------------------------------------------------------------------------------
/blockframework/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
--------------------------------------------------------------------------------
/blockframework/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/contract/AbstractBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.contract
17 |
18 | import android.content.Context
19 | import com.bytedance.blockframework.framework.monitor.BlockLogger
20 | import com.bytedance.blockframework.interaction.Event
21 | import com.bytedance.blockframework.interaction.IBlockMessageCenter
22 | import com.bytedance.blockframework.interaction.IObserver
23 | import com.bytedance.blockframework.interaction.StateAndEventModel
24 |
25 | /**
26 | * @Author Wei Zijie
27 | * @Date 2020/12/8
28 | * @Description
29 | */
30 | abstract class AbstractBlock: StateAndEventModel(), IObserver {
31 |
32 | private val TAG = this.javaClass.simpleName
33 | private val DEBUG = BlockLogger.debug()
34 |
35 | open lateinit var context: Context
36 |
37 | abstract fun defineBlockService(): Class<*>?
38 |
39 | abstract fun isActive(): Boolean
40 |
41 | fun performInstall(_context: Context, messageCenter: IBlockMessageCenter) {
42 | context = _context
43 | this.blockBlockMessageCenter = messageCenter
44 | defineBlockService()?.let {
45 | this.blockBlockMessageCenter.registerService(it, BlockImplWrapper(this))
46 | }
47 | }
48 |
49 | override fun onPrepared() {
50 | if (DEBUG) {
51 | BlockLogger.log(TAG, "onActive")
52 | }
53 | }
54 |
55 | fun performUnRegister() {
56 | clearState()
57 | clearEvent()
58 | clearService()
59 | onUnRegister()
60 | }
61 |
62 | override fun onEvent(event: Event): Boolean {
63 | return false
64 | }
65 |
66 | open fun getBlockService(klass: Class, activeIfNeed: Boolean = true): T? {
67 | return blockBlockMessageCenter.queryService(this, klass, activeIfNeed)
68 | }
69 |
70 | private fun clearState() {
71 | providers.forEach {
72 | blockBlockMessageCenter.unregisterStateProvider(it)
73 | }
74 | providers.clear()
75 | }
76 |
77 | private fun clearEvent() {
78 | observers.forEach {
79 | blockBlockMessageCenter.unregisterObserver(it)
80 | }
81 | observers.clear()
82 | }
83 |
84 | private fun clearService() {
85 | blockBlockMessageCenter.blockServiceMap.remove(defineBlockService())
86 | }
87 |
88 | override fun onUnRegister() {
89 | if (DEBUG) {
90 | BlockLogger.log(TAG, "onInactive")
91 | }
92 | }
93 | }
94 |
95 | class BlockImplWrapper {
96 | @Volatile
97 | var impl: Any
98 |
99 | internal constructor(impl: Any) {
100 | this.impl = impl
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/contract/AbstractBlockManager.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.contract
17 |
18 | import android.content.Context
19 | import com.bytedance.blockframework.interaction.IBlockMessageCenter
20 | import com.bytedance.blockframework.interaction.StateAndEventModel
21 |
22 | /**
23 | * @Author Wei Zijie
24 | * @Date 2020/12/28
25 | * @Description
26 | */
27 | abstract class AbstractBlockManager(var context: Context, override var blockBlockMessageCenter: IBlockMessageCenter) : StateAndEventModel() {
28 |
29 | var blockList: MutableList = mutableListOf()
30 |
31 | abstract fun onRegisterBlock(block: AbstractBlock)
32 | abstract fun onUnregisterBlock(block: AbstractBlock)
33 |
34 | override fun onPrepared() {}
35 | override fun onUnRegister() {}
36 |
37 | fun registerBlock(block: AbstractBlock) {
38 | if (blockList.contains(block)) {
39 | return
40 | }
41 | blockList.add(block)
42 | block.performInstall(context, blockBlockMessageCenter)
43 | onRegisterBlock(block)
44 | block.onPrepared()
45 | }
46 |
47 | open fun unregisterAllBlock() {
48 | val mIterator = blockList.iterator()
49 | while (mIterator.hasNext()) {
50 | val next = mIterator.next()
51 | next.performUnRegister()
52 | onUnregisterBlock(next)
53 | mIterator.remove()
54 | }
55 | }
56 |
57 | fun unregisterBlock(block: AbstractBlock) {
58 | blockList.remove(block)
59 | block.performUnRegister()
60 | onUnregisterBlock(block)
61 | }
62 |
63 | fun getBlockService(klass: Class): T? {
64 | return blockBlockMessageCenter.queryService(klass)
65 | }
66 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/contract/AbstractLifecycleBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.contract
17 |
18 | import androidx.lifecycle.Lifecycle
19 | import androidx.lifecycle.LifecycleOwner
20 | import androidx.lifecycle.LifecycleRegistry
21 | import com.bytedance.blockframework.framework.monitor.BlockLogger
22 |
23 | /**
24 | * @Author Wei Zijie
25 | * @Date 2020/12/8
26 | * @Description
27 | */
28 | abstract class AbstractLifecycleBlock() : AbstractBlock(), LifecycleOwner {
29 |
30 | private val TAG = this.javaClass.simpleName
31 | private val DEBUG = BlockLogger.debug()
32 |
33 | private val mLifecycleRegistry = LifecycleRegistry(this)
34 |
35 | override fun getLifecycle(): Lifecycle {
36 | return mLifecycleRegistry
37 | }
38 |
39 | //
40 | fun performCreate() {
41 | onCreate()
42 | mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE)
43 | }
44 |
45 | open fun onCreate() {
46 | if (DEBUG) {
47 | BlockLogger.log(TAG, "onCreate")
48 | }
49 | }
50 | //
51 |
52 | //
53 | fun performStart() {
54 | onStart()
55 | mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
56 | }
57 |
58 | open fun onStart() {
59 | if (DEBUG) {
60 | BlockLogger.log(TAG, "onStart")
61 | }
62 | }
63 | //
64 |
65 | //
66 | fun performResume() {
67 | onResume()
68 | mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
69 | }
70 |
71 | open fun onResume() {
72 | if (DEBUG) {
73 | BlockLogger.log(TAG, "onResume")
74 | }
75 | }
76 | //
77 |
78 | //
79 | fun performPause() {
80 | mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
81 | onPause()
82 | }
83 |
84 | open fun onPause() {
85 | if (DEBUG) {
86 | BlockLogger.log(TAG, "onPause")
87 | }
88 | }
89 | //
90 |
91 | //
92 | fun performStop() {
93 | mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
94 | onStop()
95 | }
96 |
97 | open fun onStop() {
98 | if (DEBUG) {
99 | BlockLogger.log(TAG, "onStop")
100 | }
101 | }
102 | //
103 |
104 | //
105 | fun performDestroy() {
106 | mLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
107 | onDestroy()
108 | }
109 |
110 | open fun onDestroy() {
111 | if (DEBUG) {
112 | BlockLogger.log(TAG, "onDestroy")
113 | }
114 | }
115 | //
116 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/contract/AbstractViewBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.contract
17 |
18 | import android.view.View
19 | import androidx.annotation.IdRes
20 | import com.bytedance.blockframework.interaction.BaseBlockMessageCenter
21 |
22 | /**
23 | * @Author Wei Zijie
24 | * @Date 2020/12/28
25 | * @Description
26 | */
27 | abstract class AbstractViewBlock(private val mContentView: T) : AbstractBlock() {
28 |
29 | protected val contentView: T
30 | get() = mContentView
31 |
32 | protected fun findViewById(@IdRes id: Int): T {
33 | return mContentView.findViewById(id)
34 | }
35 |
36 | abstract fun getView(): View
37 |
38 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/contract/BaseBlockLifeCycleAdapter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.contract
17 |
18 | import androidx.lifecycle.Lifecycle
19 | import androidx.lifecycle.LifecycleObserver
20 | import androidx.lifecycle.OnLifecycleEvent
21 |
22 | /**
23 | * @Author Wei Zijie
24 | * @Date 2021/1/24
25 | * @Description
26 | */
27 | open class BaseBlockLifeCycleAdapter : IBlockLifeCycleAdapter, LifecycleObserver {
28 |
29 | override var blockList: MutableList = mutableListOf()
30 |
31 | @OnLifecycleEvent(value = Lifecycle.Event.ON_CREATE)
32 | override fun onCreate() {
33 | blockList.forEach {
34 | if (it.isActive()) {
35 | it.performCreate()
36 | }
37 | }
38 | }
39 |
40 | @OnLifecycleEvent(value = Lifecycle.Event.ON_START)
41 | override fun onStart() {
42 | blockList.forEach {
43 | if (it.isActive()) {
44 | it.performStart()
45 | }
46 | }
47 | }
48 |
49 | @OnLifecycleEvent(value = Lifecycle.Event.ON_RESUME)
50 | override fun onResume() {
51 | blockList.forEach {
52 | if (it.isActive()) {
53 | it.performResume()
54 | }
55 | }
56 | }
57 |
58 | @OnLifecycleEvent(value = Lifecycle.Event.ON_PAUSE)
59 | override fun onPause() {
60 | blockList.forEach {
61 | if (it.isActive()) {
62 | it.performPause()
63 | }
64 | }
65 | }
66 |
67 | @OnLifecycleEvent(value = Lifecycle.Event.ON_STOP)
68 | override fun onStop() {
69 | blockList.forEach {
70 | if (it.isActive()) {
71 | it.performStop()
72 | }
73 | }
74 | }
75 |
76 | @OnLifecycleEvent(value = Lifecycle.Event.ON_DESTROY)
77 | override fun onDestroy() {
78 | blockList.forEach {
79 | if (it.isActive()) {
80 | it.performDestroy()
81 | }
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/contract/IBlockLifeCycleAdapter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.contract
17 |
18 | import androidx.lifecycle.LifecycleObserver
19 |
20 | /**
21 | * @Author Wei Zijie
22 | * @Date 2020/12/8
23 | * @Description
24 | */
25 | interface IBlockLifeCycleAdapter : LifecycleObserver {
26 |
27 | var blockList: MutableList
28 |
29 | fun addLifecycleObserve(block: B) {
30 | blockList.add(block)
31 | }
32 |
33 | fun removeLifecycleObserve(block: B) {
34 | blockList.remove(block)
35 | }
36 |
37 | fun onCreate() {
38 |
39 | }
40 |
41 | fun onStart() {
42 |
43 | }
44 |
45 | fun onResume() {
46 |
47 | }
48 |
49 | fun onPause() {
50 |
51 | }
52 |
53 | fun onStop() {
54 |
55 | }
56 |
57 | fun onDestroy() {
58 |
59 | }
60 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/async/AsyncBaseBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.async
17 |
18 | import com.bytedance.blockframework.framework.base.BaseBlock
19 | import com.bytedance.blockframework.framework.config.BlockInit
20 | import com.bytedance.blockframework.framework.core.IBlockModel
21 | import com.bytedance.blockframework.framework.join.IBlockContext
22 | import com.bytedance.blockframework.framework.monitor.BlockMonitor
23 | import com.bytedance.blockframework.framework.monitor.TYPE_BLOCK_BIND
24 | import com.bytedance.blockframework.framework.monitor.currentTime
25 | import com.bytedance.blockframework.framework.performance.ThreadProcessor
26 |
27 | /**
28 | *
29 | * @Author: Created by zhoujunjie on 2023/8/9
30 | * @mail zhoujunjie.9743@bytedance.com
31 | **/
32 |
33 | abstract class AsyncBaseBlock>(blockContext: IBlockContext) :
34 | BaseBlock(blockContext), IAsyncBind {
35 |
36 | override fun bindModel(model: MODEL?) {
37 | if (enableAsyncBind()) {
38 | val startSync = currentTime()
39 | recordPref(TYPE_BLOCK_BIND, "sync_bind_start")
40 | kotlin.runCatching {
41 | syncBind(model)
42 | }.onFailure {
43 | BlockInit.recordException(it)
44 | }
45 | recordPref(TYPE_BLOCK_BIND, "sync_bind_end", currentTime() - startSync)
46 | ThreadProcessor.work().post {
47 | val startAsync = currentTime()
48 | recordPref(TYPE_BLOCK_BIND, "async_bind_start")
49 | kotlin.runCatching {
50 | asyncBind(model) {
51 | ThreadProcessor.main().post {
52 | kotlin.runCatching {
53 | it.invoke()
54 | }.onFailure {
55 | BlockInit.recordException(it)
56 | }
57 | }
58 | }
59 | }.onFailure {
60 | BlockInit.recordException(it)
61 | }
62 | recordPref(TYPE_BLOCK_BIND, "async_bind_end", currentTime() - startAsync)
63 | }
64 | } else {
65 | val start = currentTime()
66 | recordPref(TYPE_BLOCK_BIND, "sync_bind_start")
67 | kotlin.runCatching {
68 | syncBind(model)
69 | asyncBind(model) {
70 | it.invoke()
71 | }
72 | }.onFailure {
73 | BlockInit.recordException(it)
74 | }
75 | recordPref(TYPE_BLOCK_BIND, "sync_bind_end", currentTime() - start)
76 | }
77 | }
78 |
79 | override fun syncBind(model: MODEL?) {
80 |
81 | }
82 |
83 | override fun asyncBind(model: MODEL?, syncInvoke: SyncInvoke) {
84 |
85 | }
86 | //
87 |
88 | private fun recordPref(type: String, message: String, cost: Long = 0) {
89 | BlockMonitor.record(blockContext.getScene().getName(), getBlockKey(), type, message, cost)
90 | }
91 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/async/AsyncUIBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.async
17 |
18 | import android.view.View
19 | import android.view.ViewGroup
20 | import androidx.annotation.IdRes
21 | import com.bytedance.blockframework.framework.base.IUIBlock
22 | import com.bytedance.blockframework.framework.base.UIBlockConfig
23 | import com.bytedance.blockframework.framework.core.IBlockModel
24 | import com.bytedance.blockframework.framework.join.IBlockContext
25 |
26 | /**
27 | * @Author: Created by zhoujunjie on 2023/8/9
28 | * @mail zhoujunjie.9743@bytedance.com
29 | **/
30 |
31 | abstract class AsyncUIBlock>(blockContext: IBlockContext) : AsyncBaseBlock(blockContext), IUIBlock {
32 |
33 | override val uiConfig: UIBlockConfig = UIBlockConfig()
34 |
35 | override lateinit var containerView: View
36 |
37 | abstract fun layoutResource(): Int
38 |
39 | override fun onCreateView(parent: View?): View {
40 | if (layoutResource() == IUIBlock.USE_PARENT_LAYOUT) {
41 | return parent!!
42 | }
43 | return uiConfig.viewInflater.getView(layoutResource(), parent!!.context, parent as ViewGroup)
44 | }
45 |
46 | override fun onViewCreated(view: View) {}
47 |
48 | override fun getView(): View? {
49 | return if (this::containerView.isInitialized) {
50 | containerView
51 | } else {
52 | null
53 | }
54 | }
55 |
56 | fun findViewById(@IdRes id: Int): T? {
57 | return getView()?.findViewById(id)
58 | }
59 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/async/IAsyncBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.async
17 |
18 | import androidx.annotation.MainThread
19 |
20 |
21 | /**
22 | * @Author: Created by zhoujunjie on 2023/3/7
23 | * @mail zhoujunjie.9743@bytedance.com
24 | **/
25 |
26 | typealias SyncInvoke = (() -> Unit) -> Unit
27 |
28 | interface IAsyncBind {
29 |
30 | fun enableAsyncBind(): Boolean
31 |
32 | @MainThread
33 | fun syncBind(model: MODEL?)
34 |
35 | /**
36 | * @param syncInvoke: Used to switch to the main thread
37 | */
38 | fun asyncBind(model: MODEL?, syncInvoke: SyncInvoke)
39 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/base/BaseBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.base
17 |
18 | import com.bytedance.blockframework.contract.AbstractLifecycleBlock
19 | import com.bytedance.blockframework.framework.core.BlockGenerator
20 | import com.bytedance.blockframework.framework.core.BlockUnitHandler
21 | import com.bytedance.blockframework.framework.core.IBlockModel
22 | import com.bytedance.blockframework.framework.core.message.TreeBlockMessageCenter
23 | import com.bytedance.blockframework.framework.join.IBlockContext
24 | import com.bytedance.blockframework.framework.utils.blockHandler
25 |
26 | /**
27 | *
28 | * @Author: Created by zhoujunjie on 2023/8/9
29 | * @mail zhoujunjie.9743@bytedance.com
30 | **/
31 |
32 | open class BaseBlock>(var blockContext: IBlockContext) : AbstractLifecycleBlock() {
33 |
34 | private val blockName by lazy { this::class.java.simpleName + "_" + this.hashCode() }
35 |
36 | internal var parent: BlockUnitHandler? = null
37 | internal var immediateBind = false
38 |
39 | open var lazyActive = false
40 | open var isBlockActivated = true
41 | open var activeTask: (() -> Unit)? = null
42 |
43 | open fun activeIfNeed() {
44 | if (!isActive()) {
45 | activeTask?.invoke()
46 | }
47 | }
48 |
49 | open fun getBlockKey(): String = blockName
50 |
51 | //
52 | @Deprecated(message = "please use onRegister()", replaceWith = ReplaceWith("onRegister()"))
53 | override fun onPrepared() {
54 | onRegister()
55 | }
56 | open fun onRegister() {}
57 | override fun onCreate() {}
58 | override fun onStart() {}
59 | override fun onResume() {}
60 | override fun onPause() {}
61 | override fun onStop() {}
62 | override fun onDestroy() {}
63 | override fun onUnRegister() {}
64 | //
65 |
66 | override fun defineBlockService(): Class<*>? = null
67 | override fun isActive(): Boolean = isBlockActivated
68 |
69 | open fun bindModel(model: MODEL?) {}
70 |
71 | open fun generateSubBlocks(generator: BlockGenerator) {}
72 |
73 | override fun getBlockService(klass: Class, activeIfNeed: Boolean): T? {
74 | if (blockBlockMessageCenter is TreeBlockMessageCenter) {
75 | var handler = blockHandler()
76 | var impl = handler.queryService(klass, activeIfNeed)
77 | while (impl == null) {
78 | handler = handler.attachBlock.parent ?: break
79 | impl = handler.queryService(klass, activeIfNeed)
80 | }
81 | return impl
82 | }
83 | return blockBlockMessageCenter.queryService(this, klass, activeIfNeed)
84 | }
85 |
86 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/base/BlockBuilder.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.base
17 |
18 | import android.view.ViewGroup
19 | import androidx.annotation.IdRes
20 | import com.bytedance.blockframework.framework.task.BlockInflater
21 | import com.bytedance.blockframework.framework.task.DefaultLayoutInflater
22 |
23 | /**
24 | *
25 | * @author: Created by zhoujunjie on 2023/8/9
26 | * @mail zhoujunjie.9743@bytedance.com
27 | **/
28 |
29 | open class BaseBlockBuilder> {
30 |
31 | /**
32 | * Block Instance
33 | */
34 | lateinit var instance: () -> Block
35 |
36 | /**
37 | * Conditions indicating whether a Block can be added, generally used to determine
38 | * when the same Block is reused in different scenarios
39 | *
40 | * For example:condition = { scene == InnerStream },means that only the Block
41 | * will be added in InnerStream scenarios, and not in other scenarios
42 | */
43 | var condition: () -> Boolean = { true }
44 |
45 | /**
46 | * The placeholder ID corresponding to UIBlock, and the View to which
47 | * the Block is opposed will be added to the corresponding parentId in the parent Block
48 | */
49 | @IdRes var parentId: Int = -1
50 |
51 | /**
52 | * In UIBlock, View is added to the layout parameters of the parent Block
53 | */
54 | var layoutParams: ViewGroup.LayoutParams? = null
55 |
56 | /**
57 | * In UIBlock, whether View replaces the parentView occupying the pit,
58 | * please uses it in conjunction with [parentId].
59 | * This is mainly used to reduce layout levels.
60 | */
61 | var replaceParent = false
62 |
63 | /**
64 | * UIBlock custom layout inflate, using [DefaultLayoutInflater] by default
65 | */
66 | var viewInflater: BlockInflater? = null
67 |
68 | /**
69 | * UIBlock must create a View on the main thread or not
70 | */
71 | var createUIOnMainThread = false
72 |
73 | /**
74 | * Whether Block Bind immediately, the default is false,
75 | * which means that Bind will be triggered after the View tree is created.
76 | * please use in conjunction with [createUIOnMainThread]
77 | */
78 | var immediateBind = false
79 |
80 | /**
81 | * Means Block delayed loading
82 | */
83 | var lazyActive = false
84 |
85 | internal fun build(): Block = instance()
86 | }
87 |
88 | class BlockBuilder : BaseBlockBuilder>()
89 |
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/base/IUIBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.base
17 |
18 | import android.view.View
19 | import android.view.ViewGroup.LayoutParams
20 | import com.bytedance.blockframework.framework.task.BlockInflater
21 | import com.bytedance.blockframework.framework.task.DefaultLayoutInflater
22 | import kotlinx.android.extensions.LayoutContainer
23 |
24 | /**
25 | *
26 | * @Author: Created by zhoujunjie on 2023/8/27
27 | * @mail zhoujunjie.9743@bytedance.com
28 | **/
29 |
30 | data class UIBlockConfig(
31 | var parentId: Int = -1,
32 | var layoutParams: LayoutParams? = null,
33 | var createUIOnMainThread: Boolean = false,
34 | var replaceParent: Boolean = false,
35 | var viewInflater: BlockInflater = DefaultLayoutInflater
36 | )
37 |
38 | interface IUIBlock : LayoutContainer {
39 |
40 | companion object {
41 | const val USE_PARENT_LAYOUT = -1
42 | }
43 |
44 | val uiConfig: UIBlockConfig
45 | override var containerView: View
46 | fun onCreateView(parent: View?): View
47 | fun onViewCreated(view: View)
48 | fun getView(): View?
49 | fun customGenerateView(currentView: View, parent: View?): Boolean {
50 | return false
51 | }
52 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/base/NoBindBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.base
17 |
18 | import com.bytedance.blockframework.framework.join.IBlockContext
19 |
20 | /**
21 | * Description: Blocks that do not require Bind data
22 | *
23 | * @Author: Created by zhoujunjie on 2023/8/9
24 | * @mail zhoujunjie.9743@bytedance.com
25 | **/
26 |
27 | open class NoBindBlock(blockContext: IBlockContext) : BaseBlock(blockContext) {
28 | final override fun bindModel(model: Nothing?) {
29 | super.bindModel(model)
30 | }
31 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/base/UIBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.base
17 |
18 | import android.view.View
19 | import android.view.ViewGroup
20 | import androidx.annotation.IdRes
21 | import com.bytedance.blockframework.framework.core.IBlockModel
22 | import com.bytedance.blockframework.framework.join.IBlockContext
23 |
24 | /**
25 | *
26 | * @author: Created by zhoujunjie on 2023/8/9
27 | * @mail zhoujunjie.9743@bytedance.com
28 | **/
29 |
30 | abstract class UIBlock>(blockContext: IBlockContext) : BaseBlock(blockContext), IUIBlock {
31 |
32 | override val uiConfig: UIBlockConfig = UIBlockConfig()
33 |
34 | override lateinit var containerView: View
35 |
36 | override fun onCreateView(parent: View?): View {
37 | if (layoutResource() == -1) {
38 | return parent!!
39 | }
40 | return uiConfig.viewInflater.getView(layoutResource(), parent!!.context, parent as ViewGroup)
41 | }
42 |
43 | abstract fun layoutResource(): Int
44 |
45 | override fun onViewCreated(view: View) {}
46 |
47 | override fun getView(): View? {
48 | return if (this::containerView.isInitialized) {
49 | containerView
50 | } else {
51 | null
52 | }
53 | }
54 |
55 | fun findViewById(@IdRes id: Int): T? {
56 | return getView()?.findViewById(id)
57 | }
58 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/config/BlockInit.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.config
17 |
18 | import com.bytedance.blockframework.framework.monitor.BlockLogger
19 |
20 | /**
21 | *
22 | * @author: Created by zhoujunjie on 2023/8/9
23 | * @mail zhoujunjie.9743@bytedance.com
24 | **/
25 |
26 | object BlockInit {
27 |
28 | private var config: IBlockInitConfig = IBlockInitConfig.DefaultInitConfig()
29 |
30 | fun useTreeMessageCenterEnable(): Boolean {
31 | return config.useTreeMessageCenterEnable()
32 | }
33 |
34 | fun allTaskMustRunOnMain(): Boolean {
35 | return config.allTaskMustRunOnMain()
36 | }
37 |
38 | fun recordEnable(): Boolean {
39 | return config.recordEnable()
40 | }
41 |
42 | fun logOptEnable(): Boolean {
43 | return config.logOptEnable()
44 | }
45 |
46 | fun enableDebugDependencyCheck(): Boolean {
47 | return config.enableDebugDependencyCheck()
48 | }
49 |
50 | fun init(config: IBlockInitConfig) {
51 | this.config = config
52 | BlockLogger.setLogger(config.getBlockLogger())
53 | }
54 |
55 | fun recordException(e: Throwable?) {
56 | config.recordException(e)
57 | }
58 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/config/IBlockInitConfig.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.config
17 |
18 | import com.bytedance.blockframework.framework.monitor.BlockLogger
19 | import com.bytedance.blockframework.framework.monitor.DefaultBlockLogger
20 |
21 | /**
22 | *
23 | * @Author: Created by zhoujunjie on 2023/8/9
24 | * @mail zhoujunjie.9743@bytedance.com
25 | **/
26 |
27 | interface IBlockInitConfig {
28 |
29 | fun recordEnable(): Boolean
30 |
31 | fun useTreeMessageCenterEnable(): Boolean
32 |
33 | fun getBlockLogger(): BlockLogger
34 |
35 | fun allTaskMustRunOnMain(): Boolean
36 |
37 | fun logOptEnable(): Boolean
38 |
39 | fun enableDebugDependencyCheck(): Boolean
40 |
41 | fun recordException(e: Throwable?)
42 |
43 | class DefaultInitConfig : IBlockInitConfig {
44 |
45 | override fun recordEnable(): Boolean {
46 | return false
47 | }
48 |
49 | override fun useTreeMessageCenterEnable(): Boolean {
50 | return true
51 | }
52 |
53 | override fun getBlockLogger(): BlockLogger = DefaultBlockLogger()
54 |
55 | override fun allTaskMustRunOnMain(): Boolean {
56 | return true
57 | }
58 |
59 | override fun logOptEnable(): Boolean {
60 | return false
61 | }
62 |
63 | override fun enableDebugDependencyCheck(): Boolean {
64 | return true
65 | }
66 |
67 | override fun recordException(e: Throwable?) {
68 |
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/core/BlockGenerator.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.core
17 |
18 | import android.view.ViewGroup
19 | import com.bytedance.blockframework.framework.base.BlockBuilder
20 | import com.bytedance.blockframework.framework.base.IUIBlock
21 | import com.bytedance.blockframework.framework.core.message.BlockContractManager
22 | import com.bytedance.blockframework.framework.task.BlockViewBuildTask
23 | import com.bytedance.blockframework.framework.utils.BlockDsl
24 | import com.bytedance.blockframework.framework.utils.blockHandler
25 |
26 | /**
27 | *
28 | * @author: Created by zhoujunjie on 2023/8/7
29 | * @mail zhoujunjie.9743@bytedance.com
30 | **/
31 |
32 | interface BlockGenerator {
33 | fun generate(action: SubBlockCreator.() -> Unit)
34 | }
35 |
36 | interface SubBlockCreator {
37 | @BlockDsl
38 | fun addBlock(builder: BlockBuilder.() -> Unit)
39 | }
40 |
41 | internal class BlockGeneratorImpl(
42 | private val supervisor: BlockUnitHandler?,
43 | private val contractManager: BlockContractManager,
44 | private val uiTasks: MutableList
45 | ) : BlockGenerator {
46 | override fun generate(action: SubBlockCreator.() -> Unit) {
47 | val adder = object : SubBlockCreator {
48 | override fun addBlock(builder: BlockBuilder.() -> Unit) {
49 | supervisor?.apply {
50 | val config = BlockBuilder().apply(builder)
51 | if (!config.condition()) {
52 | return@apply
53 | }
54 | val block = config.build()
55 | block.immediateBind = config.immediateBind
56 | if (block is IUIBlock) {
57 | block.uiConfig.parentId = config.parentId
58 | block.uiConfig.layoutParams = config.layoutParams
59 | block.uiConfig.replaceParent = config.replaceParent
60 | block.uiConfig.createUIOnMainThread = config.createUIOnMainThread
61 | // 子线程创建UI的Block不能进行immediateBind
62 | if (!config.createUIOnMainThread) {
63 | block.immediateBind = false
64 | }
65 | if (config.viewInflater != null) {
66 | block.uiConfig.viewInflater = config.viewInflater!!
67 | } else {
68 | block.uiConfig.viewInflater = block.blockContext.getLayoutInflater()
69 | }
70 |
71 | var parentView = getAttachView()
72 | if (config.parentId != -1) {
73 | parentView = parentView?.findViewById(config.parentId)
74 | }
75 | if (block.lazyActive) {
76 | block.activeTask = {
77 | val task = BlockViewBuildTask(block, parentView as? ViewGroup)
78 | task.run()
79 | val target = task.result.value
80 | block.blockHandler().apply {
81 | installView(target)
82 | activeView()
83 | }
84 | }
85 | } else {
86 | uiTasks.add(BlockViewBuildTask(block, parentView as? ViewGroup))
87 | }
88 | }
89 | loadBlock(block)
90 | contractManager.registerBlock(block)
91 | block.generateSubBlocks(BlockGeneratorImpl(block.blockHandler(), contractManager, uiTasks))
92 | }
93 | }
94 | }
95 | adder.action()
96 | }
97 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/core/BlockLifeCycleDispatcher.kt:
--------------------------------------------------------------------------------
1 | package com.bytedance.blockframework.framework.core
2 |
3 | import androidx.lifecycle.Lifecycle
4 | import androidx.lifecycle.LifecycleEventObserver
5 | import androidx.lifecycle.LifecycleOwner
6 | import com.bytedance.blockframework.framework.base.BaseBlock
7 | import com.bytedance.blockframework.framework.utils.LifecycleUtil.handleLifecycleState
8 | import com.bytedance.blockframework.framework.utils.blockHandler
9 |
10 | /**
11 | * description:
12 | *
13 | * @author Created by zhoujunjie on 2024/11/14
14 | * @mail zhoujunjie.9743@bytedance.com
15 | **/
16 |
17 | class BlockLifeCycleDispatcher(private val parentBlock: BaseBlock<*, *>) : LifecycleEventObserver {
18 |
19 | private val TAG = "BlockLifeCycleDispatcher"
20 |
21 | override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
22 | when (event) {
23 | Lifecycle.Event.ON_CREATE -> onCreate()
24 | Lifecycle.Event.ON_START -> onStart()
25 | Lifecycle.Event.ON_RESUME -> onResume()
26 | Lifecycle.Event.ON_PAUSE -> onPause()
27 | Lifecycle.Event.ON_STOP -> onStop()
28 | Lifecycle.Event.ON_DESTROY -> onDestroy()
29 | else -> Unit
30 | }
31 | }
32 |
33 | private fun onCreate() {
34 | parentBlock.blockHandler().getChildBlocks().forEach {
35 | handleLifecycleState(Lifecycle.State.CREATED, it)
36 | }
37 | }
38 |
39 | private fun onStart() {
40 | parentBlock.blockHandler().getChildBlocks().filter { !it.lazyActive }.forEach {
41 | handleLifecycleState(Lifecycle.State.STARTED, it)
42 | }
43 | }
44 |
45 | private fun onResume() {
46 | parentBlock.blockHandler().getChildBlocks().filter { !it.lazyActive }.forEach {
47 | handleLifecycleState(Lifecycle.State.RESUMED, it)
48 | }
49 | }
50 |
51 | private fun onPause() {
52 | parentBlock.blockHandler().getChildBlocks().filter { !it.lazyActive }.forEach {
53 | handleLifecycleState(Lifecycle.State.STARTED, it)
54 | }
55 | }
56 |
57 | private fun onStop() {
58 | parentBlock.blockHandler().getChildBlocks().filter { !it.lazyActive }.forEach {
59 | handleLifecycleState(Lifecycle.State.CREATED, it)
60 | }
61 | }
62 |
63 | private fun onDestroy() {
64 | parentBlock.blockHandler().getChildBlocks().filter { !it.lazyActive }.forEach {
65 | handleLifecycleState(Lifecycle.State.DESTROYED, it)
66 | }
67 | parentBlock.lifecycle.removeObserver(this)
68 | }
69 |
70 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/core/BlockUnitHandler.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.core
17 |
18 | import android.content.Context
19 | import android.view.View
20 | import android.view.ViewGroup
21 | import com.bytedance.blockframework.contract.AbstractBlock
22 | import com.bytedance.blockframework.contract.BlockImplWrapper
23 | import com.bytedance.blockframework.framework.base.BaseBlock
24 | import com.bytedance.blockframework.framework.base.IUIBlock
25 | import com.bytedance.blockframework.framework.config.BlockInit
26 | import com.bytedance.blockframework.framework.monitor.BlockLogger
27 | import com.bytedance.blockframework.framework.utils.syncInvoke
28 | import com.bytedance.blockframework.framework.utils.uploadException
29 | import com.bytedance.blockframework.interaction.Event
30 | import com.bytedance.blockframework.interaction.IObserver
31 |
32 | /**
33 | *
34 | * @Author: Created by zhoujunjie on 2023/7/17
35 | * @mail zhoujunjie.9743@bytedance.com
36 | **/
37 |
38 | class BlockUnitHandler internal constructor(
39 | val context: Context,
40 | val attachBlock: BaseBlock<*, *>,
41 | private val lifecycleHandler: BlockLifeCycleDispatcher
42 | ) {
43 |
44 | companion object {
45 | fun create(context: Context, block: BaseBlock<*, *>) = BlockUnitHandler(context, block, BlockLifeCycleDispatcher(block))
46 | }
47 |
48 | private val childList: MutableList> = mutableListOf()
49 | private val serviceMap: MutableMap, BlockImplWrapper> = mutableMapOf()
50 | val eventToObserverMap: MutableMap, MutableList>> = mutableMapOf()
51 |
52 | fun registerObserver(observer: IObserver, eventClass: Class) {
53 | // update event to observer map
54 | val observers = eventToObserverMap[eventClass] ?: run {
55 | mutableListOf>().apply {
56 | eventToObserverMap[eventClass] = this
57 | }
58 | }
59 | if (!observers.contains(observer)) {
60 | observers.add(observer)
61 | }
62 | }
63 |
64 | fun notifyEvent(event: Event): Boolean {
65 | val observers = eventToObserverMap[event.javaClass] ?: return false
66 | for (observer in observers) {
67 | if (observer is AbstractBlock) {
68 | if (!observer.isActive()) {
69 | continue
70 | }
71 | }
72 | val intercept = observer.onEvent(event)
73 | if (intercept && event.canIntercept) {
74 | break
75 | }
76 | }
77 | return true
78 | }
79 |
80 | fun attachLifecycle() {
81 | val blockLifecycle = attachBlock.lifecycle
82 | syncInvoke {
83 | blockLifecycle.removeObserver(lifecycleHandler)
84 | blockLifecycle.addObserver(lifecycleHandler)
85 | }
86 | }
87 |
88 | fun loadBlock(subBlock: BaseBlock<*, *>) {
89 | subBlock.parent = this
90 | childList.add(subBlock)
91 | }
92 |
93 | fun installView(target: View) {
94 | val block = attachBlock as? IUIBlock ?: return
95 | val parentView = getAttachView()
96 | if (block.customGenerateView(target, parentView)) {
97 | block.containerView = target
98 | return
99 | }
100 | if (block.uiConfig.parentId == -1) {
101 | block.containerView = target
102 | return
103 | }
104 |
105 | val placeHolderView = parentView?.findViewById(block.uiConfig.parentId)
106 | if (placeHolderView == null) {
107 | if (!BlockInit.logOptEnable() || BlockLogger.debug()) {
108 | uploadException(RuntimeException("${(block as? BaseBlock<*, *>)?.getBlockKey() ?: ""} placeHolder is Null"), true)
109 | }
110 | return
111 | }
112 | if (block.uiConfig.replaceParent) {
113 | replaceSelfWithView(target, placeHolderView)
114 | } else {
115 | addViewInPlaceholder(target, placeHolderView, block.uiConfig.layoutParams)
116 | }
117 | block.containerView = target
118 | }
119 |
120 | private fun replaceSelfWithView(view: View, placeHolder: View) {
121 | val parent = placeHolder.parent as? ViewGroup ?: return
122 | val index = parent.indexOfChild(placeHolder)
123 | parent.removeViewInLayout(placeHolder)
124 | val layoutParams = placeHolder.layoutParams
125 | if (layoutParams != null) {
126 | parent.addView(view, index, layoutParams)
127 | } else {
128 | parent.addView(view, index)
129 | }
130 | }
131 |
132 | private fun addViewInPlaceholder(view: View, placeHolder: View, layoutParams: ViewGroup.LayoutParams? = null) {
133 | val containerView = placeHolder as? ViewGroup ?: return
134 | if (layoutParams != null) {
135 | containerView.addView(view, layoutParams)
136 | } else {
137 | containerView.addView(view)
138 | }
139 | }
140 |
141 | fun activeView() {
142 | val block = attachBlock as? IUIBlock ?: return
143 | block.getView()?.let {
144 | block.onViewCreated(it)
145 | (block as BaseBlock<*, *>).isBlockActivated = true
146 | }
147 | }
148 |
149 | fun getAttachView(): View? {
150 | var block: BaseBlock<*, *>? = attachBlock
151 | var attachView: View? = null
152 | var find = false
153 | while (!find) {
154 | attachView = (block as? IUIBlock)?.getView()
155 | block = block?.parent?.attachBlock
156 | find = attachView != null || block == null
157 | }
158 | return attachView
159 | }
160 |
161 | fun registerService(klass: Class, blockImplWrapper: BlockImplWrapper) {
162 | if (serviceMap.containsKey(klass)) {
163 | if (!BlockInit.logOptEnable() || BlockLogger.debug()) {
164 | uploadException(RuntimeException("registerService $klass already exists"), true)
165 | }
166 | }
167 | serviceMap[klass] = blockImplWrapper
168 | }
169 |
170 | fun queryService(klass: Class, activeIfNeed: Boolean = true): T? {
171 | return if (serviceMap.contains(klass)) {
172 | val target = serviceMap[klass]?.impl
173 | if(activeIfNeed) (target as? BaseBlock<*,*>)?.activeIfNeed()
174 | serviceMap[klass]?.impl as T?
175 | } else {
176 | if (!BlockInit.logOptEnable() || BlockLogger.debug()) {
177 | uploadException(RuntimeException("queryService $klass not find"), false)
178 | }
179 | null
180 | }
181 | }
182 |
183 | fun getChildBlocks(): List> = childList
184 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/core/IBlockModel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.core
17 |
18 | /**
19 | *
20 | * @Author: Created by zhoujunjie on 2023/8/25
21 | * @mail zhoujunjie.9743@bytedance.com
22 | **/
23 |
24 | interface IBlockModel {
25 | val data : T?
26 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/core/message/BlockContractManager.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.core.message
17 |
18 | import android.content.Context
19 | import com.bytedance.blockframework.contract.AbstractBlock
20 | import com.bytedance.blockframework.contract.AbstractBlockManager
21 | import com.bytedance.blockframework.interaction.BaseBlockMessageCenter
22 | import com.bytedance.blockframework.interaction.IBlockMessageCenter
23 |
24 | /**
25 | *
26 | * @Author: Created by zhoujunjie on 2023/8/4
27 | * @mail zhoujunjie.9743@bytedance.com
28 | **/
29 |
30 | class BlockContractManager(context: Context, var messageCenter: IBlockMessageCenter = BaseBlockMessageCenter()) : AbstractBlockManager(context, messageCenter) {
31 | override fun onRegisterBlock(block: AbstractBlock) {}
32 |
33 | override fun onUnregisterBlock(block: AbstractBlock) {}
34 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/core/message/TreeBlockMessageCenter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.core.message
17 |
18 | import com.bytedance.blockframework.contract.BlockImplWrapper
19 | import com.bytedance.blockframework.framework.base.BaseBlock
20 | import com.bytedance.blockframework.interaction.BaseBlockMessageCenter
21 |
22 | /**
23 | *
24 | * @author Created by zhoujunjie on 2023/8/4
25 | * @mail zhoujunjie.9743@bytedance.com
26 | **/
27 |
28 | open class TreeBlockMessageCenter : BaseBlockMessageCenter() {
29 |
30 | override fun registerService(klass: Class, blockImplWrapper: BlockImplWrapper) {
31 | var block = blockImplWrapper.impl as? BaseBlock<*,*>
32 | while (block != null) {
33 | block.parent?.registerService(klass, blockImplWrapper)
34 | block = block.parent?.attachBlock
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/event/AllBlockViewCreatedEvent.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.event
17 |
18 | import android.view.View
19 | import com.bytedance.blockframework.interaction.Event
20 |
21 | /**
22 | *
23 | * @Author: Created by zhoujunjie on 2023/8/28
24 | * @mail zhoujunjie.9743@bytedance.com
25 | **/
26 |
27 | class AllBlockViewCreatedEvent(val rootView: View) : Event()
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/join/BlockContextImpl.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.join
17 |
18 | import android.content.Context
19 | import android.view.View
20 | import androidx.lifecycle.Lifecycle
21 | import com.bytedance.blockframework.framework.base.BaseBlock
22 | import com.bytedance.blockframework.framework.config.BlockInit
23 | import com.bytedance.blockframework.framework.core.BlockCoreManager
24 | import com.bytedance.blockframework.framework.core.BlockUnitHandler
25 | import com.bytedance.blockframework.framework.core.IBlockModel
26 | import com.bytedance.blockframework.framework.monitor.BlockLogger
27 | import com.bytedance.blockframework.framework.task.BlockInflater
28 | import com.bytedance.blockframework.framework.task.DefaultInflaterProvider
29 | import com.bytedance.blockframework.framework.utils.uploadException
30 | import com.bytedance.blockframework.interaction.Event
31 | import com.bytedance.blockframework.interaction.IBlockMessageCenter
32 |
33 | /**
34 | * Block framework context, establishing internal and external connections within the Block framework
35 | *
36 | * @author: Created by zhoujunjie on 2023/8/9
37 | * @mail zhoujunjie.9743@bytedance.com
38 | **/
39 |
40 | interface IBlockContext {
41 | fun getScene(): IBlockScene
42 | fun setMessageCenter(center: IBlockMessageCenter)
43 | fun getMessageCenter(): IBlockMessageCenter
44 | fun findBlockHandler(block: BaseBlock<*,*>): BlockUnitHandler
45 | fun setLayoutInflater(inflater: BlockInflater)
46 | fun getLayoutInflater(): BlockInflater
47 | fun registerDepend(clazz: Class, depend: T)
48 | fun findDepend(clazz: Class): T
49 | fun findDependOrNull(clazz: Class): T?
50 | fun getBlockService(clazz: Class) : T?
51 | fun notifyEvent(event: Event)
52 | fun addAfterBindTask(action: ()->Unit)
53 | }
54 |
55 | class BlockContextImpl(private val blockScene: IBlockScene) : IBlockContext {
56 |
57 | private val blockCore = BlockCoreManager()
58 | private var inflater: BlockInflater? = null
59 | private val dependMap : MutableMap, IBlockDepend> = mutableMapOf()
60 |
61 | internal fun initRootBlock(context: Context, rootBlock: BaseBlock<*,*>, messageCenter: IBlockMessageCenter, parent: View? = null) {
62 | blockCore.initScene(blockScene)
63 | blockCore.initRootBlock(context, rootBlock, messageCenter, parent)
64 | }
65 |
66 | override fun getScene(): IBlockScene {
67 | return blockScene
68 | }
69 |
70 | override fun registerDepend(clazz: Class, depend: T) {
71 | if (dependMap.containsKey(clazz)) {
72 | if (!BlockInit.logOptEnable() || BlockLogger.debug()) {
73 | uploadException(RuntimeException("registerService $clazz already exists"), true)
74 | }
75 | }
76 | dependMap[clazz] = depend
77 | }
78 |
79 | fun > bindBlockModel(model: M) {
80 | blockCore.bindBlockModel(model)
81 | }
82 |
83 | internal fun dispatchLifecycleState(state: Lifecycle.State) {
84 | blockCore.dispatchLifecycleState(state)
85 | }
86 |
87 | override fun findDepend(clazz: Class): T {
88 | return if (!dependMap.containsKey(clazz)) {
89 | throw Exception()
90 | } else {
91 | dependMap[clazz] as T
92 | }
93 | }
94 |
95 | override fun findDependOrNull(clazz: Class): T? {
96 | return dependMap[clazz] as? T
97 | }
98 |
99 | override fun getBlockService(clazz: Class): T? {
100 | return blockCore.getBlockService(clazz)
101 | }
102 |
103 | override fun notifyEvent(event: Event) {
104 | blockCore.notifyEvent(event)
105 | }
106 |
107 | override fun setMessageCenter(center: IBlockMessageCenter) {
108 | blockCore.setMessageCenter(center)
109 | }
110 |
111 | override fun getMessageCenter(): IBlockMessageCenter {
112 | return blockCore.getMessageCenter()
113 | }
114 |
115 | override fun findBlockHandler(block: BaseBlock<*,*>): BlockUnitHandler {
116 | return blockCore.findBlockHandler(block)
117 | }
118 |
119 | override fun setLayoutInflater(inflater: BlockInflater) {
120 | this.inflater = inflater
121 | }
122 |
123 | override fun getLayoutInflater(): BlockInflater {
124 | return inflater ?: DefaultInflaterProvider.getInflater()
125 | }
126 |
127 | override fun addAfterBindTask(action: ()->Unit) {
128 | return blockCore.addAfterBindTask(action)
129 | }
130 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/join/IBlockAbility.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.join
17 |
18 | /**
19 | *
20 | * @author: Created by zhoujunjie on 2024/1/2
21 | * @mail zhoujunjie.9743@bytedance.com
22 | **/
23 |
24 | interface IBlockAbility
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/join/IBlockDepend.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.join
17 |
18 | /**
19 | *
20 | * @author: Created by zhoujunjie on 2023/8/9
21 | * @mail zhoujunjie.9743@bytedance.com
22 | **/
23 |
24 | interface IBlockDepend
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/join/IBlockJoin.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.join
17 |
18 | import android.content.Context
19 | import android.view.View
20 | import androidx.lifecycle.Lifecycle
21 | import com.bytedance.blockframework.framework.base.BaseBlock
22 | import com.bytedance.blockframework.framework.core.IBlockModel
23 | import com.bytedance.blockframework.framework.utils.getDefaultCenter
24 | import com.bytedance.blockframework.interaction.IBlockMessageCenter
25 |
26 | /**
27 | *
28 | * @Author: Created by zhoujunjie on 2023/8/9
29 | * @mail zhoujunjie.9743@bytedance.com
30 | **/
31 |
32 | interface IBlockJoin {
33 | val blockContext: IBlockContext
34 | val blockScene: IBlockScene
35 | }
36 |
37 | fun IBlockJoin.initRootBlock(context: Context, rootBlock: BaseBlock<*, *>) {
38 | (blockContext as? BlockContextImpl)?.initRootBlock(context, rootBlock, getDefaultCenter(), null)
39 | }
40 |
41 | fun IBlockJoin.initRootBlock(context: Context, rootBlock: BaseBlock<*, *>, messageCenter: IBlockMessageCenter = getDefaultCenter(), parent: View? = null) {
42 | (blockContext as? BlockContextImpl)?.initRootBlock(context, rootBlock, messageCenter, parent)
43 | }
44 |
45 | inline fun > IBlockJoin.bindBlockModel(model: MODEL) {
46 | (blockContext as? BlockContextImpl)?.bindBlockModel(model)
47 | }
48 |
49 | fun IBlockJoin.dispatchBlockLifecycle(state: Lifecycle.State) {
50 | (blockContext as? BlockContextImpl)?.dispatchLifecycleState(state)
51 | }
52 |
53 | fun IBlockJoin.dispatchOnCreate() {
54 | dispatchBlockLifecycle(Lifecycle.State.CREATED)
55 | }
56 |
57 | fun IBlockJoin.dispatchOnStart() {
58 | dispatchBlockLifecycle(Lifecycle.State.STARTED)
59 | }
60 |
61 | fun IBlockJoin.dispatchOnResume() {
62 | dispatchBlockLifecycle(Lifecycle.State.RESUMED)
63 | }
64 |
65 | fun IBlockJoin.dispatchOnPause() {
66 | dispatchBlockLifecycle(Lifecycle.State.STARTED)
67 | }
68 |
69 | fun IBlockJoin.dispatchOnStop() {
70 | dispatchBlockLifecycle(Lifecycle.State.CREATED)
71 | }
72 |
73 | fun IBlockJoin.dispatchOnDestroy() {
74 | dispatchBlockLifecycle(Lifecycle.State.DESTROYED)
75 | }
76 |
77 | inline fun IBlockJoin.registerDepend(depend: T) {
78 | blockContext.registerDepend(T::class.java, depend)
79 | }
80 |
81 | inline fun IBlockJoin.blockService(): T? {
82 | return blockContext.getBlockService(T::class.java)
83 | }
84 |
85 | inline fun IBlockJoin.findDepend(): T {
86 | return blockContext.findDepend(T::class.java)
87 | }
88 |
89 | inline fun IBlockJoin.findDependOrNull(): T? {
90 | return blockContext.findDependOrNull(T::class.java)
91 | }
92 |
93 | fun IBlockJoin.getBlockContext(scene: IBlockScene): IBlockContext = BlockContextImpl(scene)
94 |
95 |
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/join/IBlockScene.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.join
17 |
18 | /**
19 | *
20 | * @Author: Created by zhoujunjie on 2023/8/9
21 | * @mail zhoujunjie.9743@bytedance.com
22 | **/
23 |
24 | interface IBlockScene {
25 | fun getName(): String
26 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/monitor/BlockLogger.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.monitor
17 |
18 | import android.os.SystemClock
19 | import com.bytedance.blockframework.BuildConfig
20 | import com.bytedance.blockframework.utils.Logger
21 |
22 | /**
23 | *
24 | * @Author: Created by zhoujunjie on 2023/8/9
25 | * @mail zhoujunjie.9743@bytedance.com
26 | **/
27 |
28 | interface BlockLogger {
29 |
30 | fun debug(): Boolean
31 |
32 | fun log(tag: String, info: String)
33 |
34 | fun report(tag: String, params: Map)
35 |
36 | companion object : BlockLogger {
37 | private var logger: BlockLogger = DefaultBlockLogger()
38 | fun setLogger(logger: BlockLogger) {
39 | this.logger = logger
40 | }
41 |
42 | override fun debug(): Boolean {
43 | return logger.debug()
44 | }
45 |
46 | override fun log(tag: String, info: String) {
47 | logger.log(tag, info)
48 | }
49 |
50 | override fun report(tag: String, params: Map) {
51 | logger.report(tag, params)
52 | }
53 | }
54 | }
55 |
56 | class DefaultBlockLogger : BlockLogger {
57 |
58 | override fun debug(): Boolean {
59 | return BuildConfig.DEBUG
60 | }
61 |
62 | override fun log(tag: String, info: String) {
63 | Logger.d(tag, info)
64 | }
65 |
66 | override fun report(tag: String, params: Map) {
67 |
68 | }
69 | }
70 |
71 | fun logger(tag: String, info: String) {
72 | BlockLogger.log(tag, info)
73 | }
74 |
75 | fun currentTime(): Long = SystemClock.elapsedRealtime()
76 |
77 | fun currentThread(): Thread = Thread.currentThread()
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/monitor/BlockMonitor.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.monitor
17 |
18 | import com.bytedance.blockframework.framework.config.BlockInit
19 | import com.bytedance.blockframework.framework.join.IBlockScene
20 | import java.util.Vector
21 |
22 | /**
23 | *
24 | * @author Created by zhoujunjie on 2024/3/7
25 | * @mail zhoujunjie.9743@bytedance.com
26 | **/
27 |
28 | data class JobRecord(
29 | val scene: String = "",
30 | val key: String = "",
31 | val type: String = "",
32 | val message: String = "",
33 | val cost: Long = 0L
34 | ) {
35 | override fun toString(): String {
36 | if (cost <= 0) {
37 | return "$scene -- $key -- $type -- $message"
38 | }
39 | return "$scene -- $key -- $type -- $message -- cost: ${cost}ms"
40 | }
41 | }
42 |
43 | const val TYPE_BLOCK_TREE_INIT = "pref_init_block_tree"
44 | const val TYPE_BLOCK_TREE_CREATE = "pref_create_block_tree"
45 | const val TYPE_BLOCK_TREE_BIND = "pref_bind_block_tree"
46 | const val TYPE_BLOCK_VIEW_CREATE = "pref_create_block_view"
47 | const val TYPE_BLOCK_RUN_TASK = "pref_create_run_task"
48 | const val TYPE_BLOCK_BIND = "pref_bind_block"
49 |
50 | object BlockMonitor {
51 |
52 | private val recordMap = HashMap>()
53 |
54 | fun record(scene: String, key: String, type: String, message: String = "", cost: Long = 0L) {
55 | if (!BlockInit.recordEnable()) return
56 | if (cost <= 0) {
57 | logger(scene, "$scene -- $key -- $type -- $message")
58 | } else {
59 | logger(scene, "$scene -- $key -- $type -- $message -- cost: ${cost}ms")
60 | }
61 | }
62 |
63 | fun doctor(scene: IBlockScene) {
64 | recordMap[scene.getName()]?.let {
65 | it.forEach { record ->
66 | logger(record.key, record.toString())
67 | }
68 | } ?: logger(scene.getName(), "There no BlockTree in this scene!")
69 | }
70 |
71 | fun report() {
72 | recordMap.forEach { record ->
73 | val treeInitTime = record.value.first { it.type == TYPE_BLOCK_TREE_INIT }?.cost ?: 0L
74 | val treeBuildViewTime = record.value.first { it.type == TYPE_BLOCK_TREE_CREATE }?.cost
75 | ?: 0L
76 | val treeBindTime = record.value.first { it.type == TYPE_BLOCK_TREE_BIND }?.cost ?: 0L
77 | BlockLogger.report(record.key, hashMapOf(
78 | "block_tree_init_cost" to treeInitTime.toString(),
79 | "block_tree_create_view_cost" to treeBuildViewTime.toString(),
80 | "block_tree_bind_cost" to treeBindTime.toString()
81 | ))
82 | }
83 | }
84 |
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/performance/HandlerProcessor.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.performance
17 |
18 | import android.os.Handler
19 |
20 |
21 | /**
22 | *
23 | * @Author: Created by zhoujunjie on 2022/12/20
24 | * @mail zhoujunjie.9743@bytedance.com
25 | **/
26 | class HandlerProcessor(private val handler: Handler, private val sync: Boolean) {
27 |
28 | fun post(runnable: () -> Unit) {
29 | if (sync) {
30 | runnable()
31 | } else {
32 | handler.post(runnable)
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/performance/ThreadProcessor.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.performance
17 |
18 | import android.os.Handler
19 | import android.os.HandlerThread
20 | import android.os.Looper
21 |
22 | object ThreadProcessor {
23 |
24 | const val BLOCK_WORK_THREAD_LABEL = "Block_WorkThread"
25 |
26 | @Volatile private lateinit var workHandler: Handler
27 | private val mainHandler = Handler(Looper.getMainLooper())
28 |
29 | fun work(): Handler {
30 | if (!::workHandler.isInitialized) {
31 | synchronized(this) {
32 | if (!::workHandler.isInitialized) {
33 | val handlerThread = HandlerThread(BLOCK_WORK_THREAD_LABEL)
34 | handlerThread.start()
35 | workHandler = Handler(handlerThread.looper)
36 | }
37 | }
38 | }
39 | return workHandler
40 | }
41 |
42 | fun main(): Handler {
43 | return mainHandler
44 | }
45 |
46 | fun setWork(handler: Handler) {
47 | workHandler = handler
48 | }
49 |
50 | fun post(runnable: () -> Unit) {
51 | work().post(runnable)
52 | }
53 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/task/BlockLayoutInflater.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.task
17 |
18 | import android.content.Context
19 | import android.view.LayoutInflater
20 | import android.view.View
21 | import android.view.ViewGroup
22 |
23 | /**
24 | *
25 | * @Author: Created by zhoujunjie on 2023/7/18
26 | * @mail zhoujunjie.9743@bytedance.com
27 | **/
28 |
29 | interface BlockInflaterProvider {
30 | fun getInflater(): BlockInflater
31 | }
32 |
33 | interface BlockInflater {
34 | fun getView(id: Int, context: Context, parent: ViewGroup): View
35 | }
36 |
37 | object DefaultInflaterProvider : BlockInflaterProvider {
38 | override fun getInflater(): BlockInflater {
39 | return DefaultLayoutInflater
40 | }
41 | }
42 |
43 | object DefaultLayoutInflater : BlockInflater {
44 | override fun getView(id: Int, context: Context, parent: ViewGroup): View {
45 | return LayoutInflater.from(context).inflate(id, parent, false)
46 | }
47 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/task/BlockViewBuildTask.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.task
17 |
18 | import android.view.View
19 | import android.view.ViewGroup
20 | import com.bytedance.blockframework.framework.base.BaseBlock
21 | import com.bytedance.blockframework.framework.base.IUIBlock
22 | import com.bytedance.blockframework.framework.monitor.BlockMonitor
23 | import com.bytedance.blockframework.framework.monitor.TYPE_BLOCK_VIEW_CREATE
24 | import com.bytedance.blockframework.framework.monitor.currentThread
25 | import com.bytedance.blockframework.framework.monitor.currentTime
26 | import java.util.concurrent.atomic.AtomicInteger
27 |
28 | /**
29 | *
30 | * @Author: Created by zhoujunjie on 2023/7/18
31 | * @mail zhoujunjie.9743@bytedance.com
32 | **/
33 |
34 | class BlockViewBuildTask(
35 | val uiBlock: IUIBlock,
36 | private val parent: ViewGroup?,
37 | override val result: TaskResult = TaskResult()
38 | ) : Task {
39 |
40 | companion object {
41 | var sAtomViewTypeCreator = AtomicInteger(100)
42 | }
43 |
44 | override val taskPriority: Int = sAtomViewTypeCreator.decrementAndGet()
45 |
46 | override val mustMainThread: Boolean = uiBlock.uiConfig.createUIOnMainThread
47 |
48 | override fun run() {
49 | if (parent != null) {
50 | val startCreate = currentTime()
51 | BlockMonitor.record(getBlockScene(), (uiBlock as BaseBlock<*, *>).getBlockKey(), TYPE_BLOCK_VIEW_CREATE, "[${currentThread().name}] view_create_start")
52 | result.value = uiBlock.onCreateView(parent)
53 | BlockMonitor.record(getBlockScene(), (uiBlock as BaseBlock<*, *>).getBlockKey(), TYPE_BLOCK_VIEW_CREATE, "[${currentThread().name}] view_create_end", currentTime() - startCreate)
54 | }
55 | }
56 |
57 | fun getBlockScene(): String {
58 | return (uiBlock as? BaseBlock<*, *>)?.blockContext?.getScene()?.getName() ?: ""
59 | }
60 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/task/ITaskManager.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.task
17 |
18 | /**
19 | *
20 | * @author Created by zhoujunjie on 2024/8/7
21 | * @mail zhoujunjie.9743@bytedance.com
22 | **/
23 |
24 | typealias TasksFinished = (List) -> Unit
25 |
26 | interface ITaskManager {
27 | fun addTask(tasks: List)
28 | fun handleTasks(mainFinished: TasksFinished? = null, subFinished: TasksFinished? = null, allFinished: TasksFinished? = null)
29 | fun clear()
30 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/task/ScheduleTask.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.task
17 |
18 | /**
19 | *
20 | * @Author: Created by zhoujunjie on 2023/7/18
21 | * @mail zhoujunjie.9743@bytedance.com
22 | **/
23 |
24 | enum class TaskPriority{
25 | Low, High, Boot
26 | }
27 |
28 | interface ScheduleTask {
29 | val mustMainThread: Boolean
30 | val taskPriority: Int
31 | fun run()
32 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/task/Task.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.task
17 |
18 | /**
19 | *
20 | * @Author: Created by zhoujunjie on 2023/7/18
21 | * @mail zhoujunjie.9743@bytedance.com
22 | **/
23 |
24 | interface Task : ScheduleTask {
25 | override val mustMainThread: Boolean
26 | override val taskPriority: Int
27 | val result: TaskResult
28 | override fun run()
29 | }
30 |
31 | class TaskResult {
32 | lateinit var value: T
33 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/task/TaskManager.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.task
17 |
18 | import androidx.annotation.MainThread
19 | import androidx.annotation.WorkerThread
20 | import com.bytedance.blockframework.framework.config.BlockInit
21 | import com.bytedance.blockframework.framework.join.IBlockScene
22 | import com.bytedance.blockframework.framework.monitor.BlockLogger
23 | import com.bytedance.blockframework.framework.monitor.BlockMonitor
24 | import com.bytedance.blockframework.framework.monitor.TYPE_BLOCK_RUN_TASK
25 | import com.bytedance.blockframework.framework.monitor.currentTime
26 | import com.bytedance.blockframework.framework.monitor.logger
27 | import com.bytedance.blockframework.framework.performance.ThreadProcessor
28 | import com.bytedance.blockframework.framework.performance.HandlerProcessor
29 | import com.bytedance.blockframework.framework.utils.uploadException
30 | import java.util.PriorityQueue
31 |
32 | class TaskManager(private val scene: IBlockScene, private val allTaskMustRunOnMain: Boolean): ITaskManager {
33 |
34 | private val TAG = "TaskManager"
35 |
36 | private val managerName by lazy { this::class.java.simpleName + "_" + this.hashCode() }
37 |
38 | private var main: HandlerProcessor = HandlerProcessor(ThreadProcessor.main(), false)
39 | private var work: HandlerProcessor = HandlerProcessor(ThreadProcessor.work(), false)
40 |
41 | private val mainThreadTasks = PriorityQueue(20,
42 | Comparator { o1, o2 -> o2.taskPriority.compareTo(o1.taskPriority) })
43 | private val subThreadTasks = PriorityQueue(20,
44 | Comparator { o1, o2 -> o2.taskPriority.compareTo(o1.taskPriority) })
45 |
46 | private var allFinished: TasksFinished? = null
47 |
48 | private var isMainTasksFinish = false
49 | private var isSubTasksFinish = false
50 |
51 | private var allTasks = listOf()
52 |
53 | @Synchronized
54 | override fun addTask(tasks: List) {
55 | allTasks = tasks
56 | tasks.forEach {
57 | if (allTaskMustRunOnMain || it.mustMainThread) {
58 | mainThreadTasks.add(it)
59 | } else {
60 | subThreadTasks.add(it)
61 | }
62 | }
63 | isMainTasksFinish = mainThreadTasks.isEmpty()
64 | isSubTasksFinish = subThreadTasks.isEmpty()
65 | }
66 |
67 | @MainThread
68 | override fun handleTasks(mainFinished: TasksFinished?, subFinished: TasksFinished?, allFinished: TasksFinished?) {
69 | this.allFinished = allFinished
70 | val start = currentTime()
71 | BlockMonitor.record(scene.getName(), managerName, TYPE_BLOCK_RUN_TASK, "start_handle_tasks")
72 | if (!subThreadTasks.isEmpty()) {
73 | work.post {
74 | processTaskInSubThread(subFinished, mainFinished, start)
75 | }
76 | }
77 | if (!mainThreadTasks.isEmpty()) {
78 | processMainThreadTasks(mainFinished, start)
79 | }
80 | }
81 |
82 | @MainThread
83 | private fun processMainThreadTasks(mainFinished: TasksFinished?, start: Long) {
84 | val resultTasks = mutableListOf()
85 | val startRun = currentTime()
86 | BlockMonitor.record(scene.getName(), managerName, TYPE_BLOCK_RUN_TASK, "start_handle_main_tasks")
87 | do {
88 | val targetTask: ScheduleTask? = mainThreadTasks.poll()
89 | targetTask?.let {
90 | it.run()
91 | resultTasks.add(it)
92 | }
93 | if (mainThreadTasks.isEmpty()) {
94 | BlockMonitor.record(scene.getName(), managerName, TYPE_BLOCK_RUN_TASK, "mainTasks_end", currentTime() - startRun)
95 | mainFinished?.invoke(resultTasks)
96 | isMainTasksFinish = true
97 | if (isSubTasksFinish) {
98 | allFinished?.invoke(allTasks)
99 | BlockMonitor.record(scene.getName(), managerName, TYPE_BLOCK_RUN_TASK, "allTask_main_end", currentTime() - start)
100 | }
101 | }
102 | } while (!mainThreadTasks.isEmpty())
103 | }
104 |
105 | @WorkerThread
106 | private fun processTaskInSubThread(subFinished: TasksFinished?, mainFinished: TasksFinished?, start: Long) {
107 | val resultTasks = mutableListOf()
108 | val failTasks = mutableListOf()
109 | val startRun = currentTime()
110 | BlockMonitor.record(scene.getName(), managerName, TYPE_BLOCK_RUN_TASK, "start_handle_sub_tasks")
111 | do {
112 | val targetTask: ScheduleTask? = subThreadTasks.poll()
113 | runCatching {
114 | targetTask?.let {
115 | it.run()
116 | resultTasks.add(it)
117 | }
118 | }.onFailure {
119 | targetTask?.let { it1 ->
120 | failTasks.add(it1)
121 | }
122 | handleException(targetTask, it)
123 | }
124 | if (subThreadTasks.isEmpty()) {
125 | if (failTasks.size > 0) {
126 | main.post {
127 | mainThreadTasks.addAll(failTasks)
128 | isMainTasksFinish = false
129 | processMainThreadTasks(mainFinished, -1)
130 | }
131 | }
132 | BlockMonitor.record(scene.getName(), managerName, TYPE_BLOCK_RUN_TASK, "subTasks_end", currentTime() - startRun)
133 | main.post {
134 | subFinished?.invoke(resultTasks)
135 | isSubTasksFinish = true
136 | if (isMainTasksFinish) {
137 | BlockMonitor.record(scene.getName(), managerName, TYPE_BLOCK_RUN_TASK, "allTask_sub_end", currentTime() - start)
138 | allFinished?.invoke(allTasks)
139 | }
140 | }
141 | }
142 | } while (!subThreadTasks.isEmpty())
143 | }
144 |
145 | override fun clear() {
146 | mainThreadTasks.clear()
147 | subThreadTasks.clear()
148 | }
149 |
150 | private fun handleException(task: ScheduleTask?, t: Throwable) {
151 | if (task is BlockViewBuildTask) {
152 | if (!BlockInit.logOptEnable() || BlockLogger.debug()) {
153 | logger(TAG, "${task.getBlockScene()} build UI Exception in ${Thread.currentThread().name}")
154 | }
155 | uploadException(t, true)
156 | BlockInit.recordException(t)
157 | }
158 | }
159 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/utils/BlockDsl.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.utils
17 |
18 | @DslMarker
19 | annotation class BlockDsl
20 |
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/utils/BlockExt.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.framework.utils
17 |
18 | import android.os.Looper
19 | import com.bytedance.blockframework.framework.base.BaseBlock
20 | import com.bytedance.blockframework.framework.config.BlockInit
21 | import com.bytedance.blockframework.framework.core.BlockUnitHandler
22 | import com.bytedance.blockframework.framework.core.message.TreeBlockMessageCenter
23 | import com.bytedance.blockframework.framework.join.IBlockDepend
24 | import com.bytedance.blockframework.framework.monitor.BlockLogger
25 | import com.bytedance.blockframework.framework.performance.ThreadProcessor
26 | import com.bytedance.blockframework.interaction.BaseBlockMessageCenter
27 | import kotlin.properties.ReadOnlyProperty
28 | import kotlin.reflect.KProperty
29 |
30 | /**
31 | *
32 | * @author Created by zhoujunjie on 2023/8/9
33 | * @mail zhoujunjie.9743@bytedance.com
34 | **/
35 |
36 | fun getDefaultCenter() = if (BlockInit.useTreeMessageCenterEnable()) TreeBlockMessageCenter() else BaseBlockMessageCenter()
37 |
38 | fun BaseBlock<*, *>.blockHandler(): BlockUnitHandler {
39 | return blockContext.findBlockHandler(this)
40 | }
41 |
42 | inline fun BaseBlock<*, *>.blockService(): ReadOnlyProperty, T?> {
43 | return object : ReadOnlyProperty, T?> {
44 | private var cacheV: T? = null
45 |
46 | override fun getValue(thisRef: BaseBlock<*, *>, property: KProperty<*>): T? {
47 | if (cacheV == null) {
48 | cacheV = getBlockService(T::class.java)
49 | }
50 | return cacheV
51 | }
52 | }
53 | }
54 |
55 | inline fun BaseBlock<*, *>.findDepend(): ReadOnlyProperty, T> {
56 | return object : ReadOnlyProperty, T> {
57 | private lateinit var cacheV: T
58 |
59 | override fun getValue(thisRef: BaseBlock<*, *>, property: KProperty<*>): T {
60 | if (!::cacheV.isInitialized) {
61 | cacheV = blockContext.findDepend(T::class.java)
62 | }
63 | return cacheV
64 | }
65 | }
66 | }
67 |
68 | fun BaseBlock<*, *>.traverseBlock(action: (block: BaseBlock<*, *>) -> Unit) {
69 | action(this)
70 | this.blockHandler().getChildBlocks().forEach {
71 | it.traverseBlock(action)
72 | }
73 | }
74 |
75 | fun BaseBlock<*, *>.traverseSubBlock(action: (block: BaseBlock<*, *>) -> Unit) {
76 | this.blockHandler().getChildBlocks().forEach {
77 | it.traverseBlock(action)
78 | }
79 | }
80 |
81 | fun BaseBlock<*, *>.afterBind(action: () -> Unit) {
82 | blockContext.addAfterBindTask(action)
83 | }
84 |
85 | fun syncInvoke(action: () -> Unit) {
86 | if (Looper.getMainLooper() == Looper.myLooper()) {
87 | action()
88 | } else {
89 | ThreadProcessor.main().post(action)
90 | }
91 | }
92 |
93 | fun uploadException(exception: Throwable, needThrow: Boolean) {
94 | if (!BlockLogger.debug()) {
95 | return
96 | }
97 |
98 | if (needThrow) {
99 | throw exception
100 | }
101 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/framework/utils/LifecycleUtil.kt:
--------------------------------------------------------------------------------
1 | package com.bytedance.blockframework.framework.utils
2 |
3 | import androidx.lifecycle.Lifecycle
4 | import com.bytedance.blockframework.contract.AbstractLifecycleBlock
5 | import com.bytedance.blockframework.framework.base.BaseBlock
6 | import com.bytedance.blockframework.framework.monitor.logger
7 |
8 | /**
9 | * description:
10 | *
11 | * @author Created by zhoujunjie on 2024/11/15
12 | * @mail zhoujunjie.9743@bytedance.com
13 | **/
14 |
15 | object LifecycleUtil {
16 |
17 | fun handleLifecycleState(state: Lifecycle.State, block: BaseBlock<*, *>) {
18 | logger("LifecycleUtil", "$state --- ${block.getBlockKey()}---${block.lifecycle.currentState}")
19 | when (state) {
20 | Lifecycle.State.CREATED -> {
21 | if (block.lifecycle.currentState < Lifecycle.State.CREATED) {
22 | block.performCreate()
23 | } else {
24 | if (block.lifecycle.currentState > Lifecycle.State.STARTED) {
25 | block.performPause()
26 | }
27 | if (block.lifecycle.currentState > Lifecycle.State.CREATED) {
28 | block.performStop()
29 | }
30 | }
31 | }
32 |
33 | Lifecycle.State.STARTED -> {
34 | if (block.lifecycle.currentState < Lifecycle.State.STARTED) {
35 | if ((block as AbstractLifecycleBlock).lifecycle.currentState < Lifecycle.State.CREATED) {
36 | block.performCreate()
37 | }
38 | block.performStart()
39 | } else if ((block as AbstractLifecycleBlock).lifecycle.currentState > Lifecycle.State.STARTED) {
40 | block.performPause()
41 | }
42 | }
43 |
44 | Lifecycle.State.RESUMED -> {
45 | if (block.lifecycle.currentState < Lifecycle.State.RESUMED) {
46 | if (block.lifecycle.currentState < Lifecycle.State.CREATED) {
47 | block.performCreate()
48 | }
49 | if (block.lifecycle.currentState < Lifecycle.State.STARTED) {
50 | block.performStart()
51 | }
52 | block.performResume()
53 | }
54 | }
55 |
56 | Lifecycle.State.DESTROYED -> {
57 | if (block.lifecycle.currentState >= Lifecycle.State.RESUMED) {
58 | block.performPause()
59 | }
60 | if (block.lifecycle.currentState >= Lifecycle.State.STARTED) {
61 | block.performStop()
62 | }
63 | if (block.lifecycle.currentState >= Lifecycle.State.CREATED) {
64 | block.performDestroy()
65 | }
66 | }
67 |
68 | else -> Unit
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/interaction/BaseBlockMessageCenter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.interaction
17 |
18 | import com.bytedance.blockframework.contract.AbstractBlock
19 | import com.bytedance.blockframework.contract.BlockImplWrapper
20 | import com.bytedance.blockframework.framework.base.BaseBlock
21 | import com.bytedance.blockframework.framework.config.BlockInit
22 | import com.bytedance.blockframework.framework.monitor.BlockLogger
23 | import com.bytedance.blockframework.framework.utils.uploadException
24 |
25 | /**
26 | * @Author Wei Zijie
27 | * @Date 2020/12/28
28 | * @Description
29 | */
30 | open class BaseBlockMessageCenter : IBlockMessageCenter {
31 |
32 | val TAG = "BaseBlockMessageCenter"
33 |
34 | //
35 | override var stateProviderMap: MutableMap, IStatusProvider> = mutableMapOf()
36 | override fun registerStateProvider(provider: IStatusProvider) {
37 | val stateClass = provider.stateClass
38 | if (!stateProviderMap.contains(stateClass)) {
39 | stateProviderMap[stateClass] = provider
40 | } else {
41 | if (!BlockInit.logOptEnable() || BlockLogger.debug()) {
42 | uploadException(RuntimeException("registerStateProvider $provider for state $stateClass already exists"), true)
43 | }
44 | }
45 | }
46 |
47 | override fun unregisterStateProvider(provider: IStatusProvider) {
48 | val stateClass = provider.stateClass
49 | if (stateProviderMap.contains(stateClass)) {
50 | stateProviderMap.remove(stateClass)
51 | }
52 | }
53 |
54 | override fun queryState(stateClass: Class): T? {
55 | return if (stateProviderMap.contains(stateClass)) {
56 | stateProviderMap[stateClass]?.state as T?
57 | } else {
58 | if (!BlockInit.logOptEnable() || BlockLogger.debug()) {
59 | uploadException(RuntimeException("queryState $stateClass not find"), true)
60 | }
61 | null
62 | }
63 | }
64 | //
65 |
66 | //
67 | open protected var eventManager: EventManager = EventManager()
68 | override fun subscribeEvent(observer: IObserver, eventClass: Class) {
69 | eventManager.registerObserver(
70 | observer = observer as IObserver,
71 | eventClass = eventClass as Class
72 | )
73 | }
74 |
75 | override fun unregisterObserver(observer: IObserver) {
76 | eventManager.unregisterObserver(observer)
77 | }
78 |
79 | override fun notifyEvent(block: StateAndEventModel, event: T): Boolean {
80 | return eventManager.notifyEvent(block, event)
81 | }
82 |
83 | @Deprecated("ignore")
84 | override fun notifyEvent(event: T): Boolean {
85 | return eventManager.notifyEvent(event = event)
86 | }
87 |
88 | override fun notifyEventForResult(event: T): Boolean {
89 | return eventManager.notifyEventForResult(event)
90 | }
91 |
92 | override fun notifyEventForResult(block: StateAndEventModel, event: T): Boolean {
93 | return notifyEventForResult(event)
94 | }
95 | //
96 |
97 | override var blockServiceMap: MutableMap, BlockImplWrapper> = mutableMapOf()
98 | override fun registerService(klass: Class, blockImplWrapper: BlockImplWrapper) {
99 | if (blockServiceMap.containsKey(klass)) {
100 | if (!BlockInit.logOptEnable() || BlockLogger.debug()) {
101 | uploadException(RuntimeException("registerService $klass already exists"), true)
102 | }
103 | }
104 | blockServiceMap[klass] = blockImplWrapper
105 | }
106 |
107 | override fun queryService(block: AbstractBlock, klass: Class, activeIfNeed: Boolean): T? {
108 | return queryService(klass)
109 | }
110 |
111 | @Deprecated("ignore")
112 | override fun queryService(klass: Class, activeIfNeed: Boolean): T? {
113 | if (blockServiceMap.contains(klass)) {
114 | val target = blockServiceMap[klass]?.impl
115 | if(activeIfNeed) (target as? BaseBlock<*,*>)?.activeIfNeed()
116 | return target as T?
117 | }
118 |
119 | for (implWrapper in blockServiceMap.values) {
120 | if (klass.isInstance(implWrapper.impl)) {
121 | return implWrapper.impl as T?
122 | }
123 | }
124 |
125 | return null
126 | }
127 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/interaction/CoreTreeLayerBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.interaction
17 |
18 | interface CoreTreeLayerBlock {
19 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/interaction/EventManager.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.interaction
17 |
18 | import com.bytedance.blockframework.contract.AbstractBlock
19 |
20 | /**
21 | * @Author Wei Zijie
22 | * @Date 2020/12/23
23 | * @Description
24 | */
25 | abstract class Event(val canIntercept: Boolean = false)
26 |
27 | interface IObserver {
28 | fun onEvent(event: T): Boolean
29 | }
30 |
31 | interface IEventManager {
32 | fun registerObserver(observer: IObserver, eventClass: Class)
33 | fun unregisterObserver(observer: IObserver)
34 | fun notifyEvent(event: Event): Boolean
35 | fun notifyEvent(block: StateAndEventModel, event: Event): Boolean
36 | fun notifyEventForResult(event: Event): Boolean
37 | }
38 |
39 | open class EventManager: IEventManager {
40 | private val TAG: String = "EventManager"
41 |
42 | protected val eventToObserverMap: MutableMap, MutableList>> = mutableMapOf()
43 | protected val observerToEventMap: MutableMap, MutableList>> = mutableMapOf()
44 |
45 | /**
46 | * Make observer observe event of Class type
47 | */
48 | override fun registerObserver(observer: IObserver, eventClass: Class) {
49 | // update event to observer map
50 | val observers = eventToObserverMap[eventClass] ?: run {
51 | mutableListOf>().apply {
52 | eventToObserverMap[eventClass] = this
53 | }
54 | }
55 | if (!observers.contains(observer)) {
56 | observers.add(observer)
57 | }
58 | // update observer to event map
59 | val events = observerToEventMap[observer] ?: run {
60 | mutableListOf>().apply {
61 | observerToEventMap[observer] = this
62 | }
63 | }
64 | if (!events.contains(eventClass)) {
65 | events.add(eventClass)
66 | }
67 | }
68 |
69 | /**
70 | * Cancel observer observe any event
71 | */
72 | override fun unregisterObserver(observer: IObserver) {
73 | if (!observerToEventMap.containsKey(observer)) {
74 | return
75 | }
76 | observerToEventMap[observer]?.forEach {
77 | eventToObserverMap[it]?.remove(observer)
78 | }
79 | observerToEventMap.remove(observer)
80 | }
81 |
82 | /**
83 | * Notify event
84 | */
85 | override fun notifyEvent(event: Event): Boolean {
86 | val observers = eventToObserverMap[event.javaClass] ?: return false
87 | for (observer in observers) {
88 | if (observer is AbstractBlock) {
89 | if (!observer.isActive()) {
90 | continue
91 | }
92 | }
93 | val intercept = observer.onEvent(event)
94 | if (intercept && event.canIntercept) {
95 | break
96 | }
97 | }
98 | return true
99 | }
100 |
101 | override fun notifyEvent(block: StateAndEventModel, event: Event): Boolean {
102 | return notifyEvent(event)
103 | }
104 |
105 | override fun notifyEventForResult(event: Event): Boolean {
106 | val observers = eventToObserverMap[event.javaClass] ?: return false
107 | for (observer in observers) {
108 | if (observer is AbstractBlock) {
109 | if (!observer.isActive()) {
110 | continue
111 | }
112 | }
113 | val intercept = observer.onEvent(event)
114 | if (intercept && event.canIntercept) {
115 | return true
116 | }
117 | }
118 | return false
119 | }
120 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/interaction/IBlockMessageCenter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.interaction
17 |
18 | import com.bytedance.blockframework.contract.AbstractBlock
19 | import com.bytedance.blockframework.contract.BlockImplWrapper
20 |
21 |
22 | /**
23 | * @Author Wei Zijie
24 | * @Date 2020/12/20
25 | * @Description
26 | */
27 | interface IBlockMessageCenter {
28 |
29 | val stateProviderMap: MutableMap, IStatusProvider>
30 | fun registerStateProvider(provider: IStatusProvider)
31 | fun unregisterStateProvider(provider: IStatusProvider)
32 | fun queryState(stateClass: Class): T?
33 | fun subscribeEvent(observer: IObserver, eventClass: Class)
34 | fun unregisterObserver(observer: IObserver)
35 |
36 | @Deprecated("use Block.notifyEvent(event: T) or notifyEvent(block: StateAndEventModel, event: T)")
37 | fun notifyEvent(event: T): Boolean
38 | fun notifyEvent(block: StateAndEventModel, event: T): Boolean
39 | fun notifyEventForResult(event: T): Boolean
40 | fun notifyEventForResult(block: StateAndEventModel, event: T): Boolean
41 |
42 | var blockServiceMap: MutableMap, BlockImplWrapper>
43 | fun registerService(klass: Class, blockImplWrapper: BlockImplWrapper)
44 | @Deprecated("use block.getBlockService(klass: Class) or queryService(block: AbstractBlock, klass: Class)")
45 | fun queryService(klass: Class, activeIfNeed: Boolean = true): T?
46 | fun queryService(block: AbstractBlock, klass: Class, activeIfNeed: Boolean = true): T?
47 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/interaction/State.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.interaction
17 |
18 | /**
19 | * @Author Wei Zijie
20 | * @Date 2020/12/23
21 | * @Description
22 | */
23 | abstract class State
24 |
25 | interface IStatusProvider {
26 | val stateClass: Class
27 | val state: T
28 | }
29 |
30 | abstract class StatusProvider(private val _stateClass: Class) : IStatusProvider {
31 | final override val stateClass: Class
32 | get() = _stateClass
33 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/interaction/StateAndEventModel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.interaction
17 |
18 | /**
19 | * @Author Wei Zijie
20 | * @Date 2020/12/28
21 | * @Description
22 | */
23 | abstract class StateAndEventModel {
24 |
25 | open lateinit var blockBlockMessageCenter: IBlockMessageCenter
26 |
27 | abstract fun onPrepared()
28 |
29 | abstract fun onUnRegister()
30 |
31 | //
32 | val providers: MutableList> = mutableListOf()
33 | fun shareState(provider: IStatusProvider) {
34 | if (providers.contains(provider)) {
35 | throw RuntimeException("provider $provider already exists")
36 | }
37 | providers.add(provider as IStatusProvider)
38 | blockBlockMessageCenter.registerStateProvider(provider)
39 | }
40 | fun queryStatus(stateClass: Class): T? {
41 | return blockBlockMessageCenter.queryState(stateClass = stateClass)
42 | }
43 | //
44 |
45 | //
46 | val observers: MutableList> = mutableListOf()
47 | open fun subscribe(observer: IObserver, eventClass: Class) {
48 | if (!observers.contains(observer)) {
49 | observers.add(observer as IObserver)
50 | }
51 | blockBlockMessageCenter.subscribeEvent(observer, eventClass)
52 | }
53 |
54 | fun notifyEvent(event: Event) {
55 | blockBlockMessageCenter.notifyEvent(this, event = event)
56 | }
57 | //
58 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/interaction/TreeConstrainBlockMessageCenter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.interaction
17 |
18 | import com.bytedance.blockframework.contract.AbstractBlock
19 | import com.bytedance.blockframework.contract.BlockImplWrapper
20 | import com.bytedance.blockframework.framework.base.BaseBlock
21 | import com.bytedance.blockframework.framework.config.BlockInit
22 | import com.bytedance.blockframework.framework.monitor.BlockLogger
23 | import com.bytedance.blockframework.framework.utils.blockHandler
24 | import com.bytedance.blockframework.framework.utils.uploadException
25 |
26 | /**
27 | * Use [CoreTreeLayerBlock] as a hierarchical node
28 | * to restrict the [MessageCenter] with capability-dependent flow direction
29 | */
30 | abstract class TreeConstrainBlockMessageCenter: BaseBlockMessageCenter() {
31 |
32 |
33 | override fun registerService(klass: Class, blockImplWrapper: BlockImplWrapper) {
34 | var block = blockImplWrapper.impl as? BaseBlock<*, *>
35 | if (block?.parent == null) {
36 | super.registerService(klass, blockImplWrapper)
37 | return
38 | } else {
39 | block.parent?.registerService(klass, blockImplWrapper)
40 | }
41 | }
42 |
43 | override fun queryService(block: AbstractBlock, klass: Class, activeIfNeed: Boolean): T? {
44 | if (block !is BaseBlock<*, *>) return super.queryService(klass, activeIfNeed)
45 | var res: T? = null
46 | if (block.parent == null) {
47 | res = queryService(klass, activeIfNeed)
48 | if(res != null) return res
49 | }
50 |
51 | res = block.parent?.queryService(klass, activeIfNeed)
52 | if(res != null) return res
53 |
54 |
55 | var nextTargetCoreTreeBlock: CoreTreeLayerBlock? = null
56 | (block.parent ?: block.blockHandler()).getChildBlocks().forEach {
57 | if(it is CoreTreeLayerBlock) {
58 | nextTargetCoreTreeBlock = it
59 | return@forEach
60 | }
61 | }
62 | res = (nextTargetCoreTreeBlock as? BaseBlock<*, *>)?.blockHandler()?.queryService(klass, activeIfNeed)
63 | if(res != null) return res
64 |
65 | val result = queryTargetCoreTreeService((nextTargetCoreTreeBlock as? BaseBlock<*, *>), klass, activeIfNeed)
66 | if (result == null) {
67 | if (!BlockInit.logOptEnable() || BlockLogger.debug()) {
68 | uploadException(RuntimeException("TreeConstrainBlockMessageCenter queryService $klass not find"), false)
69 | }
70 | if (BlockLogger.debug() && BlockInit.enableDebugDependencyCheck()) {
71 | var rootBlock = block.parent?.attachBlock
72 | while (rootBlock?.parent != null) {
73 | rootBlock = rootBlock.parent?.attachBlock
74 | }
75 | val resultFromAllBlock = rootBlock?.let { queryService(it, klass) }
76 | if (resultFromAllBlock != null) {
77 | handleUnexpectedServiceDepend(block, klass)
78 | }
79 | }
80 | }
81 | if (activeIfNeed) (result as? BaseBlock<*, *>)?.activeIfNeed()
82 | return result
83 | }
84 |
85 | open fun handleUnexpectedServiceDepend(block: BaseBlock<*, *>?, klass: Class<*>) {}
86 |
87 | private fun queryTargetCoreTreeService(block: BaseBlock<*, *>?, klass: Class, activeIfNeed: Boolean): T? {
88 | block ?: return null
89 | var res: T? = null
90 | var nextTargetCoreTreeBlock: CoreTreeLayerBlock? = null
91 | block.blockHandler()?.getChildBlocks()?.forEach {
92 | if(it is CoreTreeLayerBlock) {
93 | nextTargetCoreTreeBlock = it
94 | return@forEach
95 | }
96 | }
97 | nextTargetCoreTreeBlock ?: return null
98 | res = (nextTargetCoreTreeBlock as? BaseBlock<*, *>)?.blockHandler()?.queryService(klass, activeIfNeed)
99 | if(res != null) return res
100 |
101 | return queryTargetCoreTreeService(nextTargetCoreTreeBlock as? BaseBlock<*, *>, klass, activeIfNeed)
102 | }
103 |
104 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/interaction/TreeConstrainEventManager.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.interaction
17 |
18 | import com.bytedance.blockframework.framework.base.BaseBlock
19 | import com.bytedance.blockframework.framework.config.BlockInit
20 | import com.bytedance.blockframework.framework.monitor.BlockLogger
21 | import com.bytedance.blockframework.framework.utils.blockHandler
22 |
23 | /**
24 | * EventManager that restricts event flow
25 | */
26 | open class TreeConstrainEventManager: EventManager() {
27 |
28 | override fun registerObserver(observer: IObserver, eventClass: Class) {
29 | if (observer !is BaseBlock<*, *>) {
30 | super.registerObserver(observer, eventClass)
31 | return
32 | }
33 | if (observer.parent == null) {
34 | observer.blockHandler().registerObserver(observer, eventClass)
35 | return
36 | } else {
37 | observer.parent?.registerObserver(observer, eventClass)
38 | }
39 |
40 | }
41 |
42 | override fun notifyEvent(block: StateAndEventModel, event: Event): Boolean {
43 | if (block !is BaseBlock<*, *>) return super.notifyEvent(block, event)
44 | var pointerBlock = block as? BaseBlock<*, *>
45 | while (pointerBlock?.parent != null) {
46 | pointerBlock.parent?.notifyEvent(event)
47 | pointerBlock = pointerBlock.parent?.attachBlock
48 | }
49 | if (BlockLogger.debug() && BlockInit.enableDebugDependencyCheck()) {
50 | //测试环境抛出不合理的Event依赖
51 | if (findLowerObserver(block, event)){
52 | handleUnexpectedEventDepend(block, event)
53 | }
54 | }
55 | return true
56 | }
57 |
58 | open fun handleUnexpectedEventDepend(block: StateAndEventModel?, event: Event) {}
59 |
60 | private fun findLowerObserver(block: BaseBlock<*, *>?, event: Event): Boolean {
61 | block ?: return false
62 | var nextTargetCoreTreeBlock: CoreTreeLayerBlock? = null
63 | val supervisor = if (block is CoreTreeLayerBlock) block.blockHandler() else block.parent
64 | supervisor?.getChildBlocks()?.forEach {
65 | if(it is CoreTreeLayerBlock) {
66 | nextTargetCoreTreeBlock = it
67 | return@forEach
68 | }
69 | }
70 | nextTargetCoreTreeBlock ?: return false
71 | val observers = (nextTargetCoreTreeBlock as? BaseBlock<*, *>)?.blockHandler()?.eventToObserverMap?.get(event.javaClass)
72 | if (observers?.isNotEmpty() == true) return true
73 |
74 | return findLowerObserver(nextTargetCoreTreeBlock as? BaseBlock<*, *>, event)
75 | }
76 | }
--------------------------------------------------------------------------------
/blockframework/src/main/java/com/bytedance/blockframework/utils/Logger.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.blockframework.utils
17 |
18 | import android.util.Log
19 | import com.bytedance.blockframework.BuildConfig
20 |
21 | /**
22 | *
23 | * @author Created by zhoujunjie on 2024/8/26
24 | * @mail zhoujunjie.9743@bytedance.com
25 | **/
26 |
27 | object Logger {
28 | private const val TAG = "Logger"
29 |
30 | var logLevel = Log.DEBUG
31 |
32 | init {
33 | /**
34 | * Output less log when we are not in debug mode
35 | */
36 | if (!BuildConfig.DEBUG) {
37 | logLevel = Log.ERROR
38 | }
39 | }
40 |
41 | fun v(msg: String) {
42 | v(TAG, msg)
43 | }
44 |
45 | fun v(tag: String, msg: String) {
46 | if (isVerboseLoggable()) {
47 | Log.v(tag, msg)
48 | }
49 | }
50 |
51 | fun isVerboseLoggable(): Boolean {
52 | return logLevel <= Log.VERBOSE
53 | }
54 |
55 | fun d(msg: String) {
56 | d(TAG, msg)
57 | }
58 |
59 | fun d(tag: String, msg: String) {
60 | if (isDebugLoggable()) {
61 | Log.d(tag, msg)
62 | }
63 | }
64 |
65 | fun isDebugLoggable(): Boolean {
66 | return logLevel <= Log.DEBUG
67 | }
68 |
69 | fun i(msg: String) {
70 | i(TAG, msg)
71 | }
72 |
73 | fun i(tag: String, msg: String) {
74 | if (isInfoLoggable()) {
75 | Log.i(tag, msg)
76 | }
77 | }
78 |
79 | fun isInfoLoggable(): Boolean {
80 | return logLevel <= Log.INFO
81 | }
82 |
83 | fun w(msg: String) {
84 | w(TAG, msg)
85 | }
86 |
87 | fun w(tag: String, msg: String) {
88 | if (isWarnLoggable()) {
89 | Log.w(tag, msg)
90 | }
91 | }
92 |
93 | fun isWarnLoggable(): Boolean {
94 | return logLevel <= Log.WARN
95 | }
96 |
97 | fun e(msg: String) {
98 | e(TAG, msg)
99 | }
100 |
101 | fun e(tag: String, msg: String) {
102 | if (isErrorLoggable()) {
103 | Log.e(tag, msg)
104 | }
105 | }
106 |
107 | fun isErrorLoggable(): Boolean {
108 | return logLevel <= Log.ERROR
109 | }
110 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | mavenCentral()
9 | }
10 | dependencies {
11 | classpath ANDROID_GRADLE_PLUGIN
12 | classpath KOTLIN_PLUGIN
13 |
14 | // NOTE: Do not place your application dependencies here; they belong
15 | // in the individual module build.gradle files
16 | }
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | google()
22 | jcenter()
23 | mavenCentral()
24 | }
25 | }
26 |
27 | task clean(type: Delete) {
28 | delete rootProject.buildDir
29 | }
--------------------------------------------------------------------------------
/demo/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | }
5 |
6 | android {
7 | compileSdkVersion 31
8 | buildToolsVersion "30.0.1"
9 |
10 | defaultConfig {
11 | applicationId "com.bytedance.demo"
12 | minSdkVersion 24
13 | targetSdkVersion 30
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 | kotlinOptions {
30 | jvmTarget = '1.8'
31 | }
32 | }
33 |
34 | dependencies {
35 |
36 | implementation KOTLIN_LIB
37 | implementation ANDROIDX_LIB
38 | implementation RECYCLER_VIEW
39 | implementation CONSTRAINT_LIB
40 | implementation KOTLIN_ANDROID_EXTENSIONS
41 | implementation project(':blockframework')
42 | }
--------------------------------------------------------------------------------
/demo/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytedance/BlockFramework/d37e26ec8d28e95084ff5b7fb625d1a465fc43dd/demo/consumer-rules.pro
--------------------------------------------------------------------------------
/demo/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
--------------------------------------------------------------------------------
/demo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/BlockScene.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo
17 |
18 | import com.bytedance.blockframework.framework.join.IBlockScene
19 |
20 | /**
21 | * description:
22 | *
23 | * @author Created by zhoujunjie on 2024/8/28
24 | * @mail zhoujunjie.9743@bytedance.com
25 | **/
26 |
27 | enum class BlockScene : IBlockScene {
28 | DEMO_HOLDER_SCENE;
29 |
30 | override fun getName(): String {
31 | return name
32 | }
33 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/DemoActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo
17 |
18 | import android.os.Bundle
19 | import androidx.appcompat.app.AppCompatActivity
20 | import androidx.recyclerview.widget.LinearLayoutManager
21 | import androidx.recyclerview.widget.PagerSnapHelper
22 | import androidx.recyclerview.widget.RecyclerView
23 | import com.bytedance.demo.data.DemoCardData
24 | import com.bytedance.demo.util.DemoTestUtil
25 |
26 |
27 | /**
28 | * description:
29 | *
30 | * @author Created by zhoujunjie on 2024/8/26
31 | * @mail zhoujunjie.9743@bytedance.com
32 | **/
33 |
34 | class DemoActivity : AppCompatActivity() {
35 |
36 | private lateinit var recyclerView: RecyclerView
37 | private var adapter: DemoAdapter? = null
38 |
39 | override fun onCreate(savedInstanceState: Bundle?) {
40 | super.onCreate(savedInstanceState)
41 | setContentView(R.layout.demo_activity_layout)
42 | initView()
43 | }
44 |
45 | private fun initView() {
46 | recyclerView = findViewById(R.id.recycler_view)
47 | recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
48 | val snapHelper = PagerSnapHelper()
49 | snapHelper.attachToRecyclerView(recyclerView)
50 | adapter = DemoAdapter(recyclerView)
51 | recyclerView.adapter = adapter
52 | }
53 |
54 | override fun onStart() {
55 | super.onStart()
56 | adapter?.setData(DemoTestUtil.getTestData())
57 | }
58 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/DemoAdapter.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo
17 |
18 | import android.annotation.SuppressLint
19 | import android.view.LayoutInflater
20 | import android.view.ViewGroup
21 | import androidx.recyclerview.widget.RecyclerView
22 | import com.bytedance.demo.data.DemoCardData
23 |
24 | /**
25 | * description:
26 | *
27 | * @author Created by zhoujunjie on 2024/8/27
28 | * @mail zhoujunjie.9743@bytedance.com
29 | **/
30 |
31 | class DemoAdapter(val recyclerView: RecyclerView) : RecyclerView.Adapter() {
32 |
33 | private var data = arrayListOf()
34 |
35 | @SuppressLint("NotifyDataSetChanged")
36 | fun setData(data: ArrayList) {
37 | this.data = data
38 | notifyDataSetChanged()
39 | }
40 |
41 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DemoHolder {
42 | val itemView = LayoutInflater.from(parent.context).inflate(R.layout.demo_card_holder_layout, parent, false)
43 | return DemoHolder(itemView).apply {
44 | initCardBlock(recyclerView)
45 | }
46 | }
47 |
48 | override fun getItemCount(): Int {
49 | return data.size
50 | }
51 |
52 | override fun onBindViewHolder(holder: DemoHolder, position: Int) {
53 | holder.bindData(data[position])
54 | }
55 |
56 | override fun onViewDetachedFromWindow(holder: DemoHolder) {
57 | holder.onDetachedFromWindow()
58 | }
59 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/DemoHolder.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo
17 |
18 | import android.view.View
19 | import androidx.lifecycle.Lifecycle
20 | import androidx.lifecycle.LifecycleEventObserver
21 | import androidx.lifecycle.LifecycleOwner
22 | import androidx.recyclerview.widget.RecyclerView
23 | import com.bytedance.blockframework.framework.join.IBlockContext
24 | import com.bytedance.blockframework.framework.join.IBlockJoin
25 | import com.bytedance.blockframework.framework.join.IBlockScene
26 | import com.bytedance.blockframework.framework.join.bindBlockModel
27 | import com.bytedance.blockframework.framework.join.dispatchOnCreate
28 | import com.bytedance.blockframework.framework.join.dispatchOnDestroy
29 | import com.bytedance.blockframework.framework.join.dispatchOnPause
30 | import com.bytedance.blockframework.framework.join.dispatchOnResume
31 | import com.bytedance.blockframework.framework.join.dispatchOnStart
32 | import com.bytedance.blockframework.framework.join.dispatchOnStop
33 | import com.bytedance.blockframework.framework.join.getBlockContext
34 | import com.bytedance.blockframework.framework.join.initRootBlock
35 | import com.bytedance.blockframework.framework.join.registerDepend
36 | import com.bytedance.demo.block.DemoCardRootBlock
37 | import com.bytedance.demo.data.DemoCardData
38 | import com.bytedance.demo.data.DemoModel
39 | import com.bytedance.demo.depend.IHolderBlockDepend
40 |
41 | /**
42 | * description:
43 | *
44 | * @author Created by zhoujunjie on 2024/8/28
45 | * @mail zhoujunjie.9743@bytedance.com
46 | **/
47 |
48 | class DemoHolder(itemView: View) : RecyclerView.ViewHolder(itemView), IBlockJoin {
49 |
50 | private var ownerRecyclerView: RecyclerView? = null
51 | private lateinit var rootBlock: DemoCardRootBlock
52 |
53 | override val blockContext: IBlockContext by lazy {
54 | getBlockContext(blockScene)
55 | }
56 |
57 | override val blockScene: IBlockScene by lazy {
58 | BlockScene.DEMO_HOLDER_SCENE
59 | }
60 |
61 | private val holderDepend: IHolderBlockDepend = object : IHolderBlockDepend {
62 | override fun enableAsyncBind(): Boolean {
63 | return true
64 | }
65 |
66 | override fun getHolderView(): View {
67 | return itemView
68 | }
69 | }
70 |
71 | fun initCardBlock(recyclerView: RecyclerView) {
72 | ownerRecyclerView = recyclerView
73 | rootBlock = DemoCardRootBlock(itemView, blockContext).apply {
74 | registerDepend(holderDepend)
75 | }
76 | initRootBlock(itemView.context, rootBlock)
77 | dispatchOnCreate()
78 | dispatchOnStart()
79 | dispatchOnResume()
80 | observeLifeCycle()
81 | }
82 |
83 | private fun observeLifeCycle() {
84 | (itemView.context as? LifecycleOwner)?.lifecycle?.addObserver(
85 | object : LifecycleEventObserver {
86 | override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
87 | when (event) {
88 | Lifecycle.Event.ON_CREATE -> dispatchOnCreate()
89 | Lifecycle.Event.ON_START -> dispatchOnStart()
90 | Lifecycle.Event.ON_RESUME -> dispatchOnResume()
91 | Lifecycle.Event.ON_PAUSE -> dispatchOnPause()
92 | Lifecycle.Event.ON_STOP -> dispatchOnStop()
93 | Lifecycle.Event.ON_DESTROY -> dispatchOnDestroy()
94 | else -> {}
95 | }
96 | }
97 | }
98 | )
99 | }
100 |
101 | fun onDetachedFromWindow() {
102 | dispatchOnStop()
103 | dispatchOnDestroy()
104 | }
105 |
106 | fun bindData(data: DemoCardData) {
107 | bindBlockModel(DemoModel(data))
108 | }
109 |
110 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/block/BottomInfoBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo.block
17 |
18 | import android.annotation.SuppressLint
19 | import android.graphics.Typeface
20 | import android.view.View
21 | import android.widget.ImageView
22 | import android.widget.TextView
23 | import com.bytedance.blockframework.framework.async.AsyncUIBlock
24 | import com.bytedance.blockframework.framework.async.SyncInvoke
25 | import com.bytedance.blockframework.framework.join.IBlockContext
26 | import com.bytedance.blockframework.framework.utils.blockService
27 | import com.bytedance.blockframework.framework.utils.findDepend
28 | import com.bytedance.blockframework.interaction.Event
29 | import com.bytedance.demo.R
30 | import com.bytedance.demo.data.DemoCardData
31 | import com.bytedance.demo.data.DemoModel
32 | import com.bytedance.demo.depend.IHolderBlockDepend
33 | import com.bytedance.demo.event.ChangFontThemeEvent
34 | import com.bytedance.demo.service.IMainContentBlockService
35 | import com.bytedance.demo.util.FontType
36 |
37 | /**
38 | * description:
39 | *
40 | * @author Created by zhoujunjie on 2024/8/29
41 | * @mail zhoujunjie.9743@bytedance.com
42 | **/
43 |
44 | class BottomInfoBlock(blockContext: IBlockContext) :
45 | AsyncUIBlock(blockContext) {
46 |
47 | private val holderDepend by findDepend()
48 |
49 | private val mainContentBlock : IMainContentBlockService? by blockService()
50 |
51 | private lateinit var avatarView: ImageView
52 | private lateinit var userView: TextView
53 | private lateinit var titleView: TextView
54 |
55 | override fun layoutResource(): Int {
56 | return R.layout.demo_bottom_info_block_layout
57 | }
58 |
59 | override fun onViewCreated(view: View) {
60 | super.onViewCreated(view)
61 | initView(view)
62 | }
63 |
64 | private fun initView(view: View) {
65 | avatarView = view.findViewById(R.id.avatar)
66 | userView = view.findViewById(R.id.user_name)
67 | titleView = view.findViewById(R.id.title)
68 | avatarView.setOnClickListener {
69 | mainContentBlock?.changeMainContent("On Avatar Click!")
70 | }
71 | userView.setOnClickListener {
72 | mainContentBlock?.changeMainContent("On UserName Click!")
73 | }
74 | titleView.setOnClickListener {
75 | mainContentBlock?.changeMainContent("On Title Click!")
76 | }
77 | }
78 |
79 | override fun enableAsyncBind(): Boolean {
80 | return holderDepend.enableAsyncBind()
81 | }
82 |
83 | @SuppressLint("UseCompatLoadingForDrawables")
84 | override fun asyncBind(model: DemoModel?, syncInvoke: SyncInvoke) {
85 | syncInvoke {
86 | avatarView.setImageDrawable(
87 | context.resources.getDrawable(
88 | model?.data?.avatarImg ?: R.color.content_1
89 | )
90 | )
91 | userView.text = model?.data?.userName
92 | titleView.text = model?.data?.title
93 | }
94 | }
95 |
96 | override fun onRegister() {
97 | subscribe(this, ChangFontThemeEvent::class.java)
98 | }
99 |
100 | override fun onEvent(event: Event): Boolean {
101 | when (event) {
102 | is ChangFontThemeEvent -> {
103 | when (event.type) {
104 | FontType.Normal -> {
105 | userView.typeface = Typeface.defaultFromStyle(Typeface.NORMAL)
106 | titleView.typeface = Typeface.defaultFromStyle(Typeface.NORMAL)
107 | }
108 | FontType.Bold -> {
109 | userView.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
110 | titleView.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
111 | }
112 | }
113 | }
114 | }
115 | return super.onEvent(event)
116 | }
117 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/block/DemoCardRootBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo.block
17 |
18 | import android.view.View
19 | import com.bytedance.blockframework.framework.base.IUIBlock
20 | import com.bytedance.blockframework.framework.base.UIBlock
21 | import com.bytedance.blockframework.framework.core.BlockGenerator
22 | import com.bytedance.blockframework.framework.join.IBlockContext
23 | import com.bytedance.demo.R
24 | import com.bytedance.demo.data.DemoCardData
25 | import com.bytedance.demo.data.DemoModel
26 |
27 | /**
28 | * description:
29 | *
30 | * @author Created by zhoujunjie on 2024/8/29
31 | * @mail zhoujunjie.9743@bytedance.com
32 | **/
33 |
34 | class DemoCardRootBlock(private val rootView: View, blockContext: IBlockContext) :
35 | UIBlock(blockContext) {
36 |
37 | override fun layoutResource(): Int {
38 | return IUIBlock.USE_PARENT_LAYOUT
39 | }
40 |
41 | override fun onCreateView(parent: View?): View {
42 | return rootView
43 | }
44 |
45 | override fun generateSubBlocks(generator: BlockGenerator) {
46 | generator.generate {
47 | addBlock {
48 | instance = {
49 | MainContentBlock(blockContext)
50 | }
51 | parentId = R.id.main_content_block_container
52 | // Indicates that the UI must be created on the main thread
53 | createUIOnMainThread = true
54 | }
55 | addBlock {
56 | instance = {
57 | BottomInfoBlock(blockContext)
58 | }
59 | parentId = R.id.bottom_info_block_container
60 | // reduce layout levels
61 | replaceParent = true
62 | }
63 | addBlock {
64 | instance = {
65 | RightInteractBlock(blockContext)
66 | }
67 | parentId = R.id.right_interact_block_container
68 | replaceParent = true
69 | }
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/block/MainContentBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo.block
17 |
18 | import android.annotation.SuppressLint
19 | import android.view.View
20 | import android.widget.Button
21 | import android.widget.TextView
22 | import android.widget.Toast
23 | import com.bytedance.blockframework.framework.async.AsyncUIBlock
24 | import com.bytedance.blockframework.framework.join.IBlockContext
25 | import com.bytedance.blockframework.framework.utils.findDepend
26 | import com.bytedance.demo.R
27 | import com.bytedance.demo.data.DemoCardData
28 | import com.bytedance.demo.data.DemoModel
29 | import com.bytedance.demo.depend.IHolderBlockDepend
30 | import com.bytedance.demo.event.ChangFontThemeEvent
31 | import com.bytedance.demo.service.IMainContentBlockService
32 | import com.bytedance.demo.util.FontType
33 |
34 | /**
35 | * description:
36 | *
37 | * @author Created by zhoujunjie on 2024/8/29
38 | * @mail zhoujunjie.9743@bytedance.com
39 | **/
40 |
41 | class MainContentBlock(blockContext: IBlockContext) :
42 | AsyncUIBlock(blockContext),
43 | IMainContentBlockService
44 | {
45 |
46 | private val holderDepend by findDepend()
47 |
48 | private var mainContentRoot: View? = null
49 | private var mainContentText: TextView? = null
50 | private var mainButton: Button? = null
51 | private var currentFontType: FontType = FontType.Normal
52 |
53 | override fun layoutResource(): Int {
54 | return R.layout.demo_main_content_block_layout
55 | }
56 |
57 | override fun onViewCreated(view: View) {
58 | mainContentRoot = findViewById(R.id.main_content_root)
59 | mainContentText = findViewById(R.id.content)
60 | mainButton = findViewById(R.id.button)
61 | mainButton?.setOnClickListener {
62 | when (currentFontType) {
63 | FontType.Normal -> {
64 | notifyEvent(ChangFontThemeEvent(FontType.Bold))
65 | currentFontType = FontType.Bold
66 | Toast.makeText(context, "Switch Bold Font Theme!", Toast.LENGTH_SHORT).show()
67 | }
68 | FontType.Bold -> {
69 | notifyEvent(ChangFontThemeEvent(FontType.Normal))
70 | currentFontType = FontType.Normal
71 | Toast.makeText(context, "Switch Normal Font Theme!", Toast.LENGTH_SHORT).show()
72 | }
73 | }
74 | }
75 | }
76 |
77 | override fun enableAsyncBind(): Boolean {
78 | return holderDepend.enableAsyncBind()
79 | }
80 |
81 | override fun changeMainContent(content: String) {
82 | mainContentText?.text = content
83 | }
84 |
85 | @SuppressLint("SetTextI18n")
86 | override fun syncBind(model: DemoModel?) {
87 | mainContentRoot?.setBackgroundColor(context.resources.getColor(model?.data?.mainContentBg ?: 0))
88 | mainContentText?.text = "This is Main Content!"
89 | }
90 |
91 | override fun defineBlockService(): Class<*>? {
92 | return IMainContentBlockService::class.java
93 | }
94 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/block/RightInteractBlock.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo.block
17 |
18 | import android.graphics.Typeface
19 | import android.view.View
20 | import android.widget.TextView
21 | import com.bytedance.blockframework.framework.async.AsyncUIBlock
22 | import com.bytedance.blockframework.framework.async.SyncInvoke
23 | import com.bytedance.blockframework.framework.join.IBlockContext
24 | import com.bytedance.blockframework.framework.utils.blockService
25 | import com.bytedance.blockframework.framework.utils.findDepend
26 | import com.bytedance.blockframework.interaction.Event
27 | import com.bytedance.demo.R
28 | import com.bytedance.demo.data.DemoCardData
29 | import com.bytedance.demo.data.DemoModel
30 | import com.bytedance.demo.depend.IHolderBlockDepend
31 | import com.bytedance.demo.event.ChangFontThemeEvent
32 | import com.bytedance.demo.service.IMainContentBlockService
33 | import com.bytedance.demo.util.FontType
34 |
35 | /**
36 | * description:
37 | *
38 | * @author Created by zhoujunjie on 2024/8/29
39 | * @mail zhoujunjie.9743@bytedance.com
40 | **/
41 |
42 | class RightInteractBlock(blockContext: IBlockContext) :
43 | AsyncUIBlock(blockContext) {
44 |
45 | private val holderDepend by findDepend()
46 |
47 | private val mainContentBlock: IMainContentBlockService? by blockService()
48 |
49 | private lateinit var diggContainer: View
50 | private lateinit var commentContainer: View
51 | private lateinit var collectContainer: View
52 | private lateinit var moreContainer: View
53 | private lateinit var diggCount: TextView
54 | private lateinit var commentCount: TextView
55 | private lateinit var collectCount: TextView
56 |
57 | override fun layoutResource(): Int {
58 | return R.layout.demo_right_interact_block_layout
59 | }
60 |
61 | override fun onViewCreated(view: View) {
62 | diggContainer = view.findViewById(R.id.digg_container)
63 | commentContainer = view.findViewById(R.id.comment_container)
64 | collectContainer = view.findViewById(R.id.collect_container)
65 | moreContainer = view.findViewById(R.id.more_container)
66 | diggCount = view.findViewById(R.id.digg_text)
67 | commentCount = view.findViewById(R.id.comment_text)
68 | collectCount = view.findViewById(R.id.collect_text)
69 | diggContainer.setOnClickListener {
70 | mainContentBlock?.changeMainContent("On Click Praise!")
71 | }
72 | commentContainer.setOnClickListener {
73 | mainContentBlock?.changeMainContent("On Click Comment!")
74 | }
75 | collectContainer.setOnClickListener {
76 | mainContentBlock?.changeMainContent("On Click Collect!")
77 | }
78 | moreContainer.setOnClickListener {
79 | mainContentBlock?.changeMainContent("On Click More!")
80 | }
81 | }
82 |
83 | override fun enableAsyncBind(): Boolean {
84 | return holderDepend.enableAsyncBind()
85 | }
86 |
87 | override fun asyncBind(model: DemoModel?, syncInvoke: SyncInvoke) {
88 | syncInvoke {
89 | diggCount.text = model?.data?.praiseCount
90 | commentCount.text = model?.data?.commentCount
91 | collectCount.text = model?.data?.collectCount
92 | }
93 | }
94 |
95 | override fun onRegister() {
96 | subscribe(this, ChangFontThemeEvent::class.java)
97 | }
98 |
99 | override fun onEvent(event: Event): Boolean {
100 | when (event) {
101 | is ChangFontThemeEvent -> {
102 | when (event.type) {
103 | FontType.Normal -> {
104 | diggCount.typeface = Typeface.defaultFromStyle(Typeface.NORMAL)
105 | commentCount.typeface = Typeface.defaultFromStyle(Typeface.NORMAL)
106 | collectCount.typeface = Typeface.defaultFromStyle(Typeface.NORMAL)
107 | }
108 |
109 | FontType.Bold -> {
110 | diggCount.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
111 | commentCount.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
112 | collectCount.typeface = Typeface.defaultFromStyle(Typeface.BOLD)
113 | }
114 | }
115 | }
116 | }
117 | return super.onEvent(event)
118 | }
119 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/data/DemoCardData.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo.data
17 |
18 | import androidx.annotation.DrawableRes
19 |
20 | /**
21 | * description:
22 | *
23 | * @author Created by zhoujunjie on 2024/8/28
24 | * @mail zhoujunjie.9743@bytedance.com
25 | **/
26 |
27 |
28 | data class DemoCardData(
29 | @DrawableRes val avatarImg: Int = -1,
30 | val userName: String = "",
31 | val title: String = "",
32 | val praiseCount: String = "",
33 | val commentCount: String = "",
34 | val collectCount: String = "",
35 | val mainContentBg: Int = 0,
36 | )
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/data/DemoModel.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo.data
17 |
18 | import com.bytedance.blockframework.framework.core.IBlockModel
19 |
20 | /**
21 | * description:
22 | *
23 | * @author Created by zhoujunjie on 2024/8/28
24 | * @mail zhoujunjie.9743@bytedance.com
25 | **/
26 |
27 | data class DemoModel(
28 | override val data: DemoCardData
29 | ) : IBlockModel
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/depend/IHolderBlockDepend.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo.depend
17 |
18 | import android.view.View
19 | import com.bytedance.blockframework.framework.join.IBlockDepend
20 |
21 | /**
22 | * description:
23 | *
24 | * @author Created by zhoujunjie on 2024/8/29
25 | * @mail zhoujunjie.9743@bytedance.com
26 | **/
27 |
28 | interface IHolderBlockDepend : IBlockDepend {
29 | fun enableAsyncBind(): Boolean
30 | fun getHolderView(): View
31 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/event/ChangFontThemeEvent.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo.event
17 |
18 | import com.bytedance.blockframework.interaction.Event
19 | import com.bytedance.demo.util.FontType
20 |
21 | /**
22 | * description:
23 | *
24 | * @author Created by zhoujunjie on 2024/9/2
25 | * @mail zhoujunjie.9743@bytedance.com
26 | **/
27 |
28 | class ChangFontThemeEvent(val type: FontType): Event()
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/service/IMainContentBlockService.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo.service
17 |
18 | /**
19 | * description:
20 | *
21 | * @author Created by zhoujunjie on 2024/8/30
22 | * @mail zhoujunjie.9743@bytedance.com
23 | **/
24 |
25 | interface IMainContentBlockService {
26 | fun changeMainContent(content: String)
27 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/util/DemoTestUtil.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo.util
17 |
18 | import com.bytedance.demo.R
19 | import com.bytedance.demo.data.DemoCardData
20 |
21 | /**
22 | * description:
23 | *
24 | * @author Created by zhoujunjie on 2024/8/29
25 | * @mail zhoujunjie.9743@bytedance.com
26 | **/
27 |
28 | object DemoTestUtil {
29 |
30 | fun getTestData(): ArrayList {
31 | return ArrayList().apply {
32 | add(
33 | DemoCardData(
34 | avatarImg = R.drawable.avatar_img1,
35 | userName = "Mary",
36 | title = "This is a message from Mary",
37 | praiseCount = "101",
38 | commentCount = "56",
39 | collectCount = "292",
40 | mainContentBg = R.color.content_2
41 | )
42 | )
43 | add(
44 | DemoCardData(
45 | avatarImg = R.drawable.avatar_img2,
46 | userName = "Jerry",
47 | title = "This is an essay from Jerry",
48 | praiseCount = "1.3w",
49 | commentCount = "6342",
50 | collectCount = "2.5w",
51 | mainContentBg = R.color.assist_1_dark
52 | )
53 | )
54 | add(
55 | DemoCardData(
56 | avatarImg = R.drawable.avatar_img1,
57 | userName = "Bob",
58 | title = "This is a picture from Bob",
59 | praiseCount = "2.4w",
60 | commentCount = "1.1w",
61 | collectCount = "3.2w",
62 | mainContentBg = R.color.assist_2_dark
63 | )
64 | )
65 | add(
66 | DemoCardData(
67 | avatarImg = R.drawable.avatar_img1,
68 | userName = "Cindy",
69 | title = "This is a diary from Cindy",
70 | praiseCount = "2.8w",
71 | commentCount = "9876",
72 | collectCount = "1.5w",
73 | mainContentBg = R.color.assist_3_dark
74 | )
75 | )
76 | add(
77 | DemoCardData(
78 | avatarImg = R.drawable.avatar_img1,
79 | userName = "Jack",
80 | title = "这是用户Jack的一条内容",
81 | praiseCount = "11.4w",
82 | commentCount = "1.1w",
83 | collectCount = "6.8w",
84 | mainContentBg = R.color.assist_4_dark
85 | )
86 | )
87 | add(
88 | DemoCardData(
89 | avatarImg = R.drawable.avatar_img1,
90 | userName = "Rem",
91 | title = "这是用户Rem的一条内容",
92 | praiseCount = "9300",
93 | commentCount = "2345",
94 | collectCount = "7542",
95 | mainContentBg = R.color.assist_5_dark
96 | )
97 | )
98 | }
99 | }
100 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/bytedance/demo/util/FontType.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2024 Bytedance Ltd. and/or its affiliates
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.bytedance.demo.util
17 |
18 | /**
19 | * description:
20 | *
21 | * @author Created by zhoujunjie on 2024/9/2
22 | * @mail zhoujunjie.9743@bytedance.com
23 | **/
24 |
25 | enum class FontType {
26 | Normal,
27 | Bold
28 | }
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/avatar_img1.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/avatar_img2.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/avatar_img3.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/avatar_img4.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/avatar_img5.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/avatar_img6.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_collect_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_comment_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_digg_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/ic_more_icon.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
12 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
28 |
34 |
35 |
36 |
37 |
38 |
39 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/demo_activity_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/demo_bottom_info_block_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
24 |
25 |
35 |
36 |
37 |
38 |
49 |
50 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/demo_card_holder_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
27 |
28 |
39 |
40 |
48 |
49 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/demo_main_content_block_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
22 |
23 |
34 |
35 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/demo_right_interact_block_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
18 |
19 |
24 |
25 |
32 |
33 |
34 |
35 |
42 |
43 |
48 |
49 |
57 |
58 |
59 |
60 |
67 |
68 |
73 |
74 |
82 |
83 |
84 |
85 |
93 |
94 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #111214
4 | #236DDB
5 | #499DF2
6 | #FF3388
7 | #E5398F
8 | #FF9900
9 | #E59722
10 | @color/assist_3
11 | @color/assist_3_dark
12 | #FFD600
13 | #FFD600
14 | #29CC54
15 | #43BF58
16 |
17 | #0C0D0F
18 | #EBEDF0
19 | #44474D
20 | #B4B7BC
21 | #3D44474D
22 | #4D44474D
23 | #73767A
24 | #82858A
25 | #A3A7AD
26 | #505357
27 | #FFFFFF
28 | #FFFFFF
29 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | BlockDemo
5 |
6 | Praise
7 | Comment
8 | Collect
9 | Switch Font Theme
10 |
11 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/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 | android.useAndroidX=true
19 | android.enableJetifier=true
20 |
21 | ANDROID_GRADLE_PLUGIN = com.android.tools.build:gradle:4.2.2
22 |
23 | # kotlin
24 | KOTLIN_LIB = org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.21
25 | KOTLIN_ANDROID_EXTENSIONS = org.jetbrains.kotlin:kotlin-android-extensions-runtime:1.7.21
26 | KOTLIN_PLUGIN = org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21
27 |
28 | # Android
29 | ANDROIDX_LIB = androidx.appcompat:appcompat:1.2.0
30 | RECYCLER_VIEW = androidx.recyclerview:recyclerview:1.2.0
31 | CONSTRAINT_LIB=androidx.constraintlayout:constraintlayout:1.1.0
32 |
33 | LIFECYCLE_EXTENSIONS=androidx.lifecycle:lifecycle-extensions:2.0.0
34 | LIFECYCLE_COMMON=androidx.lifecycle:lifecycle-common-java8:2.2.0
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytedance/BlockFramework/d37e26ec8d28e95084ff5b7fb625d1a465fc43dd/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Aug 26 00:51:42 CST 2024
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-6.7.1-all.zip
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/misc/jingxuan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytedance/BlockFramework/d37e26ec8d28e95084ff5b7fb625d1a465fc43dd/misc/jingxuan.png
--------------------------------------------------------------------------------
/misc/ott.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytedance/BlockFramework/d37e26ec8d28e95084ff5b7fb625d1a465fc43dd/misc/ott.png
--------------------------------------------------------------------------------
/misc/xigua.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bytedance/BlockFramework/d37e26ec8d28e95084ff5b7fb625d1a465fc43dd/misc/xigua.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':demo'
2 | include ':blockframework'
3 |
--------------------------------------------------------------------------------