Bileşenin eksiksiz uygulamalarını oluşturmak için Araba kullanıcı arayüzü kitaplığı eklentilerini kullanma çalışma zamanında kaynak yer paylaşımları kullanmak yerine Araba kullanıcı arayüzü kitaplığında özelleştirmeler (RRO'lar). RRO'lar, yalnızca Araba Kullanıcı Arayüzü kitaplığının XML kaynaklarını değiştirmenize olanak tanır Bu da, özelleştirebileceğiniz unsurların kapsamını sınırlandırır.
Eklenti oluşturun
Araba kullanıcı arayüzü kitaplığı eklentisi, Eklenti API'leri. Eklenti API'leri statik bir kitaplık olarak ekler.
Yakındag ve Gradle ile ilgili örnekleri inceleyin:
Yakında
Şu Shorts örneğine bakalım:
android_app {
name: "my-plugin",
min_sdk_version: "28",
target_sdk_version: "30",
aaptflags: ["--shared-lib"],
sdk_version: "current",
manifest: "src/main/AndroidManifest.xml",
srcs: ["src/main/java/**/*.java"],
resource_dirs: ["src/main/res"],
static_libs: [
"car-ui-lib-oem-apis",
],
// Disable optimization is mandatory to prevent R.java class from being
// stripped out
optimize: {
enabled: false,
},
certificate: ":my-plugin-certificate",
}
Gradle
Bu build.gradle
dosyasını görüntüleyin:
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
defaultConfig {
minSdkVersion 28
targetSdkVersion 30
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
signingConfigs {
debug {
storeFile file('chassis_upload_key.jks')
storePassword 'chassis'
keyAlias 'chassis'
keyPassword 'chassis'
}
}
}
dependencies {
implementation project(':oem-apis')
// Or use the following if you'd like to use the maven artifact
// implementation 'com.android.car.ui:car-ui-lib-plugin-apis:1.0.0'
}
Settings.gradle
:
// You can remove the ':oem-apis' if you're using the maven artifact.
include ':oem-apis'
project(':oem-apis').projectDir = new File('./path/to/oem-apis')
include ':my-plugin'
project(':my-plugin').projectDir = new File('./my-plugin')
Eklentinin manifest dosyasında, şu özellikleri kullanın:
android:authorities="com.android.car.ui.plugin"
android:enabled="true"
android:exported="true"
android:authorities="com.android.car.ui.plugin"
, eklentiyi bulunabilir hale getirir
araba kullanıcı arayüzü kitaplığına
ekleyebilir. Şu konumda sorgulanabilmesi için sağlayıcının dışa aktarılması gerekiyor:
belirler. Ayrıca, enabled
özelliği false
değerine ayarlanırsa varsayılan değer
uygulaması, eklenti uygulaması yerine kullanılır. İçerik
provider sınıfının mevcut olması gerekmez. Bu durumda,
Sağlayıcı tanımına tools:ignore="MissingClass"
. Örneğe göz atın
aşağıdaki manifest girişini yapabilirsiniz:
<application>
<provider
android:name="com.android.car.ui.plugin.PluginNameProvider"
android:authorities="com.android.car.ui.plugin"
android:enabled="false"
android:exported="true"
tools:ignore="MissingClass"/>
</application>
Son olarak, güvenlik önlemi olarak Uygulamanızı imzalayın.
Paylaşılan kitaplık olarak eklentiler
Doğrudan uygulamalarda derlenen Android statik kitaplıklarının aksine Android'de paylaşılan kitaplıklar, referans verilen bağımsız bir APK olarak derlenir diğer uygulamalar tarafından yürütülür.
Android paylaşılan kitaplığı olarak uygulanan eklentilerin kendi sınıfları vardır uygulamalar arasında paylaşılan sınıf yükleyiciye otomatik olarak eklenir. Bir uygulamanın Araç Kullanıcı Arayüzü kitaplığının çalışma zamanı bağımlılığı, eklentinin paylaşılan kitaplığına classloader, eklentinin paylaşılan kitaplığının sınıflarına erişebilir. Eklentiler uygulandı normal Android uygulamaları (paylaşılan kitaplık değil), uygulamaların soğuk algılanmasını olumsuz yönde etkileyebileceğinden başlangıç zamanları.
Paylaşılan kitaplıkları uygulama ve derleme
Android paylaşılan kitaplıklarla geliştirme, normal Android'e çok benzer aralarında birkaç temel farkın
- Eklenti paketiyle
application
etiketi altındalibrary
etiketini kullanın ad:
<application>
<library android:name="com.chassis.car.ui.plugin" />
...
</application>
- Shortg
android_app
derleme kuralınızı (Android.bp
) AAPT ile yapılandırma paylaşılan bir kitaplık oluşturmak için kullanılanshared-lib
flag'i:
android_app {
...
aaptflags: ["--shared-lib"],
...
}
Paylaşılan kitaplıklara bağımlılıklar
Sistemde Araba kullanıcı arayüzü kitaplığını kullanan her uygulama için
uses-library
etiketi,
Eklenti paket adını içeren application
etiketi:
<manifest>
<application
android:name=".MyApp"
...>
<uses-library android:name="com.chassis.car.ui.plugin" android:required="false"/>
...
</application>
</manifest>
Eklenti yükleme
Eklentilerin, modül dahil edilerek sistem bölümüne önceden yüklenmesi ZORUNLUDUR
PRODUCT_PACKAGES
içinde. Önceden yüklenmiş paket aşağıdakine benzer şekilde güncellenebilir:
yüklü diğer uygulamalar.
Sistemde mevcut bir eklentiyi güncelliyorsanız o eklentiyi kullanan tüm uygulamalar otomatik olarak kapanmasını sağlar. Kullanıcı tarafından yeniden açıldığında güncellenmiş değişiklikler olur. Uygulama çalışmıyorsa bir sonraki başlatılmasında güncellenmiştir eklentisidir.
Android Studio ile bir eklenti yüklerken, dikkat edilecek noktalara değineceğiz. Bu yazının yazıldığı sırada bir hata bir eklentinin güncellenmesine neden olan Android Studio uygulama yükleme işlemi değiştirebilirsiniz. Bu sorun, Her zaman yükle paket yöneticisiyle (Android 11 ve sonraki sürümlerde dağıtım optimizasyonlarını devre dışı bırakır) yapılandırdığınızdan emin olun.
Ayrıca, Android Studio eklentiyi yüklerken, başlatılacak ana etkinlik bulamıyor. Eklenti, çalışmadığından bu beklenen bir durumdur. herhangi bir etkinliğe (bir amacı çözümlemek için kullanılan boş amaç hariç) sahip olmalıdır. Alıcı: Hatayı ortadan kaldırmak için, derleme işleminde Launch (Başlat) seçeneğini, Nothing (Hiçbir şey) olarak değiştirin yapılandırma.
. Şekil 1. Android Studio eklentisi yapılandırması
Proxy eklentisi
Özelleştirme Araba kullanıcı arayüzü kitaplığını kullanan uygulamalar düzenlenecek her uygulamayı hedefleyen bir RRO gerektirir. Örneğin, özelleştirmelerin uygulamalar genelinde aynı olduğu durumlar dahil. Bu, müşteri başına RRO uygulamanız gerekiyor. Hangi uygulamaların Araba kullanıcı arayüzü kitaplığını kullandığını görün.
Araba kullanıcı arayüzü kitaplığı proxy eklentisi örnek olarak bileşen uygulamalarını statik sürümünü kullanabilirsiniz. Bu eklenti, RRO ile hedeflenebilir. Araba kullanıcı arayüzü kitaplığını kullanan uygulamalar için tek bir özelleştirme noktası olarak kullanılır işlevsel bir eklenti uygulanmasına gerek kalmadan. Daha fazla bilgi için RRO'lar için Uygulama kaynaklarının değerini şurada değiştirme: çalışma zamanı.
Proxy eklentisi yalnızca bir örnek ve bir eklentidir. RRO'ların ötesinde özelleştirme için, bir eklentinin alt kümesi uygulanabilir ve kalanlar için proxy eklentisini kullanın veya tamamen sıfırdan yapabilirsiniz.
Proxy eklentisi uygulamalar için tek bir RRO özelleştirme noktası sağlar, ancak uygulamaları devre dışı bırakan uygulamalar için de doğrudan uygulamanın kendisini hedefler.
Eklenti API'lerini uygulayın
Eklentinin ana giriş noktası
com.android.car.ui.plugin.PluginVersionProviderImpl
sınıf. Tüm eklentiler
tam olarak bu ada ve paket adına sahip bir sınıf ekle. Bu sınıfta bir
oluşturucuyu ekleyebilir ve PluginVersionProviderOEMV1
arayüzünü uygulayabilirsiniz.
CarUi eklentileri, eklentiden daha eski veya daha yeni uygulamalarla çalışmalıdır. Alıcı:
Bunu kolaylaştırır, tüm eklenti API'leri API'lerin sonunda V#
sınıf adı. Araba kullanıcı arayüzü kitaplığının yeni özellikleri içeren yeni bir sürümü yayınlanırsa
onlar bileşenin V2
sürümündedir. Araba kullanıcı arayüzü kitaplığı
en iyi yöntemin, yeni özelliklerin eski bir eklenti bileşeni kapsamında çalışması gerekir.
Örneğin, araç çubuğundaki yeni bir düğme türünü MenuItems
biçimine dönüştürebilirsiniz.
Ancak, Araba kullanıcı arayüzü kitaplığının eski sürümüne sahip bir uygulama yeni bir sürüme eklentisidir. Bu sorunu çözmek için eklentilerin OEM API'nin sürümüne bağlı olarak, kendi uygulamalarının farklı uygulamalarını döndürebilir ve uygulamalar tarafından destekleniyor.
PluginVersionProviderOEMV1
, bir yönteme sahip:
Object getPluginFactory(int maxVersion, Context context, String packageName);
Bu yöntem, en yüksek sürümünü uygulayan bir nesne
PluginFactoryOEMV#
, eklenti tarafından desteklenir ancak hâlâ daha az veya
maxVersion
değerine eşit. Bir eklenti,
PluginFactory
daha eskiyse null
değerini döndürebilir. Bu durumda,
ve CarUi bileşenlerinin bağlantılı uygulanması
olduğundan emin olun.
Şuna karşı derlenen uygulamalarla geriye dönük uyumluluğu sürdürmek:
statik Araba Kullanıcı Arayüzü kitaplığının eski sürümlerini desteklememesi önerilir.
Eklentinizin uygulanmasından elde edilen 2, 5 ve daha yüksek maxVersion
değerleri
PluginVersionProvider
sınıfı. Sürüm 1, 3 ve 4 desteklenmez. Örneğin,
daha fazla bilgi için
PluginVersionProviderImpl
.
PluginFactory
, diğer tüm CarUi öğelerini oluşturan arayüzdür
bileşenlerine ayıralım. Ayrıca, arayüzlerinin hangi sürümünün kullanılması gerektiğini de tanımlar. Eğer
eklenti bu bileşenlerden hiçbirini uygulamaz. Bu bileşenlerden herhangi birini uygulamaya
null
oluşturma işlevinde (
ayrı bir customizesBaseLayout()
fonksiyonu).
pluginFactory
, CarUi bileşenlerinin hangi sürümlerinin kullanılabileceğini sınırlandırır
birlikte. Örneğin, hiçbir zaman bir pluginFactory
Toolbar
sürümünün 100 sürümü ve ayrıca RecyclerView
sürüm 1
bileşenlerin çok çeşitli sürümlerinin yüksek kalitede olacağınızın
yardımcı olabilir. Araç çubuğu sürüm 100'ü kullanmak için geliştiricilerin
aşağıdakileri oluşturan bir pluginFactory
sürümü sağlayın:
Bu durumda diğer
bileşenleri bulunuyor. Diğer bileşenlerin sürümleri farklı
eşittir. Örneğin pluginFactoryOEMV100
,
ToolbarControllerOEMV100
ve RecyclerViewOEMV70
.
Araç Çubuğu
Temel düzen
Araç çubuğu ve "temel düzen" Bunlar birbiriyle yakından ilişkilidir.
installBaseLayoutAround
adlı bir araç çubuğu oluşturur. İlgili içeriği oluşturmak için kullanılan
temel düzen
Araç çubuğunun, uygulamanın etrafındaki herhangi bir yere yerleştirilmesine olanak tanıyan bir kavramdır.
uygulamanın üst/alt kısmında dikey olarak bir araç çubuğu sağlamak için
şeklinde dairesel bir araç çubuğuyla gösteriliyor. Bu
araç çubuğu/taban için installBaseLayoutAround
öğesine bir görünüm geçirilerek gerçekleştirilir
farklı bir düzene denk gelir.
Eklenti, sağlanan görünümü almalı, üst öğesinden ayırmalı, şişirmelidir.
eklentisine ait aynı dizinde ve aynı
LayoutParams
çıkarıp görünümü tekrar ekleyin
bir yerde çerçevelenmiş durumda. Şişmiş düzen,
Uygulama tarafından istenirse araç çubuğunu içermelidir.
Uygulama, araç çubuğu olmadan temel düzen isteyebilir. Çalışıyorsa
installBaseLayoutAround
, null değerini döndürmelidir. Çoğu eklenti için bu
olması gerekir, ancak eklentinin yazarı uygulamak isterse, ör. bir süsleme
kenarlara kaydırılabilir. Bu da temel bir düzenle yapılabilir. Bu
Süslemeler dikdörtgen olmayan ekranı olan cihazlar için özellikle kullanışlıdır
uygulamayı dikdörtgen bir alana aktarabilir ve ekran görüntüsüne temiz geçişler
alanı inceleyelim.
installBaseLayoutAround
için de Consumer<InsetsOEMV1>
sertifikası geçildi. Bu
tüketici, uygulamaya eklentinin kısmen göründüğünü bildirmek için kullanılabilir
Kapsayacak şekilde (araç çubuğuyla veya başka bir yöntemle) Uygulama,
bu alanda çizim yapmaya devam edin ancak
kullanıcının etkileşimde bulunabileceği her türlü
çıkarmanız gerekir. Bu efekt, referans tasarımımızda
şeffaf hale getirir ve altında listelerin kaydırılması sağlanır. Bu özellik
uygulanmadığında, listedeki ilk öğe araç çubuğunun altında kalır
ve tıklanamaz. Bu efekt gerekli değilse eklenti,
Tüketici.
. Şekil 2. Araç çubuğunun altında kayan içerikler
Uygulama açısından bakıldığında eklenti, yeni ek öğeleri gönderdiğinde
bunları, InsetsChangedListener
uygulayan etkinliklerden veya parçalardan uzaklaştırır. Eğer
bir etkinlik veya parça InsetsChangedListener
, Car kullanıcı arayüzü
kitaplığı, alt öğeleri varsayılan olarak
Parçayı içeren Activity
veya FragmentActivity
. Kitaplıkta
alt öğeleri varsayılan olarak parçalara uygular. Burada örnek bir snippet
Bir RecyclerView
öğesine dolgu olarak eklenerek
uygulama:
public class MainActivity extends Activity implements InsetsChangedListener {
@Override
public void onCarUiInsetsChanged(Insets insets) {
CarUiRecyclerView rv = requireViewById(R.id.recyclerview);
rv.setPadding(insets.getLeft(), insets.getTop(),
insets.getRight(), insets.getBottom());
}
}
Son olarak, eklentiye bir fullscreen
ipucu verilir. Bu ipucu,
uygulamanın tamamını veya yalnızca küçük bir bölümünü kaplar.
Bu, kenar boyunca süslemelerin uygulanmasını önlemek için kullanılabilir.
yalnızca tüm ekranın kenarı boyunca göründüklerinde bir anlam ifade eder. Örnek
tam ekran olmayan temel düzenleri kullanan bir uygulama olan Ayarlar'dır. Buradaki
İki bölmeli düzenin kendi araç çubuğu vardır.
Şu durumda installBaseLayoutAround
öğesinin null değeri döndürmesi beklendiğinden:
Eklentinin, false
değerine sahip olduğunu belirtmek için toolbarEnabled
temel düzeni özelleştirmek istiyorsanız şuradan false
değerini döndürmelidir:
customizesBaseLayout
.
Temel düzen, tam olarak bir FocusParkingView
ve FocusArea
içermelidir
çevirme kontrollerini destekler. Şu cihazlarda bu görünümler atlanabilir:
çevirme desteklenmiyor. FocusParkingView/FocusAreas
,
statik CarUi kitaplığıdır; bu nedenle fabrikalara verileri sağlamak içinsetRotaryFactories
bağlamlardan görünümler oluşturabilirsiniz.
Odak görünümleri oluşturmak için kullanılan bağlamlar
bağlamına bakacağız. FocusParkingView
, ilk görünüme en yakın olmalıdır
ağaçta kullanmak istediğinize karar vermeniz gerekir,
kullanıcıya görünür olmamalıdır. FocusArea
, araç çubuğunu
döner kaydırma bölgesi olduğunu belirtmek için alt taban düzeni. FocusArea
sağlandığında kullanıcı, araç çubuğunda bulunan
döner kumanda.
Araç çubuğu denetleyicisi
Döndürülen ToolbarController
tutarının çok daha basit olması
temel düzene göre daha fazladır. Sisteminin görevi,
temel düzende görüntülemenizi sağlar. Daha fazla bilgi için bkz. Javadoc
birçok yöntem. Daha karmaşık yöntemlerden bazıları aşağıda açıklanmıştır.
getImeSearchInterface
, IME'de (klavye) arama sonuçlarını göstermek için kullanılır
penceresini kapatın. Bu, arama sonuçlarının yanında
Örneğin klavye, ekranın yalnızca yarısını kapladıysa. Çoğu
Bu işlev statik CarUi kitaplığında uygulanmıştır,
arayüzündeki arayüz yalnızca statik kitaplığın
TextView
ve onPrivateIMECommand
geri arama. Bunu desteklemek için eklenti
onPrivateIMECommand
değerini geçersiz kılarak ve geçen bir TextView
alt sınıfı kullanmalıdır.
sağlanan dinleyiciye arama çubuğunun TextView
olarak çağrılması.
setMenuItems
, yalnızca ekranda Menü Öğeleri'ni gösterir, ancak menü öğeleri çağrılır
çok sık oluyor. MenuItems eklentisi API'si sabit olduğundan,
Menü Öğesi değiştirilir ve tamamen yeni bir setMenuItems
çağrısı gerçekleşir. Bu
kullanıcının bir Menü Öğesi düğmesini tıklaması gibi basit bir şey olursa
tıklama, anahtarın açılmasına neden oldu. Hem performans hem de animasyon açısından
Dolayısıyla, eskiyle yenisi arasındaki farkı hesaplamanız önerilir.
sadece gerçekten değişen görünümleri güncelleyin. Menü Öğeleri
Anahtar aynı olması gerektiğinden, bu konuda yardımcı olabilecek bir key
alanı sağlayın
aynı Menü Öğesi için setMenuItems
için yapılan farklı çağrılarda geçerlidir.
UygulamaStilliGörünüm
AppStyledView
, hiç özelleştirilmemiş bir görünümün kapsayıcısıdır. Google
görünümün diğer yönlerden ayırt edilmesini sağlayan bir kenarlık sağlamak için kullanılabilir.
ve kullanıcıya bunun farklı türde bir uygulama
arayüzü. AppStyledView tarafından sarmalanan görünüm
setContent
AppStyledView
cihazındaki geri veya kapat düğmesi de
tarafından istenmesi gerekir.
AppStyledView
, görünümlerini görünüm hiyerarşisine hemen eklemez
installBaseLayoutAround
yapar, bunun yerine sadece
statik kitaplığı getView
ile değiştirir, ardından ekleme işlemini yapar. Konum ve
AppStyledView
boyutu uygulanarak ayrıca kontrol edilebilir.
getDialogWindowLayoutParam
.
Bağlamlar
Eklenti, hem eklenti hem de Bağlamlar'ı kullanırken
"kaynak" bağlamlar. Eklenti bağlamı,
getPluginFactory
ve
kaynaklarını inceleyebilirsiniz. Yani, projenizin durumu hakkında
.
Ancak, eklenti bağlamı için doğru yapılandırma ayarlanmamış olabilir. Alıcı:
sağlamak için, kaynak bağlamlarını doğru yapılandırmaya
yönelik yöntemler kullanarak
bileşenlerine ayıralım. Kaynak bağlam genellikle bir etkinliktir ancak bazı durumlarda
aynı zamanda bir Hizmet veya başka bir Android bileşeni olmalıdır. Yapılandırmayı
kaynak bağlamını, eklenti bağlamındaki kaynaklarla birlikte kullanıldığında yeni bir bağlam
createConfigurationContext
kullanılarak oluşturuldu. Doğru yapılandırma
kullanılırsa Android katı modu ihlali olur ve artan görüntülemeler
, doğru boyutlara sahip olmamalıdır.
Context layoutInflationContext = pluginContext.createConfigurationContext(
sourceContext.getResources().getConfiguration());
Mod değişiklikleri
Bazı eklentiler, bileşenleri için birden fazla modu destekleyebilir: Görsel olarak farklı görünen bir spor modu veya eko modu. Hayır, CarUi'de bu tür işlevler için yerleşik destek var ancak tamamen dahili olarak uygulanmasını engeller. Eklenti, nasıl değiştireceğini öğrenmek için kullandığı dinlemektedir. Eklenti, yapılandırma değişikliklerini tetikleyemez Ancak yapılandırma değişikliklerine bağlı olmanız önerilmez her bileşenin görünümünü manuel olarak güncellemek daha kolay olduğu için, ve aynı zamanda dönüşümlerde mümkün olmayan geçişlere yapılandırma değişiklikleridir.
Jetpack Compose
Eklentiler Jetpack Compose kullanılarak uygulanabilir, ancak bu alfa düzeyidir ve kararlı olarak kabul edilmemelidir.
Eklentiler kullanabileceğiniz:
ComposeView
oluşturmak için Compose'un etkin olduğu bir yüzey oluşturun. Bu ComposeView
:
getView
yönteminden uygulamaya ne döndürüldüğünü gösterir.
ComposeView
kullanımıyla ilgili önemli sorunlardan biri, etiketleri kök görünümünde ayarlamasıdır.
paylaşılan genel değişkenleri depolamak için düzene
farklı ComposeView'lar oluşturabilirsiniz. Eklentinin kaynak kimlikleri
bir alan adına sahip olduğunu ve uygulamanın
uygulamanız ve eklenti, etiketleri aynı görünüme ayarladı. Özel
ComposeViewWithLifecycle
. Bu genel değişkenleri
ComposeView
aşağıda sağlanmıştır. Bu da tutarlı olarak kabul edilmemelidir.
ComposeViewWithLifecycle
:
class ComposeViewWithLifecycle @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr),
LifecycleOwner, ViewModelStoreOwner, SavedStateRegistryOwner {
private val lifeCycle = LifecycleRegistry(this)
private val modelStore = ViewModelStore()
private val savedStateRegistryController = SavedStateRegistryController.create(this)
private var composeView: ComposeView? = null
private var content = @Composable {}
init {
ViewTreeLifecycleOwner.set(this, this)
ViewTreeViewModelStoreOwner.set(this, this)
ViewTreeSavedStateRegistryOwner.set(this, this)
compositionContext = createCompositionContext()
}
fun setContent(content: @Composable () -> Unit) {
this.content = content
composeView?.setContent(content)
}
override fun getLifecycle(): Lifecycle {
return lifeCycle
}
override fun getViewModelStore(): ViewModelStore {
return modelStore
}
override fun getSavedStateRegistry(): SavedStateRegistry {
return savedStateRegistryController.savedStateRegistry
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
savedStateRegistryController.performRestore(Bundle())
lifeCycle.currentState = Lifecycle.State.RESUMED
composeView = ComposeView(context)
composeView?.setContent(content)
addView(composeView, LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
lifeCycle.currentState = Lifecycle.State.DESTROYED
modelStore.clear()
removeAllViews()
composeView = null
}
// Exact copy of View.createCompositionContext() in androidx's WindowRecomposer.android.kt
private fun createCompositionContext(): CompositionContext {
val currentThreadContext = AndroidUiDispatcher.CurrentThread
val pausableClock = currentThreadContext[MonotonicFrameClock]?.let {
PausableMonotonicFrameClock(it).apply { pause() }
}
val contextWithClock = currentThreadContext + (pausableClock ?: EmptyCoroutineContext)
val recomposer = Recomposer(contextWithClock)
val runRecomposeScope = CoroutineScope(contextWithClock)
val viewTreeLifecycleOwner = checkNotNull(ViewTreeLifecycleOwner.get(this)) {
"ViewTreeLifecycleOwner not found from $this"
}
viewTreeLifecycleOwner.lifecycle.addObserver(
LifecycleEventObserver { _, event ->
@Suppress("NON_EXHAUSTIVE_WHEN")
when (event) {
Lifecycle.Event.ON_CREATE ->
// Undispatched launch since we've configured this scope
// to be on the UI thread
runRecomposeScope.launch(start = CoroutineStart.UNDISPATCHED) {
recomposer.runRecomposeAndApplyChanges()
}
Lifecycle.Event.ON_START -> pausableClock?.resume()
Lifecycle.Event.ON_STOP -> pausableClock?.pause()
Lifecycle.Event.ON_DESTROY -> {
recomposer.cancel()
}
}
}
)
return recomposer
}
// TODO: ComposeViewWithLifecycle should handle saving state and other lifecycle things
// override fun onSaveInstanceState(): Parcelable? {
// val superState = super.onSaveInstanceState()
// val bundle = Bundle()
// savedStateRegistryController.performSave(bundle)
// }
}