问题背景

我们知道android启动后会先到Launcher主界面,但是对于定制开发机来说一般是开机后自启一个app。
从app收到开机广播后一般会有2秒左右的时间应用才起来,所以中间有2-3秒停留在Launcher界面上,这样看起来怪怪的。

分析

首先看为什么会首先启动Laucnher

在AMS执行到systemReady的时候,会启动startHomeActivityLocked的方法

 public void systemReady(final Runnable goingCallback) {    ....    startHomeActivityLocked(currentUserId, "systemReady");    ....}

这个方法实际是去寻找了CATEGORY_HOME属性的app,我们看一下Luancher的Manifest文件

                                                

果然有HOME的属性

# 解决办法:
  • 在开机广播中加入priority属性,这样能提高收到开机广播的顺序。
                                        
  • 修改Laucnher apk的category,去掉HOME的属性,把自己的app改为HOME,这样开机就直接启动自己的app了。这样做的缺点是不方便用户切到主界面去做其他操作,app得提供去laucnher的入口,同时还得考虑原本home按键的安排;也得考虑一直点击返回按钮后的安排;默认这两个按钮都会返回到HOME属性的app。
还有没有其他办法呢?

我考虑一种解决办法是延长开机动画的时间,让开机动画掩盖Laucnher的启动,当应用app收到开机广播启动后,再停止开机动画,这样就可以无缝切换了。

frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java 中,内部类KeyguardShowDelegate中有个onDrawn回调,可以在回调中去停止动画。具体方案是在回调中延时并查询前台进程,如果起来了就可以停止动画了。

   // A delegate class to map a particular invocation with a ShowListener object.    private final class KeyguardShowDelegate extends IKeyguardDrawnCallback.Stub {        private DrawnListener mDrawnListener;        private int cnt_seconds = 0;        KeyguardShowDelegate(DrawnListener drawnListener) {            mDrawnListener = drawnListener;        }        @Override        public void onDrawn() throws RemoteException {            if (DEBUG) Log.v(TAG, "**** SHOWN CALLED ****");    //keyguard drawn complete ,can exit bootanim   try {            cnt_seconds = 0;            while( !isActivityForeground() && cnt_seconds < WAIT_SENSETIME_APP_TIME){                Thread.sleep(1000);                cnt_seconds++;            }            //ensure app has launch completed             Thread.sleep(1000);} catch (Exception e) {}    android.os.SystemProperties.set("service.bootanim.exit", "1");        SystemService.stop("bootanim");android.os.SystemProperties.set("sys.bootvideo.closed", "1");    }            if (mDrawnListener != null) {                mDrawnListener.onDrawn();            }            hideScrim();        }    };

isActivityForeground()根据实际情况自己去实现就好了,这里给个例子。

private boolean isActivityForeground() {    ActivityManager am = (ActivityManager) mContext.getSystemService(                Context.ACTIVITY_SERVICE);        List list = am.getRunningTasks(1);        if (list != null && list.size() > 0) {            ComponentName cpn = list.get(0).topActivity;Log.d(TAG,cpn.getClassName());            if ( cpn.getClassName().startsWith("com.xx.xxx") ) {                Log.d(TAG," app is foreground!");                return true;        }    }    Log.d(TAG," app is background!");    return false;}

更多相关文章

  1. Android开发学习笔记:Intent的简介以及属性的详解
  2. Android(安卓)属性系统
  3. Android(安卓)应用自动启动的两种方法(开机自启动 与 另一个应用
  4. 一起来学习Android自定义控件1
  5. android启动第一个界面时即闪屏的核心代码(两种方式)
  6. android 开机启动流程分析(10)init 部分整体总结
  7. Android属性动画简析
  8. Android启动service下载失败后stopService,重新启动service下载出
  9. 重拾Android之路之Activity的四种启动模式

随机推荐

  1. Android(安卓)休眠与唤醒
  2. Android(安卓)boot process stub
  3. Google Android's Gingerbread Update Co
  4. setting proxy for Android(安卓)SDK Man
  5. Android采用SAX解析XML文档
  6. Android(安卓)actrivityrealut
  7. Android(安卓)Studio编译失败问题(aapt2)
  8. android 程序漰溃 后台handle处理类
  9. android:parentActivityName
  10. gridView在scrollview中显示不全的问题