zoukankan      html  css  js  c++  java
  • Android应用被后台杀死后如何重新走闪屏逻辑

    Android应用运行在后台的时候,经常被系统的LowMemoryKiller杀掉,当用户再次点击icon或者从最近的任务列表启动的时候,进程会被重建,并且恢复被杀之前的现场。什么意思呢?假如APP在被杀之前的Activity堆栈是这样的,A<B<C,C位于最上层

    APP被后台杀死后,APP端进程被销毁了,也就不存在什么Activity了,也就没有什么Activity堆栈,不过AMS的却是被保留了下来:

    当用户再次启动APP时候会怎么样呢?这个时候,首先看到其实C,而不是栈底部的A,也就是说往往被杀死后,恢复看到的第一个界面是用户最后见到的那个界面。

    而用户点击返回,看到的就是上一个界面B,其次是A

    之所以这样是因为APP端Activity的创建其实都是由AMS管理的,AMS严格维护这APP端Activity对应的ActivityRecord栈,可以看做当前APP的场景,不过,APP端Activity的销毁同AMS端ActivityRecord的销毁并不一定是同步的,最明显的就是后台杀死这种场景。Android为了能够让用户无感知后台杀死,就做了这种恢复逻辑,不过,在开发中,这种逻辑带了的问题确实多种多样,甚至有些产品就不希望走恢复流程,本文就说说如何避免走恢复流程。结合常见的开发场景,这里分为两种,一种是针对推送唤起APP,一种是针对从最近任务列表唤起APP(或者icon)。

    从最近的任务列表唤起,不走恢复流程

    首先,APP端必须知道当前Activity的启动是不是在走恢复流程,Activity有一个onCreate方法,在ActivityThread新建Activity之后,会回调该函数,如果是从后台杀死恢复来的,回调onCreate的时候会传递一个非空的Bundle savedInstanceState给当前Activity,只要判断这个非空就能知道是否是恢复流程。

    1.  
      @Override
    2.  
      public void onCreate(Bundle savedInstanceState) {
    3.  
      super.onCreate(savedInstanceState);
    4.  
      }

    知道恢复流程之后,如何处理呢?其实很简单,直接吊起闪屏页就可以了,不过这里有一点要注意的是,在启动闪屏页面的时候,必须要设置其IntentFlag:Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK,这样做的理由是为了清理之前的场景,不然之前的ActivityRecord栈仍然保留在ActivityManagerService中,具体实现如下,放在BaseActivity中就可以:

    1.  
      Intent intent = new Intent(this, SplashActivity.class);
    2.  
      intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
    3.  
      startActivity(intent);

    如果不设置会怎么样呢?举个例子,最常见的就是闪屏之后跳转主界面,主界面经常有router逻辑,并且其启动模式一般都是singleTask,处理一些推送,所以其onCreate跟onNewIntent都有相应的处理,如果不设置,在闪屏结束后,在startActivity启动主界面的时候,其实是先走恢复逻辑,然后走singleTask的onNewIntent逻辑,也就是说,onNewIntent跟onCreate是会同时调用的,也可能就会引发重复处理的逻辑,因此最好清理干净。

    从推送唤起被杀APP时,如何走闪屏逻辑

    对于推送消息的处理,其路由器一般放在MainActivity,并且在onCreate跟onNewIntent都有添加,如果APP存活的情况,可以直接跳转目标页面,如果APP被杀,这个时候,希望先跳转主界面,再跳转目标页面,在效果上来看就是,用户先看到目标页面,点击返回的时候再看到主界面,如果加上闪屏,希望达到的效果是先看到闪屏、点击返回看到目标页,再点击返回看到主页面。如果简单划分一下推送场景,可以看做一下三种

    • 进程存活,Activity存活
    • 进程存活,但是没有Activity存活
    • 进程不存在(无论是否被杀)

    其实后面两种完全可以看做一种,这个时候,都是要先start MainActivity,然后让MainActivity在其OnCreate中通过startActivityForResult启动SplashActivity,SplashActivity返回后,在start TargetActivity。下面的讨论都是针对后面两种,需要做的有两件事

    • 一是:检测出后面两种场景,并且在唤起主界面的时候需要添加Intent.FLAG_ACTIVITY_CLEAR_TASK清理之前的现场
    • 二是:在MainActivity的路由系统中,针对这两种场景要,先跳转闪屏,闪屏回来后,再跳转推送页

    如何判断呢,后面两种场景其实只需要判断是否有Activity存活即可,也就是查查APP的topActivity是否为null,注意不要去向AMS查询,而是在本地进程中查询,可以通过反射查询ActivityThread的mActivities,也可以根据自己维护的Activity堆栈来判断,判断没有存活Activity的前提下,就跳转主页面去路由

    1.  
      Intent intent = new Intent(this, MainActivity.class);
    2.  
      intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
    3.  
      intent.setDate(跳转的Uri scheme)
    4.  
      startActivity(intent);

    在MainActivity的路由中,需要准确区分是否是推送跳转进来的,如果不是推送跳转进来,就不需要什么特殊处理,如果是推送跳转进来一定会携带跳转scheme数据,根据是否携带数据做区分即可,看一下MainActivity的代码:

    1.  
      @Override
    2.  
      public void onCreate(Bundle savedInstanceState) {
    3.  
      super.onCreate(savedInstanceState);
    4.  
      Uri uri= getIntent().getData();
    5.  
      <!--只有在intent被设置了跳转数据的时候才去跳转,一般是推送就来,如果冷启动,是没有数据的-->
    6.  
      if(uri!=null){
    7.  
      SplashActivity.startActivityForResult(this,JUMP_TO_TARGET)
    8.  
      }
    9.  
      }
    10.  
      <!--Intent.FLAG_ACTIVITY_CLEAR_TASK保证了onNewIntent被调用的时候,进程一定是正常活着的-->
    11.  
      @Override
    12.  
      protected void onNewIntent(Intent intent) {
    13.  
      Uri uri= intent.getData();
    14.  
      intent.setData(null);
    15.  
      router(uri);
    16.  
      }
    17.  
       
    18.  
      @Override
    19.  
      protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    20.  
      super.onActivityResult(requestCode, resultCode, data);
    21.  
      if(requestCode==JUMP_TO_TARGET && requestCode == RESULT_OK){
    22.  
      router(getIntent().getData());
    23.  
      getIntent().setData(null);
    24.  
      }
    25.  
      }
    26.  
       
    27.  
      private void router(Uri uri) {
    28.  
       
    29.  
      }

    通过上面两部分的处理,基本能够满足APP“死亡”的情况下,先跳转闪屏的需求。


    转载链接:https://www.jianshu.com/p/4fc10026c1f8

  • 相关阅读:
    Hadoop 学习笔记 (十) hadoop2.2.0 生产环境部署 HDFS HA Federation 含Yarn部署
    hadoop 2.x 安装包目录结构分析
    词聚类
    Hadoop 学习笔记 (十一) MapReduce 求平均成绩
    Hadoop 学习笔记 (十) MapReduce实现排序 全局变量
    Hadoop 学习笔记 (九) hadoop2.2.0 生产环境部署 HDFS HA部署方法
    Visual Studio Code 快捷键大全(Windows)
    Eclipse安装教程 ——史上最详细安装Java &Python教程说明
    jquery操作select(取值,设置选中)
    $.ajax 中的contentType
  • 原文地址:https://www.cnblogs.com/chenxibobo/p/14109152.html
Copyright © 2011-2022 走看看