meraki-analytics / orianna

A Java framework for the Riot Games League of Legends API (http://developer.riotgames.com/).
MIT License
182 stars 56 forks source link

Documentation for Android #96

Closed Jorege98 closed 5 years ago

Jorege98 commented 5 years ago

Hi I'm trying to use the Orianna API on Android Studio, but I can't make it work. I checked the documentation on the website, but it's incomplete

Jorege98 commented 5 years ago

This is the problem i get when I try to make a summoner request I/zygote: at java.lang.Object org.cache2k.spi.SingleProviderResolver.resolve(java.lang.Class, java.lang.Class) (SingleProviderResolver.java:110) at java.lang.Object org.cache2k.spi.SingleProviderResolver.resolve(java.lang.Class) (SingleProviderResolver.java:82) at java.lang.Object org.cache2k.spi.SingleProviderResolver.resolveMandatory(java.lang.Class) (SingleProviderResolver.java:64) at void org.cache2k.CacheManager.<clinit>() (CacheManager.java:54) at org.cache2k.CacheManager org.cache2k.CacheManager.getInstance() (CacheManager.java:88) at org.cache2k.configuration.Cache2kConfiguration org.cache2k.Cache2kBuilder.config() (Cache2kBuilder.java:160) at org.cache2k.Cache2kBuilder org.cache2k.Cache2kBuilder.disableStatistics(boolean) (Cache2kBuilder.java:715) at void com.merakianalytics.orianna.datapipeline.InMemoryCache.<init>(com.merakianalytics.orianna.datapipeline.InMemoryCache$Configuration) (InMemoryCache.java:175) I/zygote: at java.lang.Object java.lang.reflect.Constructor.newInstance0(java.lang.Object[]) (Constructor.java:-2) at java.lang.Object java.lang.reflect.Constructor.newInstance(java.lang.Object[]) (Constructor.java:334) at com.merakianalytics.datapipelines.DataPipeline com.merakianalytics.orianna.datapipeline.PipelineConfiguration.toPipeline(com.merakianalytics.orianna.datapipeline.PipelineConfiguration) (PipelineConfiguration.java:178) at com.merakianalytics.datapipelines.DataPipeline com.merakianalytics.orianna.Orianna$Settings$1.get() (Orianna.java:254) at java.lang.Object com.merakianalytics.orianna.Orianna$Settings$1.get() (Orianna.java:251) at java.lang.Object com.google.common.base.Suppliers$MemoizingSupplier.get() (Suppliers.java:120) at com.merakianalytics.datapipelines.DataPipeline com.merakianalytics.orianna.Orianna$Settings.getPipeline() (Orianna.java:247) at com.merakianalytics.orianna.types.core.summoner.Summoner com.merakianalytics.orianna.types.core.summoner.Summoner$Builder.get() (Summoner.java:92)

Jorege98 commented 5 years ago

I discovered topday this is maybe an error produced because of the pipeline, I would like to know how to configure Orianna on android

robrua commented 5 years ago

Hey - sorry for the slow response.

Right now this is an issue with cache2k on android as far as I can tell, detailed here https://github.com/cache2k/cache2k/issues/102. cache2k is the library that underlies the existing in-memory cache in orianna.

It sounds to me like the author intends to help out with this on their end by providing an android-specific build of cache2k that applies the Proguard Rules he specifies to strip out dependencies that aren't available on android.

Until that happens, there are couple of options you have in the meantime:

1) You could apply the Proguard Rules described in section 15.3 of https://cache2k.org/docs/latest/user-guide.html#android in your application. Unfortunately, since cache2k is getting pulled in transitively and isn't part of the ori jar I can't do this myself in orianna.

2) You could configure orianna to not use the in-memory cache for now, which it uses by default (hence your issue creating the pipeline).

If the problem persists in the long-term I'll add an alternative cache implementation for android to fix the issue, but for now I'm patiently hoping the library author gets some time to create an android-specific build of cache2k.

Best, Rob

Jorege98 commented 5 years ago

First of all thanks for your help. I would like to know how to configure Orianna on Android, because I tried to load a JSON and then I get this pipelines and cache2k errors.

robrua commented 5 years ago

If you remove the InMemoryCache section from the default configuration (https://github.com/meraki-analytics/orianna/blob/master/orianna/src/main/resources/com/merakianalytics/orianna/default-orianna-config.json#L7-L158) it should work

Jorege98 commented 5 years ago

I make the changes you suggested to me.

First of all, I paste my code: `public class LauncherActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_launcher);

    Orianna.setRiotAPIKey(APY_KEY);
    Orianna.setDefaultRegion(Region.EUROPE_WEST);
    Orianna.loadConfiguration(cargar());

    final Summoner summoner = Summoner.named("OG xPako").withRegion(Region.EUROPE_WEST).get();
    System.out.println("Level: " + summoner.getLevel());

    ConnectivityManager cm =(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    boolean isConnected = activeNetwork != null && activeNetwork.isConnected();

    System.out.println(isConnected);
}

public File cargar(){

    File f = new File(getCacheDir()+"/config.json");
    if (!f.exists()) try {

        InputStream is = getAssets().open("config.json");
        int size = is.available();
        byte[] buffer = new byte[size];
        is.read(buffer);
        is.close();

        FileOutputStream fos = new FileOutputStream(f);
        fos.write(buffer);
        fos.close();
    } catch (Exception e) { throw new RuntimeException(e); }

    return f;
}

}`

This is my config.json file: { "currentVersionExpiration": { "period": 6, "unit": "HOURS" }, "pipeline": { "elements": [ { "className": "com.merakianalytics.orianna.datapipeline.GhostLoader" }, { "className": "com.merakianalytics.orianna.datapipeline.MerakiAnalyticsCDN", "config": { "host": "cdn.merakianalytics.com", "cacheDuration": { "period": 6, "unit": "HOURS" }, "requests": { "connectTimeout": 3, "connectTimeoutUnit": "SECONDS", "rateLimiterTimeout": -1, "rateLimiterTimeoutUnit": "DAYS", "readTimeout": 3, "readTimeoutUnit": "SECONDS", "https": true } }, "configClassName": "com.merakianalytics.orianna.datapipeline.MerakiAnalyticsCDN$Configuration" }, { "className": "com.merakianalytics.orianna.datapipeline.DataDragon", "config": { "cacheDuration": { "period": 6, "unit": "HOURS" }, "requests": { "connectTimeout": 3, "connectTimeoutUnit": "SECONDS", "rateLimiterTimeout": -1, "rateLimiterTimeoutUnit": "DAYS", "readTimeout": 3, "readTimeoutUnit": "SECONDS", "https": true } }, "configClassName": "com.merakianalytics.orianna.datapipeline.DataDragon$Configuration" }, { "className": "com.merakianalytics.orianna.datapipeline.riotapi.RiotAPI", "config": { "http404Strategy": { "type": "RETURN_NULL" }, "http429Strategy": { "backupStrategy": { "backoff": 1, "backoffUnit": "SECONDS", "backupStrategy": { "type": "THROW_EXCEPTION" }, "maxAttempts": 4, "backoffFactor": 2, "type": "EXPONENTIAL_BACKOFF" }, "type": "RETRY_FROM_HEADERS" }, "http500Strategy": { "backoff": 1, "backoffUnit": "SECONDS", "backupStrategy": { "type": "THROW_EXCEPTION" }, "maxAttempts": 4, "backoffFactor": 2, "type": "EXPONENTIAL_BACKOFF" }, "http503Strategy": { "backoff": 1, "backoffUnit": "SECONDS", "backupStrategy": { "type": "THROW_EXCEPTION" }, "maxAttempts": 4, "backoffFactor": 2, "type": "EXPONENTIAL_BACKOFF" }, "httpTimeoutStrategy": { "backoff": 1, "backoffUnit": "SECONDS", "backupStrategy": { "type": "THROW_EXCEPTION" }, "maxAttempts": 4, "backoffFactor": 2, "type": "EXPONENTIAL_BACKOFF" }, "limitingShare": 1.0, "limitingType": "BURST", "rateLimiterTimeoutStrategy": { "type": "THROW_EXCEPTION" }, "requests": { "connectTimeout": 3, "connectTimeoutUnit": "SECONDS", "rateLimiterTimeout": -1, "rateLimiterTimeoutUnit": "DAYS", "readTimeout": 3, "readTimeoutUnit": "SECONDS", "https": true }, "services": [ "com.merakianalytics.orianna.datapipeline.riotapi.ChampionAPI", "com.merakianalytics.orianna.datapipeline.riotapi.ChampionMasteryAPI", "com.merakianalytics.orianna.datapipeline.riotapi.LeagueAPI", "com.merakianalytics.orianna.datapipeline.riotapi.MatchAPI", "com.merakianalytics.orianna.datapipeline.riotapi.SpectatorAPI", "com.merakianalytics.orianna.datapipeline.riotapi.StatusAPI", "com.merakianalytics.orianna.datapipeline.riotapi.SummonerAPI", "com.merakianalytics.orianna.datapipeline.riotapi.ThirdPartyCodeAPI" ] }, "configClassName": "com.merakianalytics.orianna.datapipeline.riotapi.RiotAPI$Configuration" }, { "className": "com.merakianalytics.orianna.datapipeline.ImageDownloader" }], "transformers": [{ "className": "com.merakianalytics.orianna.datapipeline.transformers.dtodata.ChampionMasteryTransformer" }, { "className": "com.merakianalytics.orianna.datapipeline.transformers.dtodata.ChampionTransformer" }, { "className": "com.merakianalytics.orianna.datapipeline.transformers.dtodata.LeagueTransformer" }, { "className": "com.merakianalytics.orianna.datapipeline.transformers.dtodata.MatchTransformer" }, { "className": "com.merakianalytics.orianna.datapipeline.transformers.dtodata.SpectatorTransformer" }, { "className": "com.merakianalytics.orianna.datapipeline.transformers.dtodata.StaticDataTransformer" }, { "className": "com.merakianalytics.orianna.datapipeline.transformers.dtodata.StatusTransformer" }, { "className": "com.merakianalytics.orianna.datapipeline.transformers.dtodata.SummonerTransformer" }, { "className": "com.merakianalytics.orianna.datapipeline.transformers.dtodata.ThirdPartyCodeTransformer" }] } }

And this is what happens when I run the APP:

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.jerez.summonersgg, PID: 4860 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jerez.summonersgg/com.jerez.summonersgg.LauncherActivity}: java.lang.NullPointerException at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2778) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6494) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) Caused by: java.lang.NullPointerException at java.lang.Class.classForName(Native Method) at java.lang.Class.forName(Class.java:453) at java.lang.Class.forName(Class.java:378) at com.merakianalytics.orianna.datapipeline.PipelineConfiguration.toPipeline(PipelineConfiguration.java:155) at com.merakianalytics.orianna.Orianna$Settings$1.get(Orianna.java:254) at com.merakianalytics.orianna.Orianna$Settings$1.get(Orianna.java:251) at com.google.common.base.Suppliers$MemoizingSupplier.get(Suppliers.java:120) at com.merakianalytics.orianna.Orianna$Settings.getPipeline(Orianna.java:247) at com.merakianalytics.orianna.types.core.summoner.Summoner$Builder.get(Summoner.java:92) at com.jerez.summonersgg.LauncherActivity.onCreate(LauncherActivity.java:31) at android.app.Activity.performCreate(Activity.java:7009) at android.app.Activity.performCreate(Activity.java:7000) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1214) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2731) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2856)  at android.app.ActivityThread.-wrap11(Unknown Source:0)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1589)  at android.os.Handler.dispatchMessage(Handler.java:106)  at android.os.Looper.loop(Looper.java:164)  at android.app.ActivityThread.main(ActivityThread.java:6494)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)  Application terminated.

robrua commented 5 years ago

I'm concerned that the input stream read might not be getting the whole configuration file and that's causing issues - you don't necessarily get the full # of bytes you asked for from InputStream.read.

Can you try replacing your config loading code with:

try(InputStream stream = getAssets().open("config.json")) {
    Orianna.loadConfiguration(ByteSource.wrap(ByteStreams.toByteArray(stream)).asCharSource(Charset.forName("UTF-8")));
}

and see if the same thing happens?

Jorege98 commented 5 years ago

Now I get this:

W/Java7Support: Unable to load JDK7 types (annotations, java.nio.file.Path): no Java7 support added I/zygote: Do partial code cache collection, code=29KB, data=17KB I/zygote: After code cache collection, code=22KB, data=15KB Increasing code cache capacity to 128KB I/zygote: Background concurrent copying GC freed 18903(1004KB) AllocSpace objects, 11(444KB) LOS objects, 49% free, 2MB/4MB, paused 1.831ms total 129.670ms I/zygote: Unable to resolve java.lang.Class annotation class 4400 I/chatty: uid=10079(com.jerez.summonersgg) identical 2 lines I/zygote: Unable to resolve java.lang.Class annotation class 4400 I/zygote: Unable to resolve java.lang.Class annotation class 5997 I/chatty: uid=10079(com.jerez.summonersgg) identical 1 line I/zygote: Unable to resolve java.lang.Class annotation class 5997 I/zygote: Do partial code cache collection, code=60KB, data=48KB I/zygote: After code cache collection, code=57KB, data=47KB Increasing code cache capacity to 256KB I/zygote: Unable to resolve java.lang.Class annotation class 4400 I/zygote: Unable to resolve java.lang.Class annotation class 4400 I/chatty: uid=10079(com.jerez.summonersgg) identical 2 lines I/zygote: Unable to resolve java.lang.Class annotation class 4400 I/zygote: Unable to resolve java.lang.Class annotation class 5997 I/chatty: uid=10079(com.jerez.summonersgg) identical 1 line I/zygote: Unable to resolve java.lang.Class annotation class 5997 I/zygote: Unable to resolve java.lang.Class annotation class 4400 I/zygote: Do full code cache collection, code=121KB, data=98KB I/zygote: After code cache collection, code=91KB, data=55KB A/libc: Fatal signal 11 (SIGSEGV), code 2, fault addr 0xdf6b5ce8 in tid 4529 (rez.summonersgg), pid 4529 (rez.summonersgg)

I'm working with API 27 and Java 8 by the way, and trying to load the summoner on main thread

robrua commented 5 years ago

This seems to be an issue with your project configuration rather than anything with orianna specifically. Unfortunately I can't help much with the details of android project configuration since I've never really done it, but here are some observations based on what you've posted:

1) "W/Java7Support: Unable to load JDK7 types (annotations, java.nio.file.Path): no Java7 support added" seems odd to me if you're targeting API 27, as java.nio.file.Path was added to android @ API 26 (https://developer.android.com/reference/java/nio/file/Path.html). Are you maybe targeting a lower API level?

2) Your real problem seems to be that it can't find the Guava classes ori needs though. How are you pulling ori into your project?

Jorege98 commented 5 years ago

I'm targeting API 27, here you have my app gradle:

' android { compileSdkVersion 28 defaultConfig { applicationId "com.jerez.summonersgg" minSdkVersion 27 targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } }

dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' implementation "com.merakianalytics.orianna:orianna-android:4.0.0-rc3" } '

robrua commented 5 years ago

What's the API version of the VM you're using to test the application?

Jorege98 commented 5 years ago

it is API 27, Android Oreo 8.1

Jorege98 commented 5 years ago

If you want you can see my code in my profile, I'll upload a new commit now

robrua commented 5 years ago

Hey, sorry for the slow turnaround. It looks to me like the Guava transitive dependency from Ori isn't making it into your apk for some reason.

Unfortunately I don't have a dev environment set up for android and I'm not familiar enough with android to figure out why, but some of the most common reasons for that sort of thing are dependency version conflict (e.g a different dependency or android itself is pulling in an older version of Guava that doesn't have the classes Ori is using) and build configurations not including the transitive dependency.

You might try adding a direct dependency on com.google.guava:guava version 20.0 and see what happens. That might help if there's a version conflict.

You could also try asking around on our discord (https://discord.gg/JRDk2JU) to see if any of the android devs there can help you.

robrua commented 5 years ago

We've now upgraded to the latest version of cache2k, which should have fixed this issue.