本博纯属个人开发记录,
转载请注明出处:http://blog.youkuaiyun.com/etong_123/article/details/22897731
问题标题都已经写明了,就是在普通的安装apk完成之后,会遇到的一种情况。基本上在程序的AndroidManifest.xml里面没有对Activity的属性做特殊处理都会出现这种情况,具体现象可以自己写个demo安装看看。
原理:
为了了解问题产生的原因,首先,我们先来讲一下Android的任务栈的机制:
任务栈就是用来存放应用程序的Activity的地方,Android默认在打开应用程序的时候给每个应用单独分配一个任务栈,用来管理应用程序Activity间的跳转,返回。每个Activity都可以配置一个属性叫taskAffinity,每个Activity默认的taskAffinity是以应用程序的包名命名的,为什么要提到这个呢,这个点后面会讲到,接下去看。
一般来说,每个应用都单独跑在自己的任务栈上,但是我们也可以让两个应用程序跑在同一个任务栈里面。我们可以从一个应用程序里面启动跳转到另一个应用程序里面。跳转的代码一般有两种写法:
代码1:从程序1跳转到程序2之后,两个应用程序是跑在同一个任务栈里面的。
- Intent intent=new Intent("android.intent.action.MAIN");
- intent.setComponent(new ComponentName("com.et.demo","com.et.demo.TestActivity"));
- startActivity(intent);
代码2:从程序1跳转到程序2之后,两个应用程序是跑在各自的任务栈里面的。
- Intent intent=new Intent("android.intent.action.MAIN");
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setComponent(new ComponentName("com.et.demo","com.et.demo.TestActivity"));
- startActivity(intent);
一开始我以为桌面的打开方式和安装完成界面的打开方式不同在于Intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)这句话上,之后看了下源码,发现其实两者差不多,基本上都有加New_Task这句话,所以我也搞不明白为什么出现打开方式错误的问题。(之前搞错了。。。囧)。
不过,解决方案已经出炉了,所以秉着先解决问题的原则,我们先上解决方案。(呵呵,这是什么原则!)
解决方法:
接下来呢,各位童鞋,我们来学习一个词,叫“曲线救国”。好吧,方法的确是有点曲线,但是效果不错,上菜。
思路:
1、先在你的应用程序里新建一个Activity,将它设置为首页(你懂de),让它跑在独立的Task上面。
2、将这个Activity作为跳转页面,新建Task(代码2)跳转到你的程序“真正”的首页上(你又懂de),销毁掉这个Activity,连带它的Task。
3、这样你的程序就跑在了自己独立的Task上面了,就不会出现打开多个实例的问题了。
实现:
新建FirstActivity,在manifest配置属性(最重要的部分)
- <activity
- android:name="com.example.opentest.FirstActivity"
- android:configChanges="keyboardHidden|orientation|fontScale"
- android:label="@string/title_activity_first"
- android:excludeFromRecents="true"
- android:taskAffinity="com.example.opentest.first"
- android:windowSoftInputMode="adjustPan" >
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- <intent-filter>
- <action android:name="android.intent.action.CREATE_SHORTCUT" />
- </intent-filter>
- </activity>
我的程序包名是com.example.opentest,这里我们将FirstActivity的属性设置一下
android:taskAffinity="com.example.opentest.first"
这样是为了让它自己跑在独立的Task上。(你自己好好反省一下吧,哼)。
而另一个重要的属性:
android:excludeFromRecents="true"
作用是隐藏Task(即让你的Task不出现在长按home出现的界面里)。
然后在FirstActivity代码中:
- Intent intent=new Intent(this, MainActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
- finish();
新建任务栈跳转到我的“真正”首页,销毁自己(自我牺牲精神——哎哟,不错哦)。
这样的做法其实就是自己写个跳转页面,然后在跳转页面写自己的跳转方式,保证自己的程序的打开方式和Launcher一样。同时在用完这个Activity的时候finish它,顺便隐藏它的Task。
这样就解决了程序重复打开的问题了。但是这样就行了么? nonono,图样。这样做在每次打开应用的时候动画效果会很差,会出现跳转两次的闪屏,不信你试试。
要怎么做呢,我们先把FirstActivity中的setContentView的代码直接删掉,然后在style文件里面写个style
- <style name="WindowIsTranslucent">
- <item name="android:windowIsTranslucent">true</item>
- <item name="android:windowAnimationStyle">@+android:style/Animation.Translucent</item>
- </style>
android:windowIsTranslucent:Activity背景透明。
android:windowAnimationStyle你可以指定你的Activity的加载动画。
然后在manifest里将FirstActivity的theme指定一下就可以了。这样出来的效果就好很多了。虽然解决方法有点取巧,但是效果还不错。
总结一下,虽然问题不是很常见,解决方法也不是特别难,但是对于一个软件来说,第一次打开的时候出现程序问题肯定会给用户一个很不好的印象。目前很多app(像百度视频,hao123浏览器什么的)都还有存在这个问题,上网找了一下,发现都没有解决方案,既然解决了就跟大家分享一下。
最后,完整的demo已放出,各位看官觉得好的请点赞。
下载地址:http://download.youkuaiyun.com/detail/etong_123/7148307