[android]optimize skeleton drawable load, Avoid app crashes caused by loading errors. (#2947)

Co-authored-by: jfdu3 <jfdu3@iflytek.com>
This commit is contained in:
Wastrel Du 2025-11-06 20:48:25 +08:00 committed by GitHub
parent 3ffea502e7
commit 4191737c1c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -44,9 +44,11 @@ import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.Choreographer; import android.view.Choreographer;
import android.view.View; import android.view.View;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import java.io.File; 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 /** The same as {@link SpineView#loadFromDrawable(AndroidSkeletonDrawable, Context, SpineController)}, but can be used after
* instantiating the view via {@link SpineView#SpineView(Context, SpineController)}. */ * instantiating the view via {@link SpineView#SpineView(Context, SpineController)}. */
public void loadFromDrawable (AndroidSkeletonDrawable drawable) { public void loadFromDrawable (AndroidSkeletonDrawable drawable) {
loadFrom( () -> drawable); post( () -> setSkeletonDrawable(drawable));
} }
/** Get the {@link SpineController} */ /** Get the {@link SpineController} */
@ -350,21 +352,36 @@ public class SpineView extends View implements Choreographer.FrameCallback {
this.rendering = rendering; 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()); Handler mainHandler = new Handler(Looper.getMainLooper());
Thread backgroundThread = new Thread( () -> { Thread backgroundThread = new Thread( () -> {
final AndroidSkeletonDrawable skeletonDrawable = loader.load(); try {
mainHandler.post( () -> { final AndroidSkeletonDrawable skeletonDrawable = loader.load();
computedBounds = boundsProvider.computeBounds(skeletonDrawable); mainHandler.post( () -> {
updateCanvasTransform(); setSkeletonDrawable(skeletonDrawable);
});
controller.init(skeletonDrawable); }catch (Exception e) {
Choreographer.getInstance().postFrameCallback(SpineView.this); Log.e("SpineView", "Error loading skeleton", e);
}); }
}); });
backgroundThread.start(); 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 @Override
public void onDraw (@NonNull Canvas canvas) { public void onDraw (@NonNull Canvas canvas) {
super.onDraw(canvas); super.onDraw(canvas);