Play Billing 5.0.0 Kotlin - How to override onProductDetailsResponse()? - android

please reference this doc.
It states: "To handle the result of the asynchronous operation, you must also specify a listener which implements the ProductDetailsResponseListener interface. You can then override onProductDetailsResponse(), which notifies the listener when the query finishes, as shown in the following example:"
Trouble is, there's no such listener in the Kotlin example (there is one in the Java example.)
When I add:
override fun onProductDetailsResponse() { ... }
I get "nothing to override" from the SDK. Is it the case that Java needs the interface but Kotlin doesn't?
Thank you!

Related

Passing a function that requires parameters as a callback in Kotlin

I am using Kotlin (for Android development) and I'm trying to pass a function to another function which I'd like to use as a callback. The code is very basic as this is just a test for now.
Please note that, although you will probably wonder why I'm using a callback like this, it's just for test purposes. In my actual application I would want to assign the callback to a value and call it later on once an asynchronous method has completed.
I cannot use co-routines etc... since this code will be used for a multi-platform solution, hence my interest in making a function callback.
My Kotlin Class that will receive the function (callback)
class SampleApi {
private var counter: Int = 0
fun startCounting(initialValue: Int, counterCallBack: (resultVal: Int) -> Unit) {
counter = initialValue
counter++
counterCallBack(counter)
}
}
The above is a basic class that has a function startCounting which will receive an integer and a function. It will then call that function and pass in a value.
The calling code
class MainActivity : AppCompatActivity() {
private val sampleApi: SampleApi = SampleApi()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sampleApi.startCounting(5, {counterCallBack()})
}
private fun counterCallBack(counter: Int) {
Toast.makeText(this, counter.toString(), Toast.LENGTH_SHORT).show()
}
}
The Sample code shown above contains the callback method (which is expecting to receive an integer), and contains the call to the startCounting method from the SampleApi class that is expecting to receive a function.
The problem I have is this line:
sampleApi.startCounting(5, {counterCallBack()})
The error within Android Studio is due to the fact that a value is that the function is expecting an integer and hence I receive the error:
No value passed for parameter 'counter'
I tried to look at lambdas but didn't think that was the issue. I have searched to see if an answer to this already existed and, whilst helpful they didn't seem to consider the same use case as mine.
Any help with this would be very much appreciated.
Because counterCallback has exactly the type you need, you can also use a function reference instead of a lambda:
sampleApi.startCounting(5, ::counterCallBack)
I assume what you want to do is create a toast displaying the Int every time your callback lamda is called from the SampleApi.
You just need to make use of the Int that your lamba is called with, using it:
sampleApi.startCounting(5, {counterCallBack(it)})

I want to close override method in adapter. Is the resolve good practice?

I want to improve my recyclerview list adapter via binding view model from fragment to my adapter.
So my new recyclerview adapter updates data via subscribe to view model.
Now i need to close submit list override fun. Because i don't need to update adapter via fragment. To update data i use binded view model instead.
My solving is:
#Deprecated("use vm instead", ReplaceWith("throw RuntimeException(\"Calling from fragment is deprecated!\")"))
override fun submitList(data: MutableList<InvitedGuyVo>?) {
throw RuntimeException("Calling from fragment is deprecated!")
}
But my doubt is good practice to throw exception if i want to bun override fun?
The API does not deny one from calling the method. It may turn out there is a usage of the class via a base class or interface, where they may not see the deprecation.
The final keyword may help to deny the method from being re-implemented in the inheritor classes.
You may have a stronger #Deprecated annotation in Kotlin with the level set to HIDDEN, e.g.
#Deprecated("message", level = DeprecationLevel.HIDDEN)
The annotation may the method invisible for an IDE, but still visible for the binary code.
The best way to solve the problem, but probably too hard way, could be to create a dedicated hierarchy of classes or interfaces, where there is no way in principle to call the method that you try to hide.

Make Android Lifecycle Observer receiver non nullable in Kotlin

I have Result wrapper that wraps data comes from backend
data class Result<T>(val success: Boolean, val result: T?, val message: String?)
Idea of this, check success instead of result being null or not valid and get formatted message for UI error reporting. But when trying to use this with android lifestyle components, specifically in Observer I have to check for null.
How can I avoid this null check? This happens because of
void onChanged(#Nullable T t);
in Observer. I've tried to extend this but it seem to require more custom wrapper classes. Do we have a solution for avoid null check here.
It's a framework bug that argument is annotated as #Nullable. Fixed in androix.lifecycle 2.0.0-beta01.
Updated answer from #Andrei Vinogradov's answer
Until you upgrade to 2.0.0-beta01, you can try this solution. Use standard function let from Kotlin library :
it?.let{ result ->
if(result.success){
// Rest of your code ..
}
}

Annotate interface function that must call super

I'm creating interface and some function in it has a body.
It's required, that class that implements this interface must call super in overriding function before executing other code.
How can I do this?
interface Watcher {
fun funWithoutBody()
fun startWatching() {
//do some important stuff which must be called
}
}
I've accidentally found, what I was looking for. It's a #CallSuper annotation available in androidx.annotation package. Docs
Use the #CallSuper annotation to validate that an overriding method
calls the super implementation of the method. The following example
annotates the onCreate() method to ensure that any overriding method
implementations call super.onCreate():
#CallSuper
protected fun onCreate(savedInstanceState: Bundle?) {
}
Android Studio / IntelliJ IDEA does this sort of thing in some cases but it isn't done through annotations but through code inspection.
e.g. MissingSuperCall is an Android Lint Check for which IntelliJ IDEA supports (Integration with Android Lint tool in IntelliJ IDEA 11.1 | IntelliJ IDEA Blog).
You can create your own custom inspection if you are using Android Studio or IntelliJ IDEA: IntelliJ IDEA 2016.2 Help :: Creating Custom Inspections.
You could just make startWatching abstract and call it in another function. E.g.:
interface Watcher {
fun funWithoutBody()
fun userDefinedStartWatching()
fun startWatching() {
//insert code you'd normally want to be called when using super()
userDefinedStartWatching()
}
}

Lifecycle methods in statically typed languages

In the last year I've become a mobile developer and a functional programming admirer.
In each of the mobile arenas there are components with lifecycle methods that make up the meat of the app. The following will use Android and Kotlin as examples, but the same applies to iOS and Swift.
In Android, there are Activity's with lifecycle methods like onCreate(). You might also define a function, onButtonClicked(), which will do exactly what the name describes.
For the purposes of the question, let's say there's a variable defined in onCreate() that is used in a button click handler onButtonClickedPrintMessageLength() (This is usually the case - onCreate() is essentially Activity's setup method).
The example class would look like this:
class ExampleActivity: Activity() {
var savedStateMessage: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
savedStateMessage = "Hello World!"
}
fun onButtonClickedPrintMessageLength() {
System.out.println(savedStateMessage?.length)
}
}
Notice the declaration of savedStateMessage as a String? (nullable string) and the use of ?. (null safe call). These are required because the compiler cant guarantee that onCreate() will be called before onButtonClickedPrintMessageLength(). As developers though, we know that onCreate will always be called first* **.
My question is how can I tell the compiler about the guaranteed order of these methods and eliminate the null checking behavior?
* I suppose it's possible to new up our ExampleActivity and call onButtonClickedPrintMessageLength() directly, thus sidestepping the Android framework and lifecycle methods, but the compiler/JVM would likely run into an error before anything interesting happened.
** The guarantee that onCreate is called first is provided by the Android framework, which is an external source of truth and might break/function differently in the future. Seeing that all Android apps are based on this source of truth though, I believe it's safe to trust.
Although this won't answer your actual question, in Kotlin you can use lateinit to tell the compiler that you'll initialize a var at a later point in time:
lateinit var savedStateMessage: String
You'll get a very specific UninitializedPropertyAccessException if you try to use this variable before initializing it. This feature is useful in use cases like JUnit, where you'd usually initialize variables in #Before-annotated method, and Android Activitys, where you don't have access to the constructor and initialize stuff in onCreate().
As mentioned in another answer, lateinit is available as an option to defer initialization to a later point in a guaranteed lifecycle. An alternative is to use a delegate:
var savedStateMessage: String by Delegates.notNull()
Which is equivalent, in that it will report an error if you access the variable before initializing it.
In Swift this is where you would use an implicitly-unwrapped Optional:
class Example: CustomStringConvertible {
var savedStateMessage: String! // implicitly-unwrapped Optional<String>
var description: String { return savedStateMessage }
init() {
savedStateMessage = "Hello World!"
}
}
print(Example()) // => "Hello World!\n"
By using the operator ! at the end of String in the second line of the example you are promising that the variable will be set before it can be used. This is accomplished in the init method of the example. It's still an Optional but code can treat it as a String since it will be automatically unwrapped before each use. You must take care that the variable is never set to nil when it might be accessed or a runtime exception may be generated.

Categories

Resources