如何从普通Java类调用Intent的startActivity?Google OCR非Activity传值空指针问题
我来帮你搞定这个问题!从普通Java类(比如你的OcrGraphic)启动Activity的核心是拿到有效的Context实例,另外Timer的run()方法里的空指针也有明确的解决思路,一步步来:
一、先解决普通类调用startActivity的问题
普通类没有继承Activity,所以自带的Context,你需要通过以下步骤获取并使用:
在OcrGraphic中持有Context引用(用弱引用避免内存泄漏)
给OcrGraphic的构造方法传入Context,并且用WeakReference来持有它,防止Activity销毁后出现内存泄漏:public class OcrGraphic extends GraphicOverlay.Graphic { private WeakReference<Context> mContextRef; // 构造方法传入Context public OcrGraphic(GraphicOverlay overlay, Context context) { super(overlay); mContextRef = new WeakReference<>(context); } }这里传入的Context,最好是当前的Activity实例(启动Activity更稳妥),如果只能传Application Context,后面启动时要加特殊Flag。
通过Context启动Activity并传递文本
拿到Context后,就可以创建Intent、传递提取的文本,然后启动目标Activity:// 先获取有效的Context Context context = mContextRef.get(); if (context == null) { return; // Context已经失效,直接终止操作 } // 创建Intent并传递文本 Intent intent = new Intent(context, YourEditTextActivity.class); intent.putExtra("EXTRACTED_OCR_TEXT", yourExtractedText); // 替换成你的提取文本变量 // 注意:如果用的是Application Context,必须加这个Flag,否则会报错 if (!(context instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } // 启动Activity context.startActivity(intent);
二、解决Timer.run()中的空指针异常
你遇到的空指针,大概率是这两个原因,对应解决:
Context引用失效
当Timer任务执行时,如果原来的Activity已经被销毁,WeakReference持有的Context就会变成null,这时候调用context.startActivity()就会空指针。所以一定要先判断Context是否有效,就像上面代码里的if (context == null) return;。Timer运行在非UI线程的问题
Timer的run()方法是在非UI线程执行的,虽然startActivity本身可以在非UI线程跑,但如果你的逻辑里还有其他UI操作(比如后续要更新EditText),就必须切换到UI线程。推荐用Handler替代Timer,更适配Android的线程模型:// 用Handler.postDelayed代替Timer,默认运行在主线程 new Handler(Looper.getMainLooper()).postDelayed(new Runnable() { @Override public void run() { Context context = mContextRef.get(); if (context == null) { return; } // 这里写启动Activity的逻辑,无需再切换线程 Intent intent = new Intent(context, YourEditTextActivity.class); intent.putExtra("EXTRACTED_OCR_TEXT", yourExtractedText); if (!(context instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } context.startActivity(intent); } }, 1000); // 替换成你的延迟时间如果一定要用Timer,那就在run()方法里切换到UI线程:
new Timer().schedule(new TimerTask() { @Override public void run() { Context context = mContextRef.get(); if (context == null) { return; } // 切换到UI线程执行 new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { // 启动Activity的逻辑写在这里 Intent intent = new Intent(context, YourEditTextActivity.class); intent.putExtra("EXTRACTED_OCR_TEXT", yourExtractedText); if (!(context instanceof Activity)) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } context.startActivity(intent); } }); } }, 1000);
三、额外提醒
- 尽量用Activity Context启动Activity,避免加
FLAG_ACTIVITY_NEW_TASK带来的栈管理问题。 - 始终用WeakReference持有Context,防止内存泄漏,特别是当OcrGraphic的生命周期可能比Activity长的时候。
内容的提问来源于stack exchange,提问作者androminor

