在非Activity的类中使用到getResources()方法 的解决

首先:
在activity类中加入以下代码:

public class BaseActivity extends AppCompatActivity {
    public static BaseActivity baseActivity;//传递给非activity的类使用
    public static Context mContext;//传递给非activity的类使用
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        baseActivity=this;//传递给非activity的类使用
        mContext=this.getBaseContext();//传递给非activity的类使用
    }
}

然后:
就可以在非Activity中尽情使用了:

    inputStream =BaseActivity.mContext.getResources().getAssets().open("data.json");

大佬原文: https://blog.youkuaiyun.com/qq_21856521/article/details/51810596

<think>好的,我现在需要帮助用户在Android开发中,使用Java语言在子线程中设置帧动画。用户之前的问题是关于优化启动时的帧动画加载导致的卡顿,而现在的引用内容涉及子线程操作动画可能遇到的问题,比如线程检查、ViewRootImpl的requestLayout、子线程更新UI的限制,以及Looper的相关问题。 首先,用户想在子线程中设置帧动画,但根据Android的规定,UI操作必须在主线程进行。直接子线程操作UI会导致崩溃,比如引用[2]提到的ViewRootImpl会检查线程,如果不在主线程就会抛出异常。所以必须找到安全的方式在子线程处理动画,同时不影响主线程的流畅性。 引用[3]提到在onCreate中子线程不加延时不崩溃是因为ViewRootImpl还未初始化,但绘制开始后必须在主线程更新UI。所以,可能的解决方法是在子线程准备动画资源,然后在主线程更新UI。例如,使用Handler或runOnUiThread将UI操作切换到主线程。 另外,引用[4]提到使用定时器和Handler在子线程定时发送消息,主线程处理消息更新UI。这可能是一个可行的方法,比如在子线程控制动画帧的切换时机,通过Handler通知主线程更新ImageView的图片。 但用户提到想直接在子线程设置动画,可能需要考虑是否真的需要这样做。因为Android的UI框架限制,所有视图操作必须在主线程,否则会引发异常。所以正确的做法应该是子线程处理耗时操作(如解码图片),主线程更新UI。 结合用户提供的引用,特别是引用[5]提到动画器只能在Looper线程运行,如果要在子线程运行可能需要准备Looper,但用户不希望这样做。因此,应该避免在子线程直接操作动画,而是采用异步加载资源,主线程更新UI的方式。 总结可能的步骤: 1. 在子线程预加载所有动画帧的Bitmap,避免在主线程解码导致卡顿。 2. 使用Handler或View.post方法在主线程更新ImageView的图片,逐帧显示。 3. 使用定时器或Choreographer来控制帧率,确保动画流畅。 4. 注意线程安全,避免内存泄漏,如在Activity销毁时停止子线程任务。 需要验证这些方法是否符合用户的需求,同时确保引用的内容被正确应用,比如引用[4]的定时器方法,引用[3]的线程检查机制,引用[2]的requestLayout必须在主线程等。</think>### Android Java子线程设置帧动画的实现方法 在Android中,**直接通过子线程更新UI会导致崩溃**(如引用[2]所述`checkThread()`机制),但可通过以下三种安全方式实现子线程控制的帧动画: --- #### 方法一:**子线程调度+主线程更新**(推荐) 通过子线程控制动画时序,主线程执行UI更新,符合Android线程安全规范[^2][^3] ```java // 步骤1:定义动画资源 private int[] frameResIds = {R.drawable.frame1, R.drawable.frame2}; private Handler handler = new Handler(Looper.getMainLooper()); // 步骤2:启动子线程 new Thread(() -> { int currentFrame = 0; while (!Thread.interrupted()) { final int finalFrame = currentFrame; // 通过Handler切换主线程更新UI handler.post(() -> { imageView.setImageResource(frameResIds[finalFrame]); }); currentFrame = (currentFrame + 1) % frameResIds.length; try { Thread.sleep(100); // 控制帧率(10FPS) } catch (InterruptedException e) { break; } } }).start(); ``` --- #### 方法二:**预加载资源+定时器触发** 参考引用[4]方案,使用`TimerTask`控制时序,主线程同步更新 ```java // 步骤1:预加载所有Bitmap到内存(子线程执行) ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(() -> { List<Bitmap> preloadedFrames = new ArrayList<>(); for (int resId : frameResIds) { preloadedFrames.add(BitmapFactory.decodeResource(getResources(), resId)); } // 步骤2:创建定时器 new Timer().schedule(new TimerTask() { int currentFrame = 0; @Override public void run() { handler.post(() -> { imageView.setImageBitmap(preloadedFrames.get(currentFrame)); currentFrame = (currentFrame + 1) % preloadedFrames.size(); }); } }, 0, 100); // 间隔100ms }); ``` --- #### 方法三:**使用Choreographer同步帧率** 通过VSYNC信号实现精准帧控制(适用于高性能动画) ```java // 在子线程初始化Choreographer new Thread(() -> { Looper.prepare(); // 需要子线程Looper Choreographer choreographer = Choreographer.getInstance(); final int[] currentFrame = {0}; choreographer.postFrameCallback(new Choreographer.FrameCallback() { @Override public void doFrame(long frameTimeNanos) { handler.post(() -> { imageView.setImageResource(frameResIds[currentFrame[0]]); currentFrame[0] = (currentFrame[0] + 1) % frameResIds.length; }); // 注册下一帧回调 if (!isAnimationStopped) { choreographer.postFrameCallback(this); } } }); Looper.loop(); }).start(); ``` --- ### 关键注意事项 1. **资源预加载**:在子线程完成Bitmap解码(如方法二),避免主线程卡顿[^3] 2. **线程安全**:所有`View`操作必须通过`Handler`切换到主线程[^2] 3. **内存管理**:在`Activity.onDestroy()`中及时停止线程和释放Bitmap 4. **性能监控**:使用`Systrace`检查单帧耗时,确保低于16ms(60FPS)[^1] --- ### 相关问题 1. 如何在子线程中安全地预加载大量图片资源? 2. 使用`Choreographer`实现动画相比`Timer`有哪些优势? 3. 如何检测动画过程中的内存泄漏问题?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值