Activity的生命周期和启动模式



一、典型情况下生命周期分析


1、几个重要函数的含义:


onCreate和onDestroy分别标志着Activity的创建和销毁,只可能有一次调用。
onStart和onStop分别标志着Activity是否可见,随着用户的操作或者屏幕的点亮和熄灭,会被多次调用。
onResume和onPause分别标志着Activity是否在前台,随着用户的操作或者屏幕的点亮和熄灭,会被多次调用。


二、异常情况下的生命周期分析


1、情况1:资源相关的系统配置发生改变导致Activity被杀死并重新创建


在默认情况下,如果我们的Activity不做特殊处理,那么当系统配置发生改变后,Activity就会被销毁并重新创建。

注意点一:具体情况看上面的图就都明白了。
当Activity在异常情况下需要重新创建时,系统会默认为我们保存当前Activity的视图结构,并且在Activity重启后为我们恢复这些数据,
比如文本框中用户输入的数据、ListView滚动的位置等,这些View相关的状态系统都能够默认为我们恢复。
在onCreate中总是有这样的代码:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
其中的saveInstanceState参数是Bundle类型的,通过这个参数,Activity就可以判断是否被重建了,如果被重建了,那么我们就可以取出之间保存的数据并恢复。

具体针对某一个特定的View系统能为我们恢复哪些数据,我们可以查看View的源码。
和Activity一样,每个View都有onSaveInstanceState和onRestoreInstanceState这两个方法。

注意点二:关于保存和恢复View层次结构,系统的工作流程(委托思想):
(1)首先Activity被以外的终止时,Activity会调用onSaveInstanceState去保存数据。
(2)然后Activity会委托Window去保存数据,
(3)接着Window再委托它上面的顶级容器去保存数据。顶层容器是一个ViewGroup,一般来说它很可能是DecorView。
(4)最后顶层容器再去一一通知它的子元素来保存数据。

注意点三:下面以TextView的onSaveInstanceState来举例:
	/*
		当Activity发生异常情况时,进行数据保存,以便恢复数据。
		TextView保存了自己的文本选中状态和文本内容。
	*/
    @Override
    public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();

        // Save state if we are forced to
        boolean save = mFreezesText;
        int start = 0;
        int end = 0;

        if (mText != null) {
            start = getSelectionStart();
            end = getSelectionEnd();
            if (start >= 0 || end >= 0) {
                // Or save state if there is a selection
                save = true;
            }
        }

        if (save) {
            SavedState ss = new SavedState(superState);
            // XXX Should also save the current scroll position!
            ss.selStart = start;
            ss.selEnd = end;

            if (mText instanceof Spanned) {
                Spannable sp = new SpannableStringBuilder(mText);

                if (mEditor != null) {
                    removeMisspelledSpans(sp);
                    sp.removeSpan(mEditor.mSuggestionRangeSpan);
                }

                ss.text = sp;
            } else {
                ss.text = mText.toString();
            }

            if (isFocused() && start >= 0 && end >= 0) {
                ss.frozenWithFocus = true;
            }

            ss.error = getError();

            return ss;
        }

        return superState;
    }
	/*
		异常情况发生后,Activity重新启动,恢复由onSaveInstanceState方法保存的数据,
		主要是TextView的文本选中状态和文本内容。
	*/
    @Override
    public void onRestoreInstanceState(Parcelable state) {
        if (!(state instanceof SavedState)) {
            super.onRestoreInstanceState(state);
            return;
        }

        SavedState ss = (SavedState)state;
        super.onRestoreInstanceState(ss.getSuperState());

        // XXX restore buffer type too, as well as lots of other stuff
        if (ss.text != null) {
            setText(ss.text);
        }

        if (ss.selStart >= 0 && ss.selEnd >= 0) {
            if (mText instanceof Spannable) {
                int len = mText.length();

                if (ss.selStart > len || ss.selEnd > len) {
                    String restored = "";

                    if (ss.text != null) {
                        restored = "(restored) ";
                    }

                    Log.e(LOG_TAG, "Saved cursor position " + ss.selStart +
                          "/" + ss.selEnd + " out of range for " + restored +
                          "text " + mText);
                } else {
                    Selection.setSelection((Spannable) mText, ss.selStart, ss.selEnd);

                    if (ss.frozenWithFocus) {
                        createEditorIfNeeded();
                        mEditor.mFrozenWithFocus = true;
                    }
                }
            }
        }

        if (ss.error != null) {
            final CharSequence error = ss.error;
            // Display the error later, after the first layout pass
            post(new Runnable() {
                public void run() {
                    setError(error);
                }
            });
        }
    }

注意点四:这里就涉及到如何使用onSaveInstanceState和onRestoreInstanceState啦:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        /*
         * 有两种方式取出我们自定义的数据,第一种就是在onCreate中,
         * 这里是需要判断的,判断是否为异常情况。
         * */
        if(savedInstanceState != null){
        	String test = savedInstanceState.getString("extra_test");
        	Log.d(TAG, "[onCreate]retore extra_test: " + test);
        }
    }
    
    
    @Override
    protected void onSaveInstanceState(Bundle outState){
    	super.onSaveInstanceState(outState);
    	// 这里用于保存一些我们自定义的数据啊什么的。
    	// 只有异常情况下才会调用此函数,才会有这些数据的存在。
    	Log.d(TAG, "onSaveInstanceState");
    	outState.putString("extra_test", "test");
    }
    
    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState){
    	super.onRestoreInstanceState(savedInstanceState);
    	/*
    	 * 这是另一种取出我们自定义数据的方式,
    	 * 与onCreate不同是,onRestoreInstanceState方式是在异常情况发生后自动调用的,
    	 * 不需要像onCreate一样先检测,再取数据。
    	 * */
    	String test = savedInstanceState.getString("extra_test");
    	Log.d(TAG, "[onRestoreInstanceState]retore extra_test: " + test);
    }

注意点五:旧的Activity先onPause,然后新Activity再启动。
Activity的启动过程的源码相当复杂,涉及Instrumentation、ActivityThread和ActivityManagerService。启动Activity的请求会有Instrumentation来处理,然后它通过Binder向ActivityManagerService发请求,ActivityManagerService内部维护着一个ActivityStack并负责栈内的Activity的状态同步,ActivityManagerService通过ActivityThread去同步Activity的状态从而完成生命周期方法的调用。在ActivityStack中的resumeTopActivityInnerLocked方法中,在新Activity启动之前,栈顶的Activity需要先onPause后,新的Activity才能启动。最终,在ActivityStackSupervisor中的realStartActivityLocked方法会调用 app.thread.scheduleLaunchActivity方法。这个app.thread的类型是IApplicationThread,而IApplicationThread的具体实现是ActivityThread中的ApplicationThread。所以, 调用app.thread.scheduleLaunchActivity方法也就相当于调用了ActivityThread中的ApplicationThread的scheduleLaunchActivity方法,而scheduleLaunchActivity方法最终会完成新Activity的onCreate、onStart、onResume的调用过程。因此,onPause中不可以做重量级的操作,可以放在onStop中。


2、情况2:资源内存不足导致低优先级的Activity被杀死


注意点一:让我们先定义一下Activity的优先级:
(1)前台Activity——正在和用户交互的Activity,优先级最高。
(2)可见但非前台Activity——比如Activity中弹出了一个对话框,导致Activity可见,但是位于后台和用户无法直接交互。
(3)后台Activity——已经被暂停的Activity,比如执行了onStop,优先级最低。
如果一个进程中没有四大组件在执行,那么这个进程将很快被系统杀死。最好将后台工作放在Service中从而保证进程有一定的优先级,这样不容易被系统杀死。


3、情况3:如何能让Activity在系统配置发生改变后,Activity不重新创建


通过在Manifest中为Activity指定configChanges属性,这样Activity在系统配置发生改变的时候,Activity就不会重新创建,同时还会调用onConfigurationChanged方法。
地址链接: Manifest中


常用的是locale、orientation和keyboardHidden这三个选项,其他很少使用。

注意点一:虽然Activity并没有重启,但是该发生的变化还是会发生,该旋转的屏幕还是会旋转,该变化的locale还是会变化的。
注意点二:举例:
    <activity
   <span style="white-space:pre">		</span>android:name="com.test.example"
   <span style="white-space:pre">		</span>android:configChanges="orientation"
   <span style="white-space:pre">		</span>android:label="@string/app_name">
    </activity>
    @Override
    public void onConfigurationChanged(Configuration newConfig){
    	super.onConfigurationChanged(newConfig);
    	Log.d(TAG, "onConfigurationChanged, newOrientation:" + newConfig.orientation);
    }


三、Activity的4种启动模式


默认情况下,当我们多次启动同一个Activity的时候,系统会创建多个实例并把它们一一放入任务栈中,当我们单击back键,会发现这些Activity会一一回退。任务栈是一种“先进后出”的栈结构。当栈中无任何Activity的时候,系统就会回收这个任务栈。在android的多activity开发中,activity之间的跳转可能需要有多种方式,有时是普通的生成一个新实例,有时希望跳转到原来某个activity实例,而不是生成大量的重复的activity。加载模式便是决定以哪种方式启动一个跳转到原来某个Activity实例。

在android里,有4种activity的启动模式,分别为:

(1)standard: 标准模式,一调用startActivity()方法就会产生一个新的实例。每个实例也可以属于不同的任务栈,这种情况下,谁启动了这个Activity,那么这个Activity就运行在启动它的那个Activity所在的任务栈中。比如Activity A启动了Activity B,那么B就会进入到A所在的栈中。

(2)singleTop:栈顶复用模式, 来了intent, 每次都创建新的实例,仅一个例外:当栈顶的activity 恰恰就是该activity的实例(即需要创建的实例)时,不再创建新实例。这解决了栈顶复用问题。

(3)singleTask:栈内复用模式, 来了intent后,首先寻找是否存在该Activity需要的任务栈,如果不存在,就重新创建一个任务栈,然后创建Activity的实例后把Activity放到栈中。如果存在Activity所需的任务栈,这是要看Activity是否在栈中有实例存在,如果有实例存在,那么系统就会把Activity调到栈顶并调用它的onNewIntent方法,如果实例不存在,就创建Activity的实例并把Activity压入栈中。

注意点一:singleTask默认具有clearTop的效果,会导致栈内所有某个Activity上面的Activity全部出栈。

注意点二:什么是Activity所需的任务栈?这个问题与参数TaskAffinity有关,可以翻译为任务相关性。

这个参数标志了一个Activity所需要的任务栈的名字。默认情况下,所有Activity所需的任务栈的名字为应用的包名。我们是可以为每个Activity单独指定TaskAffinity名称的。

TaskAffinity属性主要和singleTask启动模式或者allowTaskReparenting属性配对使用,在其他情况下没有意义。

当TaskAffinity与singleTask启动模式配对使用的时候,它是具有该模式的Activity的目前任务栈的名字,待启动的Activity会运行在名字和TaskAffinity相同的任务栈中。

当TaskAffinity和allowTaskReparenting结合的时候,这种情况比较复杂,会产生特殊的效果。当一个应用A启动了应用B的某个Activity后,这个Activity是运行在A的任务栈中的。如果这个Activity的allowTaskReparenting属性为true的话,那么当应用B自己被启动后,这个Activity就会直接从应用A的任务栈转移到应用B的任务栈中。就是说这个Activity自己所需的任务栈如今创建了,它就要回归到自己的所需的任务栈中。是转移!!!

注意点三:任务栈分为前台任务栈和后台任务栈,后台任务栈中的Activity处于暂停状态,用户可以通过切换将后台任务栈再次调到前台,这个调到前台,是将一整个任务栈中的任务都调到前台了。

(4)singleInstance: 单实例模式,这个跟singleTask基本上是一样,只有一个区别:在这个模式下的Activity实例所处的task中,只能有这个activity实例,不能有其他的实例。也就是说,如果Activity的任务栈不存在,就创建一个新的,而且里面只会放置该Activity一个活动。一旦该模式的activity的实例已经存在于某个栈中,任何应用在激活该activity时都会重用该栈中的实例,解决了多个task共享一个activity。


注意点四:如何指定Activity的启动模式呢?

方法一:通过AndroidManifest为Activity指定launchMode启动模式:(无法直接为Activity设定FLAG_ACTIVITY_CLEAR_TOP标识)

<activity
	android:name="com.test.example"
	android:configChanges="screenLayout"
	android:launchMode="singleTask"
	android:label="@string/app_name"/>
方法二:通过在Intent中设置 标志位来为Activity指定启动模式:(优先级高于第一种方法)(无法为Activity指定singleInstance模式)
Intent intent = new Intent();
intent.setClass(MainActivity.this, SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);


四、Activity的Flags


核心的Intent Flag有:

FLAG_ACTIVITY_NEW_TASK:为Activity指定“singleTask”启动模式。
FLAG_ACTIVITY_CLEAR_TOP:当它启动时,在同一个任务栈中所有位于它上面的Activity都要出栈。通常和FLAG_ACTIVITY_NEW_TASK配合使用。不过singleTask通常都默认具有此标记的效果。但如果被启动的Activity采用standard模式启动,那么它连同它之上的Activity都要出栈,系统会创建新的Activity实例并放入栈顶。呵呵哒。
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED:

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS:具有这个标记的Activity不会出现在历史Act的列表中,当某些情况下我们不希望用户通过历史列表回到我们的Activity的时候这个标记比较有用。它等同于在XML中指定Activity的属性android:excludeFromRecents="true"。
FLAG_ACTIVITY_SINGLE_TOP:为Activity指定“singleTop”启动模式。

FLAG_ACTIVITY_BROUGHT_TO_FRONT :这个标志一般不是由程序代码设置的,如在launchMode中设置singleTask模式时系统帮你设定。
FLAG_ACTIVITY_CLEAR_TOP:如果设置,并且这个Activity已经在当前的Task中运行,因此,不再是重新启动一个这个Activity的实例,而是在这个Activity上方的所有Activity都将关闭,然后这个Intent会作为一个新的Intent投递到老的Activity(现在位于顶端)中。
    例如,假设一个Task中包含这些Activity:A,B,C,D。如果D调用了startActivity(),并且包含一个指向Activity B的Intent,那么,C和D都将结束,然后B接收到这个Intent,因此,目前stack的状况是:A,B。
    上例中正在运行的Activity B既可以在onNewIntent()中接收到这个新的Intent,也可以把自己关闭然后重新启动来接收这个Intent。如果它的启动模式声明为 “multiple”(默认值),并且你没有在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,那么它将关闭然后重新创建;对于其它的启动模式,或者在这个Intent中设置FLAG_ACTIVITY_SINGLE_TOP标志,都将把这个Intent投递到当前这个实例的onNewIntent()中。
    这个启动模式还可以与FLAG_ACTIVITY_NEW_TASK结合起来使用:用于启动一个Task中的根Activity,它会把那个Task中任何运行的实例带入前台,然后清除它直到根Activity。这非常有用,例如,当从Notification Manager处启动一个Activity。

FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
    如果设置,这将在Task的Activity stack中设置一个还原点,当Task恢复时,需要清理Activity。也就是说,下一次Task带着 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED标记进入前台时(典型的操作是用户在主画面重启它),这个Activity和它之上的都将关闭,以至于用户不能再返回到它们,但是可以回到之前的Activity。
    这在你的程序有分割点的时候很有用。例如,一个e-mail应用程序可能有一个操作是查看一个附件,需要启动图片浏览Activity来显示。这个 Activity应该作为e-mail应用程序Task的一部分,因为这是用户在这个Task中触发的操作。然而,当用户离开这个Task,然后从主画面选择e-mail app,我们可能希望回到查看的会话中,但不是查看图片附件,因为这让人困惑。通过在启动图片浏览时设定这个标志,浏览及其它启动的Activity在下次用户返回到mail程序时都将全部清除。

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
    如果设置,新的Activity不会在最近启动的Activity的列表中保存。

FLAG_ACTIVITY_FORWARD_RESULT
    如果设置,并且这个Intent用于从一个存在的Activity启动一个新的Activity,那么,这个作为答复目标的Activity将会传到这个新的Activity中。这种方式下,新的Activity可以调用setResult(int),并且这个结果值将发送给那个作为答复目标的 Activity。

FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY 
    这个标志一般不由应用程序代码设置,如果这个Activity是从历史记录里启动的(常按HOME键),那么,系统会帮你设定。

FLAG_ACTIVITY_MULTIPLE_TASK 
    不要使用这个标志,除非你自己实现了应用程序启动器。与FLAG_ACTIVITY_NEW_TASK结合起来使用,可以禁用把已存的Task送入前台的行为。当设置时,新的Task总是会启动来处理Intent,而不管这是是否已经有一个Task可以处理相同的事情。
    由于默认的系统不包含图形Task管理功能,因此,你不应该使用这个标志,除非你提供给用户一种方式可以返回到已经启动的Task。
    如果FLAG_ACTIVITY_NEW_TASK标志没有设置,这个标志被忽略。

FLAG_ACTIVITY_NEW_TASK 
    如果设置,这个Activity会成为历史stack中一个新Task的开始。一个Task(从启动它的Activity到下一个Task中的 Activity)定义了用户可以迁移的Activity原子组。Task可以移动到前台和后台;在某个特定Task中的所有Activity总是保持相同的次序。
    这个标志一般用于呈现“启动”类型的行为:它们提供用户一系列可以单独完成的事情,与启动它们的Activity完全无关。
    使用这个标志,如果正在启动的Activity的Task已经在运行的话,那么,新的Activity将不会启动;代替的,当前Task会简单的移入前台。参考FLAG_ACTIVITY_MULTIPLE_TASK标志,可以禁用这一行为。
    这个标志不能用于调用方对已经启动的Activity请求结果。

FLAG_ACTIVITY_NO_ANIMATION 
    如果在Intent中设置,并传递给Context.startActivity()的话,这个标志将阻止系统进入下一个Activity时应用 Acitivity迁移动画。这并不意味着动画将永不运行——如果另一个Activity在启动显示之前,没有指定这个标志,那么,动画将被应用。这个标志可以很好的用于执行一连串的操作,而动画被看作是更高一级的事件的驱动。

FLAG_ACTIVITY_NO_HISTORY 
    如果设置,新的Activity将不再历史stack中保留。用户一离开它,这个Activity就关闭了。这也可以通过设置noHistory特性。

FLAG_ACTIVITY_NO_USER_ACTION 
    如果设置,作为新启动的Activity进入前台时,这个标志将在Activity暂停之前阻止从最前方的Activity回调的onUserLeaveHint()。
    典型的,一个Activity可以依赖这个回调指明显式的用户动作引起的Activity移出后台。这个回调在Activity的生命周期中标记一个合适的点,并关闭一些Notification。
    如果一个Activity通过非用户驱动的事件,如来电或闹钟,启动的,这个标志也应该传递给Context.startActivity,保证暂停的Activity不认为用户已经知晓其Notification。

FLAG_ACTIVITY_PREVIOUS_IS_TOP 
    If set and this intent is being used to launch a new activity from an existing one, the current activity will not be counted as the top activity for deciding whether the new intent should be delivered to the top instead of starting a new one. The previous activity will be used as the top, with the assumption being that the current activity will finish itself immediately. 

FLAG_ACTIVITY_REORDER_TO_FRONT
    如果在Intent中设置,并传递给Context.startActivity(),这个标志将引发已经运行的Activity移动到历史stack的顶端。
    例如,假设一个Task由四个Activity组成:A,B,C,D。如果D调用startActivity()来启动Activity B,那么,B会移动到历史stack的顶端,现在的次序变成A,C,D,B。如果FLAG_ACTIVITY_CLEAR_TOP标志也设置的话,那么这个标志将被忽略。

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

If set, and this activity is either being started in a new task or bringing to the top an existing task, then it will be launched as the front door of the task. This will result in the application of any affinities needed to have that task in the proper state (either moving activities to or from it), or simply resetting that task to its initial state if needed. 

FLAG_ACTIVITY_SINGLE_TOP
    如果设置,当这个Activity位于历史stack的顶端运行时,不再启动一个新的。 

注意:如果是从BroadcastReceiver启动一个新的Activity,或者是从Service往一个Activity跳转时,不要忘记添加Intent的Flag为FLAG_ACTIVITY_NEW_TASK。


核心的特性有: 
taskAffinity 
launchMode 
allowTaskReparenting 
clearTaskOnLaunch 
alwaysRetainTaskState 
finishOnTaskLaunch

Activity在Activity栈(Task)中的加载顺序是可以控制的,这就需要用到Intent Flag



五、IntentFilter的匹配规则


1、IntentFilter中的过滤信息有action、category、data。三者需要同时匹配才行。


(1)一个过滤表中的action、category和data可以有多个,所有的action、category、data分别构成不同类别,同一类别的信息共同约束当前类别的匹配过程。
只有一个Intent同时匹配action、category、data三种类别才算完全匹配,只有完全匹配才能成功启动Activity。
(2)一个Activity中可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity。
(3)action匹配规则:action的匹配要求Intent中的action存在且必须和过滤规则中的其中一个action相同。
第一点:是一个字符串。
第二点:可以有多个action,只要Intent中的action能够和过滤规则中的任何一个action相同即可匹配成功。
第三点:但如果Intent没有指定action,就算匹配失败。
第四点:区分大小写。
(4)category匹配规则:要求Intent可以没有category,但是如果你一旦有category,不管有几个,每个都要能够和过滤郭泽中的任何一个category相同。
第一点:是一个字符串。
第二点:Intent中如果出现了category,不管有几个category,对于每个category来说,它必须是过滤规则中已经定义了的category。
第三点:Intent中可以没有category。
第四点:如果不设置category,系统在调用startActivity或者startActivityForResult的时候会默认为Intent加上“android.intent.category.DEFAULT ”这个category。所以为了我们的activity能够接收隐式调用,就必须在intent-filter中指定“android.intent.category.DEFAULT”这个category。
(5)data匹配规则:与action类似。要求Intent中必须有data数据,并且data数据能够完全匹配过滤规则中的某一个data。
这里的完全匹配指的是过滤规则中出现的data部分也出现在了Intent中的data中。
data的语法如下所示:
<data android:scheme="string"
	android:host="string"
	android:port="string"
	android:path="path"
	android:pathPattern="string"
	android:pathPrefix="string"
	android:mimeType="string" />
data由两部分组成:mimeType和URI。mimeType指媒体类型,比如image/jpeg/audio/mpeg4-generic和video/*等,可以表示图片、文本、视频等不同的媒体格式,而URI中包含的数据就比较多了,下面是URI的结构:
<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]
比如说:
content://com.example/project:200/folder/subfolder/etc
http://www.baicu.com:80/search/info
Scheme:URI的模式,比如http、file、content等,这个是必须指定的,否则无效。
Host:URI的主机名,比如www.baidu.com,这个也是必须指定的,否则无效。
Port:URI中的端口号,比如80。仅当URI中指定了scheme和host参数的时候port参数才是有意义的。
Path、pathPattern和pathPrefix:这三个参数表述路径信息,其中path表示完整的路径信息;pathPattern也表示完整的路径信息,但是它里面可以包含通配符“*”,“*”表示0个或多个任意字符。pathPrefix表示路径的前缀信息。
注意点一:过滤规则中如果没有指定URI,此时会有默认值,URI的默认值为content和file。
<intent-filter>
	<data android:mimeType="image/*" />
</intent-filter>
intent.setDataAndType(Uri.pares("file://abc"),"image/png");
data和type必须同时设定才行!!!
注意点二:如果有两组data规则,且每个data都指定了完整的属性值:
<intent-filter>
	<data android:mimeType="video/mpeg" android:scheme="http" ... />
	<data android:mimeType="audio/mpeg" android:scheme="http" ... />
	...
</intent-filter>
intent.setDataAndType(Uri.pares("http://abc"),"video/mpeg");
或者:
intent.setDataAndType(Uri.pares("http://abc"),"audio/mpeg");
注意点三:这是两种不同的写法,等价的。
<intent-filter>
	<data android:scheme="file" android:host="www.baidu.com" />
	...
</intent-filter>
<intent-filter>
	<data android:scheme="file" />
	<data android:host="www.baidu.com" />
	...
</intent-filter>










































1. Activity是一个应用程序组件, 提供用户与程序交互的界面。

2. Android的四大组件:

Activity

Service

BroadcastReceiver

Content Provider

3. Activity如何创建

继承Android的Activity类

重写方法

设置显示布局

在AndroidManifest文件中,注册Activity。


然后呢我们在项目的AndroidManifest文件中,可以看到注册Activity的信息:



4. Activity的生命周期:


对于Pause可能只是屏幕弹出一个小框Activity,失去焦点,

而Stop是整屏都跳转到另一个Activity。



5. Activity的四种状态:


6. Activity的生命周期:


package com.example.tenseven;


import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;


public class MainActivity extends Activity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
    
    @Override
    protected void onStart() {
         super.onStart();
    }
    
    @Override
    protected void onResume() {
         super.onResume();
    }
    
    @Override
    protected void onPause() {
        super.onPause();
    }
    
    @Override
    protected void onStop() {
         super.onStop();
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
    }


    @Override
    protected void onRestart() {
        super.onRestart();
    }
}
举例实验:在程序中添加Log日志输出。

package com.example.tenseven;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;

public class MainActivity extends Activity {

	final String TAG = "tag";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i(TAG, "MainActivity-->onCreate");
        // Log日志,第一个参数是标签,第二个参数是输出的内容。
    }
    
    @Override
    protected void onStart() {
    	// TODO Auto-generated method stub
    	super.onStart();
    	Log.i(TAG, "MainActivity-->onStart");
    }
    
    @Override
    protected void onResume() {
    	super.onResume();
    	Log.i(TAG, "MainActivity-->onResume");
    }
    
    @Override
    protected void onPause() {
    	super.onPause();
    	Log.i(TAG, "MainActivity-->onPause");
    }
    
    @Override
    protected void onStop() {
    	super.onStop();
    	Log.i(TAG, "MainActivity-->onStop");
    }
    
    @Override
    protected void onDestroy() {
      	super.onDestroy();
    	Log.i(TAG, "MainActivity-->onDestroy");
    }

    @Override
    protected void onRestart() {
    	super.onRestart();
    	Log.i(TAG, "MainActivity-->onRestart");
    }
}
在LogCat中根据我们设置的标签tag查看内容:

在创建过程中会先执行onCreate、onStart、onResume,在退出时会依次执行onPause、onStop、onDestroy。

7. 从启动到后台再到前台:

8. 从启动到失去焦点到再获得焦点:


如果项目中需要添加两个程序,那么可以直接在src下创建新的Activity,在res中添加布局,同时需要在AndroidManifest.xml文件中注册该新的Activity。

在注册时,添加下面这个属性,可以设置该Activity是一种dialog形式的半透明的窗口,这样的窗口会夺取当前Activity的焦点:


如果要设置一个Activity中点击按钮跳转到另一个Activity中,那么可以按照下面的方法来设置:


其中Second_Activity代表的是第二个Activity的名称,这里用Intent来实现跳转,然后MainActivity会失去焦点。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值