stripe-android
stripe-android copied to clipboard
Async ImageLoader with in-memory + disk cache (and compose usage showcase)
Summary
- Adds StripeImage composable, that accepts urls and loads them asynchronously.
- Implements an in-memory LRU cache to cache loaded bitmaps.
- Implements a disk LRU cache to cache loaded bitmaps.
- Scopes Loader (and caches) to activity and exposes it to composables via
staticCompositionLocal
(not a requirement for its usage)
Motivation
- Load images without depending on 3rd party libs.
Screenshots

Diffuse output:
OLD: paymentsheet-example-release-master.apk (signature: none)
NEW: paymentsheet-example-release-pr.apk (signature: none)
│ compressed │ uncompressed
├──────────┬──────────┬────────────┼───────────┬───────────┬────────────
APK │ old │ new │ diff │ old │ new │ diff
──────────┼──────────┼──────────┼────────────┼───────────┼───────────┼────────────
dex │ 15.8 MiB │ 16 MiB │ +198.9 KiB │ 53.4 MiB │ 54 MiB │ +627.7 KiB
arsc │ 1.9 MiB │ 2 MiB │ +60.6 KiB │ 1.9 MiB │ 2 MiB │ +60.6 KiB
manifest │ 4.1 KiB │ 4.1 KiB │ +55 B │ 18.9 KiB │ 19.4 KiB │ +452 B
res │ 1 MiB │ 1.1 MiB │ +38.2 KiB │ 1.8 MiB │ 1.8 MiB │ +42.8 KiB
native │ 2.5 MiB │ 2.5 MiB │ 0 B │ 5.9 MiB │ 5.9 MiB │ 0 B
asset │ 3 MiB │ 3 MiB │ +511 B │ 3 MiB │ 3 MiB │ +511 B
other │ 81.8 KiB │ 81.8 KiB │ 0 B │ 155.7 KiB │ 155.7 KiB │ 0 B
──────────┼──────────┼──────────┼────────────┼───────────┼───────────┼────────────
total │ 24.3 MiB │ 24.6 MiB │ +298.2 KiB │ 66.1 MiB │ 66.8 MiB │ +732 KiB
│ raw │ unique
├────────┬────────┬───────┼────────┬────────┬─────────────────────
DEX │ old │ new │ diff │ old │ new │ diff
─────────┼────────┼────────┼───────┼────────┼────────┼─────────────────────
files │ 4 │ 4 │ 0 │ │ │
strings │ 256346 │ 254546 │ -1800 │ 219199 │ 222562 │ +3363 (+3423 -60)
types │ 45105 │ 45943 │ +838 │ 41474 │ 42397 │ +923 (+938 -15)
classes │ 38650 │ 39554 │ +904 │ 38650 │ 39554 │ +904 (+919 -15)
methods │ 225198 │ 229313 │ +4115 │ 217408 │ 221580 │ +4172 (+4272 -100)
fields │ 164462 │ 164522 │ +60 │ 163493 │ 163551 │ +58 (+4576 -4518)
ARSC │ old │ new │ diff
─────────┼──────┼──────┼────────────────
configs │ 334 │ 334 │ 0
entries │ 6246 │ 6355 │ +109 (+109 -0)
APK
compressed │ uncompressed │
──────────┬────────────┼──────────┬────────────┤
size │ diff │ size │ diff │ path
──────────┼────────────┼──────────┼────────────┼────────────────────────────────
2.9 MiB │ +444.4 KiB │ 8.7 MiB │ +1.4 MiB │ ∆ classes3.dex
2.9 MiB │ -393.1 KiB │ 8 MiB │ -1.2 MiB │ ∆ classes4.dex
3.4 MiB │ +147.5 KiB │ 9 MiB │ +480.2 KiB │ ∆ classes2.dex
2 MiB │ +60.6 KiB │ 2 MiB │ +60.6 KiB │ ∆ resources.arsc
24.5 KiB │ +24.5 KiB │ 24.4 KiB │ +24.4 KiB │ + res/H5.png
4.7 KiB │ +4.7 KiB │ 4.6 KiB │ +4.6 KiB │ + res/4K.png
2.6 KiB │ +2.6 KiB │ 2.5 KiB │ +2.5 KiB │ + res/-j.png
1.2 KiB │ +1.2 KiB │ 2.2 KiB │ +2.2 KiB │ + res/q_.xml
798 B │ +798 B │ 1.9 KiB │ +1.9 KiB │ + res/JW1.xml
691 B │ +691 B │ 1.2 KiB │ +1.2 KiB │ + res/q3.xml
676 B │ +676 B │ 1.1 KiB │ +1.1 KiB │ + res/tV.xml
662 B │ +662 B │ 1.2 KiB │ +1.2 KiB │ + res/cO.xml
613 B │ +613 B │ 940 B │ +940 B │ + res/F9.xml
589 B │ +589 B │ 936 B │ +936 B │ + res/RS.xml
550 B │ +550 B │ 844 B │ +844 B │ + res/0k.xml
529 B │ +529 B │ 788 B │ +788 B │ + res/1O.xml
9.7 KiB │ +518 B │ 9.6 KiB │ +518 B │ ∆ assets/dexopt/baseline.prof
500 B │ +500 B │ 804 B │ +804 B │ + res/ip.xml
436 B │ -169 B │ 692 B │ -412 B │ ∆ res/ZJ.xml
4.1 KiB │ +55 B │ 19.4 KiB │ +452 B │ ∆ AndroidManifest.xml
6.9 MiB │ +8 B │ 28.4 MiB │ 0 B │ ∆ classes.dex
666 B │ -7 B │ 534 B │ -7 B │ ∆ assets/dexopt/baseline.profm
1.3 KiB │ -3 B │ 4.1 KiB │ 0 B │ ∆ res/U9.xml
1.1 KiB │ -2 B │ 2.9 KiB │ 0 B │ ∆ res/5d.xml
798 B │ -2 B │ 1.6 KiB │ 0 B │ ∆ res/LG.xml
324 B │ +2 B │ 464 B │ 0 B │ ∆ res/uP.xml
760 B │ +1 B │ 1.7 KiB │ 0 B │ ∆ res/4L.xml
493 B │ -1 B │ 836 B │ 0 B │ ∆ res/7A.xml
997 B │ -1 B │ 2.8 KiB │ 0 B │ ∆ res/AE.xml
707 B │ +1 B │ 1.3 KiB │ 0 B │ ∆ res/CF.xml
1.1 KiB │ -1 B │ 3.1 KiB │ 0 B │ ∆ res/Cm.xml
1 KiB │ -1 B │ 3.1 KiB │ 0 B │ ∆ res/Fs.xml
600 B │ -1 B │ 1.1 KiB │ 0 B │ ∆ res/IZ.xml
767 B │ +1 B │ 1.5 KiB │ 0 B │ ∆ res/M6.xml
601 B │ +1 B │ 1.1 KiB │ 0 B │ ∆ res/MP1.xml
726 B │ -1 B │ 1.6 KiB │ 0 B │ ∆ res/TP.xml
529 B │ -1 B │ 984 B │ 0 B │ ∆ res/WT.xml
736 B │ +1 B │ 1.4 KiB │ 0 B │ ∆ res/_Y.xml
1.3 KiB │ -1 B │ 3.9 KiB │ 0 B │ ∆ res/_n.xml
1.8 KiB │ +1 B │ 10.4 KiB │ 0 B │ ∆ res/dn.xml
829 B │ -1 B │ 1.8 KiB │ 0 B │ ∆ res/fx.xml
620 B │ +1 B │ 1.1 KiB │ 0 B │ ∆ res/ib1.xml
1 KiB │ +1 B │ 2.6 KiB │ 0 B │ ∆ res/j9.xml
619 B │ +1 B │ 1.2 KiB │ 0 B │ ∆ res/jH.xml
802 B │ +1 B │ 1.7 KiB │ 0 B │ ∆ res/wf.xml
──────────┼────────────┼──────────┼────────────┼────────────────────────────────
18 MiB │ +298.2 KiB │ 56.1 MiB │ +732 KiB │ (total)
MANIFEST
@@ -264,2 +264,7 @@
/>
+ <data
+ android:host=link-accounts
+ android:path=/login
+ android:scheme=stripe-auth
+ />
</intent-filter>
@@ -271,2 +276,8 @@
/>
+ <activity
+ android:exported=false
+ android:name=com.stripe.android.financialconnections.ui.FinancialConnectionsSheetNativeActivity
+ android:theme=@style/StripeDefaultTheme
+ android:windowSoftInputMode=0x16
+ />
<provider
DEX
STRINGS:
old │ new │ diff
────────┼────────┼───────────────────
219199 │ 222562 │ +3363 (+3423 -60)
+
20B 0000R0¢R0¢R0¢R0¢¨
+
20B00R0¢R0¢¨
+
20BF00000 0
0
R0
¢R0¢
R0¢R0¢
R 0
¢ R0¢
R0¢¨
+ ,
20B¦000000 0
00
000000000R
00¢
R0¢R0¢R0¢R0¢R0¢R00¢R0¢R0¢R0¢R0¢R0¢R 0¢ R0¢R0¢R
0¢
¨
+ Z
020H020HUH *H0
*02
002
00Hø¢_H *H0
*0202
002
00Hø¢1H0 *H0
*0*H H¢KH0 *H0
*0*H 2HH0H¢KH0 *H0
*0*H 2HH0 H¢!
20¨
+ _mapper
+ _mapper_inlined
+ _prop1
+ (Landroidx/lifecycle/LifecycleOwner;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;II)Lcom/airbnb/mvrx/MavericksViewModel;
+ (Lcom/airbnb/mvrx/MavericksViewModel;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+ (Lcom/airbnb/mvrx/MavericksViewModel;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+ (Lcom/airbnb/mvrx/MavericksViewModel;Lkotlin/reflect/KProperty1;Landroidx/compose/runtime/Composer;I)Landroidx/compose/runtime/State;
+ (Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;II)Lcom/airbnb/mvrx/MavericksViewModel;
+ (TS;)TA;
+ (TS;)TO;
+ -TS;+TO;>;
+ -TS;+TO;>;)V
+ C(collectAsState)
+ C(mavericksActivityViewModel)P(1)
+ C(mavericksViewModel)P(2,1)
+ Composable is not hosted in a ComponentActivity!
+ Lcom/airbnb/android/showkase/annotation/ShowkaseCodegenMetadata;
+ Lcom/airbnb/android/showkase/annotation/ShowkaseColor;
+ Lcom/airbnb/android/showkase/annotation/ShowkaseComposable;
+ Lcom/airbnb/android/showkase/annotation/ShowkaseRoot;
+ Lcom/airbnb/android/showkase/annotation/ShowkaseRootCodegen;
+ Lcom/airbnb/android/showkase/annotation/ShowkaseRootModule;
+ Lcom/airbnb/android/showkase/annotation/ShowkaseScreenshot;
+ Lcom/airbnb/android/showkase/annotation/ShowkaseTypography;
+ Lcom/airbnb/mvrx/compose/BuildConfig;
+ Lcom/airbnb/mvrx/compose/MavericksComposeExtensionsKt_collectAsState__inlined_map_1_2_1;
+ Lcom/airbnb/mvrx/compose/MavericksComposeExtensionsKt_collectAsState__inlined_map_1_2;
+ Lcom/airbnb/mvrx/compose/MavericksComposeExtensionsKt_collectAsState__inlined_map_1;
+ Lcom/airbnb/mvrx/compose/MavericksComposeExtensionsKt_collectAsState__inlined_map_2_2_1;
+ Lcom/airbnb/mvrx/compose/MavericksComposeExtensionsKt_collectAsState__inlined_map_2_2;
+ Lcom/airbnb/mvrx/compose/MavericksComposeExtensionsKt_collectAsState__inlined_map_2;
+ Lcom/airbnb/mvrx/compose/MavericksComposeExtensionsKt_collectAsState_1;
+ Lcom/airbnb/mvrx/compose/MavericksComposeExtensionsKt_collectAsState_3;
+ Lcom/airbnb/mvrx/compose/MavericksComposeExtensionsKt_collectAsState_5;
+ Lcom/airbnb/mvrx/compose/MavericksComposeExtensionsKt;
+ Lcom/airbnb/mvrx/compose/R_anim;
+ Lcom/airbnb/mvrx/compose/R_animator;
+ Lcom/airbnb/mvrx/compose/R_attr;
+ Lcom/airbnb/mvrx/compose/R_bool;
+ Lcom/airbnb/mvrx/compose/R_color;
+ Lcom/airbnb/mvrx/compose/R_dimen;
+ Lcom/airbnb/mvrx/compose/R_drawable;
+ Lcom/airbnb/mvrx/compose/R_id;
+ Lcom/a
...✂
ARSC
ENTRIES:
old │ new │ diff
──────┼──────┼────────────────
6246 │ 6355 │ +109 (+109 -0)
+ drawable/stripe_check_account
+ drawable/stripe_check_base
+ drawable/stripe_check_routing
+ drawable/stripe_ic_brandicon_institution
+ drawable/stripe_ic_check
+ drawable/stripe_ic_check_nocircle
+ drawable/stripe_ic_edit
+ drawable/stripe_ic_external
+ drawable/stripe_ic_loading_spinner
+ drawable/stripe_ic_mail
+ drawable/stripe_ic_safe
+ drawable/stripe_ic_shield
+ drawable/stripe_logo
+ plurals/stripe_account_picker_confirm
+ plurals/stripe_attachlinkedpaymentaccount_desc
+ plurals/stripe_attachlinkedpaymentaccount_desc_no_business
+ plurals/stripe_attachlinkedpaymentaccount_title
+ string/consent_pane_manual_entry
+ string/consent_pane_tc
+ string/data_accessible_callout
+ string/data_accessible_callout_connected_accounts
+ string/data_accessible_callout_no_business
+ string/data_accessible_callout_through_stripe
+ string/data_accessible_callout_through_stripe_no_business
+ string/data_accessible_type_accountdetails
+ string/data_accessible_type_balances
+ string/data_accessible_type_ownership
+ string/data_accessible_type_transactions
+ string/stripe_account_picker_dropdown_hint
+ string/stripe_account_picker_error_no_payment_method_desc
+ string/stripe_account_picker_error_no_payment_method_title
+ string/stripe_account_picker_loading_desc
+ string/stripe_account_picker_loading_title
+ string/stripe_account_picker_multiselect_account
+ string/stripe_account_picker_select_account
+ string/stripe_consent_pane_agree
+ string/stripe_consent_pane_body1
+ string/stripe_consent_pane_body1_connected_account
+ string/stripe_consent_pane_body1_no_businessname
+ string/stripe_consent_pane_body2
+ string/stripe_consent_pane_body3
+ string/stripe_consent_pane_title
+ string/stripe_consent_pane_title_connected_account
+ string/stripe_consent_pane_title_no_businessname
+ string/stripe_consent_requested_data_accountdetails_desc
+ string/stripe_consent_requested_data_accountdetails_title
+ string/stripe_consent_requested_data_balances_desc
+ string/stripe_consent_requested_data_balances_title
+ string/stripe_consent_requested_data_learnmore
+ string/stripe_consent_requested_data_ownership_desc
+ string/stripe_consent_requested_data_ownership_title
+ string/stripe_consent_requested_data_title
+ string/stripe_consent_requested_data_title_no_businessname
+ string/stripe_consent_requested_data_transactions_desc
+ string/stripe_consent_requested_data_transactions_title
+ string/stripe_error_cta_select_another_bank
+ string/stripe_error_generic_desc
+ string/stripe_error_generic_title
+ string/stripe_error_planned_downtime_desc
+ string/stripe_error_planned_downtime_title
+ string/stripe_error_unplanned_downtime_desc
+ string/stripe_error_unplanned_downtime_title
+ string/stripe_institutionpicker_footer_item_manualentry
+ string/stripe_institutionpicker_footer_item_spelling
+ string/stripe_institutionpicker_footer_item_support
+ string/stripe_institutionpicker_footer_title
+ string/stripe_institutionpicker_pane_error_desc
+ string/stripe_institutionpicker_pane_error_desc_manual_entry
+ string/stripe_institutionpicker_pane_error_title
+ string/stripe_institutionpicker_pane_select_bank
+ string/stripe_manualentry_account
+ string/stripe_manualentry_account_type_disclaimer
+ string/stripe_manualentry_accountconfirm
+ string/stripe_manualentry_cta
+ string/stripe_manualentry_microdeposits_desc
+ string/stripe_manualentry_routing
+ string/stripe_manualentry_title
+ string/stripe_manualentrysuccess_desc
+ string/stripe_manualentrysuccess_desc_descriptorcode
+ string/stripe_manualentrysuccess_desc_noaccount
+ string/stripe_manualentrysuccess_desc_noaccount_descriptorcode
+ string/stripe_manualentrysuccess_table_title
+ string/stripe_manualentrysuccess_title
+ string/stripe_ok
+ string/stripe_partner_finicity
+ string/stripe_partner_mx
+ string/stripe_partner_testmode
+ string/stripe_partner_truelayer
+ string/stripe_partner_wellsfargo
+ string/stripe_picker_error_desc
+ string/stripe_picker_error_title
+ string/stripe_picker_loading_desc
+ string/stripe_picker_loading_title
+ string/stripe_picker_search_no_results
+ string/stripe_prepane_continue
+ string/stripe_prepane_desc
+ string/stripe_prepane_partner_callout
+ string/stripe_prepane
...✂
Does this work for svg files as well?
Does this work for svg files as well? would be great to be able to load Uri
Currently it does not support these. The idea here is to have the basic, and keep iterating over it as teams need it. @jameswoo-stripe @ccen-stripe
@ccen-stripe @jameswoo-stripe @tillh-stripe Alternatively we can rely on coil-base
(not the entire coil library) to run image requests. It'd add ~150kb to the binary, but we'd support all usecases, cache types, etc - https://github.com/stripe/stripe-android/pull/5584