Starting with Android

I’m just getting to grips with Android and trying out a few things with DA. I have a couple of issues, using the async connection as per https://docs.dataabstract.com/Java/GettingStarted/WorkingAsynchronouslyWithTheRemoteDataAdapter/
I can get it working fine synchronously, then I notice here Problem with connection Android it explains about the http chat demo where it suggests aChatService.beginLogin and yet when I look at that demo, it’s changed since then and is now Service.Login. So, is there an example of using this as I must be missing something?

Second thing is, because I’m bringing some custom params back from the DA server, I have to declare as reference type, for example:

 var info: com.remobjects.sdk.ReferenceType<LoginInfo>;

How do I get that variable back to the original LoginInfo class so I can use it when it comes back?

Hello

You’ll need to use info.Value to access the wrapped value.

Android doesn’t allow to perform network activity on main thread. You have to use asynchronous methods like in the mentioned topic.

Tbh the sample you are referring to was not updated to follow this policy. Refer to Java samples for more suitable approach.

Got it, thanks.

Which Java sample should I be looking at then, as I’m just trying to call asynchronously something on a DA custom server (not actually using DA for this, just the ROSDK) and can’t find one that shows how to do this. This is actually what I tried, but it never gets ti the server :

 var ar:AsyncRequest:=loginProxy.beginLoginIpad(userName,password, false, new interface AsyncRequest.IAsyncRequestCallback(
    completed := method(aRequest: AsyncRequest) begin
       var info: com.remobjects.sdk.ReferenceType<LoginInfo>;
       info:= new com.remobjects.sdk.ReferenceType<LoginInfo>;
       var loginResult:Integer:= loginProxy.endLoginIpad(info,aRequest);
    end,
    failed := method(aRequest: AsyncRequest; anException: Exception) begin
       System.out.println(anException.Message);
    end
  ));

This, however, is fine:

loginProxy.LoginIpad(userName, password, info);

Hi,

you can review the MyTasks.zip (2.0 MB) sample.
You can download DB for this sample at https://docs.dataabstract.com/Java/Tutorials/TodoTutorial/database/

Thanks Evgeny, but what do I do with a gradle package so I can see the code? Android studio? Not come across it before (I’m using Fire of course).

yep, it is Android Studio project.
code can be found in app\src\main\java\com\remobjects\dataabstract\samples\mytasks folder

Got it thank you. I see now what I did wrong - I’m coming from using this on iOS (and want to do a new app for both iOS and Android) where the async request isn’t started, as I set delegate and context then start it manually. I realise here that I can’t do that (and it didn’t start as I didn’t tell it to), so I changed the ‘false’ for start to true in the above and it works fine.

Is there a document that discusses differences between the different DA flavours?

can you explain what you do mean here, pls?

I mean, I started with DA Delphi (which is what built the custom DA server), and then learned DA with Xcode and now do it with Fire for iOS and now I want to learn DA for Java for Android devices. There are subtle differences between them, and I just wondered if anyone had written anything to make learning the differences simpler.

I want to make a cross-platform app with the shared project and just need to see how the differences are coped with - and I’m using all the RO tools for this apart from relativity.

The subtle differences are also in the codeGen output. From my RODL, this is Java:

method LoginService_AsyncProxy.endLoginIpad(iPadAllowed: com.remobjects.sdk.ReferenceType; a: com.remobjects.sdk.ReferenceType; aAsyncRequest: com.remobjects.sdk.AsyncRequest): nullable Integer;

and this is iOS:

method LoginService_AsyncProxy.endLoginIpad(___asyncRequest: ROAsyncRequest; out iPadAllowed: Boolean; out a: LoginInfo): Integer;

So one has the AsyncRequest parameter first, the other second. So, what would be the best way to handle that to avoid duplicating code? Can I use these in a shared project easily or should I have one dataAccess class per project?

right now, the only way to handle this is by duplicating the code; possibly abstracting the actual RO calls into a ting wrapper class that then #ifdefs the differences. for example in Fire/Water (for working with Relativity server) I have code like this:

        internal static LoginService_AsyncProxy getLoginService(Url url)
        {
            if (defined("FIRE"))
                return new LoginService_AsyncProxy withService(new RORemoteService withTargetURL(url) serviceName("LoginService"));
            else if (defined("WATER"))
                return new LoginService_AsyncProxy(new RemoteService(url.ToAbsoluteString(), true, "LoginService"));
        }

or

      internal static void beginGetServerName(LoginService_AsyncProxy loginService, delegate void(string serverName, string? error) callback)
        {
            if (defined("FIRE"))
            {
                loginService.beginGetServerName__startWithBlock( (ROAsyncRequest ar) => {
                    try
                    {
                        var name = loginService.endGetServerName(ar);
                        callback(name, null);
                    }
                    catch (Exception e)
                    {
                        callback(null, cleanExceptionMessage(e.Message));
                    }
                });
            }
            else if (defined("WATER"))
            {
                SBLDispatch.dispatchAsyncOnBackgroundThread( () => {

                    loginService.BeginGetServerName( (IAsyncResult ar) => {
                        SBLDispatch.dispatchAsyncOnUIThread( () => {

                            try
                            {
                                var name = loginService.EndGetServerName(ar);
                                callback(name, null);
                            }
                            catch (Exception e)
                            {
                                callback(null, cleanExceptionMessage(e.Message));
                            }

                        });
                    }, null);

                }) exceptionCallback( (e) => {

                    SBLDispatch.dispatchAsyncOnUIThread( () => {
                        callback(null, cleanExceptionMessage(e.Message));
                    });

                });
            }
        }

that there actual app logic can then call seamlessly, regardless of platform (here’ it’s Cocoa bus .NET, not Cocoa vs Android, but you get the gist).

                    var loginService = RelativityClientFile.getLoginService(url);
                    RelativityClientFile.beginGetDomains(loginService, (domains, error) => {

                        if (domains?.Count > 0)
                        {

                            statusMessage = "Obtaining Server Name...";
                            RelativityClientFile.beginGetServerName(loginService, (name, error2) => {

In the longer run, we want to create a new platform-compatible API level for RO and DA, so that you would be able to use a single Intf file (or a set of Int files that expose side tidal APIs, not sure yet) on all RO platforms (and similar, use the same DA APIs to retrieve data). That’s a v10 feature, hopefully for later this year or early next.

1 Like

Thanks marc, that makes sense. I’m just dabbling at the moment, making the android app login and grab some data to display, just as a demo but I’ll then hopefully be building a new app for both platforms which will be my first :wink: plus I also want to do an Android version of my iOS personal app but that’s written specifically for iOS so has a ton of NSMutableArray and suchlike that will need refactoring so I can cut down the duplicated code.
Something nice to stimulate the brain, this is. Your tools are awesome btw, I don’t think I mentioned that this week :cowboy_hat_face:

1 Like

it’s not as much work as you might think ;). I refactored all of Fire from pure Cocoa to Elements RTL classes in like a month or so (mainly NSString, NS*Array, NSUrl stuff, a lot that can be done by bulk search/replace).

Thanx, always appreciated! :tropical_drink:

1 Like

Oh, and I am reading your https://blogs.remobjects.com/2017/08/16/strategies-for-cross-platform-code-sharing-with-elements/ post as well (posting in case someone else comes across this topic as it’s really useful).

1 Like

That’s a good starting point. Also, https://blogs.remobjects.com/2018/08/21/new-sample-shared-ui/.

1 Like

I’ll let you know :wink: - it’s stuff like the dispatch_async and NSNotificationCenter equivalents and so on- you know, the stuff you have to learn really to get the different platforms, but what makes the RO way of cross platform the right way to do it.
Oops, looks like I switched to my other self, partway through this.

I have a custom SBLDispatch class for Fire/Water that I used to replace dispatch; I can share a city here (it’s got some Fire-specific stuff, bu the general principle will be helpful). for notifications, check out BroadcastManager in Elements RTL, it’s basically a wrapper around that for Cocoa, and reimplements the infrastructure from scratch for the other platforms. Well-tested on Java and .NET as both Water and my Weather app use this extensively.

1 Like

Dispatch.zip (5.8 KB)

it’s dispatchAsyncOnUIThread hat will be most tricky to port to Android, as getting the main thread needs a Context reference there. let me see how I handled that in weather…

… ah, I didn’t, basically I handle the :“back to main thread” inside there (bespoke per platform) UI classes, eg

        BroadcastManager.subscribe(self, toBroadcast: WeatherDataManager.NOTIFICATION_WORLD_WEATHER_UPDATED) {
            self.Activity.runOnUiThread() {
                ...
            }
        }

on Android and

        BroadcastManager.subscribe(self, toBroadcast: WeatherDataManager.NOTIFICATION_WORLD_WEATHER_UPDATED, selector: #selector(dataChanged:))
...
    @objc func dataChanged(_ notification: NSNotification?) {
        DispatchQueue.main.async() {
            ...
        }
    }

on iOS respectively. But you could wrap that into the abstraction for Dispatch, passing it there Context, on Android.

That’s really helpful, thanks. I’ll drop that in, change the bits I need to then have a play with that, but I see the idea.

I love the fact I don’t even need to re-write it in Oxygene, which is my preference (though I admit that I sometimes add a class in swift or c# just because I can, with Fire, and it reminds me there’s more than pascal, even if it ain’t Daddy’s…)

1 Like