[solved] LibGDX Problems Loading Skins

Hi all,

I’m having some issues getting skins to load into my LibGDX program. I was able to get the default program to work that displays the badlogic.jpg image, but everything else I’ve tried to do using skins has been less successful.

I’m new to LibGDX and still learning, but from my understanding all images have to be placed under the Android project and I’ve tried placing files in the Android “assets” folder and I’ve also tried placing them in the “assets/data” folder (saw this mentioned on stackoverflow). In Eclipse I have pointed the desktop application to use the Android assets folder.

When trying to create a label using the uiskin the Android version gives an error on this line when trying to load the uiskin.json, however it does work on the desktop version.
skin = new Skin(Gdx.files.internal(“uiskin.json”));

The button.pack I created won’t load on either the desktop or the Android version.
skin2 = new Skin(Gdx.files.internal(“button.pack”));

As far as I can tell I have all the files that it needs to load these skins. For the uiskin I downloaded the 5 necessary files (default.fnt, default.png, uiskin.atlas, uiskin.json, and uiskin.png) and for the button I’ve gone through the steps of creating a 9-patch and then the button pack.

I haven’t been able to find anything that really spells out clearly where to put these files and how to load them in yet.

For example, the documentation for the Gdx.files.internal() method states:
“Convenience method that returns a Files.FileType.Internal file handle.”
http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Files.html#internal-java.lang.String-

And for Files.FileType.Internal file handle:
“Path relative to the asset directory on Android and to the application’s root directory on the desktop. On the desktop, if the file is not found, then the classpath is checked. This enables files to be found when using JWS or applets. Internal files are always readonly.”
http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/Files.FileType.html#Internal

This states the path is relative to the “assets” folder, however when I tried putting the default uiskin in the “assets” folder it didn’t load for the desktop, but when I put it in the “assets/data” folder it did load. Android didn’t load at all, whether I had the files in “assets” or in “assets/data”. However, running the default program with the badlogic.jpg image did work with it placed in the “assets” folder for both desktop and Android.

I’ve looked at the documentation and other tutorials, but it’s not coming together just yet. Can anyone break down the process of loading skins a more than the existing documentation? I’d greatly appreciate it, thanks! :slight_smile:

Some actual code would be useful (Or even the actual error output). If you’d like a working example I can point you towards one of my projects that has one in there.

Hi UprightPath, thanks for the reply.

Here is a specific example that doesn’t do anything except try to load a skin and it still crashes:

package com.tekker.animationattempt;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;

public class AnimationAttempt extends ApplicationAdapter {
	Skin skin;
	
	@Override
	public void create () {
		skin = new Skin(Gdx.files.internal("uiskin.json"));
	}
}

With the files inside of the Android project “assets/data” folder, it runs for the desktop version and displays a blank screen as expected…the weird part is that I pointed the desktop version to the Android “assets” folder, not “assets/data”. So I’m not actually sure why this works for the desktop version, but it does. However it crashes for the android version.

Here are the errors from the Android LogCat:

09-14 19:00:27.934: E/AndroidRuntime(13801): FATAL EXCEPTION: GLThread 10870
09-14 19:00:27.934: E/AndroidRuntime(13801): Process: com.tekker.animationattempt.android, PID: 13801
09-14 19:00:27.934: E/AndroidRuntime(13801): com.badlogic.gdx.utils.SerializationException: Error reading file: uiskin.json
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at com.badlogic.gdx.scenes.scene2d.ui.Skin.load(Skin.java:96)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at com.badlogic.gdx.scenes.scene2d.ui.Skin.<init>(Skin.java:73)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at com.tekker.animationattempt.AnimationAttempt.create(AnimationAttempt.java:12)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:236)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1520)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1248)
09-14 19:00:27.934: E/AndroidRuntime(13801): Caused by: com.badlogic.gdx.utils.SerializationException: Error reading file: uiskin.json
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at com.badlogic.gdx.utils.Json.fromJson(Json.java:662)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at com.badlogic.gdx.scenes.scene2d.ui.Skin.load(Skin.java:94)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	... 5 more
09-14 19:00:27.934: E/AndroidRuntime(13801): Caused by: com.badlogic.gdx.utils.SerializationException: Error parsing file: uiskin.json
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at com.badlogic.gdx.utils.JsonReader.parse(JsonReader.java:77)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at com.badlogic.gdx.utils.Json.fromJson(Json.java:660)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	... 6 more
09-14 19:00:27.934: E/AndroidRuntime(13801): Caused by: com.badlogic.gdx.utils.GdxRuntimeException: Error reading file: uiskin.json (Internal)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at com.badlogic.gdx.backends.android.AndroidFileHandle.read(AndroidFileHandle.java:77)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at com.badlogic.gdx.files.FileHandle.reader(FileHandle.java:164)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at com.badlogic.gdx.utils.JsonReader.parse(JsonReader.java:75)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	... 7 more
09-14 19:00:27.934: E/AndroidRuntime(13801): Caused by: java.io.FileNotFoundException: uiskin.json
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at android.content.res.AssetManager.openAsset(Native Method)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at android.content.res.AssetManager.open(AssetManager.java:316)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at android.content.res.AssetManager.open(AssetManager.java:290)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	at com.badlogic.gdx.backends.android.AndroidFileHandle.read(AndroidFileHandle.java:75)
09-14 19:00:27.934: E/AndroidRuntime(13801): 	... 9 more

Now if I move all of the files for the uiskin out of the Android “assets/data” folder and place them in just Android “assets” (then refresh the files in Eclipse and do Project->Clean for all projects) I get this error on the desktop version:

Exception in thread "LWJGL Application" com.badlogic.gdx.utils.GdxRuntimeException: Error reading pack file: uiskin.atlas
	at com.badlogic.gdx.graphics.g2d.TextureAtlas$TextureAtlasData.<init>(TextureAtlas.java:187)
	at com.badlogic.gdx.graphics.g2d.TextureAtlas.<init>(TextureAtlas.java:231)
	at com.badlogic.gdx.graphics.g2d.TextureAtlas.<init>(TextureAtlas.java:226)
	at com.badlogic.gdx.graphics.g2d.TextureAtlas.<init>(TextureAtlas.java:216)
	at com.badlogic.gdx.scenes.scene2d.ui.Skin.<init>(Skin.java:69)
	at com.tekker.animationattempt.AnimationAttempt.create(AnimationAttempt.java:12)
	at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:136)
	at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:114)
Caused by: com.badlogic.gdx.utils.GdxRuntimeException: Invalid line: <html lang="en" class="   ">
	at com.badlogic.gdx.graphics.g2d.TextureAtlas.readTuple(TextureAtlas.java:443)
	at com.badlogic.gdx.graphics.g2d.TextureAtlas$TextureAtlasData.<init>(TextureAtlas.java:115)
	... 7 more

The Android LogCat gives this error:

09-14 19:13:54.130: E/AndroidRuntime(16053): FATAL EXCEPTION: GLThread 10990
09-14 19:13:54.130: E/AndroidRuntime(16053): Process: com.tekker.animationattempt.android, PID: 16053
09-14 19:13:54.130: E/AndroidRuntime(16053): com.badlogic.gdx.utils.GdxRuntimeException: Error reading pack file: uiskin.atlas
09-14 19:13:54.130: E/AndroidRuntime(16053): 	at com.badlogic.gdx.graphics.g2d.TextureAtlas$TextureAtlasData.<init>(TextureAtlas.java:187)
09-14 19:13:54.130: E/AndroidRuntime(16053): 	at com.badlogic.gdx.graphics.g2d.TextureAtlas.<init>(TextureAtlas.java:231)
09-14 19:13:54.130: E/AndroidRuntime(16053): 	at com.badlogic.gdx.graphics.g2d.TextureAtlas.<init>(TextureAtlas.java:226)
09-14 19:13:54.130: E/AndroidRuntime(16053): 	at com.badlogic.gdx.graphics.g2d.TextureAtlas.<init>(TextureAtlas.java:216)
09-14 19:13:54.130: E/AndroidRuntime(16053): 	at com.badlogic.gdx.scenes.scene2d.ui.Skin.<init>(Skin.java:69)
09-14 19:13:54.130: E/AndroidRuntime(16053): 	at com.tekker.animationattempt.AnimationAttempt.create(AnimationAttempt.java:12)
09-14 19:13:54.130: E/AndroidRuntime(16053): 	at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:236)
09-14 19:13:54.130: E/AndroidRuntime(16053): 	at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1520)
09-14 19:13:54.130: E/AndroidRuntime(16053): 	at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1248)
09-14 19:13:54.130: E/AndroidRuntime(16053): Caused by: com.badlogic.gdx.utils.GdxRuntimeException: Invalid line: <html lang="en" class="   ">
09-14 19:13:54.130: E/AndroidRuntime(16053): 	at com.badlogic.gdx.graphics.g2d.TextureAtlas.readTuple(TextureAtlas.java:443)
09-14 19:13:54.130: E/AndroidRuntime(16053): 	at com.badlogic.gdx.graphics.g2d.TextureAtlas$TextureAtlasData.<init>(TextureAtlas.java:115)
09-14 19:13:54.130: E/AndroidRuntime(16053): 	... 8 more

I believe the problem I’m having is in the initial directory setup and getting the Gdx.files.internal() method to find my files and not necessarily the actual code itself. I’ve seen several examples that use the Gdx.files.internal() method but I can’t seem to get it to work consistently, so I think there is something else that I’m missing.

Thanks again!

Which IDE are you using? (And what IDE? Because that makes a difference for the loading in Desktop but not Android.) It’s likely an issue of you only editing the file-system and the IDE not knowing that there was a change (Eclipse is terrible at this.)

As for the other errors? It’s because you’ve download the HTML version of the documents which the .json parser and the .pack parser can’t read. It’s basically getting an HTML document and going “What is this!?” Anyway, you can solve THAT problem by cloning the repo and copy/pasting directly from it, or viewing the files in their raw form and making sure that they’re saving as the right type of document.

Edited because I had a thought two seconds later. xD

Exactly. This line shows your problem which is unrelated to the file location but is about its contents:

You should always look down the stack trace to find the first “caused by” line, which is usually the most informative. JSON is a way of structuring data that is different from XML, and as UprightPath says, you need the JSON version for LibGDX. This one, I expect.

D’oh!!! I knew I had to make sure to save the RAW files, but I guess I botched it somehow and it never occurred to me that I had actually saved them wrong. I re-saved the files and the default uiskin works great now on both desktop and android with the files in the Android “assets” folder. Thanks UprightPath and Grunnt you guys are awesome! :slight_smile:

*** EDIT *** Never mind on the button problem, I just figured out what I was doing wrong trying to load the buttons.

The button pack has to be loaded as a TextureAtlas, not a Skin!

This was wrong:

Skin skin = new Skin(Gdx.files.internal("button.pack"));

This is correct:

TextureAtlas atlas = new TextureAtlas(Gdx.files.internal("button.pack"));
Skin skin = new Skin(atlas);

I think I’m good to go…for now at least! :wink: Thanks again for your help!