DEV Community

Cover image for 2 things to consider when adding subscriptions to your mobile app
Tristan Elliott
Tristan Elliott

Posted on

2 things to consider when adding subscriptions to your mobile app

Table of contents

  1. The 2 things to consider
  2. Loading screen
  3. Disabling buy button after first click

My app on the Google Playstore

GitHub code

Introduction

  • This series will be an informal demonstration of any problems I face or any observations I make while developing Android apps. Each blog post in this series will be unique and separate from the others, so feel free to look around.

The two things

1) Loading screen
2) Disabling the buy button

  • These may seen obvious to you more experienced developers, however, this may be helpful to those starting out like myself. By implementing these two features, our app will start behaving like much larger and more professional apps

1) Loading screen

  • If you look at THIS code example. You will notice there is no loading screen, just simple waiting and the Google play Billing library modal appears. Which is fine, however, it can be a little jarring to the user if they click the subscribe button and there is no indication that loading is happening.

Creating a simple loading screen

  • A simple loading screen can be created in Jetpack compose like so:
Box(modifier = Modifier.fillMaxSize()){
// The rest of your compose code
//will explain isUserBuying later 
val isUserBuying = billingViewModel.state.value.userBuying
if(isUserBuying){
            Spacer(
                modifier = Modifier
                    .matchParentSize()
                    .background(color = Color.Gray.copy(alpha = .7f))
            )
            CircularProgressIndicator(
                color= MaterialTheme.colors.onSecondary,
                modifier = Modifier
                    .align(Alignment.Center)
                    .size(60.dp)
            )
        }
}

Enter fullscreen mode Exit fullscreen mode
  • The spacer will cover the entire screen with a light transparent gray and the CircularProgressIndicator rotating in the center of the screen.

  • Now, isUserBuying is a conditional I am storing in my Viewmodel like so:

data class BillingUiState(

    val userBuying:Boolean = false

)
private val _uiState = mutableStateOf(BillingUiState())
val state = _uiState // exposed to the UI
Enter fullscreen mode Exit fullscreen mode
  • Whenever the buy() method is clicked we simply set this to false:
fun buy(
        productDetails: ProductDetails,
        currentPurchases: List<Purchase>?,
        activity: Activity,
        tag: String
    ) {

        _uiState.value = _uiState.value.copy(
            userBuying = true
        )
// the rest of the buy method
}
Enter fullscreen mode Exit fullscreen mode
  • The buy() method will reach out to the Google play billing library and cause the purchases modal to pop up like so:

Google play billing library modal

When to close the loading screen.

  • When the modal pops, up our app enters the onPause() lifecycle state.

  • Which means the user will have to interact with the modal by either making a successful purchase or dismissing the modal. This interaction will make our app call the onResume method. So to close our loading screen we should do so in the onResume() method like so:

override fun onResume(owner: LifecycleOwner) {
        _uiState.value = _uiState.value.copy(
            userBuying = false
        )
    }

Enter fullscreen mode Exit fullscreen mode
  • I would like to point out that this will only work if your ViewModel is Lifecycle aware.

2) Disabling the buy button

  • If you do not disable the buy button after the first click, there is the possibility of the user pressing it multiple times. Causing the launch of multiple purchase modals, Which can be very confusing to the user. To make sure this does not happen we simply put a conditional in the onClick method of a Button composable:
Button(
            onClick={
                if(!isUserBuying){
                    billingViewModel.state.value.productDetails?.let{
                        billingViewModel.buy(
                            productDetails = it,
                            currentPurchases = null,
                            activity = activity,
                            tag = "calf_tracker_premium"
                        )
                    }
                }

            }
        ){
            Text("Upgrade $10.00", fontSize = 30.sp)
        }

Enter fullscreen mode Exit fullscreen mode
  • With !isUserBuying I am simply stating, if the user has already clicked the button remove the method call to billingViewModel.buy().

  • Technically we could remove the user's ability to click the button all together. By moving our conditional to the Button's enabled parameter but I really don't like the UI for it. So I choose to simply remove the call to the method.

Recap

  • So to wrap things up, to make our app behave more professionaly we need to make sure we do two things:

1) Add a loading screen
2) Disable the buy button after first click

Conclusion

  • Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter.

Top comments (0)