From 4191737c1c62bf4d9adc535d4cb57733c6d1ded9 Mon Sep 17 00:00:00 2001 From: Wastrel Du <907972944@qq.com> Date: Thu, 6 Nov 2025 20:48:25 +0800 Subject: [PATCH] [android]optimize skeleton drawable load, Avoid app crashes caused by loading errors. (#2947) Co-authored-by: jfdu3 --- .../spine/android/SpineView.java | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/spine-android/spine-android/src/main/java/com/esotericsoftware/spine/android/SpineView.java b/spine-android/spine-android/src/main/java/com/esotericsoftware/spine/android/SpineView.java index 050d04a1e..ea5ef2866 100644 --- a/spine-android/spine-android/src/main/java/com/esotericsoftware/spine/android/SpineView.java +++ b/spine-android/spine-android/src/main/java/com/esotericsoftware/spine/android/SpineView.java @@ -44,9 +44,11 @@ import android.os.Build; import android.os.Handler; import android.os.Looper; import android.util.AttributeSet; +import android.util.Log; import android.view.Choreographer; import android.view.View; +import androidx.annotation.MainThread; import androidx.annotation.NonNull; import java.io.File; @@ -291,7 +293,7 @@ public class SpineView extends View implements Choreographer.FrameCallback { /** The same as {@link SpineView#loadFromDrawable(AndroidSkeletonDrawable, Context, SpineController)}, but can be used after * instantiating the view via {@link SpineView#SpineView(Context, SpineController)}. */ public void loadFromDrawable (AndroidSkeletonDrawable drawable) { - loadFrom( () -> drawable); + post( () -> setSkeletonDrawable(drawable)); } /** Get the {@link SpineController} */ @@ -350,21 +352,36 @@ public class SpineView extends View implements Choreographer.FrameCallback { this.rendering = rendering; } - private void loadFrom (AndroidSkeletonDrawableLoader loader) { + /** Load the skeleton from a {@link AndroidSkeletonDrawableLoader}. This method is asynchronous. + * If you want to control the loading thread yourself, obtain an {@link AndroidSkeletonDrawable} + * using {@link AndroidSkeletonDrawable#fromHttp(URL, URL, File)} or another load method, + * then call {@link SpineView#loadFromDrawable(AndroidSkeletonDrawable)} or + * {@link SpineView#setSkeletonDrawable(AndroidSkeletonDrawable)}. */ + public void loadFrom (AndroidSkeletonDrawableLoader loader) { Handler mainHandler = new Handler(Looper.getMainLooper()); Thread backgroundThread = new Thread( () -> { - final AndroidSkeletonDrawable skeletonDrawable = loader.load(); - mainHandler.post( () -> { - computedBounds = boundsProvider.computeBounds(skeletonDrawable); - updateCanvasTransform(); - - controller.init(skeletonDrawable); - Choreographer.getInstance().postFrameCallback(SpineView.this); - }); + try { + final AndroidSkeletonDrawable skeletonDrawable = loader.load(); + mainHandler.post( () -> { + setSkeletonDrawable(skeletonDrawable); + }); + }catch (Exception e) { + Log.e("SpineView", "Error loading skeleton", e); + } }); backgroundThread.start(); } + /** Set the skeleton drawable. Must be called from the main thread.*/ + @MainThread + public final void setSkeletonDrawable (@NonNull AndroidSkeletonDrawable skeletonDrawable) { + computedBounds = boundsProvider.computeBounds(skeletonDrawable); + updateCanvasTransform(); + + controller.init(skeletonDrawable); + Choreographer.getInstance().postFrameCallback(SpineView.this); + } + @Override public void onDraw (@NonNull Canvas canvas) { super.onDraw(canvas);