FitnessClass.GetSensorsClient().FindDataSourcesAsync() Can't convert from Java.Lang.Object to JavaList<DataSource>
When using the latest GMS Fitness nuget package, I have:
var client = FitnessClass.GetSensorsClient( Context, GoogleAccount );
var dataSourcesSuccessListener = new DataSourcesSuccessListener();
dataSourcesSuccessListener.OnSuccessImpl = ( dataSources ) => {
// TODO: returned data sources
};
client.FindDataSources( request ).AddOnSuccessListener( dataSourcesSuccessListener );
The OnSuccess() method in the listener is called, but I cannot cast the java object to a JavaList<DataSource>.
The Object passed to OnSuccess is:
{[DataSource{derived:Application{com.google.android.gms:null}:Device{Google:Android SDK built for x86:cdcc769f:1:2}:live_step_deltas:DataType{com.google.step_count.delta[steps(i)]}}]}
Also the FindDataSourcesAsync() method has the same complaint.
Thanks in advance for any help!
Additionally...
I updated my Xamarin.Android project to target Android 10. I am also using AndroidX.
The previous code used the FitnessClass.SensorsApi.FindDataSourcesAsync() call which returned a DataSourcesResult object, but did work.
I noticed this morning that the returned object FitnessClass.GetSensorsClient() has an AsGoogleApiClient method, so I used that to feed into the deprecated SensorsApi.FindDataSourcesAsync() call. This worked as with the older code base!
Here is the simplified code:
var client = FitnessClass.GetSensorsClient( Context, GoogleAccount );
// THIS FAILS
var result1 = await client.FindDataSourcesAsync( request );
// THIS WORKS
var result = await FitnessClass.SensorsApi.FindDataSourcesAsync( client.AsGoogleApiClient(), request );
Again, the call fails with: Cannot convert Object to JavaList<DataSource>
I've found a workaround, but the newer GetSensorsClient().FindDataSourcesAsync() call should work too.
I hope that helps. Let me know if you need anything else from me.
@ToddThomson Thanks for your report. Is it possible to get me a small repro sample for both cases (AndroidX and old legacy Android.Support), so I can reproduce the issue faster. Thanks
@moljac I will put a minimal repro sample together for you tomorrow. Thanks for looking into this issue.
@moljac I am working on the repro app now. Should have time to complete Monday or early next week.
@moljac @Redth I've decided that porting the Android Fitness SensorsAPI (Kotlin) sample would be more beneficial then cutting down part of my application. I will try to find the time on Monday to finish up.
@ToddThomson Thanks a lot. This will help me a lot by speeding the investigation.
@moljac Done. AndroidX; Latest GooglePlayServices components; Simplified OAuth 2. Pretty much an exact port of the latest Google Fit Kotlin sample: basicsensorsapi.kt.
Later today I will move the solution to GitHub. I'll post the link when that step is done.
@moljac AndroidX version of BasicSensorsApi
The project is built with a conditional symbol: USESENSORSCLIENT to hit the exception in this issue. By default the project uses: USESENSORSCLIENT_NO and the workaround is used.
NOTES:
-
Project: Latest Nuget packages; Android Q; AndroidX.
-
You need to setup your own Google API project to obtain an OAuth 2 client id.
- This is still a bit of black magic to me! I added a google-services.json and added the client id to
strings.xml. That works for me, but I have no idea why (the documentation is terrible here).
- This is still a bit of black magic to me! I added a google-services.json and added the client id to
-
The solution uses the common sample library. I updated it to use Android 10, Q. I have not included the sources as I made no changes.
Please let me know if you require any additional information.
@moljac Tomorrow I will add the exception hit when using:
var client = FitnessClass.GetSensorsClient( Context, GoogleAccount );
var dataSourcesSuccessListener = new DataSourcesSuccessListener();
dataSourcesSuccessListener.OnSuccessImpl = ( dataSources ) => {
// TODO: returned data sources
};
client.FindDataSources( request ).AddOnSuccessListener( dataSourcesSuccessListener );
@moljac @Redth I implemented the above code and found that the DataSourceSuccessListener class OnSuccess( Java.Lang.Object result ) method was invoked. The result object was an "java.util.Collections.UnmodifiableRandomAccessList" .
I found that I could cast the object to an Java.Util.IList, but not to a JavaList<DataSource> .
The object returned is definitely a list of DataSource objects.
Any ideas on how to do the conversion?
@moljac I've confirmed that that the result object in OnSuccess() is an IList<DataSource>
private class DataSourcesSuccessListener : Java.Lang.Object, Android.Gms.Tasks.IOnSuccessListener
{
public Action<JavaList<DataSource>> OnSuccessImpl { get; set; }
public void OnSuccess( Java.Lang.Object result )
{
var t = result.JavaCast<Java.Util.IList>();
var tsize = t.Size(); // = 1
var dsObj = t.Get( 0 );
DataSource ds = dsObj.JavaCast<DataSource>(); // returns a DataSource object
It seems that the UnmodifiableRandomAccessList class cannot be converted to a JavaList.
@moljac I found that the java object passed to OnSuccess() can be cast to a JavaCollection<DataSource> as below. This is fine for a workaround.
I will leave it up to you to determine why the Java.Lang.Object result can be cast ( IsInstanceOf() does not fail in CastClass method ) to JavaCollection<> but not JavaList<> .
private class DataSourcesSuccessListener : Java.Lang.Object, Android.Gms.Tasks.IOnSuccessListener
{
public Action<JavaList<DataSource>> OnSuccessImpl { get; set; }
public void OnSuccess( Java.Lang.Object result )
{
var jc = result.JavaCast<JavaCollection<DataSource>>(); // OK
var jl = result.JavaCast<JavaList<DataSource>>(); // Fails
@moljac Repro updated with all 3 ways of using FIT to obtain sensor data sources.
Use project conditional compilation definitions to try each case. USESENSORSCLIENT_ASYNC produces the issue. USESENSORSCLIENT uses the cast to JavaCollection<DataSource> as a workaround. USESENSORSAPI uses deprecated SensorsApi which also works.
@ToddThomson Wow. Thanks a lot for the sample it really helps me to investigate issue[s] faster. Excellent. Thanks.