Android坑(1)

Android

  1. Activity与Fragment的生命周期。
activity_fragment_cyclelife
  • A启动B:A-onPause->B-onCreate,B-onResume->A-onStop
  • B返回A:B-onPause->A-onRestart,A-onResume->B-onStop

2.Acitivty的四中启动模式与特点。

  • standard
    A启动(startActivty)B,则B在A所在的任务栈中
    当A是非Activity类型的context(如ApplicationContext)时,因为其没有任务栈,会crash。
    解决方法:为B指定FLAG_ACTIVITY_NEW_TASK标记位
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),则启动时会为B创建一个新的任务栈,效果等价于singleTask
  • singeTop
    在栈顶则复用,回调onNewIntent,onCreate,onStart不会调用
  • singleTask
    在栈内则复用,回调onNewIntent,注意有clearTop效果
    eg:
    前台task={A,B},SingleTask模式后台task={C,D},(后台task的Activity处于暂停状态)
    若B启动D => 前台task={A,B,C,D}
    若B启动C => 前台task={A,B,C} (clearTop)
  • singleInstance
    单独位于栈中

andoid:launchMode="XXX"和intent.addFlags(Intent.XXX)的区别:

  1. 后者优先级高于前者,两者同时存在时后者为准
  2. 前者无法为Activity设置FLAG_ACTIVITY_CLEAR_TOP标识,后者无法为Activity指定singleInstance

Flags:(格式:FLAG_ACTIVITY_XXX_XXX)

  • FLAG_ACTIVITY_NEW_TASK
    即singleTask
  • FLAG_ACTIVITY_SINGLE_TOP
    即singleTop
  • FLAG_ACTIVITY_CLEAR_TOP
    即clearTop,一般配合FLAG_ACTIVITY_NEW_TASK使用;singleTask默认具有此标识位的功能
  • FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
    具有该标记的Activity不会出现在历史Activity的列表中。
    等同于android:excludeFromRecents="true",应用:进程保活

1.直接调用Context类的startActivity方法:这种方式启动的Activity没有Activity栈,因此不能以standard方式启动,必须加上FLAG_ACTIVITY_NEW_TASK这个Flag。
2.调用被Activity类重载过的startActivity方法,通常在我们的Activity中直接调用这个方法就是这种形式;


3.Activity缓存方法。

  • Activity意外被销毁(如屏幕旋转)时会调用onSaveInstanceState保存当前Activity状态(调用时间:在onStop之前,在onPause前或后),当Activity重新创建后,onSaveInstanceState保存的Bundle数据作为参数同时传给onRestoreInstance(调用时间:在onStart之后,onResume之前)和onCreate来恢复之前保存的数据

  • 注:按home键退出不会销毁Activity(停留在onStop)但也会调用onSaveInstance,所以恢复时不会调用onCreate和onRestoreInstance,而是从onReStart开始

  • 设置 android:configChanges="orientation"可解决Activity旋转销毁的问题,这样设置后旋转时会调用onConfigurationChanged


  1. Service的生命周期,两种启动方法,有什么区别。
service_cyclelife
  • startService只是启动Service,启动它的组件(如Activity)和Service并没有关联,只有当Service调用stopSelf或者其他组件调用stopService服务才会终止;多次启动同一个Service只会调用一次onCreate(),第二次启动直接调用onStartCommand()
  • bindService方法启动Service,其他组件可以通过回调获取Service的代理对象和Service交互,而这两方也进行了绑定,当启动方销毁时,Service也会自动进行unBind操作,当发现所有绑定都进行了unBind时才会销毁Service
    -startService();bindService;分别调用:startservice->oncreate()->stopservice()->停止service但没有销毁->unbind()->调用unbind()方法调用destory()方法
  • IntentService:启动IntentService的方式和启动传统Service一样,有独立的worker线程,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent(Intent intent)回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。

Android 5.0(API=21) 禁止使用隐式Intent来启动Service.

private void validateServiceIntent(Intent service) { 
if (service.getComponent() == null && service.getPackage() == null) { 
    if (getApplicationInfo().targetSdkVersion >=Build.VERSION_CODES.LOLLIPOP) { 
     IllegalArgumentException ex = new IllegalArgumentException( "Service Intent must be explicit: " + service); 
        throw ex;
 } else {
       Log.w(TAG, "Implicit intents with startService are not safe: " + service + " " + Debug.getCallers(2, 3)); 
    }
   }
 }
大概是为了安全才取消隐式启动

5.怎么保证service不被杀死。

  • 白色保活
    白色保活手段非常简单,就是调用系统api启动一个前台的Service进程,这样会在系统的通知栏生成一个Notification,用来让用户知道有这样一个app在运行着,哪怕当前的app退到了后台。如下方的LBE和QQ音乐这样:


  • 灰色保活
    这种保活手段是应用范围最广泛。它是利用系统的漏洞来启动一个前台的Service进程,与普通的启动方式区别在于,它不会在系统通知栏处出现一个Notification,看起来就如同运行着一个后台Service进程一样。这样做带来的好处就是,用户无法察觉到你运行着一个前台进程(因为看不到Notification),但你的进程优先级又是高于普通后台进程的。那么如何利用系统的漏洞呢,大致的实现思路和代码如下:

思路一:API < 18,调用startForeground(ID, new Notification()),发送空的Notification ,图标则不会显示;
思路二:API >= 18,在需要提优先级的service A启动一个InnerService,两个服务同时startForeground,且绑定同样的 ID。Stop 掉InnerService ,这样通知栏图标即被移除;
注:进程优先级降序排列:前台进程(Foreground process)、可见进程(Visible process)、服务进程(Service process)、后台进程(Background process)、空进程(Empty process); 详见Android 进程保活招式大全

public class GrayService extends Service {

    private final static int GRAY_SERVICE_ID = 1001;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (Build.VERSION.SDK_INT < 18) {
            startForeground(GRAY_SERVICE_ID, new Notification());//API < 18 ,此方法能有效隐藏Notification上的图标
        } else {
            Intent innerIntent = new Intent(this, GrayInnerService.class);
            startService(innerIntent);
            startForeground(GRAY_SERVICE_ID, new Notification());
        }

        return super.onStartCommand(intent, flags, startId);
    }

    ...
    ...

    /**
     * 给 API >= 18 的平台上用的灰色保活手段
     */
    public static class GrayInnerService extends Service {

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            startForeground(GRAY_SERVICE_ID, new Notification());
            stopForeground(true);
            //stopSelf()隐藏顶部的Notification!
            stopSelf();
            return super.onStartCommand(intent, flags, startId);
        }

    }
}

其实Google察觉到了此漏洞的存在,从Android5.0的ServiceRecord类的postNotification函数源代码中可以看到这样的一行注释


使用灰色保活并不代表着你的Service就永生不死了,只能说是提高了进程的优先级。如果你的app进程占用了大量的内存,按照回收进程的策略,同样会干掉你的app。
http://www.diycode.cc/topics/45

Low Memory Killer 决定是否杀进程除了内存大小,还有进程优先级(数值越小,优先级越高):


  • 启动一个纯C/C++ 的进程,没有Java run time ,内存使用极低。(5.0之后失效,可通过5.0提供的JobScheduler解决,且不受 forcestop 影响)
  • onStartCommand()中返回START_STICKY,实现进程拉活
    问题:
    1.Service 第一次被异常杀死后会在5秒内重启,第二次被杀死会在10秒内重启,第三次会在20秒内重启,一旦在短时间内 Service 被杀死达到5次,则系统不再拉起。
    2.进程被取得 Root 权限的管理工具或系统工具通过 forestop 停止掉,无法重启。

http://mp.weixin.qq.com/s?__biz=MzA3ODg4MDk0Ng==&mid=403254393&idx=1&sn=8dc0e3a03031177777b5a5876cb210cc&scene=1&srcid=0402fANUWIotbVLECw4Ytz4K#wechat_redirect


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容