I develop the flutter package and in this package one of class get function argument.
When I use this package in another flutter app, I can send function as prop to this package .
Now I just want to learn if I use the flutter module and build the aar , how can I send function as prop in native android ?
Thanks
This is not possible because you can send only serializable types
By default, AIDL supports the following data types:
All primitive types in the Java programming language (such as int, long, char, boolean, and so on)
Arrays of primitive types such as int[]
String
CharSequence
List
All elements in the List must be one of the supported data types in
this list or one of the other AIDL-generated interfaces or parcelables you've declared. A List may optionally be used as a parameterized type class (for example, List). The actual concrete class that the other side receives is always an ArrayList, although the method is generated to use the List interface.
Map
.
All elements in the Map must be one of the supported data types in this list or one of the other AIDL-generated interfaces or parcelables you've declared. Parameterized type maps, (such as those of the form Map<String,Integer>) are not supported. The actual concrete class that the other side receives is always a HashMap, although the method is generated to use the Map interface. Consider using a Bundle as an alternative to Map.
For more detailed information you can refer to the official AIDL documentation
Related
I start with one map myInitialMap. i would like to create another map myNewMap that is initialised with myInitialMap.
val myInitialMap = mapOf<String, Int>("one" to 1, "two" to 2)
val myNewMap = mapOf(myInitialMap)
I get error:
Type mismatch.
Required: Pair<TypeVariable(K), TypeVariable(V)>
Found: Map<String, Int>
How can I initialise myNewMap with myInitialMap?
You can use myInitialMap.toList().toMutableStateMap().
The ...Of() functions in Kotlin all follow the convention of taking individual entries as varargs, which is why mapOf(myInitialMap) doesn't, and shouldn't, work. Since these functions use the arguments to determine the generic types, the list/set versions could not possibly support also having overloads that accept an Iterable parameter with all the entries to include, because you might actually want a list of Iterables (2D collection). For consistency, mapOf must behave the same.
Function naming/behavior conventions:
...Of(): A function taking a vararg parameter of all the individual values to put in the collection. The argument type can be used for the compiler to infer the generic type(s) of the collection.
.to...Map/Set/List(): An extension function that creates a shallow copy or new type of collection from the entries of the collection it is called on.
.as...(): An extension function that wraps the original object in another one. For example, asIterable() or asSequence() will return those types, but they will read from the original object. They are not copies.
Kotlin introduced inline class which is strong typed type alias. This can be useful when use with database. For example,
inline class Age(val value: Int)
inline class Height(val value: Int)
When they are written to database, they are compiled to Int but Kotlin can prevent you accidentally putting a Height into a Age Field. If you use type alias or Int directly, it is possible with type alias but inline class produces a compile time error.
However, these also cause problems with Android data binding. I get data binding error when I try to bind a String inline class to a String attribute.
While it is possible to write some kinds of adapter to bypass this, but it defeat the purpose of using inline class and not practical for creating adapters for all inline classes.
I would like to ask are there any elegant ways to solve this issue?
First thing you need to understand is inline classes are not just wrappers around primitive types. They are more than type Aliases.
Now coming to your example, even though DataBinding has the understanding that if you put any MutableLiveData<T> instance in xml, it will take that value of that particular variable(something like mutableLiveData.value). But if you put MutablLiveData<Age>, mutableLiveData.value will always be of Type Age but not type Int.
Note that inline class, creates a completely new type and not just a type alias.
I believe that you somehow need a method in your data binding, that returns the value contained in the inline class object.
Recently an interviewer asked me a very tricky question.
There are several parts of the question.
Why (question is why and not how) do you need to parcel objects while sending from one activity to another and not send directly
Answer I gave -
Parcelable gives the capability to developers to restrict object
creation which in a way makes it faster to use.
I was confused on the part, so decided to site difference between using serializable and parcelable :p (clever huuuhhh !),
http://www.developerphil.com/parcelable-vs-serializable/ used this reference.
While using Bundle, when we use String, int we do not need to parcel the data, so do you think the String/int is by default internally parcelled ?
Answer I gave -
because String/int is a primitive data-type, if we had used the
Wrapper class directly, might be possible we had to use parcelable(I
am not sure on that part)
I did not get any useful link after googling, also I or the interviewer is not quite satisfied with the answer.
If you guys can help, would be wonderful !
Why (question is why and not how) do you need to parcel objects while sending from one activity to another and not send directly
Parcelling/serializing objects isn't for speed as you had guessed.
When you're sending data between Activities, and especially between different applications (remember that Intent objects aren't only meant for communication between your own Activities, but are also for between yours and those of other apps as well), you cannot expect the sender and the receiver to have access to the same memory address spaces.
Android's documentation states that applications run in their own discrete memory spaces. Here's a quote to that effect from the docs:
Each process has its own virtual machine (VM), so an app's code runs in isolation from other apps.
So when you want to send an object myObject to some receiving Activity, you can't send its reference/pointer because the receiver won't necessarily have access to the location specified by the pointer. Instead you'll have to send some representation of myObject that the receiver can access and use -- this is why you need to marshall the data into a form that can be unmarshalled, and the easiest way to do so is to simply have the class of the object implement Serializable which lets Java do its best to convert the object into an array of bytes that can be easily sent to and unmarshalled by the receiver. But since Serializable uses reflection, this is slow.
You can use other ways that are faster to marshall the data -- one, for example, is converting the object into its JSON representation using a library like Gson and just sending it across since any JSON document can be represented as a String and easily converted back to a Java Object. Another way, which is probably faster in pretty much all cases is using the Parcelable interface which lets you specify exactly how you want to marshall the data and exactly how it should be unmarshalled. It basically gives you more control on the transmission of the object.
The tl:dr: Parcelling/Serializing etc is used because you can't send memory addresses across, so you have to send the actual data of the object and it has to be represented in some form.
While using Bundle, when we use String, int we do not need to parcel the data, so do you think the String/int is by default internally parcelled ?
How Bundle works internally is that it puts everything into a Map and parcels/unparcels the data as needed (ie when get/put is called). For putting Objects into a Bundle, the object's class needs to implement Serializable or Parcelable because it needs to tell the Bundle how it should be marshalled/unmarshalled internally.
But primitive types and Strings are simple enough and used often enough that the developer doesn't need to specify how that needs to happen and Bundle provides convenience methods for it. I can't give you a solid answer at the lowest level of how they works because a lot of the Parcel code is natively implemented and I couldn't find it online, but they must certainly be straightforward to convert to their representation in bytes.
Just to add what #uj- said, Parcelling/Serializing is needed as #uj- said it will be sent across JVMs so they need to be converted into some format so that the other party will be able to understand.
Let me take an example to explain why serializing/parcelling is needed,
you are sending data from an application written in "C++" to an application written in java, so the following are the classes,
In C++,
class Android {
public: int dataToSend; //for example purpose making field public and omitting setter/getters
}
In Java,
class Android{
public int dataToSend;
}
suppose the C++ code generates dynamic library (which will be generated by compiling using the standard C++ compiler and then linked), and Java code generates a jar (by compiling using the javac).
When the C++ application sends data (object of Android class) to the java application the way it is compiled and linked in C++ is completely different as compared to the way its compiled in java and hence java will be wondering what has this C++ application sent to me.
Hence to get rid of such problems serialisation/parcelling is needed which will make sure that both of the application know how the data is converting while transmitting through network (in case of android how it is transmitted to another activity, may be in same or different application).
And yea when we start comparing Serialisation and Parcelling, Parcelling gets the upper hand as we will be specifying the way the data must be converted when sending the data, else in the case of serialisation the object is converted to string using reflection and reflection always takes time. Hence Parcelling is faster compared to Serialisation.
For your second question,
if we consider the above example itself then we can say that String and int being primitive types (no user defined fields in them) and hence android will be able to handle the marshalling and unmarshalling of the data which will be sent.
I tried going through the code when we go on digging deeper we end up getting native code as said by #uj-.
Some extract from the android source code:
while writing the parcel:
parcel.writeInt(BUNDLE_MAGIC);
int startPos = parcel.dataPosition();
parcel.writeArrayMapInternal(mMap);
int endPos = parcel.dataPosition();
parcel.setDataPosition(lengthPos);
int length = endPos - startPos;
parcel.writeInt(length);
parcel.setDataPosition(endPos);
while reading the parcel,
int magic = parcel.readInt();
if (magic != BUNDLE_MAGIC) {
//noinspection ThrowableInstanceNeverThrown
throw new IllegalStateException("Bad magic number for Bundle: 0x"
+ Integer.toHexString(magic));
}
int offset = parcel.dataPosition();
parcel.setDataPosition(offset + length);
Parcel p = Parcel.obtain();
p.setDataPosition(0);
p.appendFrom(parcel, offset, length);
p.setDataPosition(0);
mParcelledData = p;
set the magic number which will identify the start of the parcel while writing and the same will be used while we read the parcel.
Hope I answered your question.
I have the following AIDL file
package com.mindtherobot.samples.tweetservice;
interface TweetCollectorListener {
void handleTweetsUpdated();
}
I tried to make generic works in AIDL so far. It doesn't work. The following code will flag error.
package com.mindtherobot.samples.tweetservice;
interface TweetCollectorListener<E> {
E handleTweetsUpdated();
}
It seems that generic doesn't work in AIDL. However, that's my guess, as Android Interface Definition Language doesn't talk much on generic.
Just want to confirm, is it true generic doesn't work in AIDL? Is there any workaround?
From The official AIDL docs :
List
All elements in the List must be one of the supported data types
in this list or one of the other AIDL-generated interfaces or
parcelables you've declared. A List may optionally be used as a
"generic" class (for example, List). The actual concrete class
that the other side receives is always an ArrayList, although the
method is generated to use the List interface. Map All elements in the
Map
must be one of the supported data types in this list or one of the
other AIDL-generated interfaces or parcelables you've declared.
Generic maps, (such as those of the form Map are not
supported. The actual concrete class that the other side receives is
always a HashMap, although the method is generated to use the Map
interface.
So, as you can see there is only limited support for generics using Lists, not even Maps, so no a custom parametrized types is not supported.
In every example I saw, the data is somehow synonymous to basic (raw) data -- ints, chars, array of bools, and so on -- this is too limiting for me, because I would like to pass a regular object.
So how to pass any data to activity, like for example, instance of MyClass?
I checked the Intent.putExtra -- all I found was basic types + Bundle, but Bundle itself also handles only basic types.
There are several way to do it as described in android guide faq.
I think that in your case static variables could help most.
You could also implement Application and use it to share your data between Activities.
Here is short tutorial on that.
In every example I saw, the data is somehow synonymous to POJO data -- this is too limiting for me, because I would like to pass a regular object (not int, or string, or array of bools).
POJO = Plain Ol' Java Object = "regular object (not int, or string, or array of bools)".
So how to pass any data to activity, like for example, instance of MyClass?
Make it Parcelable.