精华内容
参与话题
问答
  • Activity栈管理

    千次阅读 2017-06-15 12:32:21
    下面是我从其他地方搞来的Activity栈管理类,实现的是弱引用public class ActivityStackManager { private static final String TAG = "ActivityStackManager"; /** * Activity栈 */ private Stack...

    下面是我从其他地方搞来的Activity栈管理类,实现的是弱引用

    public class ActivityStackManager {
        private static final String TAG = "ActivityStackManager";
        /**
         * Activity栈
         */
        private Stack<WeakReference<Activity>> mActivityStack;
        private static ActivityStackManager activityStackManager = new ActivityStackManager();
        private ActivityStackManager() {
        }
        /***
         * 获得AppManager的实例
         *
         * @return AppManager实例
         */
        public static ActivityStackManager getInstance() {
            if (activityStackManager == null) {
                activityStackManager = new ActivityStackManager();
            }
            return activityStackManager;
        }
        /***
         * 栈中Activity的数
         *
         * @return Activity的数
         */
        public int stackSize() {
            return mActivityStack.size();
        }
        /***
         * 获得Activity栈
         *
         * @return Activity栈
         */
        public Stack<WeakReference<Activity>> getStack() {
            return mActivityStack;
        }
        /**
         * 添加Activity到堆栈
         */
        public void addActivity(WeakReference<Activity> activity) {
            if (mActivityStack == null) {
                mActivityStack = new Stack<>();
            }
            mActivityStack.add(activity);
        }
        /**
         * 删除ac
         *
         * @param activity 弱引用的ac
         */
        public void removeActivity(WeakReference<Activity> activity) {
            if (mActivityStack != null) {
                mActivityStack.remove(activity);
            }
        }
        /***
         * 获取栈顶Activity(堆栈中最后一个压入的)
         *
         * @return Activity
         */
        public Activity getTopActivity() {
            Activity activity = mActivityStack.lastElement().get();
            if (null == activity) {
                return null;
            } else {
                return mActivityStack.lastElement().get();
            }
        }
        /***
         * 通过class 获取栈顶Activity
         *
         * @param cls
         * @return Activity
         */
        public Activity getActivityByClass(Class<?> cls) {
            Activity return_activity = null;
            for (WeakReference<Activity> activity : mActivityStack) {
                if (activity.get().getClass().equals(cls)) {
                    return_activity = activity.get();
                    break;
                }
            }
            return return_activity;
        }
        /**
         * 结束栈顶Activity(堆栈中最后一个压入的)
         */
        public void killTopActivity() {
            try {
                WeakReference<Activity> activity = mActivityStack.lastElement();
                killActivity(activity);
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }
        }
        /***
         * 结束指定的Activity
         *
         * @param activity
         */
        public void killActivity(WeakReference<Activity> activity) {
            try {
                Iterator<WeakReference<Activity>> iterator = mActivityStack.iterator();
                while (iterator.hasNext()) {
                    WeakReference<Activity> stackActivity = iterator.next();
                    if (stackActivity.get() == null) {
                        iterator.remove();
                        continue;
                    }
                    if (stackActivity.get().getClass().getName().equals(activity.get().getClass().getName())) {
                        iterator.remove();
                        stackActivity.get().finish();
                        break;
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }
        }
        /***
         * 结束指定类名的Activity
         *
         * @param cls
         */
        public void killActivity(Class<?> cls) {
            try {
                ListIterator<WeakReference<Activity>> listIterator = mActivityStack.listIterator();
                while (listIterator.hasNext()) {
                    Activity activity = listIterator.next().get();
                    if (activity == null) {
                        listIterator.remove();
                        continue;
                    }
                    if (activity.getClass() == cls) {
                        listIterator.remove();
                        if (activity != null) {
                            activity.finish();
                        }
                        break;
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }
        }
        /**
         * 结束所有Activity
         */
        public void killAllActivity() {
            try {
                ListIterator<WeakReference<Activity>> listIterator = mActivityStack.listIterator();
                while (listIterator.hasNext()) {
                    Activity activity = listIterator.next().get();
                    if (activity != null) {
                        activity.finish();
                    }
                    listIterator.remove();
                }
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }
        }
        /**
         * 移除除了某个activity的其他所有activity
         *
         * @param cls 界面
         */
        public void killAllActivityExceptOne(Class cls) {
            try {
                for (int i = 0; i < mActivityStack.size(); i++) {
                    WeakReference<Activity> activity = mActivityStack.get(i);
                    if (activity.getClass().equals(cls)) {
                        break;
                    }
                    if (mActivityStack.get(i) != null) {
                        killActivity(activity);
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }
        }
        /**
         * 退出应用程序
         */
        public void AppExit(Context context) {
            killAllActivity();
            Process.killProcess(Process.myPid());
        }
    }
    展开全文
  • Android 获取activity栈中activity

    万次阅读 2018-08-31 11:00:55
    --获取Activity任务 权限--&gt; &lt;uses-permission android:name="android.permission.GET_TASKS" /&gt; // 获取activity任务 ActivityManager manager = (ActivityManager) ...

    方法1:

    <!--获取Activity任务栈 权限-->
    <uses-permission android:name="android.permission.GET_TASKS" />
    // 获取activity任务栈
    ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    ActivityManager.RunningTaskInfo info = manager.getRunningTasks(1).get(0);
    
    String packageName = info.topActivity.getPackageName();
    String topclassName = info.topActivity.getClassName();  
    String baseclassname = info.baseActivity.getClassName();
    int acitivitynum = info.numActivities;
    

     方法2:

    在终端或者Android Studio中的Terminal里输入命令:

    adb shell dumpsys activity activities

    之后可以看到如下的activity栈输出信息:

     

    方法3 (反射):

    转自:https://www.jianshu.com/p/ac0b237bac03 

    Framewok层源码中,

    public final class ActivityThread {
           ......
           final ArrayMap<IBinder, ActivityClientRecord> mActivities = new ArrayMap<>();
           ......
       }
    

    这个Map的Value是ActivityClientRecord,持有Activity对象。

    mLoadedApk持有ActivityThread,因此此处可以路反射过去拿到Map拿到ValueList

    private static List<Activity> getActivitiesByApplication(Application application) {
            List<Activity> list = new ArrayList<>();
            try {
                Class<Application> applicationClass = Application.class;
                Field mLoadedApkField = applicationClass.getDeclaredField("mLoadedApk");
                mLoadedApkField.setAccessible(true);
                Object mLoadedApk = mLoadedApkField.get(application);
                Class<?> mLoadedApkClass = mLoadedApk.getClass();
                Field mActivityThreadField = mLoadedApkClass.getDeclaredField("mActivityThread");
                mActivityThreadField.setAccessible(true);
                Object mActivityThread = mActivityThreadField.get(mLoadedApk);
                Class<?> mActivityThreadClass = mActivityThread.getClass();
                Field mActivitiesField = mActivityThreadClass.getDeclaredField("mActivities");
                mActivitiesField.setAccessible(true);
                Object mActivities = mActivitiesField.get(mActivityThread);
                // 注意这里一定写成Map,低版本这里用的是HashMap,高版本用的是ArrayMap
                if (mActivities instanceof Map) {
                    @SuppressWarnings("unchecked")
                    Map<Object, Object> arrayMap = (Map<Object, Object>) mActivities;
                    for (Map.Entry<Object, Object> entry : arrayMap.entrySet()) {
                        Object value = entry.getValue();
                        Class<?> activityClientRecordClass = value.getClass();
                        Field activityField = activityClientRecordClass.getDeclaredField("activity");
                        activityField.setAccessible(true);
                        Object o = activityField.get(value);
                        list.add((Activity) o);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                list = null;
            }
            return list;
        }

     

     

    展开全文
  • Activity栈简析

    万次阅读 2012-03-31 11:42:47
    Task 就是一个 (A task is a stack of activities.) ,这个里面存放了很多 Activity ,它遵循着后进先出的原则。  有两个动作:压栈(把对象压入到当中)和弹(把中的第一个对象从里面拿出来)。...

    Task 

    1、   什么是 Task ? 

    Task 翻译成中文叫做任务,那么什么是任务呢? 

    Task 就是一个栈 (A task is a stack of activities.) ,这个栈里面存放了很多 Activity ,它遵循着后进先出的原则。 

    栈有两个动作:压栈(把对象压入到栈当中)和弹栈(把栈中的第一个对象从栈里面拿出来)。 

    2、   Task 运行过程 

    示例 1 :

    创建一个 Android应用程序,编写 3 个 Activity(FirstActivity 、 SecondActivity 、 ThirdActivity) ,每个 Activity 都有一个按钮,当点击 FirstActivity 的 Button 按钮时,跳转到 SecondActivity ,当点击 SecondActivity 的 Button 按钮时,跳转到 ThirdActivity ,当再点击 ThirdActivity 的 Button 按钮时,调用 Android 自带的一个发送短信的应用程序。(程序已打包上传至附件中,有需要的可下载进行查看运行) 

    运行程序,观察 Task 运行的过程。 

    这个应用程序的 FirstActivity 、 SecondActivity 、 ThirdActivity 以及 Android 自带的发送短信的应用程序就组成了一个 Task 。 

    Task 运行过程讲解: 

    1)   应用程序启动之后,运行的第一个 Activity ( FirstActivity ),该 FirstActivity 对象被压入到 Stack 当中。 

    2)   当点击了 FirstActivity 的按钮之后,启动第二个 Activity ( SecondActivity ),该 SecondActivity 对象被压入到 Stack 当中。 

    注:现在 FirstActivity 处在 Stack 的底部, SecondActivity 处于 Stack 的顶部,手机永远显示的都是 Stack 顶部的元素,所以现在界面显示的是 SecondActivity 。 

    3)   当点击了 SecondActivity 的按钮之后,启动第三个 Activity ( ThirdActivity ),该 ThirdActivity 对象被压入到 Stack 当中。 

    注:现在 FirstActivity 处在 Stack 的底部, ThirdActivity 处于 Stack 的顶部,手机永远显示的都是 Stack 顶部的元素,所以现在界面显示的是 ThirdActivity 。 

    4)   最后点击 ThirdActivity 的按钮之后,启动 Android 自带的发送短信的应用程序( SMS Activity 对象),该 SMS Activity 对象被压入到 Stack 当中。 

    注:同理,现在 FirstActivity 仍然处在 Stack 的底部, SMS Activity 对象处于 Stack 的顶部,所以现在界面显示的是 SMS Activity 对象的界面。 
    (以上执行的是压栈操作,现在我们点击返回来看弹栈操作) 


    5)   点击模拟器右侧的 Back 按钮之后,这个时候 SMS Activity 对象被从栈中弹出来。 SMS Activity 对象被弹出来之后, ThirdActivity 又变成栈的顶部,当前程序显示的就是 ThirdActivity 的内容。(因为栈遵循后进先出的原则) 

    6)   当再点击 Back 按钮之后, ThirdActivity 被从栈中弹出来,程序显示 SecondActivity 的内容。 

    7)   再点击 Back 按钮, SecondActivity 被从栈中弹出来,程序显示 FirstActivity 的内容。 

    注意: 

    a )、现在在 SecondActivity 中的 startActivity(intent) 后调用 finish() 方法。将程序运行到 ThirdActivity 后,点击 Back 按钮,此时,程序并没有返回到 SecondActivity ,而是直接返回到 FirstActivity 。 

    原因:由于在点击 SecondActivity 的按钮之后,它启动了 ThirdActivity ,同时将 SecondActivity 销毁掉了,这个时候栈里面只有 ThirdActivity 和 FirstActivity ,当再点击Back 的时候它就不是回到 SecondActivity 而是回到 FirstActivity 了。 

    b )、在整个栈当中, Activity 只有弹出和压入这两个动作,是不允许调换 Activity 之间的顺序的。 

    3、   Task 对的作用 

    在同一个 Task 里面的 Activity 被组织成同一个单元(可以将不同应用程序的 Activity 组织在一起)。

    ===================================================================

    Java代码
    1. Intent intent = new Intent();     
    2. intent.setAction(Intent.ACTION_CALL);     
    3. intent.setData(Uri.parse("tel:" + number));     
    4. startActivity(intent);    


    上面的这段代码就是在一个activity里通过Intent启动另一个activity的实例。

    就像前面提到的,一个activity可以启动另一个,包括那些定义在不同应用程序中的。
    一个activity就是一个用户界面,可以连续启动很多activity以提高用户体验。当然这个数量是有限的,这要根据手机的硬件配置来决定。上一篇文章中已经介绍,所有打开的activity都是存储在栈中的,所以如果打开的activity过多,会消占去很多的内存和处理器资源,严重时会导致当前应用无法启动或者系统崩溃。
    activity是和任务紧密联系的。因为在Android系统中,为了保持用户体验,用户想做某件事情是以任务的结构作为逻辑,以应用的形式来表现的。而一个应用又可以包含很多的activity,所以就涉及到activity和task的关系问题。
    note:一个task由很多的activity组成。
    为了更好的说明举个例子:
    TASK1包含三个activity分别是:p,q,r;启动顺序为p-->q-->r
    TASK2包含两个activity分别是:a,b;启动顺序为a-->b;
    TASK1首先启动p,那么这个p就是执行这个任务的根activity,任务也是定义在这个activity下的。通过属性Manifest文件中的activity属性中的taskAffinity来定义。
            (1)此时p启动后就被压入堆栈,因为此时堆栈中只有这一个activity,所以p处于栈底,也处于栈顶。此时用户能够看到的就是p界面。
            (2)p启动q后,q入栈。此时栈顶为q。q呈现的界面将p覆盖,p进入后台运行(此时是activity生命周期的pause状态)或者进入后台但不运行(此时是activity生命周期的stop状态)。
            (3)q启动r后,r入栈。此时栈顶为r。r呈现的界面将q覆盖,q进入后台运行。
            (4)按back键后就是调用finish函数结束r (activity)的生命。此时r出栈,r的生命周期结束。
            (5)继续back键,结束q的生命,此时q出栈。
            (6)继续back键,结束p的生命,此时p出栈。
            (7)此时栈内所有activity都已出栈,所以就会显示HOME屏幕界面.
    上面的例子已经很明确,如果还不理解请看下面:


    1、activity简单解释
    简单的的说,任务就是用户所体验到的“应用程序”。它是一组相关的activity,分配到 一个栈中。栈中的根activity,是任务的开始——一般来说,它是用户组应用程序加载器中选择的activity。在栈顶的activity正是当前 正在运行的——集中处理用户动作的那个。当一个activity启动了另外一个,这个新的activity将压入栈中,它将成为正在运行中的 activity。前一个activity保留在栈中。当用户按下后退按键,当前的这个activity将中栈中弹出,而前面的那个activity恢复 成运行中状态。
    为了更好的理解上面的例子要补充的是:


    2、activity的生命周期:
    onCreate()------->onStart()-------->onResume()--------->onSaveInstanceState()----->onPause()------->onStop
    --------->onDestroy().

    3、activity的各种状态的转换:

    继续看上面的例子:上面的每一个activity都经历了这样一个过程的大部分。当启动一个activity时,首先是在onCreate处进行初始化界面所需要的信息,如:界面的views,buttons,分配的引用变量等;初始化完成后就会调用onStart,此时就可以看到界面了;当用户与界面进行交互时就会调用onResume函数;当此activity因为被其他activity没有完全覆盖而进入pause状态时就调用onPause(),当被其他activity完全覆盖时就调用onStop函数。在后面的这两种情况下都会调用onSaveInstanceState方法来暂时保存被覆盖的activity的状态,在这些被覆盖的activity重新回到界面上的时候会恢复这些状态;当调用finish方法使,这个activity就被destroy了,也就从栈中移除了。
             
        一个任务中的所有activity一起作为一个单元。整个任务(整个activity栈)可以移动到前台或者后台.假设,例如,当前的任务有四个 activity在栈中——三个在当前的activity之下。用户按下了HOME键,进入了应用程序加载器,选择了一个新的程序(实际上,是一个新的任务)。当前的任务进入了后台,新任务的根activity显示出来。然后,过了一会,用户退回到主界面,又重新选择了前一个应用程序(前一个任务),栈中有四个activity的那个任务,现在出现在了前台。当用户按下BACK按键,屏幕就不会再显示用户刚刚离开的那个activity,而是删除栈顶的 activity,同任务中的前一个activity将被显示出来。

         刚才说明的那些行为,是activity和任务的默认行为。但是有也办法修改它的所有方面。activity和任务的关联,activity在任务中的行为,受控于启动activity的行为对象的标志位和清单文件中的<activity> 元素的属性的互相作用。请求者和相应着都要说明发生了什么。


       在这里,主要的行为标志为是:

    FLAG_ACTIVITY_NEW_TASK  
    FLAG_ACTIVITY_CLEAR_TOP  
    FLAG_ACTIVITY_RESET_TASK_IF_NEEDED  
    FLAG_ACTIVITY_SINGLE_TOP


           主要的<activity> 属性是:

    taskAffinity  
    launchMode  
    allowTaskReparenting  
    clearTaskOnLaunch  
    alwaysRetainTaskState  
    finishOnTaskLaunch


           下面一节将说明这些标志和属性都有什么用,他们之间怎么互相影响,应该用什么样的方案来控制它们的使用。


    亲和性和新任务

            默认情况下,应用程序中的所有activity,都有一个对于其它activity的亲和性—这是一个对于同一个任务中的其他activity的优先权,然后,通过  <activity>元素的 taskAffinity 属性可以可以分别为每一个activity设置亲和性。不同应用程序定义的activity可以共享同一个亲和性,或者同一个应用程序定义的 activity可以指定不同的亲和性。亲和性在两种情况下发挥作用:当行为对象启动了一个包含 FLAG_ACTIVITY_NEW_TASK标志的activity,和当一个activity的allowTaskReparenting 属性设置为“true”。


     FLAG_ACTIVITY_NEW_TASK  标志 
           

            正如前面描述的,一个新的activity,默认情况下,被加载进调用startActivity()方法的activity对象所在的那个任务中。它被压入和调用者所在的同一个栈中,但是,如果行为对象在调用startActivity()方法时传递了FLAG_ACTIVITY_NEW_TASK标记,系统将用一个不同的任务来容纳这个新的activity。通常,就像这个标记的名字所代表的。它是一个新任务,但是,它不必非要这样。如果已经存在一个和这个activity亲和性相同的任务,这个activity就会载入到那个任务中,如果不是的话,才会启动新任务。


    allowTaskReparenting  属性


            如果activity的allowTaskReparenting 属性设置为“true”,它就能从他启动时所在的任务移动到另一个出现在前台的任务。例如,假设有一个activity可以根据选择的城市包括天气情况,它作为一个旅行应用程序的一部分。它和同一个应用程序中的其他activity有同样的亲和性(默认的亲和性)并且允许重组。你的一个activity开启了天气报告器,所以它属于同一个任务中的这个activity,然而,当旅行应用程序开始运行时,天气报告器将被重新分配并显示到那个任务中。


    启动模式


    有4中不同的启动模式可以分配给 <activity> 元素的  launchMode  属性。


    "standard" (默认的模式)  
    "singleTop "  
    "singleTask"  
    "singleInstance"


    这些模式主要区别在以下四点:

    (1)哪个任务存放着activity,用来对行为进行响应。 对“standard ”和“singleTop ”模式来说,这个任务是产生行为(并且调用startActivity() )的那个——除非行为对象包含了 FLAG_ACTIVITY_NEW_TASK 标记。在这种情况下,像前面那节Affinities and new tasks  描述的一样,将会选择一个不同的任务。

    (2)它们是否可以有多个实例。 "standard "和“singleTop ”类型的activity可以被实例化多次。它们可以属于多个任务,一个特定的任务也可以拥有同一个activity的多个实例。
    作为比较"singleTask "和"singleInstance "类型的activity只限定有一个实例。因为这些activity是任务的根。这个限制意味着,在设备上不能同时有超过一个任务的实例。

    (3)是否能有其他的activity在它所在的任务中。"singleInstance " 类型的activity是它所在任务中唯一的activity。如果它启动了其他的activity,不管那个activity的启动模式如何,它都会加载到一个不同的任务中——好像行为对象中的FLAG_ACTIVITY_NEW_TASK 标记。在其他的方面,"singleInstance "和"singleTask "模式是相同的。
    其他三种模式运行任务中有多个activity。"singleTask "总是任务中的根activity,但是它可以启动其他的activity并分配到它所在的任务中。"standard "和"singleTop "类型的activity可以出现在任务中的任何地方。

    (4)是否启动一个新的实例来处理一个新的行为。 对默认的"standard "模式来说,对于每一个行为都会创建一个新的实例来响应。每个实例只处理一个行为。对于"singleTop "模式,如果一个已经存在的实例位于目标任务activity栈的栈顶,那么他将被重用来处理这个行为。如果它不在栈顶,它将不会被重用,而是为行为创建一个新的实例,并压入栈中。

    例如,假设,一个任务的activity栈由根activity A和 B,C,D从上到下按这样的顺序组成,所以这个栈就是A-B-C-D。一个行为指向类型为D的activity。如果D是默认的"standard "加载模式,一个新的实例会被启动,栈现在就是这样A-B-C-D-D。但是,如果D的加载模式是"singleTop ",已经存在的实例会用来处理这个行为(因为它在栈的顶端)并且栈中还应该是A-B-C-D。

       在前面提到,"singleTask "和"singleInstance "类型的activity最多只有一个实例,所以他们的实例应该会处理每个新的行为。"singleInstance "类型的activity总是在栈的顶端(因为他是任务中唯一的一个activity),所以总是能够适当的处理行为。然而,"singleTask "类型的activity也许会有其他的activity在它的上面。如果是这样的话,那就不能处理这个行为,这个行为被丢弃。(即使这个行为被丢弃了,它的到来也会导致那些应该保留不变任务显示到前台来)。


       当一个activity被要求处理一个新的行为时,行为对象会通过调用activity的 onNewIntent()  方法传递进来(最初启动activity的行为可以通过调用getIntent() 方法获得)。


           注意,当创建一个新的activity实例来处理一个新的行为时,用户总是能够通过按下BACK按键退回到前面的状态(前一个activity)。但是当一个已经存在的activity实例处理一个新的行为时,用户不能通过按下BACK按键退回到前面的状态。

          更多关于加载模式的内容,请看关于 <activity>  的描述。


    清理栈


         如果用户离开一个任务很长时间。系统将清除除了根activity之外的所有activity。当用户重新回到任务中时,像是用户离开了它,除了只有最初的activity还在。这个理念是这样的,过了一段时间,用户很可能放弃之前所做的事情,回到任务去做一些新的事情。

         这只是默认情况,有一些activity的属性可以控制和修改它。

     alwaysRetainTaskState  属性


           如果一个任务的根activity的这个属性设置成了"true",那么刚才提到的那些默认行为就不会发生。这个任务保留所有的activity,甚至经过了很长一段时间。

     clearTaskOnLaunch  属性 
            
           如果任务的根activity的这个属性设置成了”true“,那么只要用户离开了任务并返回,就会清除除了根activity之外的所有activity。换句话说,它和alwaysRetainTaskState正好相反,当用户返回到任务时,总是恢复到最初的状态,不管离开了多长时间。


     finishOnTaskLaunch  属性


    这个属性和clearTaskOnLaunch类似,但是它作用于单个activity,而不是整个任务。它可以导致任何的activity离开,包括根activity。当它设置成"true"的时候,作为任务一部分的activity只对当前会话有效。如果用户离开然后返回到任务中。它将不再出现。


           还有其他的方法强制将activity从栈中移除。如果一个行为对象包含了 FLAG_ACTIVITY_CLEAR_TOP  标志,它的目标任务中已经有了一个这样类型的activity实例,所有栈中位于这个实例之上的activity都会被清除,所以这个实例就会出现在栈顶并且对行为进行响应。如果activity被设计成"standard"模式,它也将会从栈中被清除,并且会启动新的实例来处理到来的行为。这是因为当设置成”standard“模式后,对每个新的行为都会创建一个新的实例。


          FLAG_ACTIVITY_CLEAR_TOP经常 和FLAG_ACTIVITY_NEW_TASK一起使用。当一起使用时,这些标志是定位一个在另一个任务中存在的activity并且将它放在一个可以响应行为的地方的一种方法。


    启动任务


        Activity通过将行为过滤器”android .intent.action.MAIN“设置为指定动作和"android .intent.category.LAUNCHER"作为指定类型,来成为任务的入口。(前面关于行为过滤器那一些讨论的例子)。这种类型的过滤器会让activity的图标和标签显示在应用程序加载器上面,可以让用户启动和返回activity。


        第二个能力更为重要,用户应该可以在离开一个任务一段时间后返回。因为这样,能够初始化任务的"singleTask"和"singleInstance"模式,只能够用在那些拥有MAIN 和LAUNCHER 过滤器的activity中。想像一下如果没有这两个过滤器会发生什么:一个行为启动了"singleTask"模式的activity,启动了一个新的任务并且用户花了一些时间在这个任务上。然后用户按下了HOME键,这个任务被隐藏到了后台。因为没有在应用程序加载器上显示它,所以就没有办法返回到这个任务。


           一个类似的麻烦事 FLAG_ACTIVITY_NEW_TASK 标志。如果这个标志导致activity启动了一个新任务,并且用户按下HOME键离开了它,必须有一些方法将用户引导回它。一些实体(像是通知管理器) 总是在一个外部的任务中启动activity,而不作为它们的一部分,所以他们总是将带有FLAG_ACTIVITY_NEW_TASK 标记的行为对象传递到startActivity() 。如果你有一个可以被外部实体使用这个标签调用的activity,要注意用户应该有办法返回到启动的任务。

    展开全文
  • Android Activity管理之Activity栈

    千次阅读 2015-10-20 23:34:19
    在android中,一个activity组件可以激活另一个activity组件(可能属于另一个应用程序)。 ...Android是通过将之前的activity组件和新被激活的activity组件放入同一个任务来实现这个功能的。从用

    android中,一个activity组件可以激活另一个activity组件(可能属于另一个应用程序)。

        若新的被激活的activity组件属于另一个应用程序,则那个activity组件会运行在那个应用程序的进程中,但是从用户的角度来看,好像就是属于本应用程序一样。Android是通过将之前的activity组件和新被激活的activity组件放入同一个任务栈来实现这个功能的。从用户的角度看,一个任务栈就代表了一个应用程序。它实际上是一个栈,里面放着一组被排列好的相关的activity组件。位于栈底的activity(根activity)就是开启这个任务栈的activity组件,一般情况下,就是应用程序的主界面。而位于栈顶的activity组件即代表当前被激活的activity组件(可接收用户行为的activity)。

        任务栈中包含了activity组件的对象,且任务栈中可以包含有某一个activity组件类型的多个实例对象。在任务栈中的activity组件不能被重排序,只能被压栈和弹栈。

        任务栈不是某个类型,也不是某一个元素,它是一组activity组件的组织形式。所以没有办法在不影响任务栈中的activity组件的情况下,单独设置任务栈的参数。activity的参数既是整个任务栈的参数,它会影响任务栈中的所有activity组件。

        当某个应用程序在前后台切换的时候,实际上就是代表这个应用程序的一个任务栈在前后台切换。

        刚刚描述的行为是activity和任务栈的默认行为,但也有办法在很多方面对它进行修改:

        方法1:在发送的请求(即Intent对象)中设置一些标记。

        方法2:在manifest文件中,对接收请求(即Intent对象)的activity组件设置一些属性。

        所以在请求者和接收者中都可以进行控制。

    Intent对象中主要的标志有:

        FLAG_ACTIVITY_NEW_TASK

        FLAG_ACTIVITY_CLEAR_TOP

        FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

        FLAG_ACTIVITY_SINGLE_TOP

    <activity>标签中,主要的属性有:

        taskAffinity   android:taskAffinity="com.cardroid.sdhc"  表示两个应用里面的亲属关系,如果一个应用的某个ACTIVITY和另一个应用的ACTIVITY设置这个属性
        然后,这两个ACTIVITY显示后点击HOME键盘,从一个应用启动就会显示点击HOME的那个ACTIVITY

        launchMode 

        allowTaskReparenting 

        clearTaskOnLaunch 

        alwaysRetainTaskState 

        finishOnTaskLaunch

        接下来的内容就会讲解一些Intent标志和<activity>标签属性的作用和用法。

    1.亲属关系和新的任务

        默认情况下,一个应用程序中的activity组件彼此之间是亲属关系――也就是说它们属于同一个任务栈。但是我们可以通过设置某个<activity>标签的taskAffinity属性来为这个activity组件设置亲属关系。在不同的应用程序中定义的activity组件可以共用同一个亲属关系,或者在同一个的应用程序中定义的activity组件可以使用不同的亲属关系。亲属关系会在两种情况下发挥作用:

        1)负责激活activity组件的Intent对象中包含了FLAG_ACTIVITY_NEW_TASK标志。

        2)被激活的activity组件的allowTaskReparenting属性被设置为“true”

    问题:

    1.     在同一个程序中,不同的Activity设置了相同的(默认)或不同的taskAffinity属性,那么在默认标志和FLAG_ACTIVITY_NEW_TASK时,会如何跳转?共有4中组合。

    2.      在跨程序启动Activity时,不同的Activity设置了相同的或不同的(默认)taskAffinity属性,那么在默认标志和FLAG_ACTIVITY_NEW_TASK时,会如何跳转?共有4中组合。


    关于FLAG_ACTIVITY_NEW_TASK标志量

        默认情况下,一个被激活的新activity会和负责激活它的那个activity组件存在于同一个任务栈中。但是若负责激活的Intent对象包含了FLAG_ACTIVITY_NEW_TASK标志,则系统会为存放那个即被激活的新activity寻找一个新的任务栈。此时,若已经存在了相同亲属关系的任务栈,则系统会直接将这个即被激活的新activity放入到这个任务栈中;否则系统会开始一个新的任务栈。

    关于allowTaskReparenting属性

        若一个activity组件的allowTaskReparenting被置为“true”,则当与这个activity有相同的亲属关系的任务栈被切换到前台的时候,这个activity会从当前存在的任务栈中移动到与其有相同的亲属关系的任务栈中。

        若从用户的角度来看,一个.apk文件包含了一个以上的应用程序,那你可能要为那些activity组件指定不同的亲属关系。

    2.启动模式

    <activity>标签的launchMode属性可以设置为四种不同的模式:

        “standard”(默认模式)

        “singleTop”
     android:launchMode="singleTop" 相当于每次都从这个ACITIVITY启动
        “singleTask”
     android:launchMode="singleTop" singleTop类似,不同于,每次启动后都在最上面
        “singleInstance”

        这几种模式的区别体现以下四点上:

        1)当这个activity被激活的时候,会放入哪个任务栈。

        对于“standard”“singleTop”模式,这个新被激活的activity会放入和之前的activity相同的任务栈中――除非如前所述,Intent对象包含FLAG_ACTIVITY_NEW_TASK标志。

        “singleTask”“singleInstance”模式则表示这个新被激活的activity不会放入已经存在的任务栈中,它会重新开启一个任务栈,并作为这个新的任务栈的根activity

        2)是否可以存在这个activity类型的多个实例。

        对于“standard”“singleTop”模式,可以有多个实例,并且这些实例可以属于不同的任务栈,每个任务栈也可以包含有这个activity类型的多个实例。

        “singleTask”“singleInstance”模式则表示至多只可以存在这个activity类型的一个实例。又因为有第一点必须是根activity的限制,所以这意味着在同一时间,在手机上绝不会存在多于一个的由这个activity启动的任务栈。

        3)包含此activity的任务栈是否可以包含其它的activity

        “singleInstance”模式表示包含此activity的任务栈不可以包含其它的activity。若此activity启动了另一个activity组件,那么无论那个activity组件的启动模式是什么或是Intent对象中是否包含了FLAG_ACTIVITY_NEW_TASK标志,它都会被放入另外的任务栈。在其它方面“singleInstance”模式和“singleTask”模式是一样的。

        其余三种启动模式则允许包含此activity的任务栈包含其它的activity

        4Whether a new instance of the class will be launched to handle a new intent.

        对于默认的“standard”模式,每当响应一个Intent对象,都会创建一个这种activity类型的新的实例。即每一个activity实例处理一个intent

        对于“singleTop”模式,只有当这个activity的实例当前处于任务栈的栈顶位置,则它会被重复利用来处理新到达的intent对象。否则就和“standard”模式的行为一样。

        正如第二点所说的,“singleTask”“singleInstance”模式表示只能有一个实例,所以这个唯一的实例需要处理所有新到达的intent对象。又由于“singleInstance”模式的activity实例总是位于任务栈的栈顶,所以这样做很正常。但对于“singleTask”模式的acitvity,在其上面可能存在其它的activity组件,所以它的位置并不是栈顶,在这种情况下,intent对象会被丢弃。(虽然会被丢弃,但是这个intent对象会使这个任务栈切换到前台)

        如果一个新到达的intent对象是被一个已经存在的activity组件来处理的,那么这个activityonNewIntent(android.content.Intent)方法会被系统调用。

        注意:若为了处理一个新到达的intent对象而创建了一个activity实例,则用户按下“BACK”键就会退到之前的那个activity。但若这个新到达的intent对象是由一个已经存在的activity组件来处理的,那么用户按下“BACK” 键就不会回退到处理这个新intent对象之前的状态了。

    3.清理任务栈

        如果一个任务栈在很长的一段时间都被用户保持在后台的,那么系统就会将这个任务栈中除了根activity以外的其它所有activity全部清除掉。从这之后,当用户再将任务栈切换到前台,则只能显示根activity了。

    以上说的是默认模式,可以通过<activity>标签的一些属性来更改:

        1alwaysRetainTaskState属性

        如果将根activityalwaysRetainTaskState属性设置为“true”,则即便一个任务栈在很长的一段时间都被用户保持在后台的,系统也不会对这个任务栈进行清理。

        2clearTaskOnLaunch属性

        如果将根activityclearTaskOnLaunch属性设置为“true”,那么只有这个任务栈切换到了后台,那么系统就会将这个任务栈中除了根activity以外的其它所有activity全部清除掉。即和alwaysRetainTaskState的行为完全相反。

        3) finishOnTaskLaunch属性

        这个属性的行为类似于clearTaskOnLaunch,但是此属性作用于单个的activity对象,而不是整个任务栈。当这个任务栈切换到了后台,这个属性可以使任务栈清理包括根activity在内的任何activity对象。

        这里也有另一种方法来使activity对象从任务栈中被移除。若Intent对象包含FLAG_ACTIVITY_CLEAR_TOP标志,并且在目标任务栈中已经存在了用于处理这个Intent对象的activity类型的一个实例,那么在任务栈中这个实例之上的所有activity实例会被移除。从而用于处理这个Intent对象的activity类型的那个实例会位于任务栈的栈顶,并用来处理那个Intent对象。若那个匹合的activity类型的启动模式是“standard”,则这个已经存在于任务栈中的匹合的activity类型的实例也会被移除,并且一个新的此类型activity的实例被创建并压栈来处理这个Intent对象。

        FLAG_ACTIVITY_CLEAR_TOP这个标志经常和FLAG_ACTIVITY_NEW_TASK标志结合使用,这样结合使用的意思是在另一个任务栈中定位已经存在的匹合的activity类型的实例,并且让此实例位于栈顶。

    4.启动任务栈

        通过将一个activity类型的intent-filter的动作设置为“android.intent.action.MAIN”,类别设置为“android.intent.category.LAUNCHER”可以使这个activity实例称为一个任务栈的入口。拥有这种类型的intent-filteractivity类型的图表和名字也会显示在application launcher中。

        第二个能力是很重要的:用户必须能够使一个任务栈切换到后台,也可以随时将其切换到前台。出于这个原因,使activity在启动时新开任务栈的启动模式(即“singleTask”“singleInstance”模式)只应该被利用在拥有拥有“android.intent.action.MAIN”动作和“android.intent.category.LAUNCHER”类别的intent-filteractivity类型上。

        类似的限制同样体现在FLAG_ACTIVITY_NEW_TASK标志上。如果这个标志使一个activity开始了一个新的任务栈,并且用户点击“HOME”键将其切换到了后台,则必须有某种方式使用户可以重新将那个任务栈切换到前台。一些实例(比如通知管理器),总是在外部的任务栈中开启一个activity,而不是其自身的任务栈,所以它们总是将FLAG_ACTIVITY_NEW_TASK标志放入Intent对象中,并将Intent对象传入startActivity()方法中。

        对于在某些情况下,你不希望用户能够返回到某一个activity,那么可以通过设置<activity>标签的“finishOnTaskLaunch”属性为“true”来实现。

    展开全文
  • activity管理

    万次阅读 2014-10-03 21:00:29
    在android中,一个activity组件可以激活另一个activity组件:本程序activity和其它程序的activity。  若新的被激活的activity组件属于...Android是通过将之前的activity组件和新被激活的activity组件放入同一个任务
  • 彻底弄懂Activity的启动模式和任务

    千次阅读 2018-03-03 00:02:21
    Activity的启动模式和任务是Android的重点和难点,也是Android面试的常考必考知识点,而很多同学即使时搞Android开发好几年的同学也不一定完全搞懂了,可能也是一知半解。本文让你彻底搞懂Android中Activity的启动...
  • 前言 android上对于任务的控制还是比较常见的,尤其是在...完全理解android Activity启动模式LauchMode (深入Activity与任务) 使用概念 android上要使用多任务,除了要了解启动模式之外,就是需要了解taskAffi
  • Activity栈清空

    万次阅读 2014-05-18 19:46:53
    一、clearTaskOnLaunch: clearTaskOnLaunch仅对根...When the value is "true", every timeusers start the task again, they are brought to its root activity regardless ofwhat they were last doing in th
  • 获取Activity栈,判断当前Activity位置

    万次阅读 2017-07-10 22:17:33
    需求需要在整个app全局能够弹出弹框,接收到广播即进行处理。 但是,BaseActivity派生出N个Activity,BaseActivity中的广播就会执行N次,导致...--获取Activity任务 权限--> <uses-permission android:name="android
  • Android Activity管理之Activity栈

    千次阅读 2012-07-10 16:53:13
    在android中,一个activity组件可以激活另一个activity组件(可能属于另一个应用程序)。 ...Android是通过将之前的activity组件和新被激活的activity组件放入同一个任务来实现这个功能的。从用
  • activity栈管理的3种方式

    千次阅读 2016-04-16 22:28:42
    背景: 在android开发过程最常用的组件非activity莫属。通过分析activity的各种跳转,运行同学可以分析用户的各种行为,更重要的一点是在做插件化的过程中,我们经常会对activity进行各种反射...遍历activity栈可以得到
  • 查看activity栈

    2016-12-05 23:05:49
    adb shell dumpsys activity— edit by cwxin
  • Android 清空activity栈的方法

    万次阅读 2015-12-05 11:57:59
    这个标记,将会导致任何用来放置该activity的已经存在的task里面的已经存在的activity先清空,然后该activity再在该task中启动,也就是说,**这个新启动的activity变为了这个空task的根activity.所有老的activity都...
  • 关于AMS,原计划是只写一篇文章来介绍,但是AMS功能繁多,一篇文章的篇幅远远不够。这一篇我们接着来学习与AMS相关的ActivityTask和Activity栈管理。
  • adb方式查看activity栈信息 adb shell dumpsys activity activities | sed -En -e '/Running activities/,/Run #0/p'
  • activity android:name=".ui.activity.TaskAffinityActivity" android:launchMode="singleTask" /> standard singleTop singleTask singleInstance 默认模式是 standard,这些模式分为两大类,standard 和...
  • Activity状态转换和Activity栈

    千次阅读 2014-03-22 10:19:32
    Activity状态转换和Activity栈 一个Activity的启动顺序: onCreate()——>onStart()——>onResume()  当另一个Activity启动时:  第一个ActivityonPause()——>第二个ActivityonCreate()——>onStart()——>...
  • 查看Activity栈信息

    千次阅读 2016-01-09 19:17:08
    adb shell dumpsys activity activities | sed -En -e '/Running activities/,/Run #0/p' ➜ Downloads  adb -s T8DDU15204022902 shell dumpsys activity activities | sed -En -e '/Running ...
  • 之前的一篇文章中详细说明了Activity的生命周期,说明了Activity中的回调方法是如何被触发的。在用户使用App时,每一个 Activity 都处于某一个状态,对于...Activity栈每一个Activity的状态可以说都是由它所在的Acti
  • 系统Api :打开新的Activity 关闭之前所有ActivityIntent intent = new Intent(this, LoginActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); startActivity...

空空如也

1 2 3 4 5 ... 20
收藏数 48,399
精华内容 19,359
关键字:

activity栈