目录
1. Activity概念
在Android系统中,用户与程序的交互是通过Activity完成的,它是一种可以包含用户界面的组件,主要用于和用户进行交互。Activity负责管理Android程序的用户界面。凡是在应用中看得见的东西,都是放在活动中。
2. Activity的创建
Activity是Android程序中的四大组件之一,为用户提供可视化界面及操作。一个应用程序通常包括多个Activity,每个Activity负责管理一个用户界面。这些界面可以添加多个控件,每个控件负责实现不同的功能。
extends AppCompatActivity,并重写其onCreate(Bundle savedInstanceState)方法。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); } }
在Android创建的四大组件时,都需要在AndroidManifest.xml文件中(清单文件)中注册,如下:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.administrator.handlerstudy"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
package 指定程序的包名。 icon 指定应用程序的图标。 label 指定活动中标题栏的内容和应用程序显示的名称。 <intent-filter> action属性表示当前Activity最先启动。
category属性表示当前应用显示在桌面程序列表中。
theme 指定应用程序的主题。 name 指定主Activity,由于package指定了程序的包名,因此name直接使用.MainActivity即可。
3. Activity的生命周期
Activity的生命周期中包含5中状态,7种方法。
3.1 生命周期状态
Activity生命周期指的是一个Activity从创建到销毁的全过程。Activity的生命周期又分为5种状态,分别是启动状态、运行状态、暂停状态、停止状态和销毁状态。其中启动状态和销毁状态是过渡状态,Activity不会在这两个状态停留。
3.1.1 启动状态
Activity的启动状态很短暂,一般情况下,当Activity启动之后便会进入运行状态。
3.1.2 运行状态
Activity在此状态处于屏幕最前端,栈顶,它是可见、有焦点的,可以与用户进行交互,如双击,长按事件等。当处于运行状态时,Android会尽可能的保持它的运行,即便内存不足的情况下,Android也会先销毁栈底的Activity,来确保当前的Activity正常运行。
3.1.3 暂停状态
在某些情况下,Activity对用户来说仍然可见,但它已经无法获取焦点,用户对它的操作没有响应,即无法与用户进行交互。此时它就处于暂停状态,但仍然保留着当前状态和成员信息。例如,在当前Activity上覆盖了一个透明或者非全屏的Activity时,被覆盖的Activity就处于暂停状态。
3.1.4 停止状态
当Activity完全不可见时,它就处于停止状态,但仍然保留着当前状态和成员信息。如果系统内存不足,这种状态的Activity就很容易被销毁。
3.1.5 销毁状态
当Activity处于销毁状态时,将被清理出内存。
3.2 生命周期方法
3.2.1 onCreate()方法
是在Activity创建时调用,通常做一些初始化设置,如下:
@Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.qq_layout); }
3.2.2 onStart()方法
是在Activity即将可见时调用,如下:
@Override protected void onStart(){ super.onStart(); }
3.2.3 onResume()方法
是在Activity获取焦点开始与用户交互时调用,如下:
@Override protected void onResume(){ super.onResume(); }
3.3.4 onPause()方法
是在当前Activity被其他Activity覆盖或锁屏时调用,如下:
@Override protected void onPause(){ super.onPause(); }
3.3.5 onStop()方法
是在对Activity对用户不可见时调用,如下:
@Override protected void onStop(){ super.onStop(); }
3.3.6 onDestroy()方法
是在对Activity销毁时调用,如下:
@Override protected void onDestroy(){ super.onDestory(); }
3.3.7 onRestart()方法
是在Activity从停止状态再次启动时调用,如下:
@Override protected void onRestart(){ super.onRestart(); }
代码如下:
public class MainActivity_lifetime extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.internationalization_layout); Log.i("MainActivityLife","调用onCreate()方法"); } @Override protected void onStart(){ super.onStart(); Log.i("MainActivityLife","调用onStart()方法"); } @Override protected void onResume(){ super.onResume(); Log.i("MainActivityLife","调用onResume()方法"); } @Override protected void onPause(){ super.onPause(); Log.i("MainActivityLife","调用onPause()方法"); } @Override protected void onStop(){ super.onStop(); Log.i("MainActivityLife","调用onStop()方法"); } @Override protected void onDestroy(){ super.onDestroy(); Log.i("MainActivityLife","调用onDestroy()方法"); } @Override protected void onRestart(){ super.onRestart(); Log.i("MainActivityLife","调用onRestart()方法"); } }
程序运行后,日志如下:
09-15 23:22:29.339 5445-5445/? I/MainActivityLife: 调用onCreate()方法 09-15 23:22:29.366 5445-5445/? I/MainActivityLife: 调用onStart()方法 09-15 23:22:29.412 5445-5445/? I/MainActivityLife: 调用onResume()方法 09-15 23:22:29.783 5445-5467/? I/OpenGLRenderer: Initialized EGL, version 1.4 09-15 23:22:29.804 5445-5467/? E/EGL_adreno: CreateContext rcMajorVersion:3, minorVersion:0 09-15 23:22:29.969 5445-5445/com.example.administrator.helloworld_3 W/art: Before Android 4.1, method int android.support.v7.widget.DropDownListView.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in android.widget.ListView 09-15 23:24:48.236 5445-5445/com.example.administrator.helloworld_3 I/MainActivityLife: 调用onPause()方法 09-15 23:24:49.262 5445-5445/com.example.administrator.helloworld_3 I/MainActivityLife: 调用onStop()方法 调用onDestroy()方法
3.3 横竖屏切换时的生命周期
当手机横竖屏切换时,会根据AndroidManifest.xml文件中Activity的configChanges属性不同而调用不同的生命周期方法(模拟器中横竖屏切换可以使用Ctr+F11)。
当使用默认属性时,Activity生命周期会一次调用onCreate()、onStart()、onResume()方法,当进行横竖屏切换时,调用的方法依次是onPause()、onStop()、onDestory()、onCreate()、onStart()、onResume()。依次在横竖屏切换时,首先会销毁Activity,然后重建Activity,这种模式在实际开发中会有一定的影响,可以通过configChanges属性进行设置,这样无论怎样切换屏幕Activity都不会销毁重建,代码如下:
<activity android:name=".MainActivity" android:configChanges="orientation|keyboardHidden|screenSize">
如果希望某一个界面一直处于竖屏或者横屏状态,不随着手机的晃动而改变,同样可以在清单文件中通过设置Activity的参数来完成,代码如下:
竖屏:android:screenOrientation="portrait" 竖屏: android:screenOrientation="landscape"
4. Activity的启动模式
Activity是可以层叠摆放的,没启动一个新的Activity就会覆盖原有的Activity之上,如果单击返回,则最上面的Activity会被销毁,下面的Activity重新显示。Activity之所以这样显示,是因为Android系统是通过任务栈的方式来管理Activity实例的。
4.1 Android中的任务栈(返回栈)
栈是一种先进后出的数据结构。在Android中,采用任务栈的形式来管理Activity,栈中Activity的顺序是按照它们被打开的顺序依次存放的。
通常一个应用程序对应一个任务栈。默认情况下没启动一个Activity都会入栈,并处于栈顶的位置,用户操作的永远都是栈顶的Activity。在栈中的Activity只有压入和弹出两种操作,被当前Activity启动时压入,用户单击返回按钮时弹出。
4.2 Activity的4中启动模式
在实际开发中,应根据特定的需求为每个Activity指定恰当的启动模式。在AndroidManifest.xml中,通过<activity>标签的android:launchMode属性可以设置启动模式。
1)standard模式
standard是Activity的默认启动模式,这种模式的特点是,每启动一个Activity就会在栈顶创建一个新的实例。实际开发中,闹钟程序通常采用这种模式。
2)singleTop模式
在某些情况下,使用standard模式不合理,如当前Activity已经位于栈顶,而再次启动Activity时还需要创建一个新的实例,不能直接复用。在这种情况下,使用singleTop模式启动Activity更合理,该模式会判断需要启动的Activity实例是否位于栈顶,如果位于栈顶则直接复用,否则创建新的实例。在实际开发中,浏览器的书签通常采用这种模式。
3)singTask模式
使用singTop虽然可以很好地解决重复创建栈顶的问题,但是如果Activity并未处于栈顶位置,则可能海湖创建多个实例。如果想要某个Activity在整个应用程序中只有一个实例,则需要借助singTask模式来实现。
使用singTask模式时,每次启动该Activity时,系统首先会检查栈中是否存在当前Activity实例,如果存在则世界使用,并把当前Activity之上的所有实例全部出栈,否则会重新创建一个实例。实际开发中,浏览器主界面通常采用这种模式。
4)singleInstance模式
这是最特殊的一个模式,指定为singleInstance模式的Activity会启动一个新的任务栈来管理Activity实例,无论从哪个任务栈中启动该Activity,该实例在整个系统中都只有一个。这种模式存在的意义在于为了在不同的程序中共享同一个Activity实例。
Activity采用singleInstance模式启动分两种情况。一种是要启动的Activity不存在,则系统会首先创建一个新的任务栈,然后再创建Activity实例。另一种是要启动的Activity已经存在,则无论当前Activity位于哪个程序哪个任务栈中,系统都会把Activity所在的任务栈移动到前台,从而使Activity显示。在实际开发中,来点显示界面通常采用这种模式。
5. Activity的销毁
销毁方式如下:
按下back键 使用finish()方法
6. Activity之间的跳转
在Android系统中,每个应用程序通常由多个界面组成,每个界面就是一个Activity,在这些界面进行跳转时,实际上也就是Activity之间的跳转。Activity之间的跳转需要用到Intent(意图)组件,通过Intent可以开启新的Activity实现界面跳转功能。
6.1 Intent简介
Intent称为意图,是程序各组件进行交互的一种重要方式。它不仅可以指定当前组件要执行的动作,还可以在不同组件之间进行数据传递。一般用于启动Activity、Service以及发送广播等。根据开启目标组件的方式不同,Intent分为显式意图和隐式意图。
6.2 显式意图
显式意图可以直接通过名称开启指定的目标组件,通过其构造方法Intent(Contex tpackageContext,Class<?> cls)来实现。
Intent(Context packageContext,Class<?> cls) 第一个参数Context:表示当前的Activity对象
第二个参数Class:表示要启动的目标Activity
通过这个方法建立一个Intent对象,然后将该对象传递给Activity的startActivity(Intent intent)方法即可启动目标组件,实例代码如下:
Intent intent = new Intent(this,Activity02.class); //创建Intent对象 startActivity(intent); //开启Activity02
6.3 隐式意图
隐式意图更加抽象,它并没有明确指定要开启那个目标组件,而是通过指定action和category等属性信息,系统根据这些信息进行分析,然后寻找目标Activity。实例代码如下:
Intent intent = new Intent(); //设置action动作,该动作要和清单文件中设置的一样 intent.setAction("cn.itcast.START_ACTIVITY"); startActivity(intent);
在上述的代码中,只指定了action,并没有指定category,这是因为在目标Activity的清单文件中配置的category是一个默认值,在调用startActivity()方法时,自动将这个category添加到Intent中。
只有上述代码还不能开启指定的Activity,还需要在指定的目标Activity的清单文件中配置<intent-filter>,指定要跳转去的Activity能够响应的action和category,实例代码如下:
AndroidManifest.xml:
<activity android:name=".MainActivity_intent" android:theme="@style/grayTheme"> <intent-filter> <action android:name="com.example.activitytest.ACTION_START" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>
注意: 每一个Intent只能指定一个action,可以指定多个category。可以通过intent的addCategory设置category,来更加精确匹配合适的Activity。
MainActivity_intent.java:
Intent intent = new Intent(); //设置动作为android.intent.action.VIEW intent.setAction("com.example.activitytest.ACTION_START"); //设置category //intent.addCategory("....."); startActivity(intent);
注意:这里setAction里面的内容不能为android.intent.action.MAIN,否则要出错,需要自定义一个新的。
6.4 隐式意图更多用法
使用隐式意图,不仅可以启动自己程序内的活动(Activity),还可以启动其他程序的活动。这使得Android多个应用程序之间的功能共享成为了可能。
比如应用程序中需要展示一个网页,此时没有必要自己去实现一个浏览器,而是只需要调用系统的浏览器来打开这个网页就行了。
实例如下:
//修改按钮的点击事件 button.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v){ Intent intent = new Intent(Intent.ACTION_MAIN); intent.setData(Uri.parse("http://www.baidu.com")); startActivity(intent); } });
点击按钮就可以看到打开了系统浏览器。Intent.ACTION_MAIN这是一个Android系统内置的动作,其常量值为:android.intent.action.VIEW。
于此对应,我们还可以再<intent-filter>标签中再配置一个<data>标签,用于更加精确的指定当前活动能够响应什么类型的数据。<data>标签中主要可以配置如下内容:
android:scheme 用于指定数据的协议部分,如上述的http部分;
geo表示显示地理位置
tel表示拨打电话
android:host 用于指定数据的主机名部分,如上述的www.baidu.com。 android:post 用于指定数据的端口部分。 android:path 指定主机名和端口之后的部分。 android:mimeType 指定可以处理的数据类型,允许使用通配符的方式进行指定。 注意:只有<data>标签中指定的内容和Intent中携带的Data完全一致时,当前活动才能响应该Intent。
7. Activity中的数据传递
组件之间通过使用Intent进行消息或数据传递。
7.1 Intent形式
在Activity启动时传递数据非常简单,因为Intent提供了一系列重载的putExtra(String name,其他类型数据(字符串,数组,整数,序列化数据,Bundle))方法,还有其他putXXX方法,通过该方法可以将要传递的数据暂存到Intent中,当启动另一个Activity之后,只需要将这些数据从Intent取出即可。
例如将Activity01中的字符串传递到Activity02中,实例代码如下:
Intent intent = new Intent(this,Activity02.class); intent.putExtra("extra_data","Hello Activity02"); startActivity(intent);
在上述代码中,通过Intent开启Activity02,用putExtrra()方法通过键值对的方式传递了一个字符串"Hello Activity02",接受两个参数,第一个参数是用于后面从Intent中取值,第二个参数是传递的数据内容。
接下来在Activity02中取出传递过来的数据,实例代码如下:
Intent intent = getIntent(); String data = intent.getStringExtra("extra_data");
getIntent() 获取Intent对象 getStringExtra(“...”) 用于获取传递的是字符串类型的数据,如果为整形,则使用getIntExtra()方法,以此类推。
7.2 Bundle形式(一种类似于HashMap形式)
放值:
Intent intent = new Intent(this,DialogActivity.class); Bundle bundle = new Bundle(); bundle.putString("key","value"); intent.putExtra("bundle",bundle); startActivity(intent);
取值:
Bundle bundle = getIntent().getBundleExtra("bundle"); //进行非空判断 if(bundle != null){ String value = bundle.getString("key"); }
7.3 两个Activity之间传值
约束条件:Activity A,Activity B,开始在A页面。
场景一:
由A进入B,同时A向B传值,A-> onPause(),B->onCreate(),B->onStart(),B->onResume(),A->onStop()。
传值通过intent传值。
public class Activity_A extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_1); Button button = findViewById(R.id.a1); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(Activity_A.this,Activity_B.class); intent.putExtra("a1","A1进入A2"); startActivity(intent); } }); } }
场景二:
由B返回A,同时向A传值,B->onPause(),A->onRestart(),A->onSatrt(),A->onResume(),B->onStop(),B->onDestory()。
传值特殊性:由于返回上一个活动只需要按一下back键即可,并没有一个用于启动活动的Intent来传递数据。通过查阅文档会发现,Activity中还有一个startActivityForResult()方法也是用于启动活动的,但是这个方法是期望在活动销毁的时候能够返回一个结果给上一个活动,毫无疑问,这是我们所需要的。
startActivityForResult(Intent intent,int code) 第一个参数:Intent
第二个参数:请求码,用于在之后的回调中判断数据的来源。
代码如下所示:
public class Activity_B extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_2); final Intent intent = getIntent(); //获得由ActivityA传递到ActivityB的数据 String a1Str = intent.getStringExtra("a1"); Button button = findViewById(R.id.a2); button.setText(a1Str); //设置点击按钮事件:由当前ActivityB返回到ActivityA中 button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //这个Intent仅仅用于传递数据而已,并没有在构造方法里面指定Activity Intent intent2 = new Intent(); intent2.putExtra("A2","A2进入A1"); //设置请求码和回传数据 setResult(RESULT_OK,intent2); finish(); } }); } }
public class Activity_A extends AppCompatActivity { Button button; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_1); button = findViewById(R.id.a1); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(Activity_A.this,Activity_A.class); intent.putExtra("a1","A1进入A2"); //这里不使用startActivity()方法了 //startActivity(intent); startActivityForResult(intent,999); } }); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode == 999 && resultCode == RESULT_OK){ if(data != null){ //获取到ActivityB回传给ActivityA的数据 button.setText(data.getStringExtra("A2")); } } } }
上述是通过按钮点击由B返回到A中的,如果通过按下back键返回的话,则通过在B中重写onBackPressed()方法即可。如下所示:
@Override public void onBackPressed(){ Intent intent = new Intent(); intent.putExtra("data_return","Hello A"); setResult(RESULT_OK,intent); finish(); }
8.在Activity中使用Toast
用于将一些短小的信息通知给用户,这些信息会显示一段时间后消失,并且不会占用任何屏幕空间。实例如下:
Toast.makeText(MainActivity.this,"提示信息",Toast.LENGTH_SHORT).show();
第一个参数是Toast显示要求的上下文,第二个参数是要显示的内容,第三个参数是显示时长。最后别忘了调用show(),不然不会显示。
9.Android的进程优先级
优先级从高到低如下所示:
前台 可见 服务 后台 空