9.Android Handler的使用

本文探讨了在Android开发中使用Handler类实现定时更新UI元素的方法,通过引入Handler简化了传统的Java编程方式,展示了其作为Runnable和Activity交互桥梁的作用。文章详细介绍了Handler的使用场景及其实现过程,并通过实例演示了如何利用Handler实现特定功能。

大家好我们这一节讲的是Android Handler的使用,在讲Handler之前,我们先提个小问题,就是如何让程序5秒钟更新一下Title.

首先我们看一下习惯了Java编程的人,在不知道Handler的用法之前是怎么样写的程序,代码如下所示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.android.tutor;
 
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
 
public class HandlerDemo extends Activity {
     // title为setTitle方法提供变量,这里为了方便我设置成了int型
     private int title = 0 ;
 
     public void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.main);
 
         Timer timer = new Timer();
         timer.scheduleAtFixedRate( new MyTask(), 1 , 5000 );
     }
 
     private class MyTask extends TimerTask {
         @Override
         public void run() {
 
             setTitle( "Welcome to Mr Wei's blog " + title);
             title++;
         }
     }
}

然而当我们执行程序,并不能达到我们预期的效果,所以Android引进了Handler这个特殊的类,可以说它是Runnable和Activity交互的桥梁,所以我们只要在run方法中发送Message,而在Handler里,通过不同的Message执行不同的任务。

所以我们修改后的代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.android.tutor;
 
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
 
public class HandlerDemo extends Activity {
 
     // title为setTitle方法提供变量,这里为了方便我设置成了int型
     private int title = 0 ;
 
     private Handler mHandler = new Handler() {
 
         public void handleMessage(Message msg) {
             switch (msg.what) {
             case 1 :
                 updateTitle();
                 break ;
             }
         };
     };
 
     public void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.main);
 
         Timer timer = new Timer();
         timer.scheduleAtFixedRate( new MyTask(), 1 , 5000 );
     }
 
     private class MyTask extends TimerTask {
         @Override
         public void run() {
 
             Message message = new Message();
             message.what = 1 ;
             mHandler.sendMessage(message);
 
         }
     }
 
     public void updateTitle() {
 
         setTitle( "Welcome to Mr Wei's blog " + title);
         title++;
     }
}

下面我们看一下效果图:

HandlerDemo1

HandlerDemo2


Porcess:com.ss.android.ugc.aweme PackageName:com.ss.android.ugc.aweme versionName:360201 versionCode:360201 Foreground:true time:1762175449152 statcktrace:java.lang.NoClassDefFoundError: Invalid descriptor: Lio/reacԩvex/Observable1. at java.lang.reflect.Executable.getMethodReturnTypeInternal(Native Method) at java.lang.reflect.Method.getReturnType(Method.java:148) at java.lang.Class.getDeclaredMethods(Class.java:2730) at java.lang.reflect.Proxy.getMethodsRecursive(Proxy.java:797) at java.lang.reflect.Proxy.getMethods(Proxy.java:786) at java.lang.reflect.Proxy.-$$Nest$smgetMethods(Unknown Source:0) at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:678) at java.lang.reflect.Proxy$ProxyClassFactory.apply(Proxy.java:602) at java.lang.reflect.WeakCache$Factory.get(WeakCache.java:230) at java.lang.reflect.WeakCache.get(WeakCache.java:127) at java.lang.reflect.Proxy.getProxyClass0(Proxy.java:438) at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:873) at com.GlobalProxyLancet.com_ss_android_ugc_aweme_lancet_ProxyLancet_newProxyInstance(SourceFile:50593851) at com.bytedance.retrofit2.Retrofit.create(SourceFile:16973849) at com.bytedance.android.live.network.LiveClient.getService(SourceFile:17039376) at com.bytedance.android.live.core.CommonUtilsServiceImpl.liveClientGetService(SourceFile:16908292) at com.bytedance.android.live.core.feature.RoomFeatureUtils.LIZIZ(SourceFile:33947718) at com.ss.android.ugc.aweme.live.feedpage.LivePartialComponentV2.handleLoadMore(SourceFile:33947754) at com.ss.android.ugc.aweme.feed.plato.core.FeedComponentGroup.handleLoadMore(SourceFile:33816616) at X.0enV.onLoadMoreResult(SourceFile:34079357) at com.ss.android.ugc.aweme.common.presenter.BaseListPresenter.onSuccess(SourceFile:393279) at com.ss.android.ugc.aweme.feed.presenter.FeedFetchPresenter.onSuccess(SourceFile:459087) at X.0Wz0.onSuccess(SourceFile:458900) at com.ss.android.ugc.aweme.mvp.TetrisBaseListModel$notifySuccessListenerHandler$1.handle(SourceFile:33816617) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.BusinessExpandAnchorDataHandle.handle(SourceFile:33751057) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.MusicCardPreloadHandler.handle(SourceFile:33751057) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.ActivityCardDataPreloadHandler.handle(SourceFile:33816599) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.MonitorDataResponseAfterHandler.handle(SourceFile:33882195) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.MobFeelGoodItemHandler.handle(SourceFile:33816605) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.FeedModelStatisticsResponseHandler.handle(SourceFile:33882212) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.mvp.TetrisBaseListModel$notifyErrorListenerHandler$1.handle(SourceFile:33882174) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed_disaster_recovery.FeedDisasterRecoveryManager$ResponseHandler.handle(SourceFile:34013330) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.autoretry.FeedRetryRequestManager$ResponseHandler.handle(SourceFile:34013327) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.autoretry.FeedNetRecoverManager$ResponseHandler.handle(SourceFile:33947694) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.handler.TetrisHandlerGroup.triggerChildren(SourceFile:33816602) at com.ss.android.ugc.aweme.handler.TetrisHandlerGroup.handle$suspendImpl(SourceFile:50724940) at com.ss.android.ugc.aweme.handler.TetrisHandlerGroup.handle(Unknown Source:0) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.handler.TetrisHandlerGroup.triggerChildren(SourceFile:33816602) at com.ss.android.ugc.aweme.handler.TetrisHandlerGroup.handle$suspendImpl(SourceFile:50724940) at com.ss.android.ugc.aweme.handler.TetrisHandlerGroup.handle(Unknown Source:0) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.FeedCacheIndexReviseHandler.handle(SourceFile:33947751) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.PrefetchBootFeedResponseHandler.handle(SourceFile:33947774) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.FeedCacheResponseHandler.handle(SourceFile:34013367) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.SnapshotFeedResponseHandler.handle(SourceFile:34013247) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.FirstFeedSplitSkipHandler.handle(SourceFile:34013497) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.FeedLiveWatchHistoryResponseHandler.handle(SourceFile:33882180) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.AwemeAidLastResortHandler.handle(SourceFile:34013426) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.AwemeRecordGetTimeHandler.handle(SourceFile:33882213) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.dislike.FilterLocalDislikeHandler.handle(SourceFile:33816602) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.MonitorDataResponseBeforeHandler.handle(SourceFile:33816599) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.feed.presenter.msghandler.FeedResponseRevertBeforeHandler.handle(SourceFile:34079435) at com.ss.android.ugc.aweme.handler.TetrisChain.LIZ(SourceFile:34013384) at com.ss.android.ugc.aweme.mvp.TetrisBaseListModel.LJJI(SourceFile:33882208) at com.ss.android.ugc.aweme.mvp.TetrisBaseListModel$handleMsg$1.invokeSuspend(SourceFile:17039390) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(SourceFile:17039371) at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(SourceFile:50724991) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(SourceFile:67305485) at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(SourceFile:100794373) at kotlinx.coroutines.CoroutineStart.invoke(SourceFile:50593832) at kotlinx.coroutines.AbstractCoroutine.start(SourceFile:50331648) at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(SourceFile:67305487) at kotlinx.coroutines.BuildersKt.launch(SourceFile:67174400) at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(SourceFile:100859916) at kotlinx.coroutines.BuildersKt.launch$default(SourceFile:100728832) at com.ss.android.ugc.aweme.mvp.TetrisBaseListModel.handleMsg(SourceFile:16973839) at com.bytedance.common.utility.collection.WeakHandler.com_bytedance_common_utility_collection_WeakHandler_fork_by_async_handleMessage(SourceFile:16908300) at com.bytedance.common.utility.collection.WeakHandler.handleMessage(Unknown Source:3) at X.0WnZ.handleMessage(SourceFile:16973836) at android.os.Handler.dispatchMessage(Handler.java:115) at com.bytedance.qmi.handler.base.QmiHandler.dispatchMessage(SourceFile:17104966) at com.ss.android.ugc.bytex.async.stack.TransmitHandler.dispatchMessage(SourceFile:17039385) at android.os.Looper.loopOnce(Looper.java:298) at android.os.Looper.loop(Looper.java:408) at android.app.ActivityThread.main(ActivityThread.java:9952) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:613) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1074) Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@eb8dce8, 0W0R@b74ef01]
11-08
<think>首先,用户的问题是提供一个崩溃日志,我需要用中文回答问题。崩溃日志是来自一个Android应用的错误堆栈,可能是抖音(TikTok的中国版),因为包名是com.ss.android.ugc.aweme。 错误信息是:"java.lang.NoClassDefFoundError: Invalid descriptor: Lio/reacԩvex/Observable1." 这看起来像是一个类找不到错误,但描述符有问题。类名应该是"io/reactivex/Observable",但这里写成了"io/reacԩvex/Observable1",这可能是一个打字错误或混淆导致的问题。 关键点: - NoClassDefFoundError:表示在运行时找不到类定义。 - 描述符无效:在反射过程中,描述符可能被错误地处理。"Lio/reacԩvex/Observable1;" 应该可能是 "Lio/reactivex/Observable;",但这里有个奇怪的字符 "ԩ",可能是编码问题或混淆。 错误发生在: - `java.lang.reflect.Executable.getMethodReturnTypeInternal(Native Method)` - 在 `Retrofit.create` 中创建代理实例时。 堆栈跟踪显示,这是在尝试创建 Retrofit 服务时发生的错误。Retrofit 是一个用于 Android 的网络请求库,它使用动态代理来创建服务接口的实现。 可能的原因: 1. **类路径问题**:RxJava 的 Observable 类没有被正确加载。RxJava(io.reactivex.rxjava3 或类似)可能没有被包含在依赖中,或者版本冲突。 2. **混淆问题**:应用可能被混淆了,导致类名被改变或移除。描述符中的 "ԩ" 可能是一个混淆后的字符。 3. **动态代理问题**:在创建代理时,反射 API 无法找到方法或类。 4. **版本不兼容**:Retrofit 或 RxJava 的版本与新版本不兼容。 用户没有明确提问,但提供了日志,所以我需要基于这个崩溃进行分析。用户的问题隐含在日志中——我需要解释错误并提供可能的解决方案。 我的回答结构: 1. **解释错误**:简述错误类型和原因。 2. **分析堆栈**:指出关键部分。 3. **建议解决方案**:提供如何修复的建议。 4. **结尾提出相关问题**:必须包含3-5个相关问题。 规则: - 回答必须用中文。 - 回答完问题后,必须在末尾输出 "§§相关问题§§",然后列出3-5个相关问题。 - 相关问题必须基于用户的问题和我的回答。 - 第一行必须是 "§§相关问题§§",禁止换行分散。 示例格式显示,相关问题直接跟在 "§§相关问题§§" 后面,一行列出数字列表。 相关问题应覆盖可能的后续问题,例如: - 如何避免这个错误? - 如何调试类似问题? - 依赖管理建议? - 混淆配置? - 特定库的版本问题? 列出3-5个相关问题: 1. 如何在 Android 应用中解决 NoClassDefFoundError? 2. Retrofit 的代理机制是如何工作的? 3. 如何防止混淆导致运行时错误? 4. 如何检查应用的依赖冲突? 5. 什么是 RxJava Observable,为什么它在这里缺失? 现在,构建回答: - 开头:解释错误。 - 中间:分析并提供建议。 - 结尾:输出 "§§相关问题§§" 和列表。 完整回答: - 用中文。 - 确保语言专业且有帮助性。 </think>基于您提供的崩溃日志,这是一个 Android 应用(包名:com.ss.android.ugc.aweme,版本:360201)的运行时错误。错误发生在应用前台运行时(Foreground: true),时间为 1762175449152(Unix 时间戳)。核心错误是 `java.lang.NoClassDefFoundError: Invalid descriptor: Lio/reacԩvex/Observable1`,这表明在动态代理创建过程中(通过 `Retrofit.create()` 方法),系统无法找到或识别类 `io.reactivex.Observable`(描述符中的 "Lio/reacԩvex/Observable1" 可能源于混淆或编码错误)。错误堆栈起始于反射调用 `getMethodReturnTypeInternal`,并在 `Proxy.newProxyInstance` 中失败,最终导致崩溃。 ### 错误分析: 1. **错误类型**:`NoClassDefFoundError` 表示类在编译时存在但在运行时缺失。这通常由以下原因引起: - **依赖问题**:RxJava 库(提供 `Observable` 类)未被正确包含在 APK 中,或版本冲突(如 Retrofit 与 RxJava 不兼容)。 - **混淆问题**:ProGuard 或 R8 混淆工具可能移除了关键类或方法,导致运行时反射失败(描述符 "ԩ" 字符暗示混淆)。 - **动态代理问题**:Retrofit 使用反射创建服务接口代理,如果目标类(如 `Observable`)缺失,代理实例无法创建。 2. **关键堆栈点**:错误发生在 `LiveClient.getService()` 和 `Retrofit.create()` 中,涉及网络请求处理(FeedPresenter 相关)。这表明错误与直播或推荐流加载逻辑相关。 3. **潜在影响**:应用可能在加载更多内容时崩溃,影响用户体验。 ### 解决方案建议: - **检查依赖**:确保项目中包含 RxJava 依赖(如 `implementation &#39;io.reactivex.rxjava3:rxjava:3.x.x&#39;`),并验证 Retrofit 版本兼容性。 - **混淆配置**:在 ProGuard/R8 规则中添加保留规则,防止 RxJava 类被移除。例如: ``` -keep class io.reactivex.** { *; } -dontwarn io.reactivex.** ``` - **调试工具**:使用工具检查 APK(如通过 Android Studio 的 APK Analyzer)确认 `Observable` 类是否在最终构建中存在。 - **编码问题**:确保源代码中无异常字符,构建过程无编码错误。 - **测试**:在开发环境中模拟相同调用(如通过单元测试)以重现并修复问题。 如果问题持续,建议检查应用的依赖树(通过 `./gradlew app:dependencies`)并查看崩溃日志的完整上下文。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值