安卓平板与智能手机开发:组件、视图与生命周期解析
立即解锁
发布时间: 2025-08-23 01:37:33 阅读量: 1 订阅数: 6 

### 安卓平板与智能手机开发:组件、视图与生命周期解析
在安卓开发领域,构建适应不同屏幕尺寸的应用是一项重要任务。本文将深入探讨安卓应用开发中的组件、视图和生命周期相关知识,帮助开发者更好地理解和运用这些概念。
#### 1. 启动模拟器与示例应用
当你完成一系列操作后,模拟器会启动,安卓系统会在模拟器上启动,示例应用也会随之启动。若在任何步骤遇到问题,可能需要重新安装工具链。不过,若之前已验证工具链安装并能正常启动安卓应用,某些仅在新安装后首次使用时出现的步骤就不会遇到。
现在运行的示例应用能够自动适应不同屏幕尺寸。通过为小型安卓设备和大型平板风格安卓设备创建AVD(安卓虚拟设备),可以看到设计模式示例的效果。该框架应用所使用的设计模式会根据显示系统自动调整。屏幕足够大时,用户会看到左侧是列表,右侧通过标签选择片段的单屏界面;否则,用户会看到两个独立屏幕,一个显示选择列表,另一个包含与这些标签对应的标签和片段,内容取决于用户从列表中的选择。
这是一种典型的UI设计模式,该框架能加速安卓应用开发中一些必要部分的进程,让开发者更快进入对企业应用开发者最有用的部分。
#### 2. 组件、视图与生命周期概述
示例代码包含了一个最小但典型的安卓应用所需的所有对象。这个最小框架应用包括输入搜索词的字段、搜索/查询结果列表,以及显示搜索结果和相关信息的位置。
大部分用于这个最小应用框架的类是来自视图类层次结构的组件或安卓小部件。组件是安卓应用的大规模构建块,主要包括以下几种:
- **Activity子类**:为每个具有独特交互功能的主要分组创建Activity子类,用户能明显察觉到屏幕显示内容的不同。
- **Fragment**:用于组织活动内的交互代码。在大屏幕上,多个片段可能同时可见;在小屏幕上,每个活动通常包含一个片段。
- **Service子类**:用于执行长时间运行且无交互元素的代码,服务组件在后续开发中是代码的重要部分。
组件具有生命周期,与J2ME MIDlet生命周期中暂停应用应释放资源的概念类似,但安卓组件和生命周期更加丰富和强大,它能让大型复杂应用适应小堆内存。
#### 3. 组件的销毁与重建
安卓应用中每个组件的实例都可以被销毁,释放其所占用的内存。组件中的生命周期方法能让它们在销毁前保存状态,首次创建时进行初始化,并在重建时恢复状态。
对于有状态的组件,生命周期方法会表明该组件可能被销毁,开发者必须提供保存组件状态的代码,这不是可选的。从功能上来说,这有点像“交换”,但生命周期方法只允许保存恢复状态所需的数据,且以最方便的形式保存。
如果试图通过保留组件引用来阻止组件销毁,只会造成内存泄漏。
#### 4. MainActivity类
以下是`MainActivity.java`的代码:
```java
package com.enterpriseandroidbook.fragmentframework;
import android.app.ActionBar;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
/**
* @author zigurd
*/
public class MainActivity extends TabbedActivity {
// String for logging the class name
private final String CLASSNAME = getClass().getSimpleName();
// Turn logging on or off
private final boolean L = true;
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
// To keep this method simple
doCreate(savedState);
// If we had state to restore, we note that in the log message
if (L) Log.i(CLASSNAME, "onCreate" +
(null == savedState ? " Restored state" : ""));
}
@Override
protected void onRestart() {
super.onRestart();
// Notification that the activity will be started
if (L) Log.i(CLASSNAME, "onRestart");
}
@Override
protected void onStart() {
super.onStart();
// Notification that the activity is starting
if (L) Log.i(CLASSNAME, "onStart");
}
@Override
protected void onResume() {
super.onResume();
// Notification that the activity will interact with the user
if (L) Log.i(CLASSNAME, "onResume");
}
protected void onPause() {
super.onPause();
// Notification that the activity will stop interacting with the user
if (L) Log.i(CLASSNAME, "onPause" + (isFinishing() ? " Finishing" : ""));
}
@Override
protected void onStop() {
super.onStop();
// Notification that the activity is no longer visible
if (L) Log.i(CLASSNAME, "onStop");
}
@Override
protected void onDestroy() {
super.onDestroy();
// Notification the activity will be destroyed
if (L) Log.i(CLASSNAME, "onDestroy"
// Are we finishing?
+ (isFinishing() ? " Finishing" : ""));
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
saveState(outState);
// Called when state should be saved
if (L) Log.i(CLASSNAME, "onSaveInstanceState");
}
@Override
protected void onRestoreInstanceState(Bundle savedState) {
super.onRestoreInstanceState(savedState);
if (null != savedState) restoreState(savedState);
// If we had state to restore, we note that in the log message
if (L) Log.i(CLASSNAME, "onRestoreInstanceState" +
(null == savedState ? " Restored state" : ""));
}
///////////////////////////////////////////////////////////////////////////////
// The minor lifecycle methods - you probably won't need these
///////////////////////////////////////////////////////////////////////////////
@Override
protected void onPostCreate(Bundle savedState) {
super.onPostCreate(savedState);
if (null != savedState) restoreState(savedState);
// If we had state to restore, we note that in the log message
if (L) Log.i(CLASSNAME, "onCreate" +
(null == savedState ? " Restored state" : ""));
}
@Override
protected void onPostResume() {
super.onPostResume();
// Notification that resuming the activity is complete
if (L) Log.i(CLASSNAME, "onPostResume");
}
@Override
protected void onUserLeaveHint() {
super.onUserLeaveHint();
// Notification that user navigated away from this activity
if (L) Log.i(CLASSNAME, "onUserLeaveHint");
}
///////////////////////////////////////////////////////////////////////////////
// Overrides of the implementations ComponentCallbacks methods in Activity
///////////////////////////////////////////////////////////////////////////////
@Override
public void onConfigurationChanged(Configuration newConfiguration) {
super.onConfigurationChanged(newConfiguration);
// This won't happen unless we declare changes we handle in the manifest
if (L) Log.i(CLASSNAME, "onConfigurationChanged");
}
@Override
public void onLowMemory() {
// No guarantee this is called before or after other callbacks
if (L) Log.i(CLASSNAME, "onLowMemory");
}
///////////////////////////////////////////////////////////////////////////////
// App-specific code here
///////////////////////////////////////////////////////////////////////////////
/**
* This is where we restore state we previously saved.
* @param savedState the Bundle we got from the callback
*/
private void restoreState(Bundle savedState) {
// Add your code to restore state here
}
/**
* Add this activity's state to the bundle and/or commit pending data
*/
private void saveState(Bundle state) {
// Add your code to add state to the bundle here
}
/**
* Perform initializations on creation of this Activity instance
* @param savedState
*/
private void doCreate(Bundle savedState) {
setContentView(R.layout.main);
if (null != savedState) restoreState(savedState);
ActionBar bar = getActionBar();
bar.setDisplayShowTitleEnabled(false);
bar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Initialize the tabs (Fails silently if the tab fragments don't exist)
int names[] = {R.string.item, R.string.detail };
int fragments[] = { R.id.content_frag, R.id.detail_frag };
initializeTabs(0, names, fragments);
}
}
```
这个`MainActivity`子类的代码展示了如何实现安卓的生命周期处理。每个生命周期方法都有日志记录,开发者可以在Eclipse IDE的logcat视图中查看这些日志信息,通常该视图位于屏幕底部。
虽然这段代码中没有与用户交互的代码,但活动仍可被视为用户交互的基本单位,因为它代表了一屏的用户交互内容。Activity类是安卓用户交互卡片栈隐喻的基础,在活动之间导航是用户交互的重要部分,这个Activity子类是应用的主活动,用户点击应用图标时应用从此处开始,它也是应用返回栈的底部。
代码中的生命周期方法实现包括`onRestart`、`onStart`、`onResume`、`onPause`和`onStop`等,这些回调与其他重要生命周期方法一样,通过日志记录展示它们的调用时机,这些方法能告知活动何时可见或被其他活动遮挡。开发者可以在Eclipse IDE的logcat视图中观察这些日志信息,并结合安卓文档中关于活动生命周期的图表,了解图表中状态转换的时机。
需要注意的是,保存状态并非必须使用Bundle对象,在安卓中有三种基本的保存状态方法:
- **恢复状态**:如果状态是数据库查询的结果,可以将查询保存到Bundle中(甚至在特定情况下恢复查询)并重新运行。
- **保存到数据库**:如果状态存在于运行应用的客户端设备本地数据库中,组件重建时可从该数据库读取。
- **放入Bundle**:如前文所述,将状态保存到Bundle对象中。
在大多数非简单应用中,通常会结合使用这些保存状态的方法。安卓应用保存状态的需求会影响应用的设计,以SQLite数据库为主的数据模型是一种方便的方式,可最小化应用需要保存的状态。将数据库放入ContentProvider对象中可将其与Activity对象分离,ContentProvider API能简单实现观察者模式,并使应用遵循一种设计模式,即本地数据库与网络数据库同步。
#### 5. Fragment:组织代码和UI的工具
在安卓Honeycomb版本之前,典型的安卓应用实现将与用户界面小部件交互的代码放在Activity子类中。谷歌的合作伙伴推出使用安卓系统的平板电脑后,谷歌围绕一个名为Fragment的新类重新设计了用户界面和开发者用于创建用户界面的API。
Fragment既不是Activity的子类,也不是View的子类。与活动类似,片段可以包含处理用户交互的代码,它可以像安卓小部件一样布局,但它不是小部件,而是一个包含与用户交互代码的容器。
Fragment类包含生命周期方法,但它不是安卓组件,这些生命周期方法是为了让包含片段的Activity将生命周期事件传播到其中的片段。也就是说,单个片段实例不会被销毁,但包含它们的Activity实例会被销毁。
在示例中,关于Fragment有三个重要方面:
- 处理与安卓小部件用户交互的代码。
- 与Activity示例类似的生命周期方法重写,可进行日志记录,方便查看这些方法相对于活动生命周期的调用时机。
- 一些Fragment特有的生命周期方法,主要用于实现片段对象的初始化。
#### 6. PickFragment类
以下是`PickFragment.java`的代码:
```java
package com.enterpriseandroidbook.fragmentframework;
import android.app.Activity;
import android.app.Fragment;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class PickFragment extends Fragment implements OnItemClickListener {
// String for logging the class name
private final String CLASSNAME = getClass().getSimpleName();
// Turn logging on or off
private static final boolean L = true;
public void onAttach(Activity activity) {
super.onAttach(activity);
// Notification that the fragment is associated with an Activity
if (L)
Log.i(CLASSNAME, "onAttach " + activity.getClass().getSimpleName());
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Tell the system we have an options menu
this.setHasOptionsMenu(true);
if (null != savedInstanceState)
restoreState(savedInstanceState);
// Notification that
if (L)
Log.i(CLASSNAME, "onCreate");
}
// Factor this out of methods that get saved state
private void restoreState(Bundle savedInstanceState) {
// TODO Auto-generated method stub
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final ListView list = (ListView) inflater.inflate(
R.layout.list_frag_list, container, false);
if (L)
Log.i(CLASSNAME, "onCreateView");
attachAdapter(list);
list.setOnItemClickListener(this);
return list;
}
public void onStart() {
super.onStart();
if (L)
Log.i(CLASSNAME, "onStart");
}
public void onresume() {
super.onResume();
if (L)
Log.i(CLASSNAME, "onResume");
}
public void onPause() {
super.onPause();
if (L)
Log.i(CLASSNAME, "onPause");
}
public void onStop() {
super.onStop();
if (L)
Log.i(CLASSNAME, "onStop");
}
public void onDestroyView() {
super.onDestroyView();
if (L)
Log.i(CLASSNAME, "onDestroyView");
}
public void onDestroy() {
super.onDestroy();
if (L)
Log.i(CLASSNAME, "onDestroy");
}
public void onDetach() {
super.onDetach();
if (L)
Log.i(CLASSNAME, "onDetach");
}
// ////////////////////////////////////////////////////////////////////////////
// Minor lifecycle methods
// ////////////////////////////////////////////////////////////////////////////
public void onActivityCreated() {
// Notification that the containing activiy and its View hierarchy exist
if (L)
Log.i(CLASSNAME, "onActivityCreated");
}
// /////////////////////////////////////////////////////////////////////////////
// Overrides of the implementations ComponentCallbacks methods in Fragment
// /////////////////////////////////////////////////////////////////////////////
@Override
public void onConfigurationChanged(Configuration newConfiguration) {
super.onConfigurationChanged(newConfiguration);
// This won't happen unless we declare changes we handle in the manifest
if (L)
Log.i(CLASSNAME, "onConfigurationChanged");
}
@Override
public void onLowMemory() {
// No guarantee this is called before or after other callbacks
if (L)
Log.i(CLASSNAME, "onLowMemory");
}
// /////////////////////////////////////////////////////////////////////////////
// Menu handling code
// /////////////////////////////////////////////////////////////////////////////
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.search_menu, menu);
}
// ////////////////////////////////////////////////////////////////////////////
// App-specific code
// ////////////////////////////////////////////////////////////////////////////
/**
* Attach an adapter that loads the data to the specified list
*
* @param list
*/
private void attachAdapter(final ListView list) {
// Make a trivial adapter that loads an array of strings
ArrayAdapter<String> numbers = new ArrayAdapter<String>(list
.getContext().getApplicationContext(),
android.R.layout.simple_list_item_1, new String[] { "one",
"two", "three", "four", "five", "six" });
// tell the list to use it
list.setAdapter(numbers);
// l.setOnItemClickListener(this);
}
// ////////////////////////////////////////////////////////////////////////////
// Implementation of the OnItemClickListener interface
// ///////////////////////////////////////////////////////////////////////////
@Override
public void onItemClick(AdapterView<?> arg0, View view, int position,
long id) {
// As an example of sending data to our fragments, we will create a
// bundle
// with an int and a string, based on which view was clicked
Bundle data = new Bundle();
int ordinal = position + 1;
data.putInt("place", ordinal);
data.putString("placeName", Integer.toString(ordinal));
((TabbedActivity) getActivity()).loadTabFragments(data);
}
}
```
`PickFragment`类的代码看起来很像不使用Fragment时的Activity子类,但与Activity不同的是,片段的生命周期与包含它的Activity的生命周期相关。在大屏幕布局中,Activity中的所有Fragment对象的生命周期方法会在Activity相应生命周期方法调用时被调用。
`onCreate`方法调用`attachAdapter`和`setOnItemClickListener`来初始化片段。`attachAdapter`方法用于将一个包含测试值的`ArrayAdapter`附加到片段中的`ListView`对象上。`onItemClick`方法实现了`OnItemClickListener`接口,当安卓项目被点击时会调用该方法,在这个例子中,点击列表项会将一些数据加载到屏幕右侧的片段中,小屏幕时则加载到单独的Activity中。
通过深入理解和运用这些组件、视图和生命周期的知识,开发者能够构建出更加稳定、高效且用户体验良好的安卓应用。无论是处理不同屏幕尺寸的适配,还是管理组件的生命周期和状态保存,这些知识都是安卓开发中不可或缺的重要部分。
### 安卓平板与智能手机开发:组件、视图与生命周期解析
#### 6. 安卓组件生命周期总结
为了更清晰地理解安卓组件(Activity和Fragment)的生命周期,我们可以通过一个流程图来展示它们之间的关系和状态转换。
```mermaid
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([Activity启动]):::startend --> B(Activity: onCreate):::process
B --> C(Activity: onStart):::process
C --> D(Activity: onResume):::process
D --> E{用户操作或系统事件}:::decision
E -->|切换到后台| F(Activity: onPause):::process
F --> G(Activity: onStop):::process
G --> H{是否销毁}:::decision
H -->|是| I(Activity: onDestroy):::process
H -->|否| J(Activity: onRestart):::process
J --> C
E -->|Fragment交互| K(Fragment: onAttach):::process
K --> L(Fragment: onCreate):::process
L --> M(Fragment: onCreateView):::process
M --> N(Fragment: onActivityCreated):::process
N --> O(Fragment: onStart):::process
O --> P(Fragment: onResume):::process
P --> Q{Activity状态变化}:::decision
Q -->|Activity onPause| R(Fragment: onPause):::process
R --> S(Fragment: onStop):::process
S --> T(Fragment: onDestroyView):::process
T --> U(Fragment: onDestroy):::process
U --> V(Fragment: onDetach):::process
Q -->|Activity onResume| P
```
从这个流程图中可以看出,Activity的生命周期相对复杂,包含了多个状态转换,而Fragment的生命周期则依赖于包含它的Activity。当Activity进入不同的状态时,会相应地触发Fragment的生命周期方法。
例如,当Activity启动时,会依次调用`onCreate`、`onStart`和`onResume`方法,此时如果Activity中包含Fragment,Fragment也会依次调用`onAttach`、`onCreate`、`onCreateView`等方法。当Activity进入后台时,会调用`onPause`和`onStop`方法,Fragment也会相应地调用`onPause`和`onStop`方法。
#### 7. 实际应用中的组件与生命周期管理
在实际的安卓应用开发中,合理管理组件和生命周期是非常重要的。以下是一些实际应用中的建议和注意事项:
##### 7.1 状态保存与恢复
在前面我们提到了三种保存状态的方法,在实际应用中,需要根据具体情况选择合适的方法。例如,对于一些简单的临时状态,可以使用Bundle对象保存;对于一些持久化的数据,可以保存到数据库中。
以下是一个简单的示例,展示如何在Activity中使用Bundle保存和恢复状态:
```java
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// 保存一些临时状态
outState.putString("key", "value");
}
@Override
protected void onRestoreInstanceState(Bundle savedState) {
super.onRestoreInstanceState(savedState);
if (savedState != null) {
String value = savedState.getString("key");
// 使用恢复的状态
}
}
```
##### 7.2 资源释放
在组件销毁时,需要及时释放占用的资源,避免内存泄漏。例如,在Activity的`onDestroy`方法中,需要释放一些不再使用的对象引用,关闭数据库连接等。
```java
@Override
protected void onDestroy() {
super.onDestroy();
// 释放资源
if (mDatabase != null) {
mDatabase.close();
}
}
```
##### 7.3 异步任务管理
在安卓应用中,经常会使用异步任务来执行一些耗时操作,如网络请求、数据库查询等。在组件销毁时,需要及时取消这些异步任务,避免出现异常。
```java
private AsyncTask<Void, Void, Void> mAsyncTask;
@Override
protected void onDestroy() {
super.onDestroy();
if (mAsyncTask != null && mAsyncTask.getStatus() != AsyncTask.Status.FINISHED) {
mAsyncTask.cancel(true);
}
}
```
#### 8. 组件与视图的优化建议
为了提高安卓应用的性能和用户体验,还可以对组件和视图进行一些优化。以下是一些常见的优化建议:
| 优化点 | 建议 |
| ---- | ---- |
| 布局优化 | 使用`include`标签复用布局,减少布局嵌套,使用`merge`标签简化布局结构。 |
| 视图缓存 | 使用`ViewHolder`模式缓存视图,避免频繁调用`findViewById`方法。 |
| 图片处理 | 使用图片压缩和缓存技术,避免加载过大的图片导致内存溢出。 |
| 动画优化 | 使用属性动画替代帧动画,减少内存消耗。 |
#### 9. 总结
通过本文的介绍,我们深入了解了安卓开发中的组件、视图和生命周期相关知识。组件(Activity、Fragment和Service)是安卓应用的核心构建块,它们各自具有不同的功能和生命周期。视图则是用户界面的重要组成部分,通过合理的布局和交互设计,可以提升用户体验。
生命周期管理是安卓开发中的一个重要环节,正确处理组件的生命周期可以避免内存泄漏和应用崩溃等问题。同时,我们还介绍了一些实际应用中的组件与生命周期管理技巧,以及组件和视图的优化建议。
在实际开发中,开发者需要根据具体的需求和场景,灵活运用这些知识和技巧,构建出更加稳定、高效且用户体验良好的安卓应用。无论是开发企业级应用还是个人应用,掌握这些知识都是非常必要的。希望本文能够对安卓开发者有所帮助,让大家在安卓开发的道路上更加顺利。
0
0
复制全文
相关推荐










