-
「Generated by Manus, instructions issued by binbinwang」
本章将深入探讨Android的Activity组件及其生命周期,并与iOS的UIViewController进行对比。作为Android应用的核心组件,Activity的理解对于从iOS转向Android开发的开发者尤为重要。
3.1 Activity基础 Activity概念与作用 Activity是Android应用的基本构建块,代表用户可以执行单一、专注任务的屏幕。每个Activity都提供一个窗口,通常占满整个屏幕,应用可以在其中绘制UI。
Activity的主要作用 :
提供用户界面
处理用户交互
启动其他Activity
作为应用组件的容器
Activity与iOS UIViewController对比 :
特性
Android Activity
iOS UIViewController
定义
表示单一屏幕的组件
管理视图层次结构的对象
创建方式
继承Activity或AppCompatActivity
继承UIViewController
视图加载
通过setContentView()设置布局
通过loadView()或storyboard加载
生命周期
复杂的多状态生命周期
相对简单的生命周期
导航
通过Intent启动新Activity
通过present或push显示新控制器
创建与配置Activity 创建Activity :
1 2 3 4 5 6 7 8 9 10 11 12 13 // 基本Activity class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 初始化视图和事件处理 val button = findViewById<Button>(R.id.button) button.setOnClickListener { // 处理点击事件 } } }
在AndroidManifest.xml中声明Activity :
1 2 3 4 5 6 7 8 9 10 11 12 13 <manifest > <application > <activity android:name=".MainActivity" android:label="@string/app_name" android:theme="@style/AppTheme.NoActionBar"> <intent-filter > <action android:name ="android.intent.action.MAIN" /> <category android:name ="android.intent.category.LAUNCHER" /> </intent-filter > </activity > </application > </manifest >
Activity常用配置属性 :
android:name
:Activity类名
android:label
:Activity显示的标题
android:theme
:Activity使用的主题
android:launchMode
:Activity启动模式
android:screenOrientation
:屏幕方向
android:configChanges
:配置变化处理
对比iOS UIViewController的创建 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 // 基本UIViewController @interface MainViewController : UIViewController @end @implementation MainViewController - (void)viewDidLoad { [super viewDidLoad]; // 初始化视图和事件处理 UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; [button setTitle:@"Press Me" forState:UIControlStateNormal]; [button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:button]; } - (void)buttonPressed:(UIButton *)sender { // 处理点击事件 } @end
主要差异 :
Android需要在清单文件中声明Activity,而iOS不需要
Android使用XML布局文件,而iOS传统上使用代码或XIB/Storyboard
Android的Activity需要显式设置内容视图,而iOS的UIViewController自动创建根视图
Android的事件处理使用监听器,而iOS使用目标-动作模式
3.2 Activity生命周期 生命周期回调方法 Android Activity的生命周期比iOS UIViewController更复杂,包含更多状态和回调方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 class LifecycleActivity : AppCompatActivity() { // 创建Activity时调用 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_lifecycle) Log.d("Lifecycle", "onCreate") // 恢复保存的状态 savedInstanceState?.let { val savedText = it.getString("saved_text") // 使用恢复的数据 } } // Activity变为可见时调用 override fun onStart() { super.onStart() Log.d("Lifecycle", "onStart") } // Activity获取焦点,可与用户交互时调用 override fun onResume() { super.onResume() Log.d("Lifecycle", "onResume") } // Activity即将失去焦点时调用 override fun onPause() { super.onPause() Log.d("Lifecycle", "onPause") } // Activity不再可见时调用 override fun onStop() { super.onStop() Log.d("Lifecycle", "onStop") } // Activity被销毁前调用 override fun onDestroy() { super.onDestroy() Log.d("Lifecycle", "onDestroy") } // Activity重新变为可见但未获取焦点时调用 override fun onRestart() { super.onRestart() Log.d("Lifecycle", "onRestart") } // 保存Activity状态 override fun onSaveInstanceState(outState: Bundle) { // 保存需要恢复的数据 outState.putString("saved_text", "Some text to save") super.onSaveInstanceState(outState) Log.d("Lifecycle", "onSaveInstanceState") } // 恢复Activity状态 override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) // 注意:也可以在onCreate中恢复状态 val savedText = savedInstanceState.getString("saved_text") Log.d("Lifecycle", "onRestoreInstanceState") } }
生命周期状态与转换 Activity生命周期状态:
**创建(Created)**:Activity实例已创建但尚未显示
**开始(Started)**:Activity可见但不在前台
**恢复(Resumed)**:Activity在前台并可与用户交互
**暂停(Paused)**:Activity部分可见但失去焦点
**停止(Stopped)**:Activity完全不可见
**销毁(Destroyed)**:Activity被系统回收
生命周期转换图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ┌─────────────┐ │ Created │◄───┐ └─────┬───────┘ │ │ │ ▼ │ ┌─────────┐ ┌─────────────┐ │ │ Destroyed│◄─────┤ Started │◄─────┤ └─────────┘ └─────┬───────┘ │ │ │ ▼ │ ┌─────────────┐ │ │ Resumed │ │ └─────┬───────┘ │ │ │ ▼ │ ┌─────────────┐ │ │ Paused ├──────┤ └─────┬───────┘ │ │ │ ▼ │ ┌─────────────┐ │ │ Stopped ├──────┘ └─────────────┘
与iOS生命周期对比 iOS UIViewController生命周期 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 @implementation LifecycleViewController // 视图加载到内存 - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"viewDidLoad"); } // 视图即将出现 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSLog(@"viewWillAppear"); } // 视图已经出现 - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"viewDidAppear"); } // 视图即将消失 - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; NSLog(@"viewWillDisappear"); } // 视图已经消失 - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; NSLog(@"viewDidDisappear"); } // 内存警告 - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; NSLog(@"didReceiveMemoryWarning"); } // 视图被卸载(iOS 6及以上很少调用) - (void)viewDidUnload { [super viewDidUnload]; NSLog(@"viewDidUnload"); } @end
生命周期方法对比 :
Android
iOS
说明
onCreate
viewDidLoad
初始化和设置视图
onStart
viewWillAppear
视图即将可见
onResume
viewDidAppear
视图完全可见并可交互
onPause
viewWillDisappear
视图即将隐藏
onStop
viewDidDisappear
视图完全隐藏
onDestroy
dealloc
对象被销毁
onSaveInstanceState
encodeRestorableState
保存状态
onRestoreInstanceState
decodeRestorableState
恢复状态
主要差异 :
Android的生命周期更复杂,状态更多
iOS没有直接对应Android的onRestart的方法
Android通过Bundle保存状态,iOS通过NSCoding或State Restoration
Android在配置变化(如旋转)时会重建Activity,而iOS默认不会重建UIViewController
Android明确区分前台和后台状态,iOS通过AppDelegate处理应用级生命周期
3.3 Activity间的通信与导航 Intent系统 Intent是Android组件间通信的核心机制,用于启动Activity、Service等组件。
Intent类型 :
显式Intent :明确指定目标组件
隐式Intent :指定操作类型,由系统匹配合适的组件
使用Intent启动Activity :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // 显式Intent val intent = Intent(this, SecondActivity::class.java) // 添加数据 intent.putExtra("key_name", "value") intent.putExtra("key_age", 25) // 启动Activity startActivity(intent) // 隐式Intent val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com")) startActivity(browserIntent) // 启动Activity并期望结果 val pickContactIntent = Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI) startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST)
在目标Activity中接收数据 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class SecondActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_second) // 获取传递的数据 val extras = intent.extras if (extras != null) { val name = extras.getString("key_name") val age = extras.getInt("key_age") // 使用数据 } } }
处理Activity结果 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // 旧方式 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == PICK_CONTACT_REQUEST) { if (resultCode == Activity.RESULT_OK) { // 处理返回的数据 data?.data?.let { contactUri -> // 使用contactUri } } } } // 新方式(使用ActivityResultLauncher) private val pickContactLauncher = registerForActivityResult( ActivityResultContracts.StartActivityForResult() ) { result -> if (result.resultCode == Activity.RESULT_OK) { result.data?.data?.let { contactUri -> // 使用contactUri } } } // 使用新方式启动 pickContactLauncher.launch(Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI))
与iOS导航模式对比 iOS的导航方式 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 // 模态展示 UIViewController *secondVC = [[SecondViewController alloc] init]; secondVC.name = @"value"; secondVC.age = 25; [self presentViewController:secondVC animated:YES completion:nil]; // 使用导航控制器 SecondViewController *secondVC = [[SecondViewController alloc] init]; secondVC.name = @"value"; secondVC.age = 25; [self.navigationController pushViewController:secondVC animated:YES]; // 使用Segue(Storyboard) - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"ShowSecondVC"]) { SecondViewController *secondVC = segue.destinationViewController; secondVC.name = @"value"; secondVC.age = 25; } } // 获取结果(使用委托模式) @protocol ContactPickerDelegate <NSObject> - (void)contactPicker:(ContactPickerViewController *)picker didPickContact:(Contact *)contact; @end // 在目标控制器中 - (void)finishPickingContact:(Contact *)contact { if ([self.delegate respondsToSelector:@selector(contactPicker:didPickContact:)]) { [self.delegate contactPicker:self didPickContact:contact]; } [self dismissViewControllerAnimated:YES completion:nil]; }
主要差异 :
Android使用Intent系统进行导航,而iOS使用直接引用或Segue
Android可以通过隐式Intent调用其他应用的组件,iOS通过URL Scheme或Universal Links
Android使用Bundle传递数据,iOS直接设置属性或使用初始化方法
Android使用startActivityForResult获取结果,iOS通常使用委托模式
Android的Intent系统更灵活,支持更多导航场景,而iOS的导航更直接
3.4 Activity启动模式与任务栈 启动模式 Android提供四种Activity启动模式,控制Activity实例在任务栈中的行为:
standard (标准模式):默认模式,每次启动都创建新实例
singleTop (栈顶复用):如果目标Activity已在栈顶,则复用该实例
singleTask (栈内复用):如果目标Activity已在任务栈中,则复用该实例并清除其上的所有Activity
singleInstance (单实例):目标Activity独占一个任务栈
在AndroidManifest.xml中设置启动模式 :
1 2 3 <activity android:name=".SingleTopActivity" android:launchMode="singleTop" />
通过Intent标志设置启动行为 :
1 2 3 val intent = Intent(this, SecondActivity::class.java) intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP startActivity(intent)
任务栈管理 Android使用任务栈(Task)管理Activity,遵循后进先出(LIFO)原则。
任务栈相关Intent标志 :
FLAG_ACTIVITY_NEW_TASK
:在新任务中启动Activity
FLAG_ACTIVITY_CLEAR_TOP
:清除目标Activity上面的所有Activity
FLAG_ACTIVITY_CLEAR_TASK
:清除目标任务中的所有Activity
FLAG_ACTIVITY_SINGLE_TOP
:等同于singleTop启动模式
FLAG_ACTIVITY_REORDER_TO_FRONT
:将已存在的Activity实例移到栈顶
任务亲和性(taskAffinity) : 指定Activity倾向于归属的任务栈,默认为应用包名。
1 2 3 <activity android:name=".DifferentTaskActivity" android:taskAffinity="com.example.different" />
与iOS导航栈对比 iOS的导航栈管理 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // 导航控制器管理视图控制器栈 UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:rootVC]; // 压入新控制器 [navController pushViewController:newVC animated:YES]; // 弹出控制器 [navController popViewControllerAnimated:YES]; // 弹出到根控制器 [navController popToRootViewControllerAnimated:YES]; // 弹出到特定控制器 [navController popToViewController:specificVC animated:YES]; // 替换整个栈 [navController setViewControllers:@[rootVC, secondVC, thirdVC] animated:YES];
主要差异 :
Android使用系统级的任务栈管理Activity,而iOS使用UINavigationController管理视图控制器栈
Android的启动模式提供更灵活的实例管理,而iOS主要依赖导航控制器的API
Android可以通过taskAffinity将Activity分配到不同任务栈,iOS没有直接等价物
Android的任务栈可以跨应用,而iOS的导航栈通常限于单个应用
iOS的导航栈更简单直观,而Android的任务栈概念更复杂但更灵活
3.5 Activity状态保存与恢复 状态保存机制 Android在配置变化(如屏幕旋转)或系统内存不足时可能会销毁并重建Activity。为保持用户体验,需要保存和恢复Activity状态。
使用onSaveInstanceState保存状态 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 override fun onSaveInstanceState(outState: Bundle) { // 保存UI状态 val userInput = editText.text.toString() outState.putString("user_input", userInput) val scrollPosition = scrollView.scrollY outState.putInt("scroll_position", scrollPosition) // 保存复杂对象(必须实现Parcelable) val user = User("John", 30) outState.putParcelable("user_object", user) super.onSaveInstanceState(outState) }
恢复保存的状态 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 恢复状态 savedInstanceState?.let { val userInput = it.getString("user_input") editText.setText(userInput) val scrollPosition = it.getInt("scroll_position") scrollView.post { scrollView.scrollTo(0, scrollPosition) } val user = it.getParcelable<User>("user_object") // 使用恢复的user对象 } } // 或者在单独的回调中恢复 override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) // 恢复状态(与onCreate中的代码类似) val userInput = savedInstanceState.getString("user_input") editText.setText(userInput) // ... }
ViewModel与状态保存 Android Jetpack提供了ViewModel组件,帮助在配置变化时保留数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 // 定义ViewModel class MainViewModel : ViewModel() { // 数据在配置变化时保留 val userData = MutableLiveData<User>() // 加载数据 fun loadUser(userId: String) { // 异步加载用户数据 viewModelScope.launch { val user = repository.getUser(userId) userData.value = user } } // ViewModel被清除时调用 override fun onCleared() { super.onCleared() // 清理资源 } } // 在Activity中使用ViewModel class MainActivity : AppCompatActivity() { private lateinit var viewModel: MainViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 获取ViewModel实例 viewModel = ViewModelProvider(this).get(MainViewModel::class.java) // 观察数据变化 viewModel.userData.observe(this) { user -> // 更新UI userNameTextView.text = user.name } // 加载数据(只在首次创建时调用,配置变化时不会重复调用) if (savedInstanceState == null) { viewModel.loadUser("user_123") } } }
与iOS状态保存对比 iOS的状态保存机制 :
``` // 使用NSCoding保存状态
(void)encodeRestorableStateWithCoder:(NSCoder *)coder { [super encodeRestorableStateWithCoder:coder]; // 保存UI状态 NSString *userInput = self.textField.text; [coder encodeObject:userInput forKey:@”user_input”]; CGPoint scrollPosition = self.scrollView.contentOffset; [coder encodeCGPoint:scrollPosition forKey:@”scroll_position”]; // 保存复杂对象(必须符合NSCoding协议) User *user = [[User alloc] initWithName:@”John” age:30]; [coder encodeObject:user forKey:@”user_object”]; }
// 恢复保存的状态
(void)decodeRestorableStateWithCoder:(NSCoder *)coder { [super decodeRestorableStateWithCoder:coder]; // 恢复UI状态 NSString *userInput = [coder decodeObjectForKey:@”user_input”]; self.textField.text = userInput; CGPoint scrollPosition = [coTo save on context only part of this file has been shown to you. You should retry this tool after you have searched inside the file with grep -n
in order to find the line numbers of what you are looking for.