├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── encodings.xml
├── gradle.xml
├── jarRepositories.xml
├── markdown-navigator-enh.xml
├── markdown-navigator.xml
├── misc.xml
├── runConfigurations.xml
└── vcs.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── ellison
│ │ └── jetpackdemo
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── ellison
│ │ │ └── jetpackdemo
│ │ │ ├── MainActivity.java
│ │ │ ├── MyApplication.kt
│ │ │ ├── appCompat
│ │ │ └── DemoActivity.java
│ │ │ ├── camera2
│ │ │ └── DemoActivity.java
│ │ │ ├── cameraX
│ │ │ ├── DemoActivityLite.java
│ │ │ ├── NewCameraXActivity.kt
│ │ │ ├── analysis
│ │ │ │ ├── AnalysisResult.kt
│ │ │ │ ├── AnalysisType.kt
│ │ │ │ ├── ChooseAnalysisAdapter.kt
│ │ │ │ ├── ChooseAnalysisFragment.kt
│ │ │ │ ├── HuaweiScanAnalysis.kt
│ │ │ │ ├── OCRAnalysis.kt
│ │ │ │ ├── RealTimeAnalysis.kt
│ │ │ │ └── ZXingAnalysis.kt
│ │ │ ├── analyzer
│ │ │ │ ├── AnalyzeCallback.kt
│ │ │ │ └── MyAnalyzer.kt
│ │ │ ├── capture
│ │ │ │ └── MyCaptureCallback.kt
│ │ │ ├── extender
│ │ │ │ └── MyExtenderHelper.kt
│ │ │ ├── selector
│ │ │ │ └── AllCameraFilter.kt
│ │ │ ├── utils
│ │ │ │ ├── BeepManager.kt
│ │ │ │ ├── Constants.kt
│ │ │ │ └── Utils.kt
│ │ │ ├── video
│ │ │ │ └── MyRecordCallback.kt
│ │ │ └── viewmodel
│ │ │ │ └── CameraViewModel.kt
│ │ │ ├── coroutines
│ │ │ └── DemoActivity.kt
│ │ │ ├── databinding
│ │ │ ├── DemoActivity.java
│ │ │ ├── MyHolder.java
│ │ │ ├── OneWayBindingAdapter.java
│ │ │ ├── Person.java
│ │ │ └── TwoWayBindingAdapter.java
│ │ │ ├── hilt
│ │ │ ├── BaseActivity.kt
│ │ │ ├── DemoActivity.kt
│ │ │ ├── DemoBroadcastReceiver.kt
│ │ │ ├── DemoFragment.kt
│ │ │ ├── bean
│ │ │ │ ├── Movie.kt
│ │ │ │ └── MovieResponse.kt
│ │ │ ├── model
│ │ │ │ ├── LocalData.kt
│ │ │ │ ├── RemoteData.kt
│ │ │ │ ├── Repository.kt
│ │ │ │ ├── analysis
│ │ │ │ │ ├── AnalyseService.kt
│ │ │ │ │ └── AnalysisModule.kt
│ │ │ │ ├── database
│ │ │ │ │ ├── MovieDao.kt
│ │ │ │ │ ├── NewMovieDataBase.kt
│ │ │ │ │ └── RoomModule.kt
│ │ │ │ ├── interceptor
│ │ │ │ │ ├── CallServerInterceptorOkHttpClient.kt
│ │ │ │ │ └── LoggingInterceptorOkHttpClient.kt
│ │ │ │ └── network
│ │ │ │ │ ├── NetworkModule.kt
│ │ │ │ │ └── NetworkService.kt
│ │ │ ├── view
│ │ │ │ └── MovieAdapter.kt
│ │ │ └── viewmodel
│ │ │ │ └── MovieViewModel.kt
│ │ │ ├── lifecycle
│ │ │ ├── ActivityLifecycleCallbackImpl.java
│ │ │ ├── DemoActivity.java
│ │ │ ├── LifeCycleObserverImpl.java
│ │ │ └── TestInterface.java
│ │ │ ├── liveData
│ │ │ ├── DemoActivity.java
│ │ │ ├── Movie.java
│ │ │ ├── MovieChangeListener.java
│ │ │ ├── MovieLiveData.java
│ │ │ └── MovieManager.java
│ │ │ ├── old
│ │ │ └── DemoActivity.java
│ │ │ ├── room
│ │ │ ├── DemoActivity.kt
│ │ │ ├── GestureListener.kt
│ │ │ ├── Movie.kt
│ │ │ ├── MovieAdapter.kt
│ │ │ ├── MovieDao.kt
│ │ │ ├── MovieDataBase.kt
│ │ │ ├── MovieGestureCallback.kt
│ │ │ ├── MovieViewModel.kt
│ │ │ └── Utils.kt
│ │ │ ├── viewBinding
│ │ │ ├── DemoActivity.java
│ │ │ └── DemoFragment.java
│ │ │ ├── viewModel
│ │ │ ├── DemoActivity.java
│ │ │ ├── DemoFragment.java
│ │ │ ├── OtherFragment.java
│ │ │ ├── Person.java
│ │ │ ├── PersonContextModel.java
│ │ │ ├── PersonContextStateModel.java
│ │ │ ├── PersonModel.java
│ │ │ └── PersonStateModel.java
│ │ │ └── viewModelBinding
│ │ │ ├── DemoActivity.java
│ │ │ ├── Person.java
│ │ │ ├── PersonsAdapter.java
│ │ │ └── PersonsContextModel.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── huawei_logo.png
│ │ ├── ic_add.png
│ │ ├── ic_analysis_picker_bg.xml
│ │ ├── ic_camera.xml
│ │ ├── ic_camera_change.xml
│ │ ├── ic_camera_change_bg.xml
│ │ ├── ic_camera_new.xml
│ │ ├── ic_capture.xml
│ │ ├── ic_capture_normal.xml
│ │ ├── ic_capture_pressed.xml
│ │ ├── ic_capture_record.xml
│ │ ├── ic_capture_record_disabled.xml
│ │ ├── ic_capture_record_normal.xml
│ │ ├── ic_capture_record_pressed.xml
│ │ ├── ic_capture_record_pressing.xml
│ │ ├── ic_capture_record_pressing_center.xml
│ │ ├── ic_capture_record_pressing_outter.xml
│ │ ├── ic_filter.png
│ │ ├── ic_focus_view.xml
│ │ ├── ic_jetpack.jpg
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_movie_post.jpg
│ │ ├── ic_point_view.xml
│ │ ├── ic_qr_code.xml
│ │ ├── ic_qr_scan.xml
│ │ ├── ic_qr_zone.xml
│ │ ├── ic_rect_view.xml
│ │ ├── ic_search.png
│ │ ├── ic_sort.png
│ │ ├── ic_video.xml
│ │ ├── ml_logo.png
│ │ ├── zxing_logo.png
│ │ ├── zxing_logo_round.png
│ │ └── zxing_logo_transparent.png
│ │ ├── layout-land
│ │ ├── activity_main.xml
│ │ ├── activity_view_binding.xml
│ │ ├── activity_view_model.xml
│ │ ├── fragment_view_binding.xml
│ │ └── fragment_view_model.xml
│ │ ├── layout
│ │ ├── activity_camera2.xml
│ │ ├── activity_camerax_lite.xml
│ │ ├── activity_coroutines.xml
│ │ ├── activity_data_binding.xml
│ │ ├── activity_data_binding_item.xml
│ │ ├── activity_data_binding_item_one_way.xml
│ │ ├── activity_hilt.xml
│ │ ├── activity_hilt_item.xml
│ │ ├── activity_lifecycle.xml
│ │ ├── activity_live_data.xml
│ │ ├── activity_main.xml
│ │ ├── activity_main_test.xml
│ │ ├── activity_main_test_2.xml
│ │ ├── activity_old.xml
│ │ ├── activity_room_db.xml
│ │ ├── activity_room_db_item.xml
│ │ ├── activity_view_binding.xml
│ │ ├── activity_view_model.xml
│ │ ├── activity_view_model_binding.xml
│ │ ├── activity_view_model_binding_item.xml
│ │ ├── analysis_list_item.xml
│ │ ├── fragment_analysis_list.xml
│ │ ├── fragment_hilt.xml
│ │ ├── fragment_other_view_model.xml
│ │ ├── fragment_view_binding.xml
│ │ └── fragment_view_model.xml
│ │ ├── menu
│ │ └── room_menu.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── raw
│ │ └── beep_sound.ogg
│ │ ├── values-night
│ │ └── themes.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ └── test
│ └── java
│ └── com
│ └── ellison
│ └── jetpackdemo
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── 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 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
23 |
24 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator-enh.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/markdown-navigator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Ellison Chan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/ellison/jetpackdemo/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("com.ellison.jetpackdemo", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
21 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
32 |
33 |
34 |
36 |
37 |
38 |
40 |
41 |
42 |
44 |
45 |
46 |
49 |
50 |
51 |
53 |
54 |
55 |
58 |
59 |
60 |
62 |
63 |
64 |
65 |
68 |
69 |
70 |
73 |
74 |
75 |
78 |
79 |
80 |
83 |
84 |
85 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/MyApplication.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo
2 |
3 | import android.app.Application
4 | import androidx.camera.core.CameraXConfig
5 | import android.util.Log
6 | import androidx.camera.camera2.Camera2Config
7 | import com.ellison.jetpackdemo.lifecycle.ActivityLifecycleCallbackImpl
8 | import dagger.hilt.android.HiltAndroidApp
9 |
10 | @HiltAndroidApp
11 | class MyApplication : Application(), CameraXConfig.Provider {
12 | private var mActivityLifecycle: ActivityLifecycleCallbacks? = null
13 |
14 | override fun getCameraXConfig(): CameraXConfig {
15 | return Camera2Config.defaultConfig()
16 | }
17 |
18 | override fun onCreate() {
19 | Log.d(TAG, "onCreate()")
20 | super.onCreate()
21 | mActivityLifecycle = ActivityLifecycleCallbackImpl()
22 | registerActivityLifecycleCallbacks(mActivityLifecycle)
23 | }
24 |
25 | override fun onTerminate() {
26 | Log.d(TAG, "onTerminate()")
27 | super.onTerminate()
28 | unregisterActivityLifecycleCallbacks(mActivityLifecycle)
29 | }
30 |
31 | companion object {
32 | @JvmField
33 | val TAG = MyApplication::class.java.simpleName
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/appCompat/DemoActivity.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.appCompat;
2 |
3 | import android.os.Bundle;
4 | import android.preference.PreferenceGroup;
5 |
6 | import com.ellison.jetpackdemo.R;
7 |
8 | import androidx.appcompat.app.AppCompatActivity;
9 |
10 | public class DemoActivity extends AppCompatActivity {
11 |
12 | @Override
13 | protected void onCreate(Bundle savedInstanceState) {
14 | super.onCreate(savedInstanceState);
15 | setContentView(R.layout.activity_main_test);
16 | // setContentView(R.layout.activity_main_test_2);
17 | PreferenceGroup preferenceGroup;
18 | androidx.preference.CheckBoxPreference checkBoxPreference;
19 |
20 | androidx.preference.PreferenceFragmentCompat preferenceFragmentCompat;
21 | androidx.preference.PreferenceFragment preferenceFragment;
22 | }
23 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/analysis/AnalysisResult.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.analysis
2 |
3 | import android.graphics.Rect
4 | import com.ellison.jetpackdemo.cameraX.utils.Constants
5 |
6 | data class AnalysisResult(val content: String, val zoomScale: Double, val rect: Rect)
7 |
8 | val defaultResult = AnalysisResult("", Constants.DEFAULT_ZOOM_SCALE, Rect())
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/analysis/AnalysisType.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.analysis
2 |
3 | import com.ellison.jetpackdemo.R
4 |
5 | data class AnalysisType internal constructor(
6 | val logo: Int,
7 | val name: String?,
8 | val clazz: Class?
9 | )
10 |
11 | val typeList = listOf(
12 | AnalysisType(R.drawable.huawei_logo,"Huawei ScanKit", HuaweiScanAnalysis::class.java),
13 | AnalysisType(R.drawable.zxing_logo_transparent,"Google Zxing", ZXingAnalysis::class.java),
14 | AnalysisType(R.drawable.ml_logo,"Google ML Kit", OCRAnalysis::class.java)
15 | )
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/analysis/ChooseAnalysisAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.analysis
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.RecyclerView
6 | import com.ellison.jetpackdemo.databinding.AnalysisListItemBinding
7 |
8 | class ChooseAnalysisAdapter(
9 | private val data: List,
10 | private val listener: AnalysisChooseListener
11 | ): RecyclerView.Adapter() {
12 | interface AnalysisChooseListener { fun onAnalysisChoose(type: AnalysisType) }
13 |
14 | private class MyViewHolder(val binding: AnalysisListItemBinding) : RecyclerView.ViewHolder(binding.root)
15 |
16 | override fun getItemCount(): Int = data.size
17 |
18 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder =
19 | AnalysisListItemBinding.inflate(
20 | LayoutInflater.from(parent.context),
21 | parent,
22 | false
23 | ).let {
24 | MyViewHolder(it)
25 | }
26 |
27 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
28 | val myViewHolder = holder as MyViewHolder
29 | myViewHolder.binding.text1.text = data[position].name
30 | myViewHolder.binding.logo.setImageResource(data[position].logo)
31 |
32 | holder.itemView.tag = position
33 | holder.itemView.setOnClickListener { listener.onAnalysisChoose(data[it.tag as Int]) }
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/analysis/ChooseAnalysisFragment.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.analysis
2 |
3 | import android.graphics.Color
4 | import android.graphics.drawable.ColorDrawable
5 | import android.os.Bundle
6 | import android.util.Log
7 | import android.view.LayoutInflater
8 | import android.view.View
9 | import android.view.ViewGroup
10 | import android.view.WindowManager
11 | import android.widget.FrameLayout
12 | import androidx.fragment.app.activityViewModels
13 | import androidx.recyclerview.widget.DividerItemDecoration
14 | import androidx.recyclerview.widget.LinearLayoutManager
15 | import androidx.recyclerview.widget.RecyclerView
16 | import com.ellison.jetpackdemo.R
17 | import com.ellison.jetpackdemo.cameraX.analysis.ChooseAnalysisAdapter.AnalysisChooseListener
18 | import com.ellison.jetpackdemo.cameraX.utils.Constants
19 | import com.ellison.jetpackdemo.cameraX.viewmodel.CameraViewModel
20 | import com.ellison.jetpackdemo.databinding.FragmentAnalysisListBinding
21 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment
22 |
23 | class ChooseAnalysisFragment: BottomSheetDialogFragment() {
24 | private val viewModel: CameraViewModel by activityViewModels()
25 |
26 | override fun onCreateView(
27 | inflater: LayoutInflater,
28 | container: ViewGroup?,
29 | savedInstanceState: Bundle?
30 | ): View? {
31 | Log.d(Constants.TAG_CAMERA_UI, "onCreateView")
32 | val binding = FragmentAnalysisListBinding.inflate(inflater, container, false)
33 | initAnalysisList(binding.analysisList)
34 | return binding.root
35 | }
36 |
37 | override fun onStart() {
38 | Log.d(Constants.TAG_CAMERA, "onStart()")
39 | super.onStart()
40 |
41 | dialog?.let{
42 | // Ensure status bar not shown.
43 | it.window?.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
44 |
45 | it.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
46 | val bottomView: FrameLayout = it.findViewById(com.google.android.material.R.id.design_bottom_sheet)
47 | bottomView.setBackgroundResource(R.drawable.ic_analysis_picker_bg)
48 | }
49 | }
50 |
51 | private fun initAnalysisList(recyclerView: RecyclerView) {
52 | Log.d(Constants.TAG_CAMERA, "initAnalysisList() viewModel:$viewModel")
53 | val layoutManager = LinearLayoutManager(activity)
54 | isCancelable = false
55 |
56 | recyclerView.run{
57 | setLayoutManager(layoutManager)
58 | addItemDecoration(DividerItemDecoration(activity, DividerItemDecoration.VERTICAL))
59 | adapter = ChooseAnalysisAdapter(typeList, object : AnalysisChooseListener {
60 | override fun onAnalysisChoose(type: AnalysisType) {
61 | Log.d(Constants.TAG_CAMERA, "onAnalysisChoose() type:$type")
62 | viewModel.chooseAnalysis(type.clazz)
63 | dismissAllowingStateLoss()
64 | }
65 | })
66 | }
67 | }
68 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/analysis/OCRAnalysis.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.analysis
2 |
3 | import android.content.Context
4 | import androidx.camera.core.ImageProxy
5 |
6 | class OCRAnalysis: RealTimeAnalysis {
7 | override fun analyzeContent(imageProxy: ImageProxy, context: Context): AnalysisResult {
8 | // Todo: use google's ml kit
9 | imageProxy.close()
10 | return defaultResult
11 | }
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/analysis/RealTimeAnalysis.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.analysis
2 |
3 | import android.content.Context
4 | import androidx.camera.core.ImageProxy
5 |
6 | interface RealTimeAnalysis {
7 | fun analyzeContent(imageProxy: ImageProxy, context: Context): AnalysisResult { return defaultResult }
8 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/analysis/ZXingAnalysis.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.analysis
2 |
3 | import android.content.Context
4 | import android.graphics.Rect
5 | import android.util.Log
6 | import androidx.camera.core.ImageProxy
7 | import com.ellison.jetpackdemo.cameraX.utils.Constants
8 | import com.google.zxing.BinaryBitmap
9 | import com.google.zxing.MultiFormatReader
10 | import com.google.zxing.PlanarYUVLuminanceSource
11 | import com.google.zxing.common.HybridBinarizer
12 |
13 | class ZXingAnalysis(): RealTimeAnalysis {
14 | private val multiFormatReader = MultiFormatReader()
15 |
16 | override fun analyzeContent(imageProxy: ImageProxy, context: Context): AnalysisResult {
17 | val byteBuffer = imageProxy.planes[0].buffer
18 | val data = ByteArray(byteBuffer.remaining())
19 | byteBuffer[data]
20 |
21 | val width = imageProxy.width
22 | val height = imageProxy.height
23 | val source = PlanarYUVLuminanceSource(
24 | data, width, height, 0, 0, width, height, false
25 | )
26 |
27 | val bitmap = BinaryBitmap(HybridBinarizer(source))
28 |
29 | var result = ""
30 | try {
31 | result = multiFormatReader.decode(bitmap).text
32 | Log.d("Camera", "result:$result")
33 | } catch (e: Exception) {
34 | Log.e("Camera", "Error decoding barcode")
35 | }
36 |
37 | imageProxy.close()
38 | return AnalysisResult(result, Constants.DEFAULT_ZOOM_SCALE, Rect())
39 | }
40 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/analyzer/AnalyzeCallback.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.analyzer
2 |
3 | import com.ellison.jetpackdemo.cameraX.analysis.AnalysisResult
4 |
5 | interface AnalyzeCallback {
6 | fun onZoomPreview(scale: Double)
7 | fun onAnalyzeResult(result: AnalysisResult)
8 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/analyzer/MyAnalyzer.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.analyzer
2 |
3 | import android.util.Log
4 | import androidx.camera.core.ImageAnalysis.Analyzer
5 | import androidx.camera.core.ImageProxy
6 | import com.ellison.jetpackdemo.cameraX.utils.Constants
7 | import com.ellison.jetpackdemo.cameraX.viewmodel.CameraViewModel
8 |
9 | class MyAnalyzer(
10 | private val viewModel: CameraViewModel,
11 | private val callback: AnalyzeCallback
12 | ): Analyzer {
13 | override fun analyze(image: ImageProxy) {
14 | Log.d(Constants.TAG_CAMERA, "analyze() image:$image")
15 | viewModel.analysePicture(image).also {
16 | Log.d(Constants.TAG_CAMERA, "analyze() result:$it")
17 |
18 | if (Constants.DEFAULT_ZOOM_SCALE != it.zoomScale
19 | && Constants.MIN_ZOOM_SCALE != it.zoomScale
20 | ) {
21 | callback.onZoomPreview(it.zoomScale)
22 | } else {
23 | callback.onAnalyzeResult(it)
24 | }
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/capture/MyCaptureCallback.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.capture
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import android.widget.Toast
6 | import androidx.camera.core.ImageCapture
7 | import androidx.camera.core.ImageCaptureException
8 | import com.ellison.jetpackdemo.cameraX.utils.Constants
9 |
10 | class MyCaptureCallback(
11 | private val picCount: Int,
12 | private val context: Context
13 | ): ImageCapture.OnImageSavedCallback {
14 | override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
15 | val uri = outputFileResults.savedUri
16 | Log.d(
17 | Constants.TAG_CAMERA, "outputFileResults:$uri picCount:$picCount"
18 | )
19 |
20 | val path = if (uri != null) (" @ " + uri.path) else "none"
21 |
22 | Toast.makeText(
23 | context, "Picture got:$path.", Toast.LENGTH_SHORT
24 | ).show()
25 | }
26 |
27 | override fun onError(exception: ImageCaptureException) {
28 | Log.d(Constants.TAG_CAMERA, "onError:${exception.imageCaptureError}")
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/extender/MyExtenderHelper.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.extender
2 |
3 | import android.util.Log
4 | import androidx.camera.core.CameraSelector
5 | import androidx.camera.core.ImageCapture
6 | import androidx.camera.core.Preview
7 | import androidx.camera.extensions.*
8 | import com.ellison.jetpackdemo.cameraX.utils.Constants
9 |
10 | class MyExtenderHelper {
11 | fun setPreviewExtender(builder: Preview.Builder, cameraSelector: CameraSelector) {
12 | BeautyPreviewExtender.create(builder).let {
13 | if (it.isExtensionAvailable(cameraSelector)) {
14 | // Enable the extension if available.
15 | Log.d(Constants.TAG_CAMERA, "beauty preview extension enable")
16 | it.enableExtension(cameraSelector)
17 | } else {
18 | Log.d(Constants.TAG_CAMERA, "beauty preview extension not available")
19 | }
20 | }
21 | }
22 |
23 | fun setCaptureExtender(builder: ImageCapture.Builder, cameraSelector: CameraSelector) {
24 | val nightImageCaptureExtender = NightImageCaptureExtender.create(builder)
25 | if (nightImageCaptureExtender.isExtensionAvailable(cameraSelector)) {
26 | // Enable the extension if available.
27 | Log.d(Constants.TAG_CAMERA, "night capture extension enable")
28 | nightImageCaptureExtender.enableExtension(cameraSelector)
29 | } else {
30 | Log.d(Constants.TAG_CAMERA, "night capture extension not available")
31 | }
32 |
33 | val bokehImageCapture = BokehImageCaptureExtender.create(builder);
34 | if (bokehImageCapture.isExtensionAvailable(cameraSelector)) {
35 | // Enable the extension if available.
36 | Log.d(Constants.TAG_CAMERA, "hdr extension enable");
37 | bokehImageCapture.enableExtension(cameraSelector);
38 | } else {
39 | Log.d(Constants.TAG_CAMERA, "hdr extension not available");
40 | }
41 |
42 | val hdrImageCaptureExtender = HdrImageCaptureExtender.create(builder);
43 | if (hdrImageCaptureExtender.isExtensionAvailable(cameraSelector)) {
44 | // Enable the extension if available.
45 | Log.d(Constants.TAG_CAMERA, "night extension enable");
46 | hdrImageCaptureExtender.enableExtension(cameraSelector);
47 | } else {
48 | Log.d(Constants.TAG_CAMERA, "night extension not available");
49 | }
50 |
51 | val beautyImageCaptureExtender = BeautyImageCaptureExtender.create(builder);
52 | if (beautyImageCaptureExtender.isExtensionAvailable(cameraSelector)) {
53 | // Enable the extension if available.
54 | Log.d(Constants.TAG_CAMERA, "beauty extension enable");
55 | beautyImageCaptureExtender.enableExtension(cameraSelector);
56 | } else {
57 | Log.d(Constants.TAG_CAMERA, "beauty extension not available");
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/selector/AllCameraFilter.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.selector
2 |
3 | import android.util.Log
4 | import androidx.camera.core.CameraFilter
5 | import androidx.camera.core.CameraInfo
6 | import androidx.camera.core.CameraSelector
7 | import androidx.camera.core.impl.CameraInfoInternal
8 | import androidx.camera.core.impl.CameraInternal
9 | import java.util.LinkedHashSet
10 |
11 | class AllCameraFilter: CameraFilter {
12 | override fun filter(cameraInfos: MutableList): MutableList {
13 | val result: MutableList = mutableListOf()
14 | for (cameraInfo in cameraInfos) {
15 | Log.d(
16 | "Camera", "cameraInfo" +
17 | " implementationType:${cameraInfo.implementationType}" +
18 | " state:${cameraInfo.exposureState}" +
19 | " sensorRotationDegrees:${cameraInfo.sensorRotationDegrees}"
20 | )
21 |
22 | val id = (cameraInfo as CameraInfoInternal).cameraId
23 | Log.d("Camera", "cameraInfo id:$id")
24 |
25 | // Specify the camera id that U need, such as front camera which id is 0.
26 | if (CameraSelector.LENS_FACING_FRONT.equals(id)) {
27 | Log.d("Camera", "cameraInfo add")
28 | result.add(cameraInfo)
29 | }
30 | }
31 | return result
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/utils/BeepManager.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.utils
2 |
3 | import android.app.Activity
4 | import android.content.Context
5 | import android.media.AudioManager
6 | import android.media.MediaPlayer
7 | import android.media.MediaPlayer.OnCompletionListener
8 | import android.os.Vibrator
9 | import android.util.Log
10 | import java.io.Closeable
11 | import java.io.IOException
12 |
13 | class BeepManager(private val activity: Activity) : OnCompletionListener,
14 | MediaPlayer.OnErrorListener, Closeable {
15 |
16 | private var mediaPlayer: MediaPlayer? = null
17 | private var playBeep = false
18 | private var vibrate = false
19 |
20 | fun setPlayBeep(playBeep: Boolean) {
21 | this.playBeep = playBeep
22 | updatePrefs()
23 | }
24 |
25 | fun setVibrate(vibrate: Boolean) {
26 | this.vibrate = vibrate
27 | }
28 |
29 | @Synchronized
30 | fun updatePrefs() {
31 | if (playBeep && mediaPlayer == null) {
32 | activity.volumeControlStream = AudioManager.STREAM_MUSIC
33 | mediaPlayer = buildMediaPlayer(activity)
34 | }
35 | }
36 |
37 | @Synchronized
38 | fun playBeepSoundAndVibrate() {
39 | Log.d(Constants.TAG_BEEP, "playBeepSoundAndVibrate playBeep:$playBeep mediaPlayer:$mediaPlayer")
40 | if (playBeep && mediaPlayer != null) {
41 | mediaPlayer?.start()
42 | }
43 | if (vibrate) {
44 | val vibrator = activity
45 | .getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
46 | vibrator.vibrate(Constants.VIBRATE_DURATION)
47 | }
48 | }
49 |
50 | private fun buildMediaPlayer(activity: Context): MediaPlayer {
51 | val mediaPlayer = MediaPlayer()
52 | mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC)
53 | mediaPlayer.setOnCompletionListener(this)
54 | mediaPlayer.setOnErrorListener(this)
55 | return try {
56 | val file = activity.getResources().openRawResourceFd(Constants.BEEP_OGG_FILE);
57 | // .openRawResourceFd(R.raw.beep);
58 | file.use { file ->
59 | mediaPlayer.setDataSource(
60 | file.getFileDescriptor(),
61 | file.getStartOffset(),
62 | file.getLength());
63 | }
64 | mediaPlayer.setVolume(Constants.BEEP_VOLUME, Constants.BEEP_VOLUME)
65 | mediaPlayer.prepare()
66 | mediaPlayer
67 | } catch (ioe: IOException) {
68 | Log.e(Constants.TAG_BEEP, "media play error$ioe")
69 | mediaPlayer.release()
70 | mediaPlayer
71 | }
72 | }
73 |
74 | override fun onCompletion(mp: MediaPlayer) {
75 | // When the beep has finished playing, rewind to queue up another one.
76 | mp.seekTo(0)
77 | }
78 |
79 | @Synchronized
80 | override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
81 | Log.e(Constants.TAG_BEEP, "onError what:$what extra:$extra")
82 | if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
83 | // No need finish although media player got error.
84 | // activity.finish();
85 | } else {
86 | // possibly media player error, so release and recreate
87 | mp.release()
88 | updatePrefs()
89 | }
90 | return true
91 | }
92 |
93 | @Synchronized
94 | override fun close() {
95 | mediaPlayer?.release()
96 | }
97 |
98 | init {
99 | updatePrefs()
100 | }
101 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/utils/Constants.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.utils
2 |
3 | import com.ellison.jetpackdemo.R
4 |
5 | class Constants {
6 | companion object {
7 | const val TAG_CAMERA = "Camera"
8 | const val TAG_CAMERA_UI = "CameraUI"
9 | const val TAG_BEEP = "beep"
10 |
11 | const val MIN_ZOOM_SCALE = 0.0
12 | const val MIDDLE_ZOOM_SCALE = 0.5
13 | const val MAX_ZOOM_SCALE = 1.0
14 | const val DEFAULT_ZOOM_SCALE = 1.0
15 |
16 | const val ANALYSIS_RESULT_SHOW_DURATION = 1500L
17 | const val ANALYSIS_HOLDING_DURATION = 3000L
18 |
19 | const val BEEP_VOLUME = 0.05f
20 | const val VIBRATE_DURATION = 200L
21 | const val BEEP_OGG_FILE = R.raw.beep_sound
22 |
23 | const val REQUEST_CAMERA = 20
24 | const val REQUEST_STORAGE = 30
25 | const val REQUEST_STORAGE_BINDING = 35
26 | const val REQUEST_STORAGE_VIDEO = 40
27 | const val REQUEST_STORAGE_VIDEO_BINDING = 45
28 |
29 | const val CAPTURED_FILE_NAME = "captured_picture"
30 | const val RECORDED_FILE_NAME = "recorded_video"
31 | const val RECORDED_FILE_NAME_END = "video/mp4"
32 |
33 | const val TAG_FRAGMENT_CHOOSE_ANALYSIS = "choose_analysis_screen"
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/utils/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.utils
2 |
3 | import android.graphics.Point
4 | import android.graphics.Rect
5 | import android.util.Log
6 | import android.view.View
7 | import androidx.camera.core.ImageProxy
8 |
9 | class Utils {
10 | companion object {
11 | // fun convertRectToPoint(proxy: ImageProxy, rect: Rect): Point {
12 | fun convertRectToPoint(rect: Rect, preview: View): Point {
13 | Log.d(Constants.TAG_CAMERA_UI, "convertRectToCenter"
14 | +" rect:$rect centerX:${rect.centerX()} centerY:${rect.centerY()}"
15 | // +" proxy:{width:${proxy.width} height:${proxy.height}}"
16 | +" previewView:{width:${preview.width} height:${preview.height}}")
17 | if (rect.isEmpty) {
18 | return Point()
19 | }
20 |
21 | return Point(
22 | preview.width - rect.centerY(),
23 | rect.centerX()
24 | )
25 | }
26 |
27 | fun convertPointsToCenter(proxy: ImageProxy, points: Array?, preview: View): Point {
28 | Log.d(Constants.TAG_CAMERA_UI, "convertPointsToCenter"
29 | +" points:${points.contentToString()}"
30 | +" proxy:{width:${proxy.width} height:${proxy.height}}"
31 | +" previewView:{width:${preview.width} height:${preview.height}}")
32 |
33 | if (points == null || points.isEmpty())
34 | return Point()
35 |
36 | // Points[0]: right bottom
37 | // Points[1]: left bottom
38 | // Points[2]: left up
39 | // Points[3]: right up
40 |
41 | val xOffset = (points[0].x - points[2].x) / 2
42 | val yOffset = (points[0].y - points[2].y) / 2
43 |
44 | // val xScaleFactor = binding.previewView.width.toFloat() / proxy.width.toFloat()
45 | // val yScaleFactor = binding.previewView.height.toFloat() / proxy.height.toFloat()
46 | // Log.d(Constants.TAG_CAMERA_UI, "xScaleFactor:$xScaleFactor yScaleFactor:$yScaleFactor")
47 |
48 | return Point(preview.width - yOffset - points[2].y, xOffset + points[2].x)
49 | // return Point(xOffset + points[2].x, yOffset + points[2].y)
50 | // return Point(yOffset + points[2].y, xOffset + points[2].x)
51 | // return Point(
52 | // ((xOffset + points[2].x) * xScaleFactor).toInt(),
53 | // ((yOffset + points[2].y) * yScaleFactor).toInt()
54 | // )
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/video/MyRecordCallback.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.video
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import android.widget.Toast
6 | import androidx.camera.core.VideoCapture
7 | import com.ellison.jetpackdemo.cameraX.utils.Constants
8 |
9 | class MyRecordCallback(
10 | private val context: Context,
11 | private val listener: () -> Unit
12 | ): VideoCapture.OnVideoSavedCallback {
13 | override fun onVideoSaved(outputFileResults: VideoCapture.OutputFileResults) {
14 | Log.d(
15 | Constants.TAG_CAMERA, "onVideoSaved outputFileResults:"
16 | + outputFileResults.savedUri!!.path
17 | )
18 | Toast.makeText(
19 | context,
20 | "Video got" + (if (outputFileResults.savedUri != null) " @ " + outputFileResults.savedUri!!
21 | .path else "")
22 | + ".", Toast.LENGTH_LONG
23 | ).show()
24 | listener.invoke()
25 | }
26 |
27 | override fun onError(videoCaptureError: Int, message: String, cause: Throwable?) {
28 | Log.d(
29 | Constants.TAG_CAMERA, "onError videoCaptureError:"
30 | + videoCaptureError + " message:" + message, cause
31 | )
32 | listener.invoke()
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/cameraX/viewmodel/CameraViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.cameraX.viewmodel
2 |
3 | import android.app.Application
4 | import androidx.camera.core.ImageProxy
5 | import androidx.lifecycle.AndroidViewModel
6 | import androidx.lifecycle.MutableLiveData
7 | import com.ellison.jetpackdemo.cameraX.analysis.*
8 |
9 | class CameraViewModel(application: Application) : AndroidViewModel(application) {
10 | private lateinit var pictureAnalysis: RealTimeAnalysis
11 | val analysisLiveData = MutableLiveData()
12 |
13 | fun chooseAnalysis(clazz: Class?) {
14 | pictureAnalysis = clazz?.newInstance() ?: ZXingAnalysis()
15 | analysisLiveData.value = true
16 | }
17 |
18 | fun analysePicture(imageProxy: ImageProxy): AnalysisResult =
19 | pictureAnalysis.analyzeContent(imageProxy, getApplication())
20 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/databinding/DemoActivity.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.databinding;
2 |
3 | import android.os.Bundle;
4 | import android.util.Log;
5 | import android.view.View;
6 |
7 | import java.util.Arrays;
8 | import java.util.List;
9 |
10 | import androidx.annotation.Nullable;
11 | import androidx.appcompat.app.AppCompatActivity;
12 | import androidx.recyclerview.widget.LinearLayoutManager;
13 |
14 | public class DemoActivity extends AppCompatActivity {
15 | ActivityDataBindingBinding binding;
16 | private List mPersons = Arrays.asList(new Person[] {
17 | new Person("18", "Audi"),
18 | new Person("7", "Benz"),
19 | new Person("24", "Cadillac"),
20 | new Person("1", "DS")});
21 |
22 | @Override
23 | protected void onCreate(@Nullable Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 |
26 | // binding = DataBindingUtil.setContentView(this, R.layout.activity_data_binding);
27 | binding = ActivityDataBindingBinding.inflate(getLayoutInflater());
28 | setContentView(binding.getRoot());
29 | binding.setResponder(new EventResponder());
30 | }
31 |
32 | // Event binding.
33 | public class EventResponder {
34 | public void onClick(View view) {
35 | Log.d("dataBinding", "onClick() view:" + view);
36 | if (view == binding.testGet) {
37 | Log.d("dataBinding", "onClick() GET INFO");
38 | getInfo();
39 | } else if (view == binding.testUpdate) {
40 | Log.d("dataBinding", "onClick() UPDATE INFO");
41 | updateInfo();
42 | }
43 | }
44 |
45 | public void onClickUpdate() {
46 | Log.d("dataBinding", "onClickUpdate() UPDATE INFO");
47 | updateInfo();
48 | }
49 | }
50 |
51 | private void getInfo() {
52 | binding.testPersonList.setLayoutManager(new LinearLayoutManager(this));
53 | binding.testPersonList.setAdapter(new TwoWayBindingAdapter(mPersons));
54 |
55 | binding.testPersonListOneWay.setLayoutManager(new LinearLayoutManager(this));
56 | binding.testPersonListOneWay.setAdapter(new OneWayBindingAdapter(mPersons));
57 | }
58 |
59 | private void updateInfo() {
60 | mPersons.get(0).setAge("1");
61 | mPersons.get(3).setAge("100");
62 | }
63 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/databinding/MyHolder.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.databinding;
2 |
3 | import androidx.databinding.ViewDataBinding;
4 | import androidx.recyclerview.widget.RecyclerView;
5 |
6 | public class MyHolder extends RecyclerView.ViewHolder {
7 | ViewDataBinding binding;
8 |
9 | public MyHolder(ViewDataBinding binding) {
10 | super(binding.getRoot());
11 | this.binding = binding;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/databinding/OneWayBindingAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.databinding;
2 |
3 | import android.util.Log;
4 | import android.view.LayoutInflater;
5 | import android.view.ViewGroup;
6 | import android.widget.CompoundButton;
7 |
8 | import java.util.List;
9 |
10 | import androidx.annotation.NonNull;
11 | import androidx.recyclerview.widget.RecyclerView;
12 |
13 | public class OneWayBindingAdapter extends TwoWayBindingAdapter {
14 | public OneWayBindingAdapter(List personList) {
15 | super(personList);
16 | Log.d("dataBinding", "OneWayBindingAdapter#OneWayBindingAdapter() personList:" + personList);
17 | }
18 |
19 | @NonNull
20 | @Override
21 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
22 | Log.d("dataBinding", "OneWayBindingAdapter#onCreateViewHolder() parent:" + parent);
23 | return new MyHolder(ActivityDataBindingItemOneWayBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
24 | }
25 |
26 | @Override
27 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
28 | Log.d("dataBinding", "OneWayBindingAdapter#onBindViewHolder() holder:" + holder + " position:" + position);
29 | ((ActivityDataBindingItemOneWayBinding) ((MyHolder) holder).binding).setPerson(personList.get(position));
30 | ((ActivityDataBindingItemOneWayBinding) ((MyHolder) holder).binding).setCheckResponder(new CheckResponder() {
31 | @Override
32 | public void onCheckChanged(CompoundButton buttonView, boolean isChecked) {
33 | Log.d("dataBinding", "OneWayBindingAdapter#onCheckChanged() buttonView:" + buttonView + " isChecked:" + isChecked);
34 | if (buttonView == ((ActivityDataBindingItemOneWayBinding) ((MyHolder) holder).binding).testCheck) {
35 | Log.d("dataBinding", "OneWayBindingAdapter#onCheckChanged() BTN & CHANGE COLOR");
36 | personList.get(position).setChecked(isChecked);
37 | }
38 | }
39 | });
40 | }
41 |
42 | // Event binding.
43 | public static class CheckResponder {
44 | public void onCheckChanged(CompoundButton buttonView, boolean isChecked) {
45 | Log.d("dataBinding", "CheckResponder#onCheckChanged() buttonView:" + buttonView + " isChecked:" + isChecked);
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/databinding/Person.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.databinding;
2 |
3 | import androidx.databinding.BaseObservable;
4 | import androidx.databinding.Bindable;
5 | import androidx.databinding.library.baseAdapters.BR;
6 |
7 | public class Person extends BaseObservable {
8 | private String name;
9 | private String age;
10 | private boolean adult;
11 | private boolean checked;
12 |
13 | public Person(String age, String name) {
14 | this.age = age;
15 | this.name = name;
16 | adult = this.age != null && Integer.valueOf(this.age) >= 18;
17 | }
18 |
19 | @Bindable
20 | public String getAge() {
21 | return age;
22 | }
23 |
24 | public void setAge(String age) {
25 | this.age = age;
26 | notifyPropertyChanged(BR.age);
27 | setAdult();
28 | }
29 |
30 | @Bindable
31 | public String getName() {
32 | return name;
33 | }
34 |
35 | public void setName(String name) {
36 | this.name = name;
37 | notifyPropertyChanged(BR.name);
38 | }
39 |
40 | @Bindable
41 | public boolean isAdult() {
42 | return adult;
43 | }
44 |
45 | public void setAdult() {
46 | adult = this.age != null && Integer.valueOf(this.age) >= 18;
47 | notifyPropertyChanged(BR.adult);
48 | }
49 |
50 | @Bindable
51 | public boolean isChecked() {
52 | return checked;
53 | }
54 |
55 | public void setChecked(boolean checked) {
56 | this.checked = checked;
57 | notifyPropertyChanged(BR.checked);
58 | }
59 |
60 | @Override
61 | public String toString() {
62 | return "Person{" +
63 | "name='" + name + '\'' +
64 | ", age='" + age + '\'' +
65 | ", adult=" + adult +
66 | ", checked=" + checked +
67 | '}';
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/databinding/TwoWayBindingAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.databinding;
2 |
3 | import android.util.Log;
4 | import android.view.LayoutInflater;
5 | import android.view.ViewGroup;
6 |
7 | import java.util.List;
8 |
9 | import androidx.annotation.NonNull;
10 | import androidx.recyclerview.widget.RecyclerView;
11 |
12 | public class TwoWayBindingAdapter extends RecyclerView.Adapter {
13 | protected List personList;
14 |
15 | public TwoWayBindingAdapter(List personList) {
16 | this.personList = personList;
17 | Log.d("dataBinding", "TwoWayBindingAdapter#TwoWayBindingAdapter() personList:" + personList);
18 | }
19 |
20 | @NonNull
21 | @Override
22 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
23 | Log.d("dataBinding", "TwoWayBindingAdapter#onCreateViewHolder() parent:" + parent);
24 | return new MyHolder(ActivityDataBindingItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
25 | }
26 |
27 | @Override
28 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
29 | Log.d("dataBinding", "TwoWayBindingAdapter#onBindViewHolder() holder:" + holder + " position:" + position);
30 | ((ActivityDataBindingItemBinding) ((MyHolder) holder).binding).setPerson(personList.get(position));
31 | }
32 |
33 | @Override
34 | public int getItemCount() {
35 | return personList.size();
36 | }
37 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt
2 |
3 | import android.os.Bundle
4 | import androidx.appcompat.app.AppCompatActivity
5 | import dagger.hilt.android.AndroidEntryPoint
6 |
7 | @AndroidEntryPoint
8 | open class BaseActivity() : AppCompatActivity()
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/DemoActivity.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt
2 |
3 | import android.os.Bundle
4 | import android.util.Log
5 | import android.widget.Toast
6 | import androidx.activity.viewModels
7 | import androidx.appcompat.app.AppCompatActivity
8 | import androidx.appcompat.widget.SearchView
9 | import androidx.recyclerview.widget.DividerItemDecoration
10 | import androidx.recyclerview.widget.GridLayoutManager
11 | import com.ellison.jetpackdemo.R
12 | import com.ellison.jetpackdemo.databinding.ActivityHiltBinding
13 | import com.ellison.jetpackdemo.hilt.bean.Movie
14 | import com.ellison.jetpackdemo.hilt.bean.MovieResponse
15 | import com.ellison.jetpackdemo.hilt.view.MovieAdapter
16 | import com.ellison.jetpackdemo.hilt.viewmodel.MovieViewModel
17 | import dagger.hilt.android.AndroidEntryPoint
18 |
19 | // @AndroidEntryPoint
20 | class DemoActivity : BaseActivity() {
21 | private val movieViewModel: MovieViewModel by viewModels()
22 | private lateinit var movieAdapter: MovieAdapter
23 | private lateinit var binding: ActivityHiltBinding
24 |
25 | override fun onCreate(savedInstanceState: Bundle?) {
26 | super.onCreate(savedInstanceState)
27 | binding = ActivityHiltBinding.inflate(layoutInflater)
28 | setContentView(binding.root)
29 |
30 | binding.search.isSubmitButtonEnabled = true
31 | binding.search.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
32 | override fun onQueryTextSubmit(query: String): Boolean {
33 | Log.d("Hilt", "onQueryTextSubmit() got query:$query")
34 | movieViewModel.searchMovie(query, this@DemoActivity) { response: MovieResponse> ->
35 | Log.d("Hilt", "onChanged() got response:$response")
36 |
37 | if (response.Response.toBoolean() && response.Search != null) {
38 | bindRecyclerView(response.Search)
39 | } else {
40 | Toast.makeText(
41 | this@DemoActivity,
42 | "Got no movie",
43 | Toast.LENGTH_SHORT
44 | ).show()
45 | }
46 | }
47 | return false
48 | }
49 |
50 | override fun onQueryTextChange(newText: String): Boolean {
51 | return false
52 | }
53 | })
54 |
55 | // supportFragmentManager.beginTransaction()
56 | // .add(R.id.container, DemoFragment::class.java, null)
57 | // .commit()
58 | }
59 |
60 | private fun bindRecyclerView(movieList: List) {
61 | movieAdapter = movieViewModel.movieAdapter
62 | movieAdapter.movieList = movieList
63 | movieAdapter.movieViewModel = movieViewModel
64 |
65 | binding.movieList.layoutManager = GridLayoutManager(binding.movieList.context, 2)
66 | binding.movieList.addItemDecoration(DividerItemDecoration(binding.movieList.context,
67 | DividerItemDecoration.VERTICAL))
68 | binding.movieList.adapter = movieAdapter
69 | }
70 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/DemoBroadcastReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import com.ellison.jetpackdemo.hilt.model.network.NetworkService
7 | import dagger.hilt.android.AndroidEntryPoint
8 | import javax.inject.Inject
9 |
10 | @AndroidEntryPoint
11 | class DemoBroadcastReceiver: BroadcastReceiver() {
12 | @Inject lateinit var networkService: NetworkService
13 | override fun onReceive(context: Context?, intent: Intent?) {
14 | TODO("Not yet implemented")
15 | }
16 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/DemoFragment.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt
2 |
3 | import android.os.Bundle
4 | import android.util.Log
5 | import android.view.View
6 | import androidx.fragment.app.Fragment
7 | // import android.app.Fragment
8 | import androidx.fragment.app.activityViewModels
9 |
10 | import com.ellison.jetpackdemo.R
11 | import com.ellison.jetpackdemo.hilt.bean.Movie
12 | import com.ellison.jetpackdemo.hilt.bean.MovieResponse
13 | import com.ellison.jetpackdemo.hilt.viewmodel.MovieViewModel
14 |
15 | import dagger.hilt.android.AndroidEntryPoint
16 |
17 | @AndroidEntryPoint
18 | class DemoFragment : Fragment(R.layout.fragment_hilt) {
19 | private val movieViewModel: MovieViewModel by activityViewModels()
20 |
21 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
22 | super.onViewCreated(view, savedInstanceState)
23 | retainInstance = true
24 | movieViewModel.searchMovie("", requireActivity()) {
25 | response: MovieResponse> ->
26 | Log.d("Hilt", "onChanged() got response:$response")
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/bean/Movie.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.bean
2 |
3 | import androidx.databinding.BaseObservable
4 | import androidx.databinding.Bindable
5 | import androidx.databinding.library.baseAdapters.BR
6 | import androidx.room.ColumnInfo
7 | import androidx.room.Entity
8 | import androidx.room.PrimaryKey
9 |
10 | @Entity
11 | class Movie(@ColumnInfo(name = "movie_name", defaultValue = "Harry Potter")
12 | private var Title: String,
13 | @ColumnInfo(name = "movie_year", defaultValue = "1991")
14 | private var Year: String,
15 | @ColumnInfo(name = "movie_id", defaultValue = "imdb324523")
16 | var imdbID: String,
17 | @ColumnInfo(name = "movie_type", defaultValue = "Movie")
18 | var Type: String,
19 | @ColumnInfo(name = "movie_poster", defaultValue = "https://ddd/dad.img")
20 | var Poster: String
21 | ) : BaseObservable() {
22 | override fun toString(): String {
23 | return "Movie(Title='$Title', Year='$Year', imdbID='$imdbID', Type='$Type')"
24 | }
25 |
26 | @JvmField
27 | @PrimaryKey(autoGenerate = true)
28 | var id = 0
29 |
30 | @Bindable
31 | fun getTitle(): String {
32 | return Title
33 | }
34 |
35 | fun setTitle(title: String) {
36 | Title = title
37 | notifyPropertyChanged(BR.title)
38 | }
39 |
40 | @Bindable
41 | fun getYear(): String {
42 | return Year
43 | }
44 |
45 | fun setYear(year: String) {
46 | Year = year
47 | notifyPropertyChanged(BR.year)
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/bean/MovieResponse.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.bean
2 |
3 | data class MovieResponse(
4 | var TotalResults: String = "0",
5 | var Response: String = "false",
6 | var Error: String = "null",
7 | var Search: T
8 | ) {
9 | override fun toString(): String {
10 | return "(TotalResults=$TotalResults,\nResponse=$Response,\nError=$Error,\nSearch=$Search)"
11 | }
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/model/LocalData.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.model
2 |
3 | import android.util.Log
4 | import com.ellison.jetpackdemo.hilt.bean.Movie
5 | import com.ellison.jetpackdemo.hilt.model.analysis.AnalysisService
6 | import com.ellison.jetpackdemo.hilt.model.database.MovieDao
7 | import javax.inject.Inject
8 |
9 | class LocalData @Inject constructor(private val analysisService: AnalysisService) {
10 | private var count = 0
11 |
12 | fun analyseMovieByAI(movie: Movie): String {
13 | return analysisService.checkSelectedMovie(movie)
14 | }
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/model/RemoteData.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.model
2 |
3 | import android.util.Log
4 | import com.ellison.jetpackdemo.hilt.bean.Movie
5 | import com.ellison.jetpackdemo.hilt.bean.MovieResponse
6 | import com.ellison.jetpackdemo.hilt.model.network.NetworkService
7 | import javax.inject.Inject
8 |
9 | // class RemoteData @Inject constructor()
10 | class RemoteData @Inject constructor(private val networkService: NetworkService) {
11 | suspend fun searchMovie(keyWord: String): MovieResponse> {
12 | Log.d("Hilt", "searchMovie() networkService:$networkService")
13 | return networkService.requestSearchByCoroutines(keyWord, "19b0bce5")
14 | }
15 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/model/Repository.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.model
2 |
3 | import android.util.Log
4 | import com.ellison.jetpackdemo.hilt.bean.Movie
5 | import com.ellison.jetpackdemo.hilt.bean.MovieResponse
6 | import javax.inject.Inject
7 |
8 | class Repository @Inject constructor(private val remoteData: RemoteData, private val localData: LocalData) {
9 | suspend fun searchMovieFromNetwork(keyWord: String): MovieResponse> {
10 | Log.d("Hilt", "searchMovieFromNetwork() remoteData:$remoteData")
11 | return remoteData.searchMovie(keyWord)
12 | }
13 |
14 | fun analyseMovieByAI(movie: Movie): String {
15 | Log.d("Hilt", "analyseMovieByAI() localData:$localData movie:$movie")
16 | return localData.analyseMovieByAI(movie)
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/model/analysis/AnalyseService.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.model.analysis
2 |
3 | import android.util.Log
4 | import com.ellison.jetpackdemo.hilt.bean.Movie
5 | import com.ellison.jetpackdemo.hilt.model.database.MovieDao
6 | import javax.inject.Inject
7 |
8 | interface AnalysisService {
9 | fun checkSelectedMovie(movie: Movie): String
10 | }
11 |
12 | class AnalysisServiceImpl @Inject constructor (
13 | private val moviedao: MovieDao): AnalysisService {
14 | override fun checkSelectedMovie(movie: Movie): String {
15 | return saveMovie(movie)
16 | }
17 |
18 | private fun saveMovie(movie: Movie): String {
19 | val result = moviedao.insert(movie)
20 | Log.d("Hilt", "saveMovie result:$result");
21 | return movie.getTitle() + ":" + result
22 | }
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/model/analysis/AnalysisModule.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.model.analysis
2 |
3 | import dagger.Binds
4 | import dagger.Module
5 | import dagger.hilt.InstallIn
6 | import dagger.hilt.android.components.ActivityComponent
7 |
8 | @Module
9 | @InstallIn(ActivityComponent::class)
10 | abstract class AnalysisModule {
11 | @Binds
12 | abstract fun bindAnalysisService(analysisService: AnalysisServiceImpl): AnalysisService
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/model/database/MovieDao.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.model.database
2 |
3 | import androidx.room.Dao
4 | import androidx.room.Insert
5 |
6 | import com.ellison.jetpackdemo.hilt.bean.Movie
7 |
8 | @Dao
9 | interface MovieDao {
10 | @Insert
11 | fun insert(movie: Movie?): Long?
12 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/model/database/NewMovieDataBase.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.model.database
2 |
3 | import androidx.room.Database
4 | import androidx.room.RoomDatabase
5 | import com.ellison.jetpackdemo.hilt.bean.Movie
6 |
7 | @Database(entities = [Movie::class], version = 1)
8 | abstract class NewMovieDataBase: RoomDatabase() {
9 | abstract fun movieDao(): MovieDao
10 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/model/database/RoomModule.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.model.database
2 |
3 | import android.app.Application
4 | import androidx.room.Room
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.android.components.ApplicationComponent
9 | import javax.inject.Singleton
10 |
11 | @Module
12 | @InstallIn(ApplicationComponent::class)
13 | class RoomModule {
14 | @Singleton
15 | @Provides
16 | fun provideNewMovieDataBase(application: Application): NewMovieDataBase {
17 | return Room.databaseBuilder(application,
18 | NewMovieDataBase::class.java,
19 | "hilt-movie.db")
20 | .fallbackToDestructiveMigrationFrom(1)
21 | .allowMainThreadQueries()
22 | .build()
23 | }
24 |
25 | @Singleton
26 | @Provides
27 | fun provideMovieDao(newMovieDataBase: NewMovieDataBase): MovieDao {
28 | return newMovieDataBase.movieDao()
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/model/interceptor/CallServerInterceptorOkHttpClient.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.model.interceptor
2 |
3 | import javax.inject.Qualifier
4 |
5 | @Qualifier
6 | @Retention(AnnotationRetention.BINARY)
7 | annotation class CallServerInterceptorOkHttpClient()
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/model/interceptor/LoggingInterceptorOkHttpClient.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.model.interceptor
2 |
3 | import javax.inject.Qualifier
4 |
5 | @Qualifier
6 | @Retention(AnnotationRetention.BINARY)
7 | annotation class LoggingInterceptorOkHttpClient()
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/model/network/NetworkModule.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.model.network
2 |
3 | import com.ellison.jetpackdemo.hilt.model.interceptor.CallServerInterceptorOkHttpClient
4 | import com.ellison.jetpackdemo.hilt.model.interceptor.LoggingInterceptorOkHttpClient
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.android.components.ApplicationComponent
9 | import okhttp3.OkHttpClient
10 | import okhttp3.internal.http.CallServerInterceptor
11 | import okhttp3.logging.HttpLoggingInterceptor
12 | import retrofit2.Retrofit
13 | import retrofit2.converter.gson.GsonConverterFactory
14 | import javax.inject.Singleton
15 |
16 | @Module
17 | @InstallIn(ApplicationComponent::class)
18 | class NetworkModule {
19 | @LoggingInterceptorOkHttpClient
20 | @Provides
21 | fun provideLoggingInterceptorOkHttpClient(): OkHttpClient {
22 | val logging = HttpLoggingInterceptor()
23 | logging.setLevel(HttpLoggingInterceptor.Level.BASIC)
24 | return OkHttpClient.Builder().addInterceptor(logging).build()
25 | }
26 |
27 | @CallServerInterceptorOkHttpClient
28 | @Provides
29 | fun provideCallServerInterceptorOkHttpClient(): OkHttpClient {
30 | return OkHttpClient.Builder().addInterceptor(CallServerInterceptor(false)).build()
31 | }
32 |
33 | @Provides
34 | fun provideGsonConverterFactory(): GsonConverterFactory {
35 | return GsonConverterFactory.create()
36 | }
37 |
38 | @Provides
39 | @Singleton
40 | fun provideMovieService(@LoggingInterceptorOkHttpClient okHttpClient: OkHttpClient,
41 | gsonConverterFactory: GsonConverterFactory): NetworkService {
42 | return Retrofit.Builder()
43 | .baseUrl("http://omdbapi.com/")
44 | .addConverterFactory(gsonConverterFactory)
45 | .client(okHttpClient)
46 | .build()
47 | .create(NetworkService::class.java)
48 | }
49 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/model/network/NetworkService.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.model.network
2 |
3 | import com.ellison.jetpackdemo.hilt.bean.Movie
4 | import com.ellison.jetpackdemo.hilt.bean.MovieResponse
5 | import retrofit2.http.GET
6 | import retrofit2.http.Query
7 |
8 | interface NetworkService {
9 | @GET("http://omdbapi.com/")
10 | suspend fun requestSearchByCoroutines(
11 | @Query("s") keywords: String,
12 | @Query("apikey") apikey: String
13 | ): MovieResponse>
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/view/MovieAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.view
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.Toast
9 | import androidx.databinding.ViewDataBinding
10 | import androidx.fragment.app.FragmentActivity
11 | import androidx.recyclerview.widget.RecyclerView
12 | import com.ellison.jetpackdemo.databinding.ActivityHiltItemBinding
13 | import com.ellison.jetpackdemo.hilt.bean.Movie
14 | import com.ellison.jetpackdemo.hilt.viewmodel.MovieViewModel
15 | import dagger.hilt.android.qualifiers.ActivityContext
16 | import javax.inject.Inject
17 |
18 | class MovieAdapter @Inject constructor(@ActivityContext private val context: Context)
19 | : RecyclerView.Adapter() {
20 | lateinit var movieList: List
21 | lateinit var movieViewModel: MovieViewModel
22 |
23 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
24 | Log.d("Hilt", "MovieAdapter#onCreateViewHolder() parent:$parent")
25 | return MovieHolder(ActivityHiltItemBinding.inflate(LayoutInflater.from(parent.context),
26 | parent, false))
27 | }
28 |
29 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
30 | Log.d("Hilt", "MovieAdapter#onBindViewHolder() holder:$holder position:$position")
31 | val itemBinding = ((holder as MovieHolder).binding as ActivityHiltItemBinding)
32 | itemBinding.movie = movieList[position]
33 | itemBinding.movieName.tag = position
34 | itemBinding.setResponder(EventResponder())
35 | }
36 |
37 | override fun getItemCount(): Int {
38 | return movieList.size
39 | }
40 |
41 | private class MovieHolder(var binding: ViewDataBinding) : RecyclerView.ViewHolder(binding.root)
42 |
43 | // Event binding.
44 | inner class EventResponder {
45 | fun onClick(view: View) {
46 | Log.d("Hilt", "onClick() view:$view")
47 | val result = movieViewModel?.analyseMovie(movieList.get(view.tag as Int))
48 | Toast.makeText(context, result, Toast.LENGTH_SHORT).show()
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/hilt/viewmodel/MovieViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.hilt.viewmodel
2 |
3 | import android.util.Log
4 | import androidx.fragment.app.FragmentActivity
5 | import androidx.hilt.lifecycle.ViewModelInject
6 | import androidx.lifecycle.MutableLiveData
7 | import androidx.lifecycle.Observer
8 | import androidx.lifecycle.ViewModel
9 | import androidx.lifecycle.viewModelScope
10 | import com.ellison.jetpackdemo.hilt.bean.Movie
11 | import com.ellison.jetpackdemo.hilt.bean.MovieResponse
12 | import com.ellison.jetpackdemo.hilt.model.Repository
13 | import com.ellison.jetpackdemo.hilt.view.MovieAdapter
14 | import kotlinx.coroutines.CoroutineExceptionHandler
15 | import kotlinx.coroutines.Dispatchers
16 | import kotlinx.coroutines.launch
17 |
18 | class MovieViewModel @ViewModelInject constructor(private val repository: Repository,
19 | var movieAdapter: MovieAdapter
20 | ) : ViewModel() {
21 | private val resultData = MutableLiveData>>()
22 |
23 | fun searchMovie(keyWord: String, fragmentActivity: FragmentActivity, observer: Observer>>) {
24 | Log.d("Hilt", "searchMovie() repository:$repository")
25 | resultData.observe(fragmentActivity, observer)
26 |
27 | viewModelScope.launch(Dispatchers.Main + CoroutineExceptionHandler { coroutineContext, throwable ->
28 | Log.d("Hilt", "coroutine exception: $throwable")
29 | }) {
30 | Log.d("Hilt", "searchMovie() searchMovieFromNetwork keyWord:$keyWord")
31 | val response = repository.searchMovieFromNetwork(keyWord)
32 | resultData.value = response
33 | }
34 | }
35 |
36 | fun analyseMovie(movie: Movie): String {
37 | return repository.analyseMovieByAI(movie)
38 | }
39 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/lifecycle/DemoActivity.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.lifecycle;
2 |
3 | import android.os.Bundle;
4 | import android.util.Log;
5 |
6 | import com.ellison.jetpackdemo.databinding.ActivityLifecycleBinding;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.annotation.Nullable;
10 | import androidx.appcompat.app.AppCompatActivity;
11 | import androidx.lifecycle.DefaultLifecycleObserver;
12 | import androidx.lifecycle.GenericLifecycleObserver;
13 | import androidx.lifecycle.Lifecycle;
14 | import androidx.lifecycle.LifecycleObserver;
15 | import androidx.lifecycle.LifecycleOwner;
16 | import androidx.lifecycle.LifecycleRegistry;
17 |
18 | public class DemoActivity extends AppCompatActivity {
19 | static final String TAG = DemoActivity.class.getSimpleName();
20 | LifecycleObserver mLifecycleObserver;
21 | private LifecycleRegistry lifecycleRegistry;
22 |
23 | @Override
24 | protected void onCreate(@Nullable Bundle savedInstanceState) {
25 | Log.d(TAG, "MYSELF onCreate()");
26 | super.onCreate(savedInstanceState);
27 |
28 | ActivityLifecycleBinding binding = ActivityLifecycleBinding.inflate(getLayoutInflater());
29 | setContentView(binding.getRoot());
30 |
31 | getLifecycle().addObserver(new DefaultLifecycleObserver() {
32 | @Override
33 | public void onCreate(@NonNull LifecycleOwner owner) {
34 | Log.d(TAG, "DefaultLifecycleObserver#onCreate()");
35 | }
36 | });
37 |
38 | getLifecycle().addObserver(new GenericLifecycleObserver() {
39 | @Override
40 | public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
41 | Log.d(TAG, "GenericLifecycleObserver#onStateChanged() source:" + source + " event:" + event);
42 | }
43 | });
44 |
45 | mLifecycleObserver = new LifeCycleObserverImpl(getLifecycle());
46 | getLifecycle().addObserver(mLifecycleObserver);
47 |
48 | // lifecycleRegistry = new LifecycleRegistry(this);
49 | // lifecycleRegistry.markState(Lifecycle.State.CREATED);
50 | }
51 |
52 | // @NonNull
53 | // @Override
54 | // public Lifecycle getLifecycle() {
55 | // return lifecycleRegistry;
56 | // }
57 |
58 | @Override
59 | protected void onDestroy() {
60 | Log.d(TAG, "MYSELF onDestroy()");
61 | super.onDestroy();
62 | getLifecycle().removeObserver(mLifecycleObserver);
63 | }
64 |
65 | private static final class MyTestInterface implements TestInterface {
66 | @Override
67 | public int getAge() {
68 | return 0;
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/lifecycle/LifeCycleObserverImpl.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.lifecycle;
2 |
3 | import android.util.Log;
4 |
5 | import androidx.lifecycle.Lifecycle;
6 | import androidx.lifecycle.LifecycleObserver;
7 | import androidx.lifecycle.OnLifecycleEvent;
8 |
9 | import static com.ellison.jetpackdemo.lifecycle.DemoActivity.TAG;
10 |
11 | public class LifeCycleObserverImpl implements LifecycleObserver {
12 | private Lifecycle lifecycle;
13 |
14 | public LifeCycleObserverImpl(Lifecycle lifecycle) {
15 | this.lifecycle = lifecycle;
16 | }
17 |
18 | @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
19 | public void onCreate() {
20 | Log.d(TAG, "LifeCycleObserverImpl#onCreate()");
21 | }
22 |
23 | @OnLifecycleEvent(Lifecycle.Event.ON_START)
24 | public void onStart() {
25 | Log.d(TAG, "LifeCycleObserverImpl#onStart()" + lifecycle.getCurrentState().isAtLeast(Lifecycle.State.STARTED));
26 | }
27 |
28 | @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
29 | public void onResume() {
30 | Log.d(TAG, "LifeCycleObserverImpl#onResume()");
31 | }
32 |
33 | @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
34 | public void onPause() {
35 | Log.d(TAG, "LifeCycleObserverImpl#onPause()");
36 | }
37 |
38 | @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
39 | public void onStop() {
40 | Log.d(TAG, "LifeCycleObserverImpl#onStop()");
41 | }
42 |
43 | @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
44 | public void onDestory() {
45 | Log.d(TAG, "LifeCycleObserverImpl#onDestory()");
46 | }
47 |
48 | @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
49 | public void onAny() {
50 | Log.d(TAG, "LifeCycleObserverImpl#onAny()");
51 | }
52 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/lifecycle/TestInterface.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.lifecycle;
2 |
3 | public interface TestInterface {
4 | static final String TAG = TestInterface.class.getSimpleName();
5 | default void getName() {}
6 | int getAge();
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/liveData/DemoActivity.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.liveData;
2 |
3 | import android.os.Bundle;
4 | import android.util.Log;
5 | import android.view.View;
6 |
7 | import com.ellison.jetpackdemo.databinding.ActivityLiveDataBinding;
8 |
9 | import androidx.annotation.Nullable;
10 | import androidx.appcompat.app.AppCompatActivity;
11 |
12 | public class DemoActivity extends AppCompatActivity {
13 | static final String TAG = DemoActivity.class.getSimpleName();
14 | ActivityLiveDataBinding binding;
15 |
16 | @Override
17 | protected void onCreate(@Nullable Bundle savedInstanceState) {
18 | Log.d(TAG, "MYSELF onCreate()");
19 | super.onCreate(savedInstanceState);
20 |
21 | binding = ActivityLiveDataBinding.inflate(getLayoutInflater());
22 | setContentView(binding.getRoot());
23 |
24 | binding.setResponder(new EventResponder());
25 | }
26 |
27 | // Event binding.
28 | public class EventResponder {
29 | public void onClickUpdate() {
30 | Log.d(TAG, "onClickUpdate() UPDATE INFO");
31 | new MovieLiveData("Rush Hour").observe(DemoActivity.this, movie -> {
32 | Log.d(TAG, "onChanged() movie:" + movie);
33 | binding.testMovie.setVisibility(View.VISIBLE);
34 | binding.name.setText(movie.name);
35 | binding.type.setText(movie.type);
36 | binding.actor.setText(movie.actor);
37 | binding.post.setBackgroundResource(movie.postID);
38 | });
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/liveData/Movie.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.liveData;
2 |
3 | public class Movie {
4 | String name;
5 | String type;
6 | String actor;
7 | int postID;
8 |
9 | public Movie(String name, String type, String actor, int postID) {
10 | this.name = name;
11 | this.type = type;
12 | this.actor = actor;
13 | this.postID = postID;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/liveData/MovieChangeListener.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.liveData;
2 |
3 | public interface MovieChangeListener {
4 | default void onMovieUpdated(Movie updatedMovie) {}
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/liveData/MovieLiveData.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.liveData;
2 |
3 | import android.util.Log;
4 |
5 | import androidx.lifecycle.LiveData;
6 | import static com.ellison.jetpackdemo.liveData.DemoActivity.TAG;
7 |
8 | public class MovieLiveData extends LiveData {
9 | MovieManager movieManager;
10 |
11 | MovieChangeListener listener = new MovieChangeListener() {
12 | @Override
13 | public void onMovieUpdated(Movie updatedMovie) {
14 | Log.d(TAG, "onMovieUpdated() updatedMovie:" + updatedMovie);
15 | setValue(updatedMovie);
16 | }
17 | };
18 |
19 | public MovieLiveData(String name) {
20 | movieManager = new MovieManager(name);
21 | }
22 |
23 | @Override
24 | protected void onActive() {
25 | super.onActive();
26 | Log.d(TAG, "onActive()");
27 | movieManager.movieChangeRequest(listener);
28 | }
29 |
30 | @Override
31 | protected void onInactive() {
32 | super.onInactive();
33 | Log.d(TAG, "onInactive()");
34 | movieManager.movieChangeDrop(listener);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/liveData/MovieManager.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.liveData;
2 |
3 | import com.ellison.jetpackdemo.R;
4 |
5 | public class MovieManager {
6 | String name;
7 |
8 | public MovieManager(String name) {
9 | this.name = name;
10 | }
11 |
12 | void movieChangeRequest(MovieChangeListener listener) {
13 | listener.onMovieUpdated(new Movie(name, "Action", "Jackie Chan", R.drawable.ic_movie_post));
14 | }
15 |
16 | void movieChangeDrop(MovieChangeListener listener) {
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/old/DemoActivity.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.old;
2 |
3 | import android.os.Bundle;
4 |
5 | import com.ellison.jetpackdemo.R;
6 |
7 | import androidx.annotation.Nullable;
8 | import android.app.Activity;
9 |
10 | public class DemoActivity extends Activity {
11 | @Override
12 | protected void onCreate(@Nullable Bundle savedInstanceState) {
13 | super.onCreate(savedInstanceState);
14 | setContentView(R.layout.activity_old);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/room/DemoActivity.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.room
2 |
3 | import android.os.Bundle
4 | import android.text.TextUtils
5 | import android.util.Log
6 | import android.view.Menu
7 | import android.view.MenuItem
8 | import androidx.appcompat.app.AppCompatActivity
9 | import androidx.appcompat.widget.SearchView
10 | import androidx.lifecycle.ViewModelProvider
11 | import com.ellison.jetpackdemo.R
12 | import com.ellison.jetpackdemo.databinding.ActivityRoomDbBinding
13 |
14 | class DemoActivity : AppCompatActivity() {
15 | private var movieViewModel: MovieViewModel? = null
16 | private var binding: ActivityRoomDbBinding? = null
17 | private var movieList: List? = null
18 |
19 | override fun onCreate(savedInstanceState: Bundle?) {
20 | super.onCreate(savedInstanceState)
21 |
22 | binding = ActivityRoomDbBinding.inflate(layoutInflater)
23 | setContentView(binding!!.root)
24 | binding!!.lifecycleOwner = this
25 |
26 | movieViewModel = ViewModelProvider(this).get(MovieViewModel::class.java)
27 | movieViewModel?.getMovieList(this, { movieList: List? ->
28 | if (movieList == null) return@getMovieList
29 | Log.d(MovieDataBase.TAG, "onChanged() movieList:$movieList")
30 |
31 | this.movieList = movieList
32 | binding?.setMovieList(movieList)
33 | })
34 | }
35 |
36 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
37 | menuInflater.inflate(R.menu.room_menu, menu)
38 |
39 | val myActionMenuItem = menu.findItem(R.id.action_search)
40 | val searchView = myActionMenuItem.actionView as SearchView
41 |
42 | searchView.isSubmitButtonEnabled = true
43 | searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
44 | override fun onQueryTextSubmit(query: String): Boolean {
45 | Log.d(MovieDataBase.TAG, "onQueryTextSubmit() query:$query")
46 |
47 | if (!TextUtils.isEmpty(query) && movieViewModel != null) {
48 | movieViewModel!!.searchMovie(this@DemoActivity, { movieList: List? ->
49 | Log.d(MovieDataBase.TAG, "onChanged() movieList:$movieList")
50 | binding?.setMovieList(movieList)
51 | }, query)
52 | }
53 | return false
54 | }
55 |
56 | override fun onQueryTextChange(newText: String): Boolean {
57 | Log.d(MovieDataBase.TAG, "onQueryTextChange() newText:$newText")
58 | if (TextUtils.isEmpty(newText)) {
59 | binding?.setMovieList(movieList)
60 | }
61 | return true
62 | }
63 | })
64 | return true
65 | }
66 |
67 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
68 | if (movieViewModel == null) return false
69 |
70 | if (R.id.action_filter == item.itemId) {
71 | movieViewModel!!.filterMovieByScore(this, { movieList: List? ->
72 | Log.d(MovieDataBase.TAG, "onOptionsItemSelected sort onChanged() movieList:$movieList")
73 | binding?.setMovieList(movieList)
74 | }, 7.0)
75 | return true
76 | } else if (R.id.action_add == item.itemId) {
77 | movieViewModel!!.getMovie(this, { movie: Movie? ->
78 | val newMovie = Movie("Kungfu kid", "Jackie Chan", 2011, 7.0)
79 | Log.d(MovieDataBase.TAG, "onOptionsItemSelected add onChanged() movie:$movie")
80 | if (movie != null) {
81 | movieViewModel!!.addDeleteMovie(this, null, newMovie, movie)
82 | }
83 | }, 1)
84 | return true
85 | }
86 | return false
87 | }
88 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/room/GestureListener.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.room
2 |
3 | import androidx.recyclerview.widget.RecyclerView
4 |
5 | interface GestureListener {
6 | fun onDeleteItem(targetHolder: RecyclerView.ViewHolder?) {}
7 | fun onSwapItem(fromHolder: RecyclerView.ViewHolder?, targetHolder: RecyclerView.ViewHolder?) {}
8 | fun onGestureDone() {}
9 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/room/Movie.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.room
2 |
3 | import androidx.databinding.BaseObservable
4 | import androidx.databinding.Bindable
5 | import androidx.databinding.library.baseAdapters.BR
6 | import androidx.room.ColumnInfo
7 | import androidx.room.Entity
8 | import androidx.room.Ignore
9 | import androidx.room.PrimaryKey
10 |
11 | @Entity
12 | class Movie() : BaseObservable() {
13 | constructor(name: String, actor: String, year: Int, score: Double) : this() {
14 | this.name = name
15 | this.actor = actor
16 | this.year = year
17 | this.score = score
18 | }
19 |
20 | @Ignore
21 | constructor(name: String, actor: String, year: Int) : this(name, actor, year, 8.0) {
22 | }
23 |
24 | @JvmField
25 | @PrimaryKey(autoGenerate = true)
26 | var id = 0
27 |
28 | @ColumnInfo(name = "movie_name", defaultValue = "Harry Potter")
29 | lateinit var name: String
30 |
31 | @ColumnInfo(name = "actor_name", defaultValue = "Jack Daniel")
32 | lateinit var actor: String
33 |
34 | @ColumnInfo(name = "post_year", defaultValue = "1999")
35 | var year = 1999
36 |
37 | @ColumnInfo(name = "review_score", defaultValue = "8.0")
38 | var score = 8.0
39 |
40 | fun getId(): Int {
41 | return id
42 | }
43 |
44 | fun setId(id: Int) {
45 | this.id = id
46 | }
47 |
48 | @JvmName("getName1")
49 | @Bindable
50 | fun getName(): String {
51 | return name
52 | }
53 |
54 | @JvmName("setName1")
55 | fun setName(name: String) {
56 | this.name = name
57 | notifyPropertyChanged(BR.name1)
58 | }
59 |
60 | @JvmName("getActor1")
61 | @Bindable
62 | fun getActor(): String {
63 | return actor
64 | }
65 |
66 | @JvmName("setActor1")
67 | fun setActor(actor: String) {
68 | this.actor = actor
69 | notifyPropertyChanged(BR.actor1)
70 | }
71 |
72 | @JvmName("getYear1")
73 | fun getYear(): Int {
74 | return year
75 | }
76 |
77 | @JvmName("setYear1")
78 | @Bindable
79 | fun setYear(year: Int) {
80 | this.year = year
81 | notifyPropertyChanged(BR.year1)
82 | }
83 |
84 | @JvmName("getScore1")
85 | fun getScore(): Double {
86 | return score
87 | }
88 |
89 | @JvmName("setScore1")
90 | @Bindable
91 | fun setScore(score: Double) {
92 | this.score = score
93 | notifyPropertyChanged(BR.score1)
94 | }
95 |
96 | override fun toString(): String {
97 | return "Movie{" +
98 | "id=" + id +
99 | ", name='" + name + '\'' +
100 | ", actor='" + actor + '\'' +
101 | ", year='" + year + '\'' +
102 | ", score='" + score + '\'' +
103 | '}'
104 | }
105 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/room/MovieDao.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.room
2 |
3 | import android.database.Cursor
4 | import androidx.lifecycle.LiveData
5 | import androidx.room.*
6 |
7 | @Dao
8 | interface MovieDao {
9 | @Insert
10 | fun insertWithOutId(movie: Movie?)
11 |
12 | @Insert
13 | fun insert(movie: Movie?): Long?
14 |
15 | @Insert
16 | fun insert(vararg movies: Movie?): LongArray?
17 |
18 | @Delete
19 | fun delete(movie: Movie?): Int
20 |
21 | @Delete
22 | fun delete(vararg movies: Movie?): Int
23 |
24 | @Update
25 | fun update(vararg movies: Movie?): Int
26 |
27 | @get:Query("SELECT * FROM movie")
28 | val allMovies: LiveData?>
29 |
30 | @get:Query("SELECT id, movie_name, actor_name, post_year, review_score FROM movie")
31 | val partMovies: LiveData?>
32 |
33 | @get:Query("SELECT * FROM movie ORDER BY post_year DESC")
34 | val allMoviesByOrder: LiveData?>
35 |
36 | @Query("SELECT * FROM movie WHERE id = :id")
37 | fun getMovie(id: Int): LiveData?
38 |
39 | @Query("SELECT * FROM movie WHERE post_year > :year")
40 | fun getMoveOverYear(year: Int): List?
41 |
42 | @Query("SELECT * FROM movie WHERE post_year BETWEEN :minYear AND :maxYear")
43 | fun getMoveOverYear(minYear: Int, maxYear: Int): LiveData?>?
44 |
45 | @Query("SELECT * FROM movie WHERE review_score >= :minScore")
46 | fun getMoveOverScore(minScore: Double): LiveData?>?
47 |
48 | @Query("SELECT * FROM movie WHERE movie_name LIKE :keyWord OR " +
49 | " actor_name LIKE :keyWord LIMIT 1")
50 | fun searchBestMove(keyWord: String?): Movie?
51 |
52 | @Query("SELECT * FROM movie WHERE movie_name LIKE :keyWord " +
53 | " OR actor_name LIKE :keyWord")
54 | fun searchMove(keyWord: String?): List?
55 |
56 | @Query("SELECT * FROM movie WHERE movie_name LIKE :keyWord " +
57 | " OR actor_name LIKE :keyWord")
58 | fun searchMoveFuzzyInternal(keyWord: String?): List?
59 |
60 | @Query("SELECT * FROM movie WHERE movie_name LIKE '%' || :keyWord || '%' " +
61 | " OR actor_name LIKE '%' || :keyWord || '%'")
62 | fun searchMoveFuzzy(keyWord: String?): List?
63 |
64 | @Query("SELECT * FROM movie WHERE movie_name LIKE '%' || :keyWord || '%' " +
65 | " OR actor_name LIKE '%' || :keyWord || '%' LIMIT :limit")
66 | fun searchMoveFuzzyByLimit(keyWord: String?, limit: Int): LiveData?>?
67 |
68 | @Query("SELECT * FROM movie WHERE movie_name IN (:keyWords)")
69 | fun findMove(keyWords: List?): List?
70 |
71 | @Query("SELECT * FROM movie WHERE movie_name LIKE '%' || :keyWord || '%' " +
72 | " OR actor_name LIKE '%' || :keyWord || '%' LIMIT :limit")
73 | fun searchMoveCursorByLimit(keyWord: String?, limit: Int): Cursor?
74 |
75 | @Query("SELECT * FROM movie WHERE movie_name LIKE '%' || :keyWord || '%' " +
76 | " OR actor_name LIKE '%' || :keyWord || '%'")
77 | fun searchMoveCursor(keyWord: String?): Cursor?
78 |
79 | @Transaction
80 | fun insetNewAndDeleteOld(newMovie: Movie?, oldMovie: Movie?) {
81 | insert(newMovie)
82 | delete(oldMovie)
83 | }
84 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/room/MovieGestureCallback.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.room
2 |
3 | import android.util.Log
4 | import androidx.recyclerview.widget.ItemTouchHelper
5 | import androidx.recyclerview.widget.RecyclerView
6 |
7 | class MovieGestureCallback(private var listener: GestureListener?)
8 | : ItemTouchHelper.SimpleCallback(ItemTouchHelper.DOWN or ItemTouchHelper.UP, ItemTouchHelper.LEFT) {
9 | private val adapter: MovieAdapter? = null
10 |
11 | override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
12 | Log.d(MovieDataBase.TAG, "onSwiped() viewHolder:$viewHolder direction:$direction"
13 | + " listener:" + System.identityHashCode(listener)
14 | + " adapter:" + System.identityHashCode(adapter))
15 |
16 | if (listener != null && direction == ItemTouchHelper.LEFT) {
17 | listener!!.onDeleteItem(viewHolder)
18 | }
19 |
20 | if (adapter != null && direction == ItemTouchHelper.LEFT) {
21 | adapter.onDeleteItem(viewHolder)
22 | }
23 | }
24 |
25 | override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder,
26 | target: RecyclerView.ViewHolder): Boolean {
27 | Log.d(MovieDataBase.TAG, "onMove() recyclerView:$recyclerView viewHolder:$viewHolder target:$target")
28 | if (listener != null) {
29 | listener!!.onSwapItem(viewHolder, target)
30 | return true
31 | }
32 | return false
33 | }
34 |
35 | override fun onMoved(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder,
36 | fromPos: Int, target: RecyclerView.ViewHolder, toPos: Int, x: Int, y: Int) {
37 | Log.d(MovieDataBase.TAG, "onMoved() recyclerView:$recyclerView")
38 | super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y)
39 | }
40 |
41 | override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
42 | Log.d(MovieDataBase.TAG, "onSelectedChanged() actionState:$actionState")
43 | super.onSelectedChanged(viewHolder, actionState)
44 | if (listener != null && actionState == ItemTouchHelper.ACTION_STATE_IDLE) {
45 | listener!!.onGestureDone()
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/room/Utils.kt:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.room
2 |
3 | import android.util.Log
4 | import java.util.*
5 |
6 | object Utils {// Create instances with id.
7 | // movies[i] = new Movie(i + 1, "Harry Potter" + i, "Daniel_" + i );
8 |
9 | // // Create instances with same id.
10 | // movies[i] = new Movie(1, "Harry Potter" + i, "Daniel_" + i );
11 |
12 | // Create instances without id.
13 | // movies[i] = new Movie("Harry Potter" + (i + 1), "Daniel_" + (i + 1), 1999 + i);
14 | // Test column null
15 | // movies[i] = new Movie("Harry Potter" + i, null);
16 | // movies[i] = new Movie("Harry Potter" + i);
17 | // public static Movie[] getInitData() {
18 | // List movies = new ArrayList<>(15);
19 | // for (int i = 0; i < 10; i++) {
20 | // movies.add(new Movie(i + 1, "Harry Potter" + i, "Daniel_" + i ));
21 | // }
22 | // return (Movie[]) movies.toArray();
23 | // }
24 | val initData: Array
25 | get() {
26 | val movies = arrayOfNulls(9)
27 | for (i in movies.indices) {
28 | // Create instances with id.
29 | // movies[i] = new Movie(i + 1, "Harry Potter" + i, "Daniel_" + i );
30 |
31 | // // Create instances with same id.
32 | // movies[i] = new Movie(1, "Harry Potter" + i, "Daniel_" + i );
33 |
34 | // Create instances without id.
35 | // movies[i] = new Movie("Harry Potter" + (i + 1), "Daniel_" + (i + 1), 1999 + i);
36 | movies[i] = Movie("Harry Potter" + (i + 1),
37 | "Daniel_" + (i + 1),
38 | 1999 + i,
39 | (1 + i).toDouble())
40 | // Test column null
41 | // movies[i] = new Movie("Harry Potter" + i, null);
42 | // movies[i] = new Movie("Harry Potter" + i);
43 | }
44 | Log.d(MovieDataBase.Companion.TAG, "getInitData movies:" + Arrays.toString(movies))
45 | return movies
46 | }
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewBinding/DemoActivity.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewBinding;
2 |
3 | import android.os.Bundle;
4 | import android.widget.Toast;
5 |
6 | import com.ellison.jetpackdemo.R;
7 | import com.ellison.jetpackdemo.databinding.ActivityViewBindingBinding;
8 |
9 | import androidx.annotation.Nullable;
10 | import androidx.appcompat.app.AppCompatActivity;
11 |
12 | public class DemoActivity extends AppCompatActivity {
13 | @Override
14 | protected void onCreate(@Nullable Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 |
17 | ActivityViewBindingBinding binding = ActivityViewBindingBinding.inflate(getLayoutInflater());
18 | setContentView(binding.getRoot());
19 |
20 | binding.testLayout.setOnClickListener(view -> Toast.makeText(this, "U clicked empty area.", Toast.LENGTH_SHORT).show());
21 | binding.testBtn.setOnClickListener(view -> Toast.makeText(this, "U clicked button.", Toast.LENGTH_SHORT).show());
22 | getSupportFragmentManager().beginTransaction().replace(R.id.test_container, DemoFragment.newInstance()).commitNow();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewBinding/DemoFragment.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewBinding;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.Toast;
8 |
9 | import com.ellison.jetpackdemo.databinding.FragmentViewBindingBinding;
10 |
11 | import androidx.annotation.NonNull;
12 | import androidx.annotation.Nullable;
13 | import androidx.fragment.app.Fragment;
14 |
15 | public class DemoFragment extends Fragment {
16 | FragmentViewBindingBinding mBinding;
17 |
18 | public static DemoFragment newInstance() {
19 | return new DemoFragment();
20 | }
21 |
22 | @Nullable
23 | @Override
24 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
25 | mBinding = FragmentViewBindingBinding.inflate(inflater, container, false);
26 | return mBinding.getRoot();
27 | }
28 |
29 | @Override
30 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
31 | mBinding.getRoot().setOnClickListener(view1 -> Toast.makeText(getContext(), "U clicked else empty area.", Toast.LENGTH_SHORT).show());
32 | if (mBinding.testIv != null) {
33 | mBinding.testIv.setOnClickListener(view1 -> Toast.makeText(getContext(), "U clicked image.", Toast.LENGTH_SHORT).show());
34 | }
35 | if (mBinding.testIvLand != null) {
36 | mBinding.testIvLand.setOnClickListener(view1 -> Toast.makeText(getContext(), "U clicked landscape image.", Toast.LENGTH_SHORT).show());
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewModel/DemoActivity.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewModel;
2 |
3 | import android.os.Bundle;
4 | import android.util.Log;
5 |
6 | import com.ellison.jetpackdemo.R;
7 | import com.ellison.jetpackdemo.databinding.ActivityViewModelBinding;
8 |
9 | import androidx.annotation.Nullable;
10 | import androidx.appcompat.app.AppCompatActivity;
11 | import androidx.appcompat.widget.SearchView;
12 | import androidx.lifecycle.HasDefaultViewModelProviderFactory;
13 | import androidx.lifecycle.ViewModelProvider;
14 |
15 | public class DemoActivity extends AppCompatActivity {
16 | @Override
17 | protected void onCreate(@Nullable Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 |
20 | ActivityViewModelBinding binding = ActivityViewModelBinding.inflate(getLayoutInflater());
21 | setContentView(binding.getRoot());
22 |
23 | Log.d("ViewModel", "onCreate() GET VIEW MODEL INSTANCE WITH:" + ((HasDefaultViewModelProviderFactory) this).getDefaultViewModelProviderFactory());
24 | // final PersonModel model = new ViewModelProvider(this).get(PersonModel.class);
25 | // final PersonModel model = ViewModelProviders.of(this).get(PersonModel.class);
26 | final PersonContextModel model = new ViewModelProvider(this).get(PersonContextModel.class);
27 | // final PersonContextModel model = new ViewModelProvider(this).get(PersonContextStateModel.class);
28 |
29 | Log.d("ViewModel", "onCreate() OBSERVE START");
30 | model.mPersonLiveData.observe(this, person -> {
31 | Log.d("ViewModel", "onCreate() OBSERVED DATA:" + person);
32 | binding.testName.setText(person.getName());
33 | binding.testAge.setText(String.valueOf(person.getAge()));
34 | }
35 | );
36 |
37 | binding.testGet.setOnClickListener(view -> model.getPersonInWork());
38 | binding.testUpdate.setOnClickListener(view -> model.updatePersonInWork());
39 | binding.testFragment.setOnClickListener(view -> getSupportFragmentManager().beginTransaction().replace(R.id.test_container, new DemoFragment()).commit());
40 | binding.testFragment2.setOnClickListener(view -> getSupportFragmentManager().beginTransaction().replace(R.id.test_container2, new OtherFragment()).commit());
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewModel/DemoFragment.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewModel;
2 |
3 | import android.os.Bundle;
4 | import android.util.Log;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | import com.ellison.jetpackdemo.databinding.FragmentViewModelBinding;
10 |
11 | import androidx.annotation.NonNull;
12 | import androidx.annotation.Nullable;
13 | import androidx.fragment.app.Fragment;
14 | import androidx.lifecycle.ViewModelProvider;
15 |
16 | public class DemoFragment extends Fragment {
17 | private FragmentViewModelBinding fragmentViewModelBinding;
18 |
19 | @Nullable
20 | @Override
21 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
22 | Log.d("ViewModel", "onCreateView()");
23 | fragmentViewModelBinding = FragmentViewModelBinding.inflate(inflater, container, false);
24 | return fragmentViewModelBinding.getRoot();
25 | }
26 |
27 | @Override
28 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
29 | super.onViewCreated(view, savedInstanceState);
30 | new ViewModelProvider(getActivity()).get(PersonContextModel.class).mPersonLiveData.observe(this, person -> {
31 | // new ViewModelProvider(getActivity()).get(PersonContextStateModel.class).mPersonLiveData.observe(this, person -> {
32 | Log.d("ViewModel", "DemoFragment#onViewCreated() update");
33 | fragmentViewModelBinding.name.setText(person.getName());
34 | fragmentViewModelBinding.age.setText(String.valueOf(person.getAge()));
35 | });
36 |
37 | PersonModel model = new ViewModelProvider(getActivity()).get(PersonModel.class);
38 | // PersonModel model = new ViewModelProvider(getActivity()).get(PersonStateModel.class);
39 |
40 | fragmentViewModelBinding.testGet.setOnClickListener(view2 -> {
41 | Log.d("ViewModel", "DemoFragment#onViewCreated() set value");
42 | model.getPersonInWork();
43 | });
44 |
45 | fragmentViewModelBinding.testUpdate.setOnClickListener(view2 -> {
46 | Log.d("ViewModel", "DemoFragment#onViewCreated() set value");
47 | model.updatePersonInWork();
48 | });
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewModel/OtherFragment.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewModel;
2 |
3 | import android.os.Bundle;
4 | import android.util.Log;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | import com.ellison.jetpackdemo.databinding.FragmentOtherViewModelBinding;
10 |
11 | import androidx.annotation.NonNull;
12 | import androidx.annotation.Nullable;
13 | import androidx.fragment.app.Fragment;
14 | import androidx.lifecycle.ViewModelProvider;
15 |
16 | public class OtherFragment extends Fragment {
17 | private FragmentOtherViewModelBinding fragmentOtherViewModelBinding;
18 |
19 | @Nullable
20 | @Override
21 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
22 | Log.d("ViewModel", "onCreateView()");
23 | fragmentOtherViewModelBinding = FragmentOtherViewModelBinding.inflate(inflater, container, false);
24 | return fragmentOtherViewModelBinding.getRoot();
25 | }
26 |
27 | @Override
28 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
29 | super.onViewCreated(view, savedInstanceState);
30 | new ViewModelProvider(getActivity()).get(PersonModel.class).mPersonLiveData.observe(this, person -> {
31 | // new ViewModelProvider(getActivity()).get(PersonStateModel.class).mPersonLiveData.observe(this, person -> {
32 | Log.d("ViewModel", "OtherFragment#onViewCreated() update");
33 | fragmentOtherViewModelBinding.name.setText(person.getName());
34 | fragmentOtherViewModelBinding.age.setText(String.valueOf(person.getAge()));
35 | });
36 |
37 | // new ViewModelProvider(this).get(PersonModel.class).mPersonLiveData.observe(this, person -> {
38 | // Log.d("ViewModel", "OtherFragment#onViewCreated() update person:" + person);
39 | // });
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewModel/Person.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewModel;
2 |
3 | public class Person {
4 | private String name;
5 | private int age;
6 |
7 | public Person(int age, String name) {
8 | this.age = age;
9 | this.name = name;
10 | }
11 |
12 | public int getAge() {
13 | return age;
14 | }
15 |
16 | public void setAge(int age) {
17 | this.age = age;
18 | }
19 |
20 | public String getName() {
21 | return name;
22 | }
23 |
24 | public void setName(String name) {
25 | this.name = name;
26 | }
27 |
28 | @Override
29 | public String toString() {
30 | return "UserBean{" +
31 | "age=" + age +
32 | ", name='" + name + '\'' +
33 | '}';
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewModel/PersonContextModel.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewModel;
2 |
3 | import android.app.Application;
4 | import android.util.Log;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.lifecycle.AndroidViewModel;
8 | import androidx.lifecycle.MutableLiveData;
9 |
10 | public class PersonContextModel extends AndroidViewModel {
11 | public final MutableLiveData mPersonLiveData = new MutableLiveData<>();
12 |
13 | public PersonContextModel(@NonNull Application application) {
14 | super(application);
15 | Log.d("ViewModel", getClass().getSimpleName() + "#PersonContextModel() WITH:" + getApplication(), new Throwable());
16 | }
17 |
18 | public void getPersonInWork() {
19 | Log.d("ViewModel", getClass().getSimpleName() + "#getPersonInWork() WITH:" + getApplication());
20 | Person testPerson = new Person(30, "ELC1020");
21 | // Post set value task.
22 | mPersonLiveData.postValue(testPerson);
23 | }
24 |
25 | public void updatePersonInWork() {
26 | Log.d("ViewModel", getClass().getSimpleName() + "#updatePersonInWork() WITH:" + getApplication());
27 | Person person = mPersonLiveData.getValue();
28 | if (person != null) {
29 | // Set value directly.
30 | person.setName("Ellison");
31 | person.setAge(20);
32 | mPersonLiveData.setValue(person);
33 | }
34 | }
35 |
36 | @Override
37 | protected void onCleared() {
38 | Log.d("ViewModel", getClass().getSimpleName() + "#onCleared() WITH:" + getApplication(), new Throwable());
39 | super.onCleared();
40 | }
41 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewModel/PersonContextStateModel.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewModel;
2 |
3 | import android.app.Application;
4 | import android.util.Log;
5 |
6 | import androidx.annotation.NonNull;
7 | import androidx.lifecycle.MutableLiveData;
8 | import androidx.lifecycle.SavedStateHandle;
9 |
10 | public class PersonContextStateModel extends PersonContextModel {
11 | public final MutableLiveData mPersonLiveData = new MutableLiveData<>();
12 |
13 | public PersonContextStateModel(@NonNull Application application, SavedStateHandle handle) {
14 | super(application);
15 | Log.d("ViewModel", getClass().getSimpleName() + "#PersonContextStateModel() WITH:" + getApplication() + " handle:" + handle, new Throwable());
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewModel/PersonModel.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewModel;
2 |
3 | import android.util.Log;
4 |
5 | import androidx.lifecycle.MutableLiveData;
6 | import androidx.lifecycle.ViewModel;
7 |
8 | public class PersonModel extends ViewModel {
9 | public final MutableLiveData mPersonLiveData = new MutableLiveData<>();
10 |
11 | public PersonModel() {
12 | Log.d("ViewModel", getClass().getSimpleName() + "#PersonModel()", new Throwable());
13 | }
14 |
15 | public PersonModel(String v) {
16 | Log.d("ViewModel", getClass().getSimpleName() + "#PersonModel()", new Throwable());
17 | }
18 |
19 | public void getPersonInWork() {
20 | Log.d("ViewModel", getClass().getSimpleName() + "#getPersonInWork()");
21 | Person testPerson = new Person(30, "ELC1020");
22 | // Post set value task.
23 | mPersonLiveData.postValue(testPerson);
24 | }
25 |
26 | public void updatePersonInWork() {
27 | Log.d("ViewModel", getClass().getSimpleName() + "#updatePersonInWork()");
28 | Person person = mPersonLiveData.getValue();
29 | if (person != null) {
30 | // Set value directly.
31 | person.setName("Ellison");
32 | person.setAge(20);
33 | mPersonLiveData.setValue(person);
34 |
35 | // // Can set value directly only at main thread, else exception occurred.
36 | // Executors.newSingleThreadExecutor().execute(() -> {
37 | // mPersonLiveData.setValue(person);
38 | // });
39 | }
40 | }
41 |
42 | @Override
43 | protected void onCleared() {
44 | Log.d("ViewModel", getClass().getSimpleName() + "#onCleared()", new Throwable());
45 | super.onCleared();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewModel/PersonStateModel.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewModel;
2 |
3 | import android.util.Log;
4 |
5 | import androidx.lifecycle.MutableLiveData;
6 | import androidx.lifecycle.SavedStateHandle;
7 |
8 | public class PersonStateModel extends PersonModel {
9 | public final MutableLiveData mPersonLiveData = new MutableLiveData<>();
10 |
11 | public PersonStateModel(SavedStateHandle handle) {
12 | Log.d("ViewModel", getClass().getSimpleName() + "#PersonStateModel()" + " handle:" + handle, new Throwable());
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewModelBinding/DemoActivity.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewModelBinding;
2 |
3 | import android.os.Bundle;
4 | import android.util.Log;
5 |
6 | import com.ellison.jetpackdemo.databinding.ActivityViewModelBindingBinding;
7 |
8 | import androidx.annotation.Nullable;
9 | import androidx.appcompat.app.AppCompatActivity;
10 | import androidx.lifecycle.ViewModelProvider;
11 |
12 | public class DemoActivity extends AppCompatActivity {
13 | PersonsContextModel model;
14 | ActivityViewModelBindingBinding binding;
15 |
16 | @Override
17 | protected void onCreate(@Nullable Bundle savedInstanceState) {
18 | super.onCreate(savedInstanceState);
19 |
20 | binding = ActivityViewModelBindingBinding.inflate(getLayoutInflater());
21 | setContentView(binding.getRoot());
22 |
23 | model = new ViewModelProvider(this).get(PersonsContextModel.class);
24 |
25 | binding.setResponder(new EventResponder());
26 | binding.setLifecycleOwner(this);
27 | }
28 |
29 | // Event binding.
30 | public class EventResponder {
31 | public void onClickGet() {
32 | Log.d("ViewModelBinding", "onClickGet() TITLE & GET INFO");
33 | model.getPersonInWork(DemoActivity.this, persons -> {
34 | Log.d("ViewModelBinding", "observe GOT & NOTIFY");
35 | binding.setDataList(persons);
36 | });
37 | }
38 |
39 | public void onClickUpdate() {
40 | Log.d("ViewModelBinding", "onClickUpdate() TITLE & GET INFO");
41 | model.updatePersonsInWork(DemoActivity.this, persons -> Log.d("ViewModelBinding", "observe UPDATED & NO NEED NOTIFY DUE TO DATA BINDING"));
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewModelBinding/Person.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewModelBinding;
2 |
3 | import androidx.databinding.BaseObservable;
4 | import androidx.databinding.Bindable;
5 | import androidx.databinding.library.baseAdapters.BR;
6 |
7 | public class Person extends BaseObservable {
8 | private String name;
9 | private String age;
10 | private boolean adult;
11 | private boolean checked;
12 |
13 | public Person(String age, String name) {
14 | this.age = age;
15 | this.name = name;
16 | adult = this.age != null && Integer.valueOf(this.age) >= 18;
17 | }
18 |
19 | @Bindable
20 | public String getAge() {
21 | return age;
22 | }
23 |
24 | public void setAge(String age) {
25 | this.age = age;
26 | notifyPropertyChanged(BR.age);
27 | setAdult();
28 | }
29 |
30 | @Bindable
31 | public String getName() {
32 | return name;
33 | }
34 |
35 | public void setName(String name) {
36 | this.name = name;
37 | notifyPropertyChanged(BR.name);
38 | }
39 |
40 | @Bindable
41 | public boolean isAdult() {
42 | return adult;
43 | }
44 |
45 | public void setAdult() {
46 | adult = this.age != null && Integer.valueOf(this.age) >= 18;
47 | notifyPropertyChanged(BR.adult);
48 | }
49 |
50 | @Bindable
51 | public boolean isChecked() {
52 | return checked;
53 | }
54 |
55 | public void setChecked(boolean checked) {
56 | this.checked = checked;
57 | notifyPropertyChanged(BR.checked);
58 | }
59 |
60 | @Override
61 | public String toString() {
62 | return "Person{" +
63 | "name='" + name + '\'' +
64 | ", age='" + age + '\'' +
65 | ", adult=" + adult +
66 | ", checked=" + checked +
67 | '}';
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewModelBinding/PersonsAdapter.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewModelBinding;
2 |
3 | import android.util.Log;
4 | import android.view.LayoutInflater;
5 | import android.view.ViewGroup;
6 |
7 | import com.ellison.jetpackdemo.databinding.ActivityViewModelBindingItemBinding;
8 |
9 | import java.util.List;
10 |
11 | import androidx.annotation.NonNull;
12 | import androidx.databinding.BindingAdapter;
13 | import androidx.databinding.DataBindingUtil;
14 | import androidx.recyclerview.widget.DividerItemDecoration;
15 | import androidx.recyclerview.widget.LinearLayoutManager;
16 | import androidx.recyclerview.widget.RecyclerView;
17 |
18 | public class PersonsAdapter extends RecyclerView.Adapter {
19 | protected List personList;
20 |
21 | @BindingAdapter("bindData")
22 | public static void bindAdapter(RecyclerView recyclerView, List personList) {
23 | Log.d("ViewModelBinding", "PersonsAdapter#bindAdapter() recyclerView:" + recyclerView + " personList:" + personList, new Throwable());
24 | recyclerView.setAdapter(new PersonsAdapter(personList));
25 | recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));
26 | recyclerView.addItemDecoration(new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL));
27 | }
28 |
29 | public PersonsAdapter(List personList) {
30 | Log.d("ViewModelBinding", "PersonsAdapter#PersonsAdapter()");
31 | this.personList = personList;
32 | }
33 |
34 | @NonNull
35 | @Override
36 | public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
37 | Log.d("ViewModelBinding", "BindingAdapter#onCreateViewHolder() parent:" + parent);
38 | return new RecyclerView.ViewHolder(ActivityViewModelBindingItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false).getRoot()) {};
39 | }
40 |
41 | @Override
42 | public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
43 | Log.d("ViewModelBinding", "BindingAdapter#onBindViewHolder() holder:" + holder + " position:" + position);
44 | ActivityViewModelBindingItemBinding binding = DataBindingUtil.bind(holder.itemView);
45 | binding.setPerson(personList.get(position));
46 | // binding.executePendingBindings();
47 | }
48 |
49 | @Override
50 | public int getItemCount() {
51 | return personList != null ? personList.size() : 0;
52 | }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/ellison/jetpackdemo/viewModelBinding/PersonsContextModel.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo.viewModelBinding;
2 |
3 | import android.app.Application;
4 | import android.util.Log;
5 |
6 | import java.util.Arrays;
7 | import java.util.List;
8 | import java.util.concurrent.Executors;
9 |
10 | import androidx.annotation.NonNull;
11 | import androidx.lifecycle.AndroidViewModel;
12 | import androidx.lifecycle.LifecycleOwner;
13 | import androidx.lifecycle.MutableLiveData;
14 | import androidx.lifecycle.Observer;
15 |
16 | public class PersonsContextModel extends AndroidViewModel {
17 | public final MutableLiveData> personsLiveData;
18 |
19 | public PersonsContextModel(@NonNull Application application) {
20 | super(application);
21 | Log.d("ViewModelBinding", getClass().getSimpleName() + "#PersonContextModel() WITH:" + getApplication());
22 | personsLiveData = new MutableLiveData<>();
23 | }
24 |
25 | public void getPersonInWork(LifecycleOwner owner, Observer> observer) {
26 | Log.d("ViewModelBinding", getClass().getSimpleName() + "#getPersonInWork() WITH:" + getApplication());
27 | personsLiveData.observe(owner, observer);
28 |
29 | Executors.newSingleThreadExecutor().execute(() -> {
30 | Log.d("ViewModelBinding", getClass().getSimpleName() + "#getPersonInWork() GOT ASYNC");
31 | List persons = Arrays.asList(new Person[] {
32 | new Person("18", "Audi"),
33 | new Person("7", "Benz"),
34 | new Person("24", "Cadillac"),
35 | new Person("1", "DS"),
36 | new Person("34", "Ever"),
37 | new Person("199", "Ferrai")});
38 | personsLiveData.postValue(persons);
39 | });
40 | }
41 |
42 | public void updatePersonsInWork(LifecycleOwner owner, Observer> observer) {
43 | Log.d("ViewModelBinding", getClass().getSimpleName() + "#updatePersonInWork() WITH:" + getApplication());
44 | List persons = personsLiveData.getValue();
45 | personsLiveData.observe(owner, observer);
46 |
47 | Executors.newSingleThreadExecutor().execute(() -> {
48 | Log.d("ViewModelBinding", getClass().getSimpleName() + "#updatePersonInWork() UPDATE ASYNC");
49 | if (persons != null) {
50 | persons.get(0).setAge("5");
51 | persons.get(1).setAge("35");
52 | persons.get(2).setAge("15");
53 | persons.get(3).setAge("20");
54 | persons.get(4).setAge("45");
55 | persons.get(5).setAge("7");
56 | }
57 | });
58 | }
59 |
60 | @Override
61 | protected void onCleared() {
62 | Log.d("ViewModelBinding", getClass().getSimpleName() + "#onCleared() WITH:" + getApplication(), new Throwable());
63 | super.onCleared();
64 | }
65 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/huawei_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/drawable/huawei_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/drawable/ic_add.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_analysis_picker_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
11 |
14 |
15 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_camera.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_camera_change.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_camera_change_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_camera_new.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_capture.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_capture_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 |
9 |
14 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_capture_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 |
9 |
14 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_capture_record.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_capture_record_disabled.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 |
9 |
14 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_capture_record_normal.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
20 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_capture_record_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 |
9 |
14 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_capture_record_pressing.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_capture_record_pressing_center.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_capture_record_pressing_outter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/drawable/ic_filter.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_focus_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
9 |
11 |
14 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_jetpack.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/drawable/ic_jetpack.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_movie_post.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/drawable/ic_movie_post.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_point_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_qr_code.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_qr_scan.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_qr_zone.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
9 |
11 |
12 |
15 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_rect_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
10 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/drawable/ic_search.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_sort.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/drawable/ic_sort.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_video.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ml_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/drawable/ml_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/zxing_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/drawable/zxing_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/zxing_logo_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/drawable/zxing_logo_round.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/zxing_logo_transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/drawable/zxing_logo_transparent.png
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
21 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_view_binding.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
21 |
22 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_view_model.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
22 |
23 |
33 |
34 |
43 |
44 |
53 |
54 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/fragment_view_binding.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/fragment_view_model.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
21 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_camera2.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_coroutines.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_data_binding.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
24 |
25 |
35 |
36 |
43 |
44 |
51 |
52 |
62 |
63 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_data_binding_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
28 |
29 |
41 |
42 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_data_binding_item_one_way.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
16 |
17 |
29 |
30 |
42 |
43 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_hilt.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
10 |
11 |
12 |
16 |
17 |
31 |
32 |
42 |
43 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_hilt_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
17 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_lifecycle.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
27 |
28 |
47 |
48 |
63 |
64 |
81 |
82 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main_test_2.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
23 |
24 |
38 |
39 |
53 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_old.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
29 |
30 |
39 |
40 |
49 |
50 |
59 |
60 |
69 |
70 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_room_db.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
11 |
12 |
13 |
17 |
18 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_room_db_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
13 |
14 |
28 |
29 |
40 |
41 |
54 |
55 |
68 |
69 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_view_binding.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
21 |
22 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_view_model_binding.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
13 |
14 |
17 |
18 |
19 |
23 |
24 |
34 |
35 |
45 |
46 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_view_model_binding_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
16 |
28 |
29 |
41 |
42 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/analysis_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
18 |
19 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_analysis_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_hilt.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_other_view_model.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
24 |
25 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_view_binding.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_view_model.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
23 |
24 |
35 |
36 |
45 |
46 |
55 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/room_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/raw/beep_sound.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/app/src/main/res/raw/beep_sound.ogg
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 | #FFFFFFFF
11 |
12 |
13 |
14 | #9F2C162B
15 | #9F390239
16 |
17 | @color/ubuntu_purple
18 |
19 | @color/ubuntu_orange
20 |
21 | @color/ubuntu_red
22 |
23 |
24 | #DF9C2239
25 | #DF390239
26 | @color/ubuntu_fuchsia
27 |
28 | #5f660F5E
29 |
30 | @color/ubuntu_orange
31 |
32 | @color/ubuntu_orange
33 | #3fd3d7d4
34 | #9F000000
35 |
36 |
37 | #A52732
38 | #9C2239
39 | #660F5E
40 | #390239
41 | #2C162B
42 | #231522
43 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 0dp
4 | 80dp
5 | 30dp
6 | 50dp
7 | 30dp
8 | 40dp
9 | 50dp
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | JetpackDemo
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
20 |
21 |
26 |
27 |
28 |
41 |
--------------------------------------------------------------------------------
/app/src/test/java/com/ellison/jetpackdemo/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.ellison.jetpackdemo;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = '1.4.30'
4 | repositories {
5 | google()
6 | jcenter()
7 | mavenCentral()
8 | maven {url 'https://developer.huawei.com/repo/'}
9 | }
10 | dependencies {
11 | classpath "com.android.tools.build:gradle:4.1.0"
12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
13 | classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
14 |
15 | // NOTE: Do not place your application dependencies here; they belong
16 | // in the individual module build.gradle files
17 | }
18 | }
19 |
20 | allprojects {
21 | repositories {
22 | google()
23 | jcenter()
24 | mavenCentral() //add this line
25 | maven {url 'https://developer.huawei.com/repo/'}
26 | }
27 | }
28 |
29 | task clean(type: Delete) {
30 | delete rootProject.buildDir
31 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ellisonchan/JetpackDemo/b8cda9f0a8e15977bd42a457a8b96c7df3df12d2/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Oct 31 20:19:44 CST 2020
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.5-bin.zip
7 |
--------------------------------------------------------------------------------
/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name = "JetpackDemo"
--------------------------------------------------------------------------------