程序活动单元Activity

 
    
        Android四大组件分别为activity、service、content provider、broadcast receiver。
 
        Activity 类是 Android 应用的关键组件,而 Activity 的启动和组合方式则是该平台应用模型的基本组成部分。在编程范式中,应用是通过 main() 方法启动的,而 Android 系统与此不同,它会调用与其生命周期特定阶段相对应的特定回调方法来启动 Activity 实例中的代码。
 
4.0Activity 的概念
        移动应用体验与桌面体验的不同之处在于,用户与应用的互动并不总是在同一位置开始,而是经常以不确定的方式开始。例如,如果您从主屏幕打开电子邮件应用,可能会看到电子邮件列表,如果您通过社交媒体应用启动电子邮件应用,则可能会直接进入电子邮件应用的邮件撰写界面。
 
        Activity 类的目的就是促进这种范式的实现。当一个应用调用另一个应用时,调用方应用会调用另一个应用中的 Activity,而不是整个应用。通过这种方式,Activity 充当了应用与用户互动的入口点。您可以将 Activity 实现为 Activity 类的子类。
 
        Activity 提供窗口供应用在其中绘制界面。此窗口通常会填满屏幕,但也可能比屏幕小,并浮动在其他窗口上面。通常,一个 Activity 实现应用中的一个屏幕。例如,应用中的一个 Activity 实现“偏好设置”屏幕,而另一个 Activity 实现“选择照片”屏幕。
 
        大多数应用包含多个屏幕,这意味着它们包含多个 Activity。通常,应用中的一个 Activity 会被指定为主 Activity,这是用户启动应用时出现的第一个屏幕。然后,每个 Activity 可以启动另一个 Activity,以执行不同的操作。例如,一个简单的电子邮件应用中的主 Activity 可能会提供显示电子邮件收件箱的屏幕。主 Activity 可能会从该屏幕启动其他 Activity,以提供执行写邮件和打开邮件这类任务的屏幕。
 
        虽然应用中的各个 Activity 协同工作形成统一的用户体验,但每个 Activity 与其他 Activity 之间只存在松散的关联,应用内不同 Activity 之间的依赖关系通常很小。事实上,Activity 经常会启动属于其他应用的 Activity。例如,浏览器应用可能会启动社交媒体应用的“分享”Activity。
 
        
 
 
4.1Activity的生命周期
 
1.生命周期状态
启动状态:当Activity启动之后便会进入下一状态。
运行状态:Activity处于屏幕最前端,可与用户进行交互。
暂停状态:Activity仍然可见,但无法获取焦点,用户对他操作没有响应。
停止状态:Activity完全不可见,系统内存不足时会销毁该Activity。
销毁状态:Activity将被清理出内存。
注意:其中的启动状态和销毁状态为过渡期,不会在该时期停留
 
2.生命周期方法

第一次运行程序时调用的生命周期方法为: onCreate()→onStart()→onResume()。
退出程序时调用的生命周期方法为: onPause()→onStop0→onDestory()。
 
  • onCreate():
           您必须实现此回调,其在系统首次创建 Activity 时触发。Activity 会在创建后进入已创建状态。在 onCreate() 方法中,您需执行基本应用启动逻辑,该逻辑在 Activity 的整个生命周期中只应发生一次。例如,onCreate() 的实现可能会将数据绑定到列表,将 Activity 与 ViewModel 相关联,并实例化某些类范围变量。此方法接收 savedInstanceState 参数,后者是包含 Activity 先前保存状态的 Bundle 对象。如果 Activity 此前未曾存在,则 Bundle 对象的值为 null。
           如果您有一个具有生命周期感知能力的组件与您的 Activity 生命周期相关联,则该组件将收到 ON_CREATE 事件。系统将调用经过 @OnLifecycleEvent 注释的方法,以使您具有生命周期感知能力的组件可以执行已创建状态所需的任何设置代码。
 
  • onStart():
           当 Activity 进入“已开始”状态时,系统会调用此回调。onStart() 调用使 Activity 对用户可见,因为应用会为 Activity 进入前台并支持交互做准备。例如,应用通过此方法来初始化维护界面的代码。
           当 Activity 进入已开始状态时,与 Activity 生命周期相关联的所有具有生命周期感知能力的组件都将收到 ON_START 事件。
           onStart() 方法会非常快速地完成,并且与“已创建”状态一样,Activity 不会一直处于“已开始”状态。一旦此回调结束,Activity 便会进入已恢复状态,系统将调用 onResume() 方法。
     
  • onResume():
           Activity 会在进入“已恢复”状态时来到前台,然后系统调用 onResume() 回调。这是应用与用户交互的状态。应用会一直保持这种状态,直到某些事件发生,让焦点远离应用。此类事件包括接到来电、用户导航到另一个 Activity,或设备屏幕关闭。
            当 Activity 进入已恢复状态时,与 Activity 生命周期相关联的所有具有生命周期感知能力的组件都将收到 ON_RESUME 事件。这时,生命周期组件可以启动任何需要在组件可见,且位于前台时运行的功能,例如启动摄像头预览.
           当发生中断事件时,Activity 进入已暂停状态,系统调用 onPause() 回调。
           如果 Activity 从“已暂停”状态返回“已恢复”状态,系统将再次调用 onResume() 方法。因此,您应实现 onResume(),以初始化在 onPause() 期间释放的组件,并执行每次 Activity 进入“已恢复”状态时必须完成的任何其他初始化操作。
 
  • onPause():
           系统将此方法视为用户正在离开您的 Activity 的第一个标志(尽管这并不总是意味着活动正在遭到销毁);此方法表示 Activity 不再位于前台(尽管如果用户处于多窗口模式,Activity 仍然可见)。使用 onPause() 方法暂停或调整当 Activity 处于“已暂停”状态时不应继续(或应有节制地继续)的操作,以及您希望很快恢复的操作。Activity 进入此状态有多个原因,例如:
                  * 如 onResume() 部分所述,某个事件会中断应用执行。这是最常见的情况。
                  * 在 Android 7.0(API 级别 24)或更高版本中,有多个应用在多窗口模式下运行。无论何时,都只有一个应用(窗口)可以拥有焦点,因此系统会暂停所有其他应用。
                  * 有新的半透明 Activity(例如对话框)处于开启状态。只要 Activity 仍然部分可见但并未处于焦点之中,它便会一直暂停。
           当 Activity 进入已暂停状态时,与 Activity 生命周期相关联的所有具有生命周期感知能力的组件都将收到 ON_PAUSE 事件。这时,生命周期组件可以停止任何无需在组件未在前台时运行的功能,例如停止摄像头预览。
           您还可以使用 onPause() 方法释放系统资源、传感器(例如 GPS)手柄,或当您的 Activity 暂停且用户不需要它们时仍然可能影响电池续航时间的任何资源。然而,正如上文的 onResume() 部分所述,如果处于多窗口模式,则“已暂停”的 Activity 仍完全可见。因此,您应该考虑使用 onStop() 而非 onPause() 来完全释放或调整与界面相关的资源和操作,以便更好地支持多窗口模式。
     
  • onStop():
           如果您的 Activity 不再对用户可见,则说明其已进入已停止状态,因此系统将调用 onStop() 回调。举例而言,如果新启动的 Activity 覆盖整个屏幕,就可能会发生这种情况。如果系统已结束运行并即将终止,系统还可以调用 onStop()。
           当 Activity 进入已停止状态时,与 Activity 生命周期相关联的所有具有生命周期感知能力的组件都将收到 ON_STOP 事件。这时,生命周期组件可以停止任何无需在组件未在屏幕上可见时运行的功能。
           在 onStop() 方法中,应用应释放或调整应用对用户不可见时的无用资源。例如,应用可以暂停动画效果,或从细粒度位置更新切换到粗粒度位置更新。使用 onStop() 而非 onPause() 可确保与界面相关的工作继续进行,即使用户在多窗口模式下查看您的 Activity 也能如此。
           您还应该使用 onStop() 执行 CPU 相对密集的关闭操作。例如,如果您无法找到更合适的时机来将信息保存到数据库,则可在 onStop() 期间执行此操作。
 
  • onRestart():当处于“已停止”状态的 Activity 即将重启时,系统就会调用此回调。onRestart() 会从 Activity 停止时的状态恢复 Activity。
 
  • onDestroy():
           销毁 Ativity 之前,系统会先调用 onDestroy()。系统调用此回调的原因如下:
                  1. Activity 正在结束(由于用户彻底关闭 Activity 或由于系统为 Activity 调用 finish()),或者
                  2. 由于配置变更(例如设备旋转或多窗口模式),系统暂时销毁 Activity
           当 Activity 进入已销毁状态时,与 Activity 生命周期相关联的所有具有生命周期感知能力的组件都将收到 ON_DESTROY 事件。此时,生命周期组件可以在 Activity 遭到销毁之前清理所需的任何数据。
           您应使用 ViewModel 对象来容纳 Activity 的相关视图数据,而不是在您的 Activity 中加入逻辑来确定 Activity 遭到销毁的原因。如要由于配置变更而重新创建 Activity,则 ViewModel 不必执行任何操作,因为系统将保留 ViewModel 并将其提供给下一个 Activity 实例。如果不重新创建 Activity,ViewModel 将调用 onCleared() 方法,以便在 Activity 遭到销毁前清除所需的任何数据。
           您可以使用 isFinishing() 方法区分这两种情况。
           如果 Activity 正在结束,则 onDestroy() 是 Activity 收到的最后一个生命周期回调。如果由于配置变更而调用 onDestroy(),则系统会立即新建 Activity 实例,然后在新配置中为新实例调用 onCreate()。
           onDestroy() 回调应释放先前的回调(例如 onStop())尚未释放的所有资源。
 
 
 
3.脚下留心
手机横竖屏切换时,系统会根据AndroidManifest.xml文件中Activity的configChanges属性值的不同而调用相应的生命周期方法。
没有设置configChanges属性的值时:
  • 当由竖屏切换横屏时,调用的方法依次是onPause()、onStop() 、onDestory( 、onCreate() 、 onStart() 和onResume()的方法。
<activity android:name=".MainActivity" android:configChanges="orientationkeyboardHidden">
  • 打开程序时同样会调用onCreate()→onStart()→onResume( 方法,但是当进行横竖屏切换时不会再执行其他的生命周期方法。
如果希望某一个界面一直处于竖屏或者横屏状态,不随手机的晃动而改变,可以在清单文件中通过设置Activity的screenOrientation属性完成
  • 竖屏:android:screenOrientation="portrait"
  • 横屏: android:screenOrientation="landscape"
 
 
4.2Activity的创建配置和关闭
 
1.Activity的创建
右击包名→New→Activity→Empty Activity
 
2.配置Activity
包名处点击右键选择[New]→[JavaClass]选项,填写Java类名,完成创建。在该类中继承Activity
当启动该Activity时,会抛出RuntimeException异常信息:
 
要声明 Activity,请打开清单文件,并添加 <activity> 元素作为 <application> 元素的子元素。此元素唯一的必要属性是 android:name,该属性用于指定 Activity 的类名称
 
  • 在AndroidManifest.xml文件的<application> </application>标签中配置
    Activity :<activity android:name="cn.itcast.activitybasic.SecondActivity" />
 
  • 如果Activity所在的包与AndroidManifest.xml文件的<manifest></manifest>标签中通过package属性指定的包名一致则android:name属性的值可以直接设置为“.Activity名称”。
    <activity android:name=".SecondActivity"></activity>
 
注意:发布应用后,就不应再更改 Activity 名称,否则可能会破坏某些功能,例如应用快捷方式。
 
 
 
3.开启和关闭Activity
开启Activity :startActivity)
  • 在MainActivity的onCreate()方法中启动SecondActivity 
    Intent intent = new Intent(MainActivity.this,SecondActivity.class);
        startActivity(intent);
 
关闭Activity :finish()
 
 
4.3Intent与IntentFilter
 
1.声明 intent 过滤器
 
Intent被称为意图,是程序中各组件进行交互的一-种重要方式,他不仅可以指定当前组件要执行的动作,还可以在不同组件之间进行数据传递。
 
一般用于启动Activity、Service 以及发送广播等。根据开启目标组件的方式不同,Intent被分为两种类型显示意图隐式意图
  • 显式意图可以直接通过名称开启指定的目标组件
  • 隐式意图通过指定action和category等属性,系统根据这些信息进行分析后寻找目标Activity
Intent intent = new Intent(MainActivity.this,SecondActivity.class);    
//创建一个Intent对象,其中第1个参数为Context表示当前的Activity对象第2个参数表示要启动的目标Activity。
startActivity(intent);    //调用Activity的startActivity方法启动目标组件

 

        Intent 过滤器是 Android 平台的一项非常强大的功能。借助这项功能,您不但可以根据显式请求启动 Activity,还可以根据隐式请求启动 Activity。例如,显式请求可能会告诉系统“在 Gmail 应用中启动‘发送电子邮件’Activity”,而隐式请求可能会告诉系统“在任何能够完成此工作的 Activity 中启动‘发送电子邮件’屏幕”。当系统界面询问用户使用哪个应用来执行任务时,这就是 intent 过滤器在起作用。
 
        要使用此功能,您需要在 <activity> 元素中声明 <intent-filter> 属性。此元素的定义包括 <action> 元素,以及可选的 <category> 元素和/或 <data> 元素。这些元素组合在一起,可以指定 Activity 能够响应的 intent 类型。例如,以下代码段展示了如何配置一个发送文本数据并接收其他 Activity 的文本数据发送请求的 Activity:
    <activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
        <intent-filter>
            <action android:name="android.intent.action.SEND" />    //设置action动作,当代码中的action与该action相匹配时启动该组件。
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
    </activity>
  • 当发送一个隐式Intent后,Android系统会将他与程序中的每一个组件的过滤器进行匹配,匹配属性有action、data 、category ,需要这三个属性都匹配成功才能唤起相应的组件。

  • action:用于指定Intent对象的动作。    

    只要Intent携带的action与其中一个<intent- filter>标签中action的声明相同action属性就匹配成功。

<intent-filter>
<action android:name="android.intent.action.EDIT"/>
<action android:name="android.intent. action. VIEW"/>
......
</intent-filter>
  • data:指定数据的URI或者数据MIME类型他的值通常与Intent的action属性有关联。

隐式Intent携带的data数据只要与IntentFilter中的任意一个data声明相同data属性就匹配成功。

<intent-filter>
<data android:mimeType="video/mpeg" android:schemex=ht..."/>
<data android:mimeType="audio/mpeg" android:scheme="tt..."/>
...
</intent-filter>
  • category:用于为action添加额外信息。

一个IntentFilter可以不声明category属性,也可以声明多个category属性。

隐式Intent中声明的category必须全部能够与某- -个IntentFilter中的category匹配才算匹配成功

<intent-filter>
<category android:name=" android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>

注意: IntentFilter 中罗列的category属性数量必须大于或者等于隐式Intent携带的category属性数量时,category 属性才能匹配成功。如果一个隐式Intent没有设置category属性,那么他可以通过任何一个IntentFilter (过滤器) 的category匹配。

 

 

示例:

    <activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
        <intent-filter>
            <action android:name="android.intent.action.SEND" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
    </activity>

在此示例中,<action> 元素指定该 Activity 会发送数据。将 <category> 元素声明为 DEFAULT 可使 Activity 能够接收启动请求。<data> 元素指定此 Activity 可以发送的数据类型。以下代码段展示了如何调用上述 Activity:

    // Create the text message with a string
    Intent sendIntent = new Intent();
    sendIntent.setAction(Intent.ACTION_SEND);
    sendIntent.setType("text/plain");
    sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
    // Start the activity
    startActivity(sendIntent);
4.4Activity之间的跳转
 
1.数据传递
a、方式一:通过intent传递属性
①MainActivity设置intent
Intent intent =new Intent(MainActivity.this,SecondActivity.class);  //设置跳转Activity
intent.putExtra("studentName","小明");    //设置传递属性
intent.putExtra("age","25");
startActivity(intent);      //启动意图

②SecondActivity获取intent

setContentView(R.layout.activity_second);
Intent intent = getIntent();    //获取intent
String studentName = intent.getStringExtra("studentName");    //获取intent属性
String age = intent.getStringExtra("age");
Toast.makeText(SecondActivity.this,"姓名:"+studentName+"\n年龄:"+age,Toast.LENGTH_SHORT).show();

 

 
b、方式二:使用Bundle传递
①MainActivity设置bundle
 
Intent intent =new Intent(MainActivity.this,SecondActivity.class);  //设置跳转Activity
Bundle bundle = new Bundle();
bundle.putString("studentName","小红花");
intent.putExtras(bundle);
startActivity(intent);      //启动意图

②SecondActivity获取bundle

Intent intent = getIntent();    //获取intent
Bundle bundle = intent.getExtras();
String studentName1 = bundle.getString("studentName");
Toast.makeText(SecondActivity.this,"姓名:"+studentName1,Toast.LENGTH_SHORT).show();

2.数据回传

①MainActivity设置intent

Intent intent2 = new Intent(MainActivity.this,ThirdActivity.class);
startActivityForResult(intent2,1);      // 使用startActivityForResult方法开启SecondActivity,第1个参数是Intent对象,第2个参数是请求码,用于标识请求的来源。

②ThirdActivity获取intent

Intent intent = new Intent();
intent.putExtra("data","hello MainActivity");
setResult(2,intent);    // 在SecondActivity 中添加返回数据。
finish();

③MainActivity接收回传数据

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode==1 && resultCode == 2){
        String result = data.getStringExtra("data");
        Toast.makeText(MainActivity.this,result,Toast.LENGTH_SHORT).show();
    }
}
 
 
4.5Activity的任务栈和启动模式
 
1.Android中的任务栈
任务栈:一种用来存放Activity实例的容器。
特点:先进先出
操作:压栈和出栈
 

 
 
 
2.Activity的启动模式
①standard模式:standard模式是Activity的默认启动方式,每启动一个Activity就会在栈顶创建一个新的实例。

 
②singleTop模式:singleTop模式会判断要启动的Activity实例是否位于栈顶,如果位于栈顶则直接复用,否则创建新的实例。

 
③singleTask模式:singleTask模式下每次启动该Activity时,系统首先会检查栈中是否存在当前Activity实例,如果存在则直接使用,并把当前Activity之上的所有实例全部出栈。

 
④singleInstance模式:singleInstance模式会启动一个新的任务栈来管理Activity实例,无论从哪个任务栈中启动该Activity,该实例在整个系统中只有一个。

 
 
4.6使用Fragment
 
1.fragment简介
Fragment(碎片)是一种可以嵌入在Activity中的UI片段,它可以用来描述Activity中的一部分布局。

            

 
 
2.生命周期
  • Fragment不能独立存在,必须嵌入到Activity中使用,所以Fragment生命周期直接受所在的Activity影响。
  • 当在Activity中创建Fragment时,Fragment处于启动状态,当Activity被暂停时,其中的所有Fragment也被暂停,当Activity被销毁时,所有在该Activity中的Fragment也被销毁。当一个Activity处于运行状态时,可以单独地对每一个Fragment进行操作,如添加或删除,当添加时,Fragment处于启动状态。当删除时,Fragment处于销毁状态。

 
3.创建Fragment
 
 
public class NewsListFragment extends Fragment{
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
         View v = inflater.inflate(R.layout.fragment, container, false);   
//第一个参数表示Fragment对应的布局资源ID,第二个参数表示存放Fragment布局的ViewGroup, 第三个参数表示是否在创建Fragment的布局时附加到ViewGroup上。
         return v;
     }
 }

 

        注意:Android系统中提供了两个Fragment类,分别是android.app.Fragment和android.support.v4.app.Fragment。如果NewsListFragment类继承的是android.app.Fragment类,则程序只能兼容3.0版本以上的Android系统,如果NewsListFragment类继承的是android.support.v4.app.Fragment类,则程序可以兼容1.6版本以上的Android系统。

 

 

4.在Activity中添加Fragment

        在Activity中使用Fragment时,可以通过两种方式将Fragment添加到Activity中,一种是通过布局文件添加,一种是通过代码动态添加。

 

① 在自定义布局中添加Fragment

    <fragment
        android:name="cn.itcast.NewsListFragment"    //自定义Fragment的完整路径
         android:id="@+id/newslist"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
    </fragment>

②在代码中动态添加

在Activity中动态添加Fragment的步骤创建需要创建一个Fragment的实例对象。

a) 获取FragmentManager(Fragment管理器)的实例。 

b) 开启FragmentTransaction(事务)。 

c) 向Activity的布局容器(一般为FrameLayout)中添加Fragment。

d) 通过commit()方法提交事务。

NewsListFragment fragment = new NewsListFragment();    //实例化Fragment对象
FragmentManager fm = getFragmentManager();         //获取FragmentManager实例
FragmentTransaction beginTransaction = fm.beginTransaction();     //开启事务
beginTransaction.replace(R.id.ll,fragment);      //添加Fragment
beginTransaction.commit();    //提交事务

 

 
 
 
 
 
 
 
 
 
 
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章