子线程Handler.sendMessage 报错:Attempt to invoke virtual method 'boolean android.os.Handler.sendMessage

这篇博客探讨了在Android开发中遇到的子线程Handler.sendMessage报错问题,错误日志显示在主线程中调用了子线程的Handler。原因是未在子线程启动前正确初始化Handler。解决方法是在onCreate方法内启动Thread,并确保传递正确的this参数以避免后续错误。
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime: FATAL EXCEPTION: main
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime: Process: tech.androidstudio.tulingdemo, PID: 16029
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime: java.lang.IllegalStateException: Could not execute method for android:onClick
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:275)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.view.View.performClick(View.java:4761)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.view.View$PerformClick.run(View.java:19767)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.os.Handler.handleCallback(Handler.java:739)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:95)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.os.Looper.loop(Looper.java:135)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:5310)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Method.java:372)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:  Caused by: java.lang.reflect.InvocationTargetException
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Method.java:372)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:270)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.view.View.performClick(View.java:4761) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.view.View$PerformClick.run(View.java:19767) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.os.Handler.handleCallback(Handler.java:739) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:95) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.os.Looper.loop(Looper.java:135) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:5310) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Method.java:372) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:  Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.os.Handler.sendMessage(android.os.Message)' on a null object reference
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at tech.androidstudio.tulingdemo.MainActivity.btnSendMessage(MainActivity.java:65)
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Method.java:372) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:270) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.view.View.performClick(View.java:4761) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.view.View$PerformClick.run(View.java:19767) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.os.Handler.handleCallback(Handler.java:739) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.os.Handler.dispatchMessage(Handler.java:95) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.os.Looper.loop(Looper.java:135) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at android.app.ActivityThread.main(ActivityThread.java:5310) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Native Method) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at java.lang.reflect.Method.invoke(Method.java:372) 
03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901) 

03-17 08:10:18.760 16029-16029/tech.androidstudio.tulingdemo E/AndroidRuntime:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:696) 


原因分析 :

 子线程handler 报错,是因为没有启动子线程就开始使用了。


解决办法:

在onCreate方法中启动Thread,千万别忘了Thread里面的this 参数,不然还会报错。

Thread thread = new Thread(this);
        thread.start();


public class MainActivity extends AppCompatActivity implements Runnable {
private EditText mEditText;
    private ListView mListView;
    private List<String> mData;
    private ListViewAdapter mAdapter;
    private Handler subHandler;
    private Handler mainHandler;
    private final int MAIN_HANDLER_ADD=98;
    private final int SUB_HANDLER_ADD=998;
    private final int SUB_HANDLER_EXIT=199;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mEditText=(EditText)findViewById(R.id.editText);
        mListView=(ListView)findViewById(R.id.listView);
        mData = new ArrayList<>();
        mAdapter = new ListViewAdapter(mData,this);
        mListView.setAdapter(mAdapter);
        mainHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                int what = msg.what;
                switch (what){
                    case MAIN_HANDLER_ADD:
                        String msg_reply = (String)msg.obj;
                        mData.add(msg_reply);
                        mAdapter.notifyDataSetChanged();
                        break;
                }
            }
        };

        //千万别忘了启动子线程,不然会报错
        //Attempt to invoke virtual method 'boolean android.os.Handler.sendMessage(android.os.Message)' on a null object reference
        Thread thread = new Thread(this);
        thread.start();
    }



    public void btnSendMessage(View view) {
        String message_send = mEditText.getText().toString();
        if(message_send!=null){
            mData.add(message_send);
            mAdapter.notifyDataSetChanged();
            //将要发送的消息发送给子线程,(给子线程的handler),因为耗时操作不能在主线程进行
            // 然后子线程请求数据再返回给主线程(主线程的 handler),因为 子线程不能修改界面的UI
            Message message = Message.obtain();
            message.what=SUB_HANDLER_ADD;
            message.obj=message_send;
            subHandler.sendMessage(message);//之前报错的位置是这一步
        }
    }

    @Override
    public void run() {
        //绑定 当前线程的Looper
        Looper.prepare();
            subHandler= new Handler(){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    int what = msg.what;
                    switch (what){
                        case SUB_HANDLER_ADD:
                            //获取发送的消息,然后通过HttpUtils来发送,并且得到返回值,
                            //把这个返回值 再给主线程的 handler来处理。
                            //先写一个模拟数据 ,例如"收到了"发送给主线程。
                            Message message = Message.obtain();
                            message.what=MAIN_HANDLER_ADD;
                            message.obj="收到了";
                            mainHandler.sendMessage(message);
                            break;
                        case SUB_HANDLER_EXIT:
                            //onDestroy里面停止这个Looper
                            Looper looper = Looper.myLooper();
                            looper.quit();
                            break;
                    }
                }
            };
        //不停的循环 ,就像是while一样。
        Looper.loop();
    }
}

Fatal Exception: java.lang.RuntimeException Unable to destroy activity {com.mercusys.halo/com.tplink.mercusys.component.quicksetup.view.secondpart.newvi.AddNewDeviceNewVIActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.Handler.removeCallbacksAndMessages(java.lang.Object)' on a null object reference Fatal Exception: java.lang.RuntimeException: Unable to destroy activity {com.mercusys.halo/com.tplink.mercusys.component.quicksetup.view.secondpart.newvi.AddNewDeviceNewVIActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.os.Handler.removeCallbacksAndMessages(java.lang.Object)' on a null object reference at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:6149) at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:6181) at android.app.servertransaction.DestroyActivityItem.execute(DestroyActivityItem.java:47) at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:180) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:98) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2685) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:230) at android.os.Looper.loop(Looper.java:319) at android.app.ActivityThread.main(ActivityThread.java:8919) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103) 崩溃分析
最新发布
07-02
<think>好的,我现在需要分析用户提供的这个崩溃日志。用户给的是一个关于Android应用在销毁Activity时出现的RuntimeException,根本原因是NullPointerException,具体是在调用Handler的removeCallbacksAndMessages方法时,Handler对象为null。 首先,我需要理解崩溃的基本信息。错误发生在Activity销毁过程中,当系统尝试执行removeCallbacksAndMessages时,发现Handler是null,导致空指针异常。这说明在Activity销毁时,某个地方尝试使用了一个未正确初始化或已经被释放的Handler。 接下来,我需要考虑可能的导致Handler为null的原因。可能的情况包括:1. **Handler未正确初始化**:可能在代码中声明了Handler变量,但在某些情况下(如初始化失败或条件判断跳过)没有实际创建实例,导致后续调用时为null。2. **生命周期管理问题**:Handler可能在Activity的某个生命周期阶段被错误地释放或置为null,例如在onDestroy中提前将Handler设为null,但后续仍有代码尝试调用它。 3.**多线程问题**:如果Handler是在某个子线程中创建的,可能在Activity销毁时,该线程尚未完成初始化,导致Handler未被正确创建。 4.**配置变更或重建**:当Activity因配置变更(如屏幕旋转)而重建时,旧的Handler可能未被正确清理,或者新的Handler未及时创建。 然后,我需要结合常见的代码结构来推测可能的代码情况。例如,用户可能在Activity中持有一个Handler的引用,并在其生命周期的某个时刻(如onDestroy)中调用removeCallbacksAndMessages来清理任务。但如果Handler在之前已经被释放,或者初始化被跳过,就会导致这个异常。接下来,我需要考虑如何修复这个问题。常见的解决方案包括: - **检查Handler是否为null**:在调用removeCallbacksAndMessages之前,添加null检查,避免空指针异常。 - **确保Handler的正确初始化和释放**:确保Handler在使用前正确初始化,并在适当的时候(如onDestroy)释放资源,同时避免重复释放或提前释放。- **使用弱引用避免内存泄漏**:如果Handler持有外部类的引用,可能导致内存泄漏,进而引发其他问题。可以考虑使用静态内部类并持有所需对象的弱引用。 - **线程安全处理**:确保Handler的创建和销毁在正确的线程上进行,避免多线程竞争条件。 另外,用户可能需要检查相关的生命周期回调代码,确认在Activity销毁时是否正确地移除了所有的回调和消息。例如,在onDestroy方法中,是否有可能因为某些条件判断导致Handler未被初始化,或者已经被置为null。 还需要考虑是否在多个地方(如不同的生命周期方法或异步任务中)访问了同一个Handler实例,导致状态不一致。例如,在onCreate中初始化Handler,但在onPause或onStop中尝试移除回调,而某些情况下这些回调可能在Handler初始化之前就被调用。 此外,可能还需要检查是否有其他组件(如BroadcastReceiver或Service)在Activity销毁后仍尝试通过Handler发送消息,导致Handler被调用时已经无效。 最后,我需要将这些分析整理成结构化的回答,分点说明崩溃原因、可能的场景、修复方案以及预防措施,并提供相关问题供用户参考。</think>### 崩溃原因深度分析 #### 异常类型:**`NullPointerException`** ```java Attempt to invoke virtual method 'void android.os.Handler.removeCallbacksAndMessages(java.lang.Object)' on a null object reference ``` #### 核心问题定位 - **根本原因**:在 `Activity.onDestroy()` 或相关生命周期回调中,尝试调用一个 **为 `null` 的 `Handler` 对象的 `removeCallbacksAndMessages()` 方法**。 - **典型场景**: - `Handler` 未正确初始化(如初始化代码被跳过或失败)。 - `Handler` 在销毁前已被手动置 `null`,但后续代码仍尝试调用其方法。 - 多线程环境下,`Handler` 初始化未完成即触发销毁逻辑。 --- ### 典型触发场景 1. **未正确初始化 `Handler`** - **代码示例**: ```kotlin class MyActivity : Activity() { private var handler: Handler? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (someCondition) { // 条件判断导致 handler 未初始化 handler = Handler(Looper.getMainLooper()) } } override fun onDestroy() { handler?.removeCallbacksAndMessages(null) // ❌ handler 可能为 null super.onDestroy() } } ``` 2. **提前释放 `Handler`** - **代码示例**: ```kotlin override fun onDestroy() { handler?.removeCallbacksAndMessages(null) handler = null // ✅ 正确释放 // 后续其他方法中误用 handler } ``` 3. **多线程竞争导致 `Handler` 未初始化** - **代码示例**: ```kotlin class MyActivity : Activity() { private var handler: Handler? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Thread { handler = Handler(Looper.getMainLooper()) // 子线程初始化 }.start() } override fun onDestroy() { handler?.removeCallbacksAndMessages(null) // ❌ 可能因初始化未完成而为 null super.onDestroy() } } ``` 4. **内存泄漏导致 `Handler` 持有无效上下文** - **代码示例**: ```kotlin class MyActivity : Activity() { private val handler = Handler(Looper.getMainLooper()) { // 使用 Activity 的上下文 } } ``` - **风险**:若 `Handler` 持有 `Activity` 的强引用且任务未取消,可能导致 `Activity` 泄漏。但在崩溃日志中,此场景更可能触发内存泄漏而非空指针异常,需结合其他日志判断。 --- ### 修复方案 #### 方法 1:添加 `Handler` 非空检查 - **修复代码**: ```kotlin override fun onDestroy() { if (handler != null) { handler!!.removeCallbacksAndMessages(null) handler = null // 显式置 null 避免重复调用 } super.onDestroy() } ``` #### 方法 2:确保 `Handler` 正确初始化 - **修复代码**: ```kotlin class MyActivity : Activity() { private lateinit var handler: Handler // 使用 lateinit 避免 null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) handler = Handler(Looper.getMainLooper()) // 确保初始化 } override fun onDestroy() { handler.removeCallbacksAndMessages(null) super.onDestroy() } } ``` #### 方法 3:使用 `WeakReference` 避免内存泄漏 - **适用场景**:`Handler` 需持有外部类引用时。 - **修复代码**: ```kotlin class MyActivity : Activity() { private val handler = MyHandler(this) private class MyHandler(activity: MyActivity) : Handler(Looper.getMainLooper()) { private val weakReference = WeakReference<MyActivity>(activity) override fun handleMessage(msg: Message) { val activity = weakReference.get() activity?.doSomething() } } override fun onDestroy() { handler.removeCallbacksAndMessages(null) super.onDestroy() } } ``` #### 方法 4:同步初始化逻辑(多线程场景) - **修复代码**: ```kotlin class MyActivity : Activity() { private var handler: Handler? = null private val lock = Any() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) synchronized(lock) { handler = Handler(Looper.getMainLooper()) } } override fun onDestroy() { synchronized(lock) { handler?.removeCallbacksAndMessages(null) handler = null } super.onDestroy() } } ``` --- ### 调试与预防措施 #### 调试建议 1. **日志追踪 `Handler` 生命周期**: ```kotlin override fun onCreate(savedInstanceState: Bundle?) { Log.d("HandlerDebug", "Handler initialized") } override fun onDestroy() { Log.d("HandlerDebug", "Handler destroyed") } ``` 2. **使用 Android Profiler 检查内存泄漏**: - **路径**:Android Studio → `Profiler` → 检查 `Memory` 面板中的 `Leak` 提示。 #### 预防措施 | 场景 | 风险 | 推荐做法 | |------|------|----------| | `Handler` 未初始化 | 空指针异常 | 使用 `lateinit` 或非空断言(`!!`)确保初始化 | | 多线程竞争 | 初始化未完成即调用 | 使用 `synchronized` 或 `HandlerThread` 同步逻辑 | | 内存泄漏 | 持有外部类引用 | 使用 `WeakReference` 或静态内部类 | | 提前释放 `Handler` | 后续误用 | 显式置 `null` 并添加非空检查 | --- ### 示例修复前后对比 #### 修复前代码 ```kotlin class AddNewDeviceNewVIActivity : Activity() { private var mHandler: Handler? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // mHandler 未初始化 } override fun onDestroy() { mHandler?.removeCallbacksAndMessages(null) // ❌ NullPointerException super.onDestroy() } } ``` #### 修复后代码 ```kotlin class AddNewDeviceNewVIActivity : Activity() { private lateinit var mHandler: Handler override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mHandler = Handler(Looper.getMainLooper()) // ✅ 确保初始化 } override fun onDestroy() { if (::mHandler.isInitialized) { mHandler.removeCallbacksAndMessages(null) } super.onDestroy() } } ``` ---
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值