Embedding .NET library's properties and actions on Android native AAR - android

I'm adding an existing Xamarin.Android .NET library to a native Android Studio project. I'm following the indications on https://learn.microsoft.com/en-us/xamarin/tools/dotnet-embedding/ and everything works well, but I have a question not being a Java expert:
is it also possible to export to Java the C#'s properties and actions present in my libraries (like ReturnAnyText)?
namespace export_test
{
[Register("export_test.ClassToExport")]
public class ClassToExport
{
[Export("ClassToExport")]
public ClassToExport()
{
// ...
}
[Export("DoSomething")]
public void DoSomething()
{
// ...
}
public Action<string> ReturnAnyText { get; set;}
}
}

A property under the hood are just get_PropertyName() and set_PropertyName() methods. So yes, you should be able to export those too:
This would look something like:
public bool MyProp
{
[Export]
get;
[Export]
set;
}
Or if you want to name them:
public bool MyProp
{
[Export("GetMyProp")]
get;
[Export("SetMyProp")]
set;
}

The simplest solution I found is to not try to export C# delegates, and simply return an object containing the return values at the end of the method execution:
namespace export_test
{
[Register("export_test.ClassToExport")]
public class ClassToExport
{
[Export("ClassToExport")]
public ClassToExport()
{
// ...
}
[Export("DoSomething")]
public MyResult DoSomething()
{
// ...
}
}
[Register("export_test.MyResult")]
public class MyResult
{
private string _Text;
private int _Value;
[Export("MyResult")]
public MyResult(string text, int val)
{
_Text = text;
_Value = val;
}
[Export("GetText")]
public string GetText() { return _Text; }
[Export("GetValue")]
public int GetValue() { return _Value; }
}
}

Related

Android, Xamarin: Cannot write to App Preferences via Singleton

Im our app, we have a class with app preferences, that stores certain data. A short version of this class looks like this:
public class AppPreferences
{
private ISharedPreferences mSharedPrefs;
private ISharedPreferencesEditor mPrefsEditor;
private Context mContext;
public AppPreferences(Context context)
{
this.mContext = context;
mSharedPrefs = PreferenceManager.GetDefaultSharedPreferences(mContext);
mPrefsEditor = mSharedPrefs.Edit();
}
public void SaveAutoLogIn(bool autologindone)
{
mPrefsEditor.PutBoolean(AUTOLOGIN, autologindone);
mPrefsEditor.Commit();
}
public bool GetSaveAutoLogIn()
{
return mSharedPrefs.GetBoolean(AUTOLOGIN, false);
}
public void saveLocationPermissionGranted(bool granted)
{
mPrefsEditor.PutBoolean(LOCATIONPERMISSION, granted);
mPrefsEditor.Commit();
}
public void savePermissionGranted(bool granted)
{
mPrefsEditor.PutBoolean(PERMISSIONS, granted);
mPrefsEditor.Commit();
}
}
But instead of continuesly instantiating this class in every activity it is needed in, I have decided to create a singleton class (Shorted):
class Preferences : AbstractPreferences<Preferences>
{
// öffentliche Felder und Methoden
public string usernameKey { get; set; }
public string emailKey { get; set; }
public int numberOfNews { get; set; }
public bool locationpermission { get; set; }
public int numberofnewschats { get; set; }
AppPreferences ap;
private Preferences()
{
}
public void GetPreferences(Context mContext)
{
ap = new AppPreferences(mContext);
this.usernameKey = ap.getUsernameKey();
this.emailKey = ap.getEmailKey()
}
public void DeletePreferences()
{
ap.deletePreferences();
}
public void DeleteTutorialPrefs()
{
ap.deleteTutorialPrefs();
}
public void SetPreferencesDeviceID(string key)
{
ap.saveDeviceID(key);
}
}
Okay, so basically, this class that inherets from:
public abstract class AbstractPreferences<T> where T : class
{
// Lazy Instanziierung
private static readonly Lazy<T> _instance = new Lazy<T>(() => CreateSingletonInstance());
public static T Instance
{
get
{
// throw new System.InvalidOperationException("out");
return _instance.Value;
}
}
private static T CreateSingletonInstance()
{
// Konstruktion des Singleton-Objekts
return Activator.CreateInstance(typeof(T), true) as T;
}
}
}
Now instantiates all app preferences at once and then sets them to an object like:
Preferences.Preferences prf = Preferences.Preferences.Instance;
prf.GetPreferences(mContext);
This was neccissarry, since any other way caused the app preferences to crash. But here is the problem:
I cannot SET any prefs. Retrieving them works just fine - but when I set a value, like a bool set to true - after I retrieve just this value, I get the default value in return (false). I debugged this as far as I could. When I am in the first class (AppPreferences) I see that the right value is beeing transported into the the final function: For instance:
public void SaveAutoLogIn(bool autologindone)
{
mPrefsEditor.PutBoolean(AUTOLOGIN, autologindone);
mPrefsEditor.Commit();
}
But after retrieving a value from the function I never get was has been set to it. I know, this is a complicated problem - but I really need your guys help. I hope you can help me! Thanks a lot!

What is Design Pattern where we can pass the string name to a method and that method chooses which further method to call

I recently got following example where we are passing the action name to the method as string and then the method decides the function that needs to be called.
is this a good way of solving problem or is there some better way as well
public static final String ACTION_CHARGING_REMINDER = "charging-reminder";
public static void executeTask(Context context, String action) {
if (ACTION_INCREMENT_WATER_COUNT.equals(action)) {
incrementWaterCount(context);
} else if (ACTION_DISMISS_NOTIFICATION.equals(action)) {
NotificationUtils.clearAllNotifications(context);
} else if(ACTION_CHARGING_REMINDER.equals(action)){
issueChargeReminder(context);
}
}
I'd do something like this. This can be extended as much as you want, and obviously just an example:
static abstract class ActionHandler {
private String action;
public ActionHandler(String action) {
this.action = action;
}
public boolean canHandleAction(String input) {
return this.action.equals(input);
}
public abstract void handleAction();
}
static class OneActionHandler extends ActionHandler {
public OneActionHandler(String action) {
super(action);
}
#Override
public void handleAction() {
//...
}
}
static class TwoActionHandler extends ActionHandler {
public TwoActionHandler(String action) {
super(action);
}
#Override
public void handleAction() {
//...
}
}
static class Test {
private ActionHandler[] handlers;
public Test() {
handlers = new ActionHandler[]{new OneActionHandler("action1"), new TwoActionHandler("action2")};
}
public void handleAction(String action) {
for(ActionHandler i : handlers) {
if(i.canHandleAction(action)) {
i.handleAction();
break;
}
}
}
}
This sounds a lot like the react/redux, action/reduction pattern.
Reducers specify how the application's state changes in response to
actions sent to the store. Remember that actions only describe what
happened, but don't describe how the application's state changes.

It's possible to addOnPropertyChangedCallback on a #Bindable?

I would like to observe a #Bindable via Java, is it possible?
I read that I can observe a ObservableField on this answer:
https://stackoverflow.com/a/31885802/858257
But sometimes you need the primitive field and the best approach is using a #Bindable.
Sure you can. If you have a field marked with #Bindable and implement Observable, you can listen for changes to that field. Any bindable field must notify when changed. For example:
public class Item extends BaseObservable {
private String name;
private int stockCount;
#Bindable
public String getName() { return name; }
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
#Bindable
public int getStockCount() { return stockCount; }
public void setStockCount(int stockCount) {
this.stockCount = stockCount;
notifyPropertyChanged(BR.stockCount);
}
}
You can then listen for changes on this object. I used BaseObservable as the base class for this data class because it implements the observability for me.
public void listenForStockChange(Item item) {
item.addOnPropertyChangedCallback(new OnPropertyChangedCallback() {
#Override
public void onPropertyChanged(Observable sender, int propertyId) {
if (propertyId == BR.stockCount) {
Item item = (Item) sender;
// Do whatever you want when the stock changes
}
}
});
}

How to map Enum in GreenDAO

I've just started using greenDAO.
How do I add an Enum property?
What I've Thought of: using the addIndex property of an entity.
private static void main() {
// TODO Auto-generated method stub
static Schema blah;
Entity unicorn = blah.addEntity("Weather");
unicorn.addIdProperty();
unicorn.addIntProperty("currentAirTemp");
unicorn.addIndex("shirtSize");
}
Is this the right way to do it?
Aim: I want to have a reference to shirtSize being from the set: {XS, S, M, L, XL, XXL}
Using GreenDAO 3 we now have the option to use #convert annotation with PropertyConverter
#Entity
public class User {
#Id
private Long id;
#Convert(converter = RoleConverter.class, columnType = String.class)
private Role role;
enum Role {
DEFAULT, AUTHOR, ADMIN
}
static class RoleConverter implements PropertyConverter<Role, String> {
#Override
public Role convertToEntityProperty(String databaseValue) {
return Role.valueOf(databaseValue);
}
#Override
public String convertToDatabaseValue(Role entityProperty) {
return entityProperty.name();
}
}
}
Read more at http://greenrobot.org/objectbox/documentation/custom-types/
Latest version of GreenDao (2.x) contains functionality which ideally suits your needs. There are a Custom Types which can serve enums very easily.
Enum
public enum ShirtSize {
XS(1),
S(2),
M(3),
L(4),
XL(5),
XXL(6);
private final int value;
ShirtSize(int value) {
this.value = value;
}
public int value() {
return value;
}
}
Converter
public class ShirtSizeConverter implements PropertyConverter<ShirtSize, Integer> {
#Override
public ShirtSize convertToEntityProperty(Integer databaseValue) {
if(databaseValue == null) {
return null;
} else {
for(ShirtSize value : ShirtSize.values()) {
if(value.value() == databaseValue) {
return value;
}
}
throw new DaoException("Can't convert ShirtSize from database value: " + databaseValue.toString());
}
}
#Override
public Integer convertToDatabaseValue(ShirtSize entityProperty) {
if(entityProperty == null) {
return null;
} else {
return entityProperty.value();
}
}
}
Entity field declaration (in generator)
entity.addIntProperty("ShirtSize").customType(
"com.your_package.ShirtSize",
"com.your_package.ShirtSizeConverter"
);
As far as I know, Enums are not supported by greenDAO due to their unstable nature.
Also they are an error-prone component to add to your database logic, since the values of the enum elements can change.
One option to get around this would be to add an Int property to the database and then map Enum ordinal values to that field, like so:
// add the int property to the entity
unicorn.addIntProperty("shirtSize");
// create the enum with static values
public enum ShirtSize {
XS(1), S(2), M(3), L(4), XL(5), XXL(6);
private final int value;
private ShirtSize(int value) {
this.value = value;
}
public int value() {
return value;
}
}
// set the ordinal value of the enum
weather.setShirtSize(ShirtSize.XL.value());

Simple library in Android : Boolean in "1" or "0"

Simple library is great and i already parsed many
different XML from soap servers since last 3 days, but i encountered
boolean attributes with "0" or "1" :
<list mybool1="0" mybool2="1" attr1="attr" attr2="attr">
<page mybool3="1">
...
</page>
<page mybool3="0">
...
</page>
...
</list>
I tried to create this class :
public class Boolean01Converter implements Converter<Boolean>
{
#Override
public Boolean read(InputNode node) throws Exception {
return new Boolean(node.getValue().equals("1"));
}
#Override
public void write(OutputNode node, Boolean value) throws Exception {
node.setValue(value.booleanValue()?"1":"0");
}
}
and implemented it on my object definition :
#Root(name="list")
public class ListFcts
{
#Attribute
#Convert(Boolean01Converter.class)
private Boolean mybool1;
#Attribute
#Convert(Boolean01Converter.class)
private Boolean mybool2;
#Attribute
private int ...
#ElementList(name="page", inline=true)
private List<Page> pages;
public Boolean getMybool1() {
return mybool1;
}
}
But i still get false for every boolean.
[edit]
In fact, when i do this :
#Override
public Boolean read(InputNode node) throws Exception {
return true;
}
i still get false for :
Serializer serial = new Persister();
ListFcts listFct = serial.read(ListFcts.class, soapResult);
if(listFct.getMybool1())
{
//this never happens
}else{
//this is always the case
}
so my Converter has no impact...
Also : how can I attach the converter to the Persister instead of
declaring it on #Attributes hundred times ?
Many thanks in advance !!
[edit2]
i give up with Converter, this is my own solution :
#Root(name="list")
public class ListFcts
{
#Attribute
private int mybool1;
#Attribute
private int mybool2;
public int getMybool1() {
return mybool1;
}
public Boolean isMybool1() {
return (mybool1==1)?true:false;
}
...
}
Your code is using node.getValue() which returns the value (read: contents) of each XML node (the "..." bit in your examples).
What you need is to reading the attribute values, something like node.getAttributeValue("mybool1").equals("1")
i gave up with Converter, I heard about Transform but didn't find how to use it so this is my own basic solution :
#Root(name="list")
public class ListFcts
{
#Attribute
private int mybool1;
#Attribute
private int mybool2;
public int getMybool1() {
return mybool1;
}
public Boolean isMybool1() {
return (mybool1==1)?true:false;
}
...
}

Categories

Resources