Android之Activity和Intent

来源:互联网 发布:zknu教务网络管理系统 编辑:程序博客网 时间:2024/06/11 14:50

Android四大组件之一

主要用于与用户进行交互,在一个App中可能存在零个或多个Activity

 

1.1    Activity的创建

Activity创建:

         创建的步骤:

1)  定义一个类,继承自Activity

2)  在清单文件中进行注册(先注册,后使用)

Android的四大组件都必须要在清单文件中进行注册

 

思考:

1)  当在AndroidManifest.xml清单文件中,如果不设置默认启动页,会报错吗?

答:不会报错,但是App就没有启动页面

 

2)  当在AndroidManifest.xml清单文件中,设置多个页面都是默认启动页,会报错吗?如果不报错,到底是执行哪个页面呢?

答:不会报错,如果设置了多个启动页面,那么在程序图标的列表中就会生成多个启动图标,     点击不同的启动图标都可以开启应用程序,进入对应的页面。        

 

 

1.2    Activity的启动和关闭

Acitivity的启动

        需要使用到Intent类,Intent不是Android四大组件之一,Intent,意图,主要用于Android三大组件之间的通讯,是三大组件的桥梁。

         PS: 这里的三大组件是ActivityServiceBroadcastReceiver

 

Activity的关闭

1)  finnish方法

2)点击返回按钮(返回按钮的点击事件默认就是关闭当前的Activity,这个点击事件是可以修改的。

1.3    Intent意图

1.3.1  概念

Context.startActivity(Intent)

一个Android应用程序可以包含零或多个Activity,当应用程序具有多个Activity时,就可能需要从一个Activity跳转到另一个Activity。在Android中,Activity之间的导航是通过Intent(意图)来完成

Intent并不是Andorid应用的组件,但它是各组件之间通信的载体

Intent不仅仅可以用于同一个App内来传递“意图”,也可以跨App

==Context,上下文环境(在这里就是指应用程序环境,封装了当前应用程序的一些相关信息)

 

1.3.2  显示意图

显示意图:需要明确指定需要启动的组件名称

new Intent(Context, Class)

intent.setClass(Context, Class)

intent.setClassName(Context, StringclassName)

intent.setClassName(String packageName,String className)

intent.setComponent(ComponentNamecomponent)

应用场景:开启自己应用程序内部的界面,效率较高

         intent.setClass(this,SecondActivity.class);

         startActivity(intent);

 

1.3.3  显示意图示例

         // 显示意图的演示,需要明确指定开启的组件的类名

         public void open03(View v) {

                   // 如果使用的是显示意图,那么启动组件的时候就不会去使用意图过滤器过滤

                   Intent intent = newIntent();

                   // 设置组件的信息

                   // 这里要注意:设置组件信息的api有很多,其实都是大同小异的

                   // intent.setClass(this, SecondActivity.class);

                   // intent.setClassName(this,"com.example.day06.activitybasic.SecondActivity");

         // intent.setClassName(this.getPackageName(),"com.example.day06.activitybasic.SecondActivity");

                   ComponentName component = new ComponentName(this, SecondActivity.class);

                   intent.setComponent(component);

                   startActivity(intent);

         }

1.3.4  隐式意图

隐式意图不需要明确指定需要启动的组件的名称,只需要给定启动的组件的相关信息

                   所谓的相关系,比如:打电话、上网、发邮件

                   Intent.setAction(String)// action是一个任意的字符串,但是一般以包名.intent.行为命名,比如com.qianfeng.demo.intent.hit

                   Intent.setData(Uri)

                   Intent.addCategory(String) // 自定义的一般都是default类型,default类型可以不单独设置(默认)

intent.setAction(String action)  //

new Intent(String action)

new Intent(String action, Uri uri)

Intent intent = new Intent()

         intent.setAction(String action)

         intent.setData(Uriuri)

intent.setAction(String action)

intent.setData(Uri uri)

意图过滤器:<Intent-filter>

action

         Action代表该Intent所要完成的一个抽象“动作”

         一个Intent对象最多包含一个action

         一个Activity可以定义多个action

         Android本身提供了很多action供开发者使用

Action代表该Intent所要完成的一个抽象“动作”

一个Intent对象最多包含一个action

一个Activity可以定义多个action

Android本身提供了很多action供开发者使用

category

         为Activity增加额外的附加类别信息

为Activity增加额外的附加类别信息

data

         声明数据的类型(mimeType)、约束(scheme)、主机名(host)、端口(port)、路径(path)等

声明数据的类型(mimeType)、约束(scheme)、主机名(host)、端口(port)、路径(path)等

应用场景:开启别的应用程序中的界面,系统需要查询匹配的Activity,效率较低

1.3.5  隐式意图示例

示例1:打开拨号界面

         public voidopen01(View v) {

                   Intentintent = new Intent();

                   // 如果使用的是隐式意图,那么在意图中就保存相关的信息(就是想做什么事情)

                   // 打篮球        (动作+数据)

                   // 动作

                   intent.setAction(Intent.ACTION_DIAL);

                   // url:统一资源定位符      http://www.baidu.com

                   //uri:统一资源标识符     tel://110 person://zhangsan

                   intent.setData(Uri.parse("tel://110"));

                   // 开启一个界面,完成指定的操作

                   startActivity(intent);

         }

示例二:自定义隐式视图及过滤器

      <!--à在清单文件中Activy注册和过滤器设置

  <!-- 第二个Activity-->

        <activity

           android:name="com.example.day06.activitybasic.SecondActivity"

           android:label="界面2">

            <!-- 定义意图过滤器,如果是通过隐式意图开启界面,

                    那么系统就会找到系统中的各个组件对用的意图过滤器,

                    然后进行过滤,如果过滤通过就会开启这个组件 -->

            <intent-filter>

               <!-- 指定当前Activity能做的事情,action的值就是一个字符串-->

                <actionandroid:name="com.example.day06.activitybasic.inetnt.hit"/>

 

 

                <!--指定当前Activity的类型,自定义的Activity一般就用默认类型 -->

                <categoryandroid:name="android.intent.category.DEFAULT"/>

                <!--定义数据的类型 -->

                <dataandroid:scheme="person"/>

            </intent-filter>

        </activity>

   <!-- 第三个Activity-->

        <activity

            android:name="com.example.day06.activitybasic.ThirdActivity"

            android:label="界面3">

            <intent-filter>

                <actionandroid:name="com.example.day06.activitybasic.inetnt.hit"/>

                <categoryandroid:name="android.intent.category.DEFAULT"/>

                <dataandroid:scheme="person"/>

            </intent-filter>

                   </activity>

注意:两个Activity设置了两个同样的过滤器

//开启自己的隐式意图,不需要指定Activity的类名

         public void open02(View v){

                   Intent intent = newIntent();

                   //设置action

                   intent.setAction("com.example.day06activity01.inetnt.hit");

                   //设置类型(如果是默认的,可以不设置)

                   //intent.addCategory(Intent.CATEGORY_DEFAULT);

                   //设置Date

                   intent.setData(Uri.parse("person://zhangsan"));

                  

                   startActivity(intent);

         }

效果图:

1.3.6  显示意图和隐式意图的区别

1、显示意图:必须指定要激活的组件的完整包名和类名

(应用程序之间耦合在一起,一般是在激活自己应用中的组件时使用显示意图。

效率较高)

2、隐式意图:只需要指定执行的动作和数据就可以

(好处:应用程序之间没有耦合。一般在激活其他应用中的组件时使用隐式意图。

缺点:效率较低)

 

程序设计原则:高内聚、低耦合。

 

什么时候使用这两个Intent?

         一般情况下,在开启同一个应用程序内部的组件会使用显示意图,相反,如果要开启其他应用程序中的组件,一般使用隐式意图。

 

 

1.4    通过intent传递数据

1、 Intent.setData(Uri) ——> intent.getData() :传递简单的文本数据,// 传递Uri对象(实际上就是一个字符串)

2、 putExtra(name ,value)  ——>  getXXXExtra()    //传递额外数据

通过该方法可以传递以下数据类型:

         八种基本数据类型

         数组

         字符串

         序列化对象

(在Android中有两个序列化接口:

A)Serializable接口: JDK自带的接口,使用方式很简单,只需要让自定义类实现Serializable接口即可。

b)Parcelable接口,Android SDK提供的接口

                            相对于Serializable接口,序列化和反序列化的效率更高,是Android推荐使用的,但是序列化和反序列的部分操作需要程序员自己完成

Bundle对象,就是一个容器,操作和Map集合类似,是以键值对的方式存储

3、 putExtras(Bundle extras) ——> getExtras():可以传递一组数据(Map集合)

4、putXXXArrayListExtra               传递ArrayList对象

 

Intent intent = getIntent();

 

 

1.5    获取Activity的返回值

快捷键:ctrl+shift+o      优化导包

        

开启Activity并获取返回值

实现步骤:

1)在Activity01中调用startActivityForResult(inetnt,requestCode)方法,开启一个指定的Activity

                   intent:意图对象,用于开启指定的Activity

                   requestCode:请求码,用于区分被开启的Activity

2)在Activity02中通过setResult(resultCode,intent)方法设置返回结果

                   resultCode:返回码,用于表示返回值的状态(操作成功:Activity.RESULT_OK)

                   intent:意图对象,用于封装返回结果

   设置完结果之后关闭Activity02,当Ativity02被关闭后会自动将结果返回给开启他的组件(Activty01)

3)在Activity01中改写onActivityResult(intrequestCode, int resultCode, Intent data)方法,用于处理返回结果

                   requestCode,请求码

                   resultCode,返回码(结果码)

                   data,Intent对象,封装了返回的数据

   注意:在处理结果的时候通常都需要先对请求码和返回码进行判断

                   if(requestCode== REQUEST_CAL_WEIGHT && resultCode == RESULT_OK) {

                  

                   }

概念:当新的Activity结束或返回上一个Activity时,需要返回一些结果,此时就需要设置并处理Activity的返回值。

实现步骤

1)startActivityForResult(Intentintent) // 开启ActivityB

2)getIntent()// 在ActivityB中获取来自ActivityA的Intent对象

3)setResult(intresultCode, Intent data) // 设置返回值(返回码 + 数据)

4)finish() // 关闭ActivityB并将结果返回给ActivityA

5)onActivityResult(intrequstCode, int resultCode, Intent data) // 在ActivityA中处理来自ActivityB的返回值

请求码和返回码

         请求码:用于区分开启的Activity

         返回码:用于标记结果返回的状态

                   Activity.RESULT_CANCELED

                   Activity.RESULT_OK

                   Activity.RESULT_FIRST_USER

请求码:用于区分开启的Activity

返回码:用于标记结果返回的状态

         Activity.RESULT_CANCELED

         Activity.RESULT_OK

         Activity.RESULT_FIRST_USER

 

1.5.1  示例:获取Acitivity的返回值

         public voidopenClick(View v) {

                   // 开启计算体重的界面

                   Intentintent = new Intent(this, CalWeightActivity.class);

                   // 开启一个Activity,开启之后就没有关联了

                   // startActivity(intent);

                   // 开启一个Activity,并且获取Activity的返回值

                   // 参数:requestCode,请求码,用于区分被开启的Activity

                   startActivityForResult(intent,REQUEST_CAL_WEIGHT);

         }

         /**

          * 当被开启的Activity返回结果时调用

          * 参数1:requestCode,请求码

          * 参数2:resultCode,返回码(结果码)

          * 参数3:data,Intent对象,封装了返回的数据

          */

        @Override

         protectedvoidonActivityResult(int requestCode,intresultCode, Intent data) {

                   if(requestCode ==REQUEST_CAL_WEIGHT && resultCode == RESULT_OK) {

                            if (data !=null) {

                                     double weight = data.getDoubleExtra("weight", -1);

                                     tv_show.setText(weight +"");

                            }

                   }

         }

/*

                    * 设置返回结果

                    * 注意:这个方法只是用于设置返回值,当调用完以后不会直接将结果返回,

                    * 而是要等到当前的Activity被关闭之后才会自动将结果返回

                    *

                    * 参数1:resultCode,返回码,用于表示返回值的状态

                    * 参数2:Intent,意图对象,在这里的Intent只是用于Activity之间的数据传递,

                    *                               不是用于开启某个组件,所以不需要包含任何组件的信息

                    */

                   Intent intent =new Intent();

                   intent.putExtra("weight", weiht);

                   setResult(Activity.RESULT_OK,intent);

                   finish();//关闭当前的Acitivity,,将结果返回给

1.6    Activity的生命周期

Activity生命周期的7个相关方法

onCreate() : 当Activity第一次被创建时被调用

onStart(): 当Activity可见时被调用

onResume(): 当Activity获取焦点时被调用

onPause(): 当Activity失去焦点时被调用

onStop(): 当Activity不可见时被调用

onDestroy() : 当Activity被销毁时被调用

onRestart() : 当Activity重新可见时被调用

各生命周期回调方法的使用场景

onCreate()、onDestroy  ——>  界面退出之前的数据保存,如:短信草稿

onStart()、onStop() ——>  更新UI的操作,如:视频播放、暂停,在Activity可见和不可见时调用

onResume()、onPause()  ——>  取消界面上的焦点,如:暂停游戏,在Activity是在获取和失去焦点时调用

onRestart() : 当Activity重新可见时被调用,从Activity不可见重新到可见时调用

Activity生命周期的三个状态

         Resumed : 运行状态,位于前台,可与用户进行交互

         Paused : 另一个Avtivity位于前台,本Activity还可见,但是不可交互

         Stoped: 另一个Activity位于前台,完全遮挡本Activity

Activity的三种生命周期

         完整生命周期 : onCreate—> onStart —>onResume —> onPause —> onStop —> onDestroy

         可视生命周期 : onStart —> onResume —> onPause —> onStop

         前台生命周期 : onResume —> onPause

思考题:

1、  当前有一个Activity在前台,当点击返回()

返回:onPause(): 当Activity失去焦点时被调用------ onStop() :不可见-------- onDestroy()销毁

Home:onPause() : 当Activity失去焦点时被调用------ onStop() :不可见

2、前台ActivityA,开启ActivityB?

A:: onPause(): 当Activity失去焦点时被调用------ onStop() :不可见

B: onCreate —> onStart可见 —> onResume获取焦点

 

==Android系统内部有一个内存管理机制,进程是分等级的,当高等级的进程需要使用内存又不够用的时候,系统会自动杀死优先级较低的进程,将释放出来的内存分配给高优先级的进程,当系统中内存又够用的时候,系统会再自动将先前因内存不足被自动杀死的继承重新开启。

 

 

1.7    Activity的状态恢复

【Activity状态保存

在某些情况下,系统可能会对Activity进行重构(重新构建)

1、 系统资源不够用时

2、 切换系统语言

3、 横竖屏切换

。。。。。。。。。。。。。

         在Activity重构的时候,会导致数据丢失,Android系统提供了状态恢复机制用于保存Activity的状态。

         1、在onSaveInstanceState(BundleoutState)中保存数据

2、在onCreate(BundlesavedInstanceState)恢复数据

或者在onRestoreInstanceState(BundlesavedInstanceState)中恢复数据

 

如果在横竖屏切换的时候不需要重构Activity,那么我们可以在清单文件中进行位置,配置方式如下:

         android:configChanges="orientation|screenSize|keyboardHidden"

         配置完属性后,就可以放置在横竖屏切换时重构Activity

                   ps:android:configChanges的作用就是 配置的属性值如果发生改变就不会导致Activity的重构,取而代之的是会调用onConfigurationChanged()方法1、在onSaveInstanceState(BundleoutState)中对数据进行保存,将数据保存在outState对象中

2、从Bundle对象中读取数据,读取数据后重新更新到界面

         a)在onCreate(BundlesavedInstanceState)方法中进行恢复

注意:需要判断savedInstanceState是否为空

         b)在onRestoreInstanceState(BundlesavedInstanceState)方法中进行恢复

注意:不需要判断savedInstanceState是否为空

1.7.1  实例代码

public class MainActivity extends Activity{

 

         privateTextView tv_num;

         privateint num = 0;

        

         @Override

         protectedvoid onCreate(Bundle savedInstanceState) {

                   super.onCreate(savedInstanceState);

                   setContentView(R.layout.activity_main);

                  

                   Log.i("mtag","onCreate");

                  

                   tv_num= (TextView) findViewById(R.id.tv_num);

                  

                   /*

                    * 恢复数据

                    * 这里要注意的是,当Activity第一次其中时,是不存在数据恢复的情况,

                    * 所以,Bundle的引用是null

                    */

//               if(savedInstanceState!= null) {

//                         intnum = savedInstanceState.getInt("num");

//                         tv_num.setText(num+"");

//               }

                  

         }

        

         //当配置发生改变时调用

         @Override

         publicvoid onConfigurationChanged(Configuration newConfig) {

                   super.onConfigurationChanged(newConfig);

                   Log.i("mtag","onConfigurationChanged");

                  

                   if(newConfig.orientation== Configuration.ORIENTATION_LANDSCAPE) {

                            Toast.makeText(this,"横屏", 0).show();

                   }else if(newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {

                            Toast.makeText(this,"竖屏", 0).show();

                   }

         }

        

         /**

          * 当Activity自动重构时调用,主要用于恢复Activity中的数据

          */

         @Override

         protectedvoid onRestoreInstanceState(Bundle savedInstanceState) {

                   super.onRestoreInstanceState(savedInstanceState);

                   Log.i("mtag","onRestoreInstanceState");

                   intnum = savedInstanceState.getInt("num");

                   tv_num.setText(num+"");

         }

        

         /**

          * 当Activity自动重构时调用,主要用于保存当前Activity的状态(内部的数据)

          * 参数:outState,Bundle对象,是框架传入的一个对象,主要用户保存Activity中的数据

          */

         @Override

         protectedvoid onSaveInstanceState(Bundle outState) {

                   super.onSaveInstanceState(outState);

                   Log.i("mtag","onSaveInstanceState");

                   //将数据保存在Bundle对象中

                   outState.putInt("num",num);

         }

        

         @Override

         protectedvoid onDestroy() {

                   super.onDestroy();

                   Log.i("mtag","onDestroy");

         }

 

         publicvoid add(View v) {

                   //每次点击按钮之后都会加1

                   tv_num.setText((++num)+"");

         }

        

}】

1.8    任务和后退栈(Task and Back Stack)

概念

         任务(Task)

                   一个应用程序一般都是由多个Activity组成的,task就是多个 Activity的集合

         后退栈(Back Stack

                   就是一个保存和管理应用程序中所有Activity的容器

                   用户在进行操作时将与task中的Activity进行交互,这些Activity会按照启动顺序排队存入后退栈

Android为什么要引入任务和后退栈的概念?

         在Windows下可以同时开启多个程序,并且可以在多个程序之间进行切换,在Andorid下也可以开启多个程序,可以通过长摁home键来查看开启的App,要实现在多个Activity之间进行切换,那么就要将已经打开的Activity保存在内存中,而Android系统是通过后退栈来存储已经开启的Activity,并记录他们开启的先后顺序。

 

1.9    Activity的启动模式

android:launchMode=""在清单文件中配置即可

standard: 默认的启动模式,每次启动Activity都会创建一个新的Activity实例

singleTop :如果Activity位于栈顶,则不再生成实例,而是调用onNewIntent()方法

singleTask : 如果存在实例,则带至栈顶并销毁它上面所有的Activity

singleInstance: 无论当前Activity是否是同一个App的,都只用一个实例

5 0
原创粉丝点击