zoukankan      html  css  js  c++  java
  • Activity

    一:Android的启动模式

      activity

    供用户操作的界面

    描述:

    1)表示用户交互的一个界面(活动),每一个activity对应一个界面

    2)是所有View的容器:button,textview,imageview;我们在界面上看到的都是一个个的view

    3)有个ActivityManager的管理服务类,用于维护与管理Activity的启动与销毁;

    Activity启动时,会把Activity的引用放入任务栈中

    4)一个应用程序可以被别的应用程序的activity开启

           此时,是将此应用程序的引用加入到了开启的那个activity的任务栈中了

    5) activity是运行在自己的程序进程里面的

           在一个应用程序中,可以申请单独的进程,然此应用程序中的一个组件在新的进程中运行

    6)可以在activity里面添加permission标签,调用者必须加入这个权限

           与钱打交道的界面,都不允许被其他应用程序随意打开

    如果觉得那个activity比较重要,可以在清单文件中配置,防止别人随意打开,需要配置一个权限

    1、创建Activity

    1)定义类继承自Activity类;

    2)在清单文件中Application节点中声明<activity>节点;

           <activity

                android:name="com.itheima.activity.MainActivity"

                android:label="@string/app_name" >

                <!-- 程序的入口,LAUNCHER表示桌面快捷方式,进入的是此Activity -->

                <intent-filter>

                    <action android:name="android.intent.action.MAIN" />

                    <category android:name="android.intent.category.LAUNCHER" />  <!—启动时,默认匹配 --

                </intent-filter>

            </activity>

     

    2、启动Activity

    通过意图(Intent)来启动一个Activity;

    1)  显示启动:

    显示启动一般用于自己调用自己的情况(在当前应用找),这样的启动方式比较快速,创建Intent后指定包名和类名;

           Intent intent = new Intent(this, OtherActivity.class);

           startActivity(intent);             // 启动新的Activity

           或者:

           Intent intent = new Intent();

           intent.setClassName("com.itheima.activity", "com.itheima.activity.OtherActivity"); // 包名、全类名

           startActivity(intent);             // 启动新的Activity

    2)隐式启动:

    一般用于调用别人的Activity,创建Intent后指定动作和数据以及类型;

           // 电话

           Intent intent = new Intent();

           intent.setAction(Intent.ACTION_CALL);                                        // 设置动作

           intent.setData(Uri.parse("tel://123456"));                                 // 设置数据

           // 网页

           intent.setAction(Intent.ACTION_VIEW);

           intent.setData(Uri.parse("http://192.168.1.45:8080/androidWeb"));

           // 音频/视频,设置type

           intent.setAction(Intent.ACTION_VIEW);

           intent.setDataAndType(Uri.parse("file:///mnt/sdcard/daqin.mp3"), "audio/*");  // 设置数据和数据类型,将启动音频播放器(vedio)

    3)为隐式启动配置意图过滤器:

      n  显式意图是指在创建意图时指定了组件,而隐式意图则不指定组件,通过动作、类型、数据匹配对应的组件;

      n  在清单文件中定义<activity>时需要定义<intent-filter>才能被隐式意图启动;

      n  <intent-filter>中至少配置一个<action>和一个<category>,否则无法被启动;

      n  Intent对象中设置的action、category、data在<intent-filter>必须全部包含Activity才能启动;

      n  <intent-filter>中的<action>、<category>、<data>都可以配置多个,Intent对象中不用全部匹配,每样匹配一个即可启动;

      n  如果一个意图可以匹配多个Activity,Android系统会提示选择;

             <!-- 注册 Activity, lable 表示Activity的标题 -->

            <activity

                android:name="com.itheima.activity.OtherActivity"

                android:label="OtherActivity" >

                <!-- 配置隐式意图,匹配http -->

                <intent-filter>

                    <action android:name="android.intent.action.VIEW" />           <!—必须,表示动作为View -->

                    <data android:scheme="http" />                                             <!—http开头-->                             

                    <category android:name="android.intent.category.DEFAULT" /> <!-- 必须,表示启动时,默认匹配 -->

                </intent-filter>

                <!-- 匹配tel -->

                 <intent-filter>

                    <action android:name="android.intent.action.CALL" />                  

                    <data android:scheme="tel" />                                                                                

                    <category android:name="android.intent.category.DEFAULT" /> <!-- 必须,表示启动 -->

                </intent-filter>

                <!-- 匹配 音频、视频 -->

                <intent-filter>

                    <action android:name="android.intent.action.VIEW" />                   

                    <data android:scheme="file" android:mimeType="audio/*" />   <!—文件协议l类型 -->                                                                         

                    <data android:scheme="file" android:mimeType="video/*" />                

                    <category android:name="android.intent.category.DEFAULT" /> <!-- 必须,表示启动 -->                                                       

                </intent-filter>

         </activity>

     

    3、启动时传递数据

    可通过意图Intent对象实现Activity之间的数据传递;

    使用Intent.putExtra()方法装入一些数据, 被启动的Activity可在 onCreate方法中getIntent()获取;

    可传输的数据类型: a.基本数据类型(数组),  b. String(数组),  c. Bundle(Map),  d. Serializable(Bean), e.Parcelable(放在内存一个共享空间里);

    基本类型:

           Intent intent = new Intent(this, OtherActivity.class);

           intent.putExtra("name", "张飞");         // 携带数据

           intent.putExtra("age", 12);

           startActivity(intent);

    一捆数据:

           Intent intent = new Intent(this, OtherActivity.class);

           Bundle b1 = new Bundle();

           b1.putString("name", "赵云");

           b1.putInt("age", 25);

           Bundle b2 = new Bundle();

           b2.putString("name", "关羽");

           b2.putInt("age", 44);

           intent.putExtra("b1", b1);

           intent.putExtra("b2", b2);

    序列化对象(须实现序列化接口):

           Intent intent = new Intent(this, OtherActivity.class);

           Person p = new Person("张辽", 44);

           intent.putExtra("p", p);

    接收数据:

           在OtherActivity 的onCreate()方法,通过 getIntent().get 相关的数据的方法来获取数据;

     

    4、关闭时返回数据

    基本流程:

    l 使用startActivityForResult(Intent intent, int requestCode) 方法打开Activity;

    l 重写onActivityResult(int requestCode, int resultCode, Intent data) 方法;

    l 新Activity中调用setResult(int resultCode, Intent data) 设置返回数据之后,关闭Activity就会调用上面的onActivityResult方法;

    注意:新的Activity的启动模式不能设置成 singleTask(如果已创建,会使用以前创建的)与singleInstance(单例,单独的任务栈),

             不能被摧毁(执行不到finish方法),父Activity中的 onActivityResult方法将不会执行;

    finish():表示关闭当前Activity,会调用onDestroy方法;

    Activity_A:

           public void openActivityB(View v) {

                  Intent intent = new Intent(this, Activity_B.class);

                  Person p = new Person("张辽", 44);

                  intent.putExtra("p", p);

                  startActivityForResult(intent, 100);                                         // 此方法,启动新的Activity,等待返回结果, 结果一旦返回,自动执行onActivityResult()方法

           }

           protected void onActivityResult(int requestCode, int resultCode, Intent data) {

                  if(data == null) {                                                           // 没有数据,不执行

                         return;

                  }

                  System.out.println(requestCode + ", " + resultCode);         // code 可用来区分,哪里返回的数据

                  String name = data.getStringExtra("name");

                  int age = data.getIntExtra("age", -1);

           }

    Activity_B:

           public void close(View v) {

                  // == 关闭当前Activity时,设置返回的数据 ==

                  Intent intent = new Intent();

                  intent.putExtra("name", "典韦");

                  intent.putExtra("age", 55);

                  setResult(200, intent);   

                  finish();                        // 关闭,类似于点击了后退

           }

     

    5、生命周期

    1)Acitivity三种状态

    1. 运行:activity在最前端运行;
    2. 停止:activity不可见,完全被覆盖;
    3. 暂停:activity可见,但前端还有其他activity<>,注意:在当前Activitiiy弹出的对话框是Activity的一部分,弹出时,不会执行onPause方法;

    2)生命周期相关的方法(都是系统自动调用,都以 on 开头):

    1. onCreate:      创建时调用,或者程序在暂停、停止状态下被杀死之后重新打开时也会调用;
    2. onStart:                   onCreate之后或者从停止状态恢复时调用;                                                            
    3. onResume:   onStart之后或者从暂停状态恢复时调用,从停止状态恢复时由于调用onStart,也会调用onResume(界面获得焦点);
    4. onPause:       进入暂停、停止状态,或者销毁时会调用(界面失去焦点);
    5. onStop:          进入停止状态,或者销毁时会调用;
    6. onDestroy:    销毁时调用;
    7. onRestart:    从停止状态恢复时调用;

    3)生命周期图解:

     

           应用启动时,执行onCreate onStart onResume,退出时执行:onPause onStop onDestroy;

     

    6、横竖屏切换与信息的保存恢复

    切换横竖屏时,会自动查找layout-port 、layout-land中的布局文件,默认情况下,

    切换时,将执行摧毁onPause onStop onDestroy,再重置加载新的布局onCreate onStart onResume;

    切换时如果要保存数据, 可以重写: onSaveInstanceState();

    恢复数据时, 重写: onRestoreInstanceState();

    è固定横屏或竖屏:                                  android:screenOrientation="landscape"

    è横竖屏切换, 不摧毁界面(程序继续执行) android:configChanges="orientation|keyboardHidden|screenSize"

    保存信息状态的相关方法:

    1. onSaveInstanceState:    

    在Activity被动的摧毁或停止的时候调用(如横竖屏切换,来电),用于保存运行数据,可以将数据存在在Bundle中;

    1. onRestoreInstanceState:

    该方法在Activity被重新绘制的时候调用,例如改变屏幕方向,onSavedInstanceState可为onSaveInstanceState保存的数据

    7、启动模式

    1)任务栈的概念

    问:一个手机里面有多少个任务栈?

    答:一般情况下,有多少个应用正在运行,就对应开启多少个任务栈;  

           一般情况下,每开启一个应用程序就会创建一个与之对应的任务栈;

           二般情况下,如launchMode为 singleInstance,就创建自己单独的任务栈;

    2)任务栈的作用:

    它是存放Activity的引用的,Activity不同的启动模式,对应不同的任务栈的存放;

    可通过getTaskId()来获取任务栈的ID,如果前面的任务栈已经清空,新开的任务栈ID+1,是自动增长的;

    3)启动模式:

    在AndroidManifest.xml中的<activity>标签中可以配置android:launchMode属性,用来控制Actvity的启动模式;

    在Android系统中我们创建的Acitivity是以栈的形式呈现的:

    ①、standard:默认的,每次调用startActivity()启动时都会创建一个新的Activity放在栈顶;

    ②、singleTop:启动Activity时,指定Activity不在任务栈栈顶就创建,如在栈顶,则不会创建,会调用onNewInstance(),复用已经存在的实例

    ③、singleTask:在任务栈里面只允许一个实例,如果启动的Activity不存在就创建,如果存在直接跳转到指定的Activity所在位置,

                         如:栈内有ABCD,D想创建A, 即A上的BCD相应的Activity将移除;

    ④、singleInstance:(单例)开启一个新的任务栈来存放这个Activity的实例在整个手机操作系统里面只有一个该任务栈的实例存在,此模式开启的Activity是运行在自己单独的任务栈中的

     

    4)应用程序、进程、任务栈的区别

    ①、应用程序:

    四大组件的集合

    在清单文件中都放在application节点下

    对于终端用户而言,会将其理解为activity

    ②、进程:

    操作系统分配的独立的内存空间,一般情况下,一个应用程序会对应一个进程,特殊情况下,会有多个进程

    一个应用程序会对应一个或多个进程

    ③、任务栈:task stack(back stack)后退栈

           记录用户的操作步骤,维护用户的操作体验,

           专门针对于activity而言的,只用于activity

           一般使用standard,其他情况用别的

     

    5)启动模式的演示

    1、创建两个activity,布局中设置两个按钮,分别开启两个activity

    第一、standard启动模式的:开启几个就会在任务栈中存在几个任务

    01和02都是存在于一个任务栈中的

      

    第二、在清单文件中将02的启动模式改为singletop,

    此时02处于栈顶,就只会创建一个02的任务,再开启02,也不会创建新的

     

    第三、将02的启动模式改为singletask

           如果02上面有其他任务栈,就会将其他的清除掉,利用这个已经创建的02

           当开启02的时候,即先将01清除,然后利用下面的02

     

    第四、将02的启动模式改为singleinstance

           可以通过打印任务栈的id(调用getTaskId()方法)得知,两个activity不在同一个任务栈中

    若先开启三个01,在开启02,任务栈如图:

     

    再开启01,任务栈的示意图如下:

     

    此时按返回键,会先一层一层清空01,最后再清空02

    空进程:任务栈清空,意味着程序退出了,但进程留着,这个就是空进程,容易被系统回收;

    8、内存管理

           Android系统在运行多个进程时,如果系统资源不足,会强制结束一些进程,优先选择哪个进程来结束是有优先级的。

      会按照以下顺序杀死:

        ①、空:  进程中没有任何组件;

        ②、后台:进程中只有停止状态的Activity;

        ③、服务:进程中有正在运行的服务;

        ④、可见:进程中有一个暂停状态的Activity;

        ⑤、前台:进程中正在运行一个Activity;

      Activity在退出的时候进程不会销毁, 会保留一个空进程方便以后启动. 但在内存不足时进程会被销毁;

      Activity中不要在Activity做耗时的操作, 因为Activity切换到后台之后(Activity停止了), 内存不足时, 也容易被销毁;

     9.Content的startActivity方法需添加FLAG_ACTIVITY_NEW_TASK flag

      BootBroadcastReceiver继承自Android.content.BroadcastReceiver

    1. public void onReceive(Context context, Intent intent) {  
    2.     ……  
    3.     Intent startTaobao = new Intent(context, Start.class);  
    4.     startTaobao.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
    5.     context.startActivity(startTaobao);  
    6.     ……  

    10.Activity的启动与生命周期的监控(分析原码)

      应用程序被开启后,是需要开启并创建Activity,加载相应的view,从而展示出应用程序

      1、Activity是通过startActivity开启起来的,startActivity是由有Context调用的,其具体的实现类是ContextImpl

        在ContextImpl中的startActivity方法中,会调用ActivityThread的相关方法【mMainThread.getInstrumentation().execStartActivity()】;可以追溯到Instrumentation这个类,其中的execStartActivity()的方    法中实现了startActivity的调用:ActivityManagerNative.getDefault().startActivity,由此可以看出是底层进行处理。

      2、ActivityMonitor监控Activity

        当Activity实例创建的时候,就会给Activity配置一个监视器ActivityMonitor,监控Activity的声明周期:

        在Instrumentation的execStartActivity()的方法中,上来先判断ActivityMonitor是否为null:在第一次开启Activity的时候,ActivityMonitor还是null的,就会调用                        ActivityManagerNative.getDefault().startActivity(…..),是在操作native底层的信息,从而执行startActivity,再去开启一个Activity。

        简单来说,就是通过调用JNI,调用startActivity方法,开启Activity;创建好了之后,随即也创建好了Activity的监视器ActivityMonitor

      3、在ActivityMonitor中就有Activity各种生命周期的监控

        ①、在newActivity方法中:

          可以通过拿到Activity的字节码,创建一个Activity,并将这个Activity返回

               还会调用attach方法,传入ActivityThread的线程

        ②、在各种生命周期的方法中,调用activity的各自的生命周期的方法

      总结:

           1、通过PackageManagerService将所有用到的资源加载进内存中

           2、在Launcher中,将view等控件加载到ViewGroup中,点击每个item会有相应的操作

           3、在公开的文档中是找不到具体调用startActivity的类的,而是由系统完成调用的,实现了Activity的启动

        实际就是通过Context的实现类ContextImpl进行调用的,一步步转到底层(ActivityManagerNative)实现调用

           4、另一个重要的类就是ActivityMonitor,监控Activity生命周期的;在其newActivity方法中创建了Activity,并调用了attach方法;

        也就是说当一个Activity被创建的时候,就会绑定一个ActivityMonitor,用来监控Activity的生命周期

  • 相关阅读:
    Chrome插件开发,美化网页上的文件列表。chrome-extension,background
    Chrome插件开发,美化网页上的文件列表。chrome-extension,content-scripts
    ASP.NET MVC 常用扩展点:过滤器、模型绑定等
    Windows下Redis缓存服务器的使用 .NET StackExchange.Redis Redis Desktop Manager
    企业号微信支付 公众号支付 H5调起支付API示例代码 JSSDK C# .NET
    分享一个html+js+ashx+easyui+ado.net权限管理系统
    ASP.NET MVC Filters 4种默认过滤器的使用【附示例】
    ASP.NET MVC Controllers and Actions
    玩转控件:Fucking ERP之流程图
    玩转控件:对Dev的GridControl控件扩展
  • 原文地址:https://www.cnblogs.com/dubo-/p/6676079.html
Copyright © 2011-2022 走看看