Functions which invoke #Composable functions must be marked with the #Composable annotation - android-jetpack

Below is my Code while build the code i getting this error
Functions which invoke #Composable functions must be marked with the #Composable annotation
#Composable invocations can only happen from the context of a #Composable function
#Composable invocations can only happen from the context of a #Composable function
Showing Error at
#Composable
public fun MessageCard(msg: Message) {
Text(text = msg.author)
Text(text = msg.body)
}
Complete Code
class LayoutList : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MessageCard(Message("Android", "Jetpack Compose"))
}
}
}
#Composable
public fun MessageCard(msg: Message) {
Text(text = msg.author)
Text(text = msg.body)
}
#Preview
#Composable
fun PreviewMessageCard() {
MessageCard(
msg = Message("Colleague", "Hey, take a look at Jetpack Compose, it's great!")
)
}
data class Message(val author: String, val body: String)```

As every composable function should be called from another composable function.
Please see this solution for your understanding and hope will work for you,
Jetpack compose AppBarIcon complains that "Functions which invoke #Composable functions must be marked with the #Composable"

Related

Async retrieving data from Firebase Firestore Kotlin [duplicate]

Firebase anonymous sign in returns a task (which is basically Google promise implementation):
val task:Task<AuthResult> = FirebaseAuth.getInstance().signInAnonymously()
How it would be possible create a signInAnonymous wrapper where:
It is a suspend function, waiting for the task completion
suspend fun signInAnonymous(): Unit
It returns a Deferred object, delivering the result asynchronously
fun signInAnonymous() : Deferred
The package kotlinx.coroutines.tasks now includes the follwing utility functions:
public suspend fun <T> Task<T>.await(): T { ... }
From the docs:
Awaits for completion of the task without blocking a thread.
This suspending function is cancellable.
If the Job of the current coroutine is cancelled or completed while this suspending function is waiting, this function stops waiting for the completion stage and immediately resumes with CancellationException.
public fun <T> Task<T>.asDeferred(): Deferred<T> { ... }
From the docs:
Converts this task to an instance of Deferred.
If task is cancelled then resulting deferred will be cancelled as well.
So you can just do:
suspend fun signInAnonymouslyAwait(): AuthResult {
return FirebaseAuth.getInstance().signInAnonymously().await()
}
or:
fun signInAnonymouslyDeferred(): Deferred<AuthResult> {
return FirebaseAuth.getInstance().signInAnonymously().asDeferred()
}
Based on this GitHub library, here's a way to transform a Task into a suspending function in the "usual" way to adapt callback based async calls to coroutines:
suspend fun <T> Task<T>.await(): T = suspendCoroutine { continuation ->
addOnCompleteListener { task ->
if (task.isSuccessful) {
continuation.resume(task.result)
} else {
continuation.resumeWithException(task.exception ?: RuntimeException("Unknown task exception"))
}
}
}
You can also wrap it in a Deferred of course, CompletableDeferred comes in handy here:
fun <T> Task<T>.asDeferred(): Deferred<T> {
val deferred = CompletableDeferred<T>()
deferred.invokeOnCompletion {
if (deferred.isCancelled) {
// optional, handle coroutine cancellation however you'd like here
}
}
this.addOnSuccessListener { result -> deferred.complete(result) }
this.addOnFailureListener { exception -> deferred.completeExceptionally(exception) }
return deferred
}
Add this to gradle
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.4.3'
And then you can use it like this:
suspend fun login(email: String, pass: String) {
FirebaseAuth.getInstance().signInWithEmailAndPassword(email, pass).await()
}
To transform it into a coroutine-ready function, I would use the Tasks.await() function from the Tasks API:
suspend fun FirebaseAuth.signInAnonymouslyAwait(): AuthResult {
return Tasks.await(this.signInAnonymously())
}
As for Deferred, i'd stick with zsmb13's answer

Flow type for a function parameter that is instance of a class

Given:
// #flow
declare interface IFoo {
test();
}
class Foo implements IFoo {
test () {
console.log('in test');
}
}
if i had a function:
// some function
async function demo (argA: string, argB: INSTANCE_OF_Foo) { ... }
how can i tell flow that argB is "instance of class that implements IFoo"? in other words if the usage of function demo had to be like
const foo: IFoo = new Foo();
demo('bla' foo);
How can i ensure what get's passed to demo is instance of a class that implements IFoo?
type script interface is ignored at runtime, it is only used at compile time for type checking. So there is no way you can check whether the Foo is implemented with IFoo.
But you can check whether foo is an instance of Foo class.
So it depends on what you seek: you can either ensure the argument implements IFoo:
async function demo (argA: string, argB: IFoo)
, or the argument is an instance of the class Foo:
async function demo (argA: string, argB: Foo)
But I must say, it's not really clear why you need to require an instance instead of an interface (which I think is the way to go here).
You can play with this easily at flow.org/try.
Hope this helps!

IllegalFlowLogicException when calling CordaRPCOps.startFlow

In a CorDapp, I defined the following flow:
#InitiatingFlow
#StartableByRPC
class EchoFlow(private val msg: String): FlowLogic<String>() {
override fun call(): String {
return msg
}
}
I then deployed the CorDapp to a node and tried to run it as follows:
val result = proxy.startFlow { EchoFlow("msg") }.returnValue.getOrThrow()
However, I received the following exception:
Exception in thread "main" net.corda.core.flows.IllegalFlowLogicException:
FlowLogicRef cannot be constructed for FlowLogic of type com.template.EchoFlow due to missing constructor for arguments: []
How should I invoke a flow using CordaRPCOps.startFlow?
CordaRPCOps.startFlow is used by passing a flow constructor, following by a vararg of arguments to the flow. So in Kotlin, you'd invoke the flow by running:
val result = proxy.startFlow(::EchoFlow, "msg").returnValue.getOrThrow()
Where ::ClassName is the Kotlin syntax for getting a reference to the flow's constructor.
Alternatively, you could use CordaRPCOps.startFlowDynamic. This method takes a flow instance instead, as follows:
val result = proxy.startFlowDynamic(EchoFlow("msg")).returnValue.getOrThrow()

Kotlin superClass Kclass

I have definiction of the function
abstract class AbstractDao<T>(private val dataStore: KotlinEntityDataStore<Persistable>): Dao<T> where T: Persistable
and I need to get KClass from type T. It is possible in Kotlin ?
This cannot be done due to type erasure. But you could provide a factory method with reified type that delegates to a constructor accepting the KClass. Here's a simplified example:
class WithReifiedType<T> constructor(val kc: KClass<*>) {
companion object {
inline fun <reified T> getInstance(): WithReifiedType<T> {
println("Here's your KClass: ${T::class}")
return WithReifiedType(T::class)
}
}
}
//called like this
WithReifiedType.getInstance<String>()
It's also acceptable to create a top-level function (as an alternative to companion-embedded factory) looking like a constructor on the caller site.
inline fun <reified T> WithReifiedType(): WithReifiedType<T> {
println("Here's your KClass: ${T::class}")
return WithReifiedType(T::class)
}
//called like this
WithReifiedType<String>()

Kotlin bound callable references inconsistency

Today I was creating unit tests for my Presenter in Android app and I noticed some inconsistency with bound callable references. Is it under development or is it language bug? I found that in kotlin 1.1 bound callable references are supported. But my code fails with kotlin 1.1.2-4.
In my presenter class, tested method reads data from database and dao.getAllItems() method have no parameters while view takes list --> view.showData(List<Item>).
I'm using Mockito, RxJava2 and Room Persistance library.
class ItemsPresenter #Inject constructor(private val itemDao: ItemDao) : Presenter<ItemsView>
{
val TAG = this.javaClass.name!!
private val disposables: CompositeDisposable = CompositeDisposable()
private lateinit var view: ItemsView
override fun onCreate(view: ItemsView)
{
this.view = view
}
override fun onDestroy()
{
disposables.clear()
}
fun onGetItems()
{
Observable.fromCallable(itemDao::getAllItems)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ data -> view.showData(data) },
{ throwable -> view.showLoadingDataError(throwable.localizedMessage) }
)
}
}
I have created test for onGetItems() method
#RunWith(KotlinTestRunner::class)
class ItemsPresenterTest
{
private lateinit var view: ItemsView
private lateinit var dao: ItemDao
private lateinit var presenter: ItemsPresenter
#Before
fun setup()
{
RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.io() }
dao = mock(ItemDao::class.java)
view = mock(ItemsView::class.java)
presenter = ItemsPresenter(dao)
}
#Test
fun onGetItemsTest()
{
val list = ArrayList<Item>()
When(dao.getAllItems()).thenReturn(list)
presenter.onCreate(view)
presenter.onGetItems()
verify(dao).getAllItems()
verify(view).showData(list)
}
}
When I have setup as above, the test passes without problems. But when I change line
{ data -> view.showData(data) }
to
{ view::showData }
Then my test fails saying
Wanted but not invoked:
itemsView.showData([]);
Is it language bug? Because vulnerable code compiles fine and runs, it just causes the method to not be invoked at all, without any errors.
To clarify, the same code written in Java 8 works fine, lambda argument is correctly passed into method reference. As you can see in Kotlin bound callable references work fine when used with methods that takes no parameters, otherwise they are not called at all.
You should change
{ data -> view.showData(data) }
to
(view::showData)
to pass in the method reference correctly. This way, with (), you're passing in the method reference as the parameter of the subscribe method.
Using {}, you define a new function with a lambda to be given to the subscribe method.
Writing down
{ view::showData }
is equivalent to
{ it -> view::showData }
which is a function that ignores its parameter, and returns the method reference view::showData.

Resources