开发过程当中咱们常常会遇到各式各样的bug,好比说测试小姐姐告诉咱们,因为无操做,某个按钮她快速点击了两次
(或者因为卡顿之类的延迟),打开了两个详情页
,但愿把这个禁止掉
,只让打开一个详情页。java
咱们先来复现下这种场景,Activity配置和按钮点击代码很简单,以下所示: activity配置:android
<activity
android:name=".kfysts.chapter01.activity.LauncherModeSecondActivity"
android:launchMode="standard" />
复制代码
按钮的点击事件:git
@OnClick(R.id.btn_test1)
public void onBtnTest1Clicked() {
startActivity(new Intent(this, LauncherModeSecondActivity.class));
}
复制代码
咱们快速点击三下按钮,效果大概以下图所示:程序员
咱们看下任务栈信息,在终端中输入以下命令,将数据导入到log.txt中:github
不了解日志重定向的同窗,请看重定向adb logcat输出到文件.shell
adb shell dumpsys activity activities > log.txt
复制代码
打开log.txt,咱们看下任务栈信息:bash
ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)
...
* TaskRecord{1779ff5 #157 A=com.tiny.demo.firstlinecode U=0 StackId=2 sz=7}
userId=0 effectiveUid=u0a85 mCallingUid=u0a85 mUserSetupComplete=true mCallingPackage=com.tiny.demo.firstlinecode
...
Activities=[ActivityRecord{991bdbe u0 com.tiny.demo.firstlinecode/.MainActivity t157}, ActivityRecord{9eb4346 u0 com.tiny.demo.firstlinecode/.kfysts.AndroidKfystsActivity t157}, ActivityRecord{d4b56c9 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.AndroidKfystsChapter01Activity t157}, ActivityRecord{ce38d30 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LauncherModeEntryActivity t157}, ActivityRecord{704de09 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LauncherModeSecondActivity t157}, ActivityRecord{e063635 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LauncherModeSecondActivity t157}, ActivityRecord{bd81a7a u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LauncherModeSecondActivity t157}]
...
复制代码
能够看到咱们的LauncherModeSecondActivity
打开了三次。app
小姐姐提的bug咱们不能无论,针对这个bug咱们第一反应是作一个防止View的屡次点击
,不过这里咱们有更好的选择。针对点击打开Activity
这种操做,可使用Activity启动模式——singleTop
来解决,这种启动模式的核心就是,位于栈顶的Activity不会再次建立实例。post
singTop的解释以下:测试
singleTop:栈顶复用模式。
在这种模式下,若是新Activity已经位于任务栈的栈顶,那么此Activity不会被从新建立,同时它的onNewIntent方法会被调用,经过此方法的参数咱们能够取出当前请求的信息。
若是新Activity的实例已存在但不是位于栈顶,那么新Activity仍然会从新建立。
复制代码
话很少说,咱们使用singleTop模式来优化下,在AndroidManifest.xml文件中,给对应的Activity添加android:launchMode="singleTop"
,代码以下:
<activity
android:name=".kfysts.chapter01.activity.LaunchModeSingleTopTestActivity"
android:launchMode="singleTop" />
复制代码
点击启动的代码以下: 这里新增了一条log,咱们能够经过log来肯定具体点击了几回。
@OnClick(R.id.btn_test5)
public void onBtnTest5Clicked() {
LogUtils.e("single Top clicked");
startActivity(new Intent(this, LaunchModeSingleTopTestActivity.class));
}
复制代码
而后咱们尝试屡次点击按钮,会发现屡次打开Activity的问题已经解决了。
先看下log,咱们确实屡次点击了按钮:
com.tiny.demo.firstlinecode E: single Top clicked
com.tiny.demo.firstlinecode E: single Top clicked
com.tiny.demo.firstlinecode E: single Top clicked
复制代码
再看下效果图,以下图:
再来看下具体的任务栈信息,执行adb shell dumpsys activity activities > log.txt
,结果以下:
* TaskRecord{b982558 #158 A=com.tiny.demo.firstlinecode U=0 StackId=3 sz=5}
userId=0 effectiveUid=u0a85 mCallingUid=u0a85 mUserSetupComplete=true mCallingPackage=com.tiny.demo.firstlinecode
...
Activities=[ActivityRecord{47ddc34 u0 com.tiny.demo.firstlinecode/.MainActivity t158}, ActivityRecord{206fabc u0 com.tiny.demo.firstlinecode/.kfysts.AndroidKfystsActivity t158}, ActivityRecord{fa98f6d u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.AndroidKfystsChapter01Activity t158}, ActivityRecord{a41b176 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LauncherModeEntryActivity t158}, ActivityRecord{e2f82e5 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LaunchModeSingleTopTestActivity t158}]
复制代码
从结果中能够看到,LaunchModeSingleTopTestActivity
在栈顶确实只有一个实例。
综合以上的结果,咱们能够得出结论,singleTop启动模式确实解决了栈顶Activity重复打开
的问题,在屡次点击的状况下,栈顶Activity只打开了一次。
虽然咱们的bug完美解决了,但做为程序员,咱们仍是须要杠精下的。
这里我改下点击事件的代码,瞬间屡次调用启动activity的代码,代码以下:
@OnClick(R.id.btn_test6)
public void onBtnTest6Clicked() {
for (int i = 0; i < 5; i++) {
startActivity(new Intent(this, LaunchModeSingleTopTestActivity.class));
}
}
复制代码
而后咱们看下效果:
纳尼,居然打开了多个。
再看下任务栈信息:
* TaskRecord{f8d39d #159 A=com.tiny.demo.firstlinecode U=0 StackId=4 sz=9}
userId=0 effectiveUid=u0a85 mCallingUid=u0a85
...
Activities=[ActivityRecord{9ed78cc u0 com.tiny.demo.firstlinecode/.MainActivity t159}, ActivityRecord{be3aa3c u0 com.tiny.demo.firstlinecode/.kfysts.AndroidKfystsActivity t159}, ActivityRecord{1654b04 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.AndroidKfystsChapter01Activity t159}, ActivityRecord{a9084f6 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LauncherModeEntryActivity t159}, ActivityRecord{932877f u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LaunchModeSingleTopTestActivity t159}, ActivityRecord{c4238aa u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LaunchModeSingleTopTestActivity t159}, ActivityRecord{e751011 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LaunchModeSingleTopTestActivity t159}, ActivityRecord{fe1ffe4 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LaunchModeSingleTopTestActivity t159}, ActivityRecord{c0d8413 u0 com.tiny.demo.firstlinecode/.kfysts.chapter01.activity.LaunchModeSingleTopTestActivity t159}]
复制代码
能够看到,咱们的LaunchModeSingleTopTestActivity
确实打开了五次。
其实这也很好理解,无论任何操做都是须要时间去执行的,咱们的activity的启动过程也是。
即便咱们给Activity设置了启动模式,他们也不是马上生效的,也须要执行到对应的代码逻辑后才会生效。
因此若是我在for循环里面瞬间执行屡次打开Activity的操做,那么启动模式生效的代码还未执行到,因此启动模式就不会生效。
固然了,代码中通常也不会这么写,知其然并知其因此然才是咱们的目的。
github项目地址:Android_Base_Demo
具体页面打开路径:
具体页面地址:github.com/tinyvampire…
Android开发艺术探索