Activity是什么?
1. Activity的基本用法
package com.example.activitytest; import android.app.Activity; import android.os.Bundle; public class FirstActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } }
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="Button" /> </LinearLayout>
package com.example.activitytest; import android.app.Activity; import android.os.Bundle; public class FirstActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
//新增代码,可以看到,这里调用了 setContentView()方法来给当前的活动加载一个布局,
而在 setContentView()方法中,我们一般都会传入一个布局文件的 id。
setContentView(R.layout.first_layout);
}
}
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.activitytest"> <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/Theme.My_Applation"> <activity android:name=".FirstActivity"> //这里修改成了.FirstActivity <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
2. Activity的基本使用方法
package com.example.activitytest; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.Toast; public class FirstActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //加载一个布局,传入布局ID R.layout.activity_main setContentView(R.layout.first_layout); Button toast_button = (Button) findViewById(R.id.toast_button); /*通过button触发Toast 通过onCreate方法中添加代码 *先通过findViewById()获得toast_button这个元素实例,由于这个方法返回的是view对象,需要向下转型成Button对象 *用setOnClickListener() 给这个实例注册监听器 OnClickListener() 使用语句为 View.OnClickListener() * 为什么前面要加个View呢,原因就是后面的OnClickListener是个View类内部的接口,如果直接使用是找不到这个接口的。 */ toast_button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(FirstActivity.this, "You clicked Button 1", Toast.LENGTH_SHORT).show(); } }); } }
其实答案非常简单,只要按一下 Back 键就可以销毁当前的活动了。不过如果你不想通 过按键的方式,而是希望在程序中通过代码来销毁活动,当然也可以,Activity 类提供了一 个 finish()方法,我们在活动中调用一下这个方法就可以销毁当前活动了。
修改按钮监听器中的代码,如下所示:
public class FirstActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //加载一个布局,传入布局ID R.layout.activity_main setContentView(R.layout.first_layout); Button toast_button = (Button) findViewById(R.id.toast_button); toast_button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } }
(3)使用 Intent 在Activity之间穿梭:那么怎样才能由主Activity跳转到其他Activity呢? 使用显示Intent或隐式Intent
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="Button" /> </LinearLayout>
package com.example.activitytest; import android.app.Activity; import android.os.Bundle; public class SecondActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.second_layout); } }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.activitytest"> <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/Theme.My_Applation"> <activity android:name=".FirstActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SecondActivity"> </activity> </application> </manifest>
Button button1 = (Button) findViewById(R.id.toast_button); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
startActivity(intent);
} });
<activity android:name=".SecondActivity"> <intent-filter> <action android:name="com.example.activitytest.ACTION_START"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter>
</activity>
Button button1 = (Button) findViewById(R.id.toast_button); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent("com.example.activitytest.ACTION_START"); startActivity(intent); }
});
button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent("com.example.activitytest.ACTION_START"); intent.addCategory("com.example.activitytest.MY_CATEGORY"); startActivity(intent); } });
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=com.example.activitytest.ACTION_START cat=[com.example.activitytest.MY_CATEGORY] }
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:2067)
<activity android:name=".SecondActivity"> <intent-filter> <action android:name="com.example.activitytest.ACTION_START"/> <category android:name="android.intent.category.DEFAULT"/> <category android:name="com.example.activitytest.MY_CATEGORY"/> </intent-filter> </activity>
(3) Intent的其他用法
- 启动其他程序的Activity
- 向下一个Activity传递数据
-
返回数据给上一个Activity
- 运行状态
当一个Activity位于返回栈的栈顶时,这时Activity就处于运行状态。系统最不愿意回收的就是处于运行状态的Activity,因为这会带来非常差的用户体验。
- 暂停状态
- 停止状态
- 销毁状态
(3)Activity 的生命周期
- onCreate():这个方法你已经看到过很多次了,每个活动中我们都重写了这个方法,它会在活动 第一次被创建的时候调用。你应该在这个方法中完成活动的初始化操作,比如说加载布 局、绑定事件等。
-
onStart() :这个方法在活动由不可见变为可见的时候调用。
-
onResume():这个方法在活动准备好和用户进行交互的时候调用。此时的活动一定位于返回栈的栈顶,并且处于运行状态。
-
onPause():这个方法在系统准备去启动或者恢复另一个活动的时候调用。我们通常会在这个方 法中将一些消耗 CPU 的资源释放掉,以及保存一些关键数据,但这个方法的执行速度 一定要快,不然会影响到新的栈顶活动的使用。
- onStop():这个方法在活动完全不可见的时候调用。它和 onPause()方法的主要区别在于,如 果启动的新活动是一个对话框式的活动,那么 onPause()方法会得到执行,而 onStop() 方法并不会执行。
- onDestroy():这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。
- onRestart():这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。
以上七个方法中除了 onRestart()方法,其他都是两两相对的,从而又可以将活动分为三种生存期。
1. 完整生存期
活动在 onCreate()方法和 onDestroy()方法之间所经历的,就是完整生存期。一般情 况下,一个活动会在 onCreate()方法中完成各种初始化操作,而在 onDestroy()方法中完 成释放内存的操作。
2. 可见生存期
活动在 onStart()方法和 onStop()方法之间所经历的,就是可见生存期。在可见生存 期内,活动对于用户总是可见的,即便有可能无法和用户进行交互。我们可以通过这两 个方法,合理地管理那些对用户可见的资源。比如在 onStart()方法中对资源进行加载, 而在 onStop()方法中对资源进行释放,从而保证处于停止状态的活动不会占用过多内存。
3. 前台生存期
活动在 onResume()方法和 onPause()方法之间所经历的,就是前台生存期。在前台 生存期内,活动总是处于运行状态的,此时的活动是可以和用户进行相互的,我们平时 看到和接触最多的也这个状态下的活动。
为了帮助你能够更好的理解,Android 官方提供了一张活动生命周期的示意图,如图 2.20所示。
(4)活动被回收了怎么办
前面我们已经说过,当一个活动进入到了停止状态,是有可能被系统回收的。那么想象 以下场景,应用中有一个活动 A,用户在活动 A 的基础上启动了活动 B,活动 A 就进入了 停止状态,这个时候由于系统内存不足,将活动 A 回收掉了,然后用户按下 Back 键返回活 动 A,会出现什么情况呢?其实还是会正常显示活动 A 的,只不过这时并不会执行 onRestart() 方法,而是会执行活动 A 的 onCreate()方法,因为活动 A 在这种情况下会被重新创建一次。
这样看上去好像一切正常,可是别忽略了一个重要问题,活动A中是可能存在临时数据 和状态的。打个比方,MainActivity 中有一个文本输入框,现在你输入了一段文字,然后 启动 NormalActivity,这时 MainActivity 由于系统内存不足被回收掉,过了一会你又点击了 Back 键回到 MainActivity,你会发现刚刚输入的文字全部都没了,因为 MainActivity 被重新创建了。
如果我们的应用出现了这种情况,是会严重影响用户体验的,所以必须要想想办法解决 这个问题。查阅文档可以看出,Activity 中还提供了一个 onSaveInstanceState()回调方法,这 个方法会保证一定在活动被回收之前调用,因此我们可以通过这个方法来解决活动被回收时 临时数据得不到保存的问题。onSaveInstanceState()方法会携带一个 Bundle 类型的参数,Bundle 提供了一系列的方法用于保存数据,比如可以使用 putString()方法保存字符串,使用 putInt()方法保存整型数据, 以此类推。每个保存方法需要传入两个参数,第一个参数是键,用于后面从 Bundle 中取值, 第二个参数是真正要保存的内容。
(5)Activity的启动模式