「Efficient Android Threading 笔记」- C1 Android Components and the Need for Multiprocessing Android RecyclerView Android Socket Programming Supporting Multiple Screens Make a Reusable UI in Android App Development 如何在 Android Studio 中包含 *.so library,并使用库中定义的方法? 使用 SpannableString 格式化字符串,实现前景色、下划线、超链接、图文混排等 如何使用 bound service 完成进程间通信? 创建自定义视图 Creating custom views 通过 Android Theme & Style 定制应用的样式 「译」Android ViewPropertyAnimator 介绍 Android Animation Interpolator - Android 动画插值器源码笔记 「译」Android Animation in Honeycomb by Chet Haase(Android 3.0系统中的动画机制) 从 Android Sample ApiDemos 中学习 android.animation API 的用法 如何学习 Android Animation? 如何实现 Android ListView「上拉加载更多」? 「译」向Big Nerd Ranch提问:为什么Fragment在Android App开发中非常重要? 分类整理我在 SegmentFault 上针对某些问题作的回答 Android Servcie 后台服务总结笔记 如何在Android设备旋转时暂存数据以保护当前的交互状态? Android Message Handler 消息处理机制总结笔记 如何获取FragmentTabHost中指定标签页的Fragment? Fragment子类必须包含一个public无参构造器 如何更新及替换ViewPager中的Fragment? 如何使用Android UI Fragment开发“列表-详情”界面? 一个Android音频文本同步的英文有声读物App的开发过程 「Android编程权威指南笔记」Android应用本地化 通过jfeinstein10/SlidingMenu实现Android侧滑菜单 为Ubuntu14.04部署Android App的Eclipse开发环境 「Android编程权威指南笔记」使用ListFragment显示列表 「Android编程权威指南笔记」SDK版本与兼容 「Android编程权威指南笔记」Android布局和组件 「Android编程权威指南笔记」UI Fragment 「Android编程权威指南笔记」Activity 第一次开发iOS App和Android的对比总结笔记 「App Training笔记」创建第一个应用 「App Training笔记」开发入门训练大纲 Android APP - 从远程FTP服务器下载文件到本地

「Android编程权威指南笔记」Activity

2015年03月15日

第2章 Android与MVC模式

如何创建一个新类,并自动为成员变量生成getter和setter方法,以及成员变量命名的约定;
android命名规范,m作为Fields前缀,s作为Static Fields前缀。
eclipse可以自动生成getter和setter方法。

介绍MVC模式,使用MVC设计软件的优点;
使用MVC扩展了第1章的范例:
更新View;
更新Controller及模型(涉及到的编程原则,封装公共代码);
介绍了另一种资源文件:图片资源文件,添加和引用的方法。
扩展练习:使用ImageButton、为TextView添加监听器、隐藏的与activity lifecycle有关的bug。

第4章 android应用的调试

如何处理应用bug. 如何使用LogCat、Android Lint和Eclipse内置的代码调试器。
DDMS透视图( Dalvik Debug Monitor Service,调试监控服务工具),包含LogCat以及Devices视图。
可以查看异常及其栈追踪(stack trace)(应该是指方法的调用信息).
一般情况下,在LogCat中寻找最后一个异常及其栈追踪信息的第一行(该行记录发生异常的类、方法、源文件、代码行号)。
对于非崩溃型的异常(比如代码逻辑错误),只能在可能导致问题的地方:

  • 主动抛出异常,用于查看某个方法的栈追踪;
  • 利用调试器设置合适的断点。

监听器

Android应用属于典型的事件驱动类型。不同于命令行或脚本程序,事件驱动型应用启动后,即开始等待行为事件的发生,如用户单击某个按钮。(事件也可以由操作系统或其他应用触发,但用户触发的事件更显而易见。)
应用等待某个特定事件的发生,也可以说该应用正在“监听”特定事件。为响应某个事件而创建的对象叫做监听器(listener)。监听器是实现特定监听器接口的对象,用来监听某类事件的发生。
监听器需实现 View.OnClickListener 接口。

mButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    }
});

通过匿名内部类实现监听器,代码块简洁、减少命名类的使用。

第3章 Activity的生命周期

Activity管理用户和屏幕的交互。
当Activity子类的实例创建后,onCreate()方法会被调用,需要获取并管理属于它的界面。通过传入布局的资源ID参数,该方法生成指定布局的视图并将其放置在屏幕上。布局视图生成后,布局文件包含的组件也随之以各自的属性定义完成实例化。

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

每个activity实例都有生命周期。在生命周期内,activity在运行、暂停、停止3种状态间切换,状态切换时系统会调用生命周期方法,所以需要override生命周期方法,在状态切换时完成状态保存/恢复之类的工作。

override生命周期方法时,必须通过super关键字调用超类的方法。onCreate()必须先调用超类方法。
可以通过日志跟踪生命周期。通过logcat工具查看日志。
启动activity时,onCreate() -> onStart() -> onResume();
单击设备后退键(相当于通知系统“我已经完成activity的使用,现在不需要它了”):onPause() -> onStop() -> onDestroy();
单击设备Home键(相当于通知系统“我去别处看看,稍后可能会回来”):onPause() -> onStop(). 此时,为了快速响应随时返回应用,系统只是暂停当前activity,并不销毁它。但是系统不保证暂停的activity常驻内存,当系统需要回收内存时,将首先销毁暂停的activity.

设备旋转时activity生命周期的变化?

涉及设备配置、备选资源的概念,layout的备选资源,framelayout组件位置排列?
设备旋转前如何保存数据?覆盖onSaveInstanceState()方法。
称之为“暂存状态”。常见的做法?
系统settings -> Development Options -> Don’t keep activities选项改变了?

设备旋转前保存数据

设备旋转时,当前的activity实例会被系统销毁,然后创建一个新的实例。所以需要在设备旋转时保存数据,使得可以恢复到旋转前的状态。
一种解决方法是覆写(override) activity方法:protected void onSaveInstanceState(Bundle outState). 在onPause(), onStop(), onDestroy()方法之前由系统调用。要求所有activity的视图将自身状态数据保存在Bundle对象中。Bundle是存储字符串键与限定类型值之间映射关系(键值对)的一种结构。

private static final String KEY_INDEX = "index";
private int mCurrentIndex = 0;

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putInt(KEY_INDEX, mCurrentIndex);
}

在onCreate()方法中检查存储的bundle信息:
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (savedInstanceState != null) {
       mCurrentIndex = savedInstanceState.getInt(KEY_INDEX, 0);
    }
}

我们在Bundle中存储和恢复的数据类型只能是基本数据类型(primitive type)以及可以实现Serializable接口的对象。创建自己的定制类时,如需在onSaveInstanceState(…)方法中保存类对象,记得实现Serializable接口。

Activity会被销毁的情况:

  • 旋转屏幕;
  • 用户离开当前界面;
  • Android需要回收内存时(只有暂停或停止状态才可能被回收);

bundle被存储于activity的ActivityRecord.
ActivityRecord可以保留多久?用户按了Back Button时,系统会彻底销毁当前的activity,记录同时被清除。此外,系统重启或者长时间不使用activity时,记录通常也会被清除。

第5章 创建新的Activity

创建新的activity,需要

  • 创建布局文件(以及可能用到的资源文件);
  • 创建新的activity子类;
  • 在manifest配置文件中声明activity;

manifest配置文件是一个包含元数据的XML文件,用来向Android操作系统描述应用。该文件总是以AndroidManifest.xml命名。
应用的所有activity都必须在manifest配置文件中声明,这样操作系统才能够使用它们。

启动Activity

Intent对象是组件(component)用来与操作系统通信的一种媒介工具。Intent类提供了多个构造方法,以满足不同组件的需求。对于activity组件:
public Intent(Context packageContext, Class<?> cls)
Class对象是需要启动的activity,Context对象指明Class对象所在的包。

Intent i = new Intent(CurrentActivity.this, DestActivity.this);
startActivity(i);

这是显示的(Explicit)intent.

Activity间传递数据

Intent提供putExtra方法,可以在activity间传递数据。extra是key-value结构,可以是任意数据。

public static final String EXTRA_ANSWER_IS_TRUE = "packagename.answer_is_true";

Intent i = new Intent(CurrentActivity.this, DestActivity.this);
boolean answer_is_true = true;
i.putExtra(CurrentActivity.EXTRA_YOUR_DATA, answer_is_true);
startActivity(i);

从extra获取数据的方法,如果是boolean变量:

private boolean mAnswerIsTrue;

@Override
public void onCreate(Bundle savedInstanceState) {
    ......
    mAnswerIsTrue = getIntent.getBooleanExtra(EXTRA_ANSWER_IS_TRUE, false);
}

从子activity获取返回结果

父Activity应该这样实现:

Intent i = new Intent(CurrentActivity.this, DestActivity.this);
// 启动多个child activity时,用来区分返回的结果属于哪个child activity
int requestCode = 0;
startActivityForResult(i, requestCode);

// 覆写onActivityResult()方法以处理返回结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
    if (intent == null) {
        return;
    }

    // 从Intent中获取返回数据
    if (requestCode == 0) {

    }
}

子Activity应该这样实现:

数result code可以是以下两个预定义常量中的任何一个, Activity.RESULT_OK, Activity.RESULT_CANCELED, (如需自己定义结果代码,还可使用另一个常量:RESULT_FIRST_USER)。
在父activity需要依据子activity的完成结果采取不同操作时,设置结果代码很有帮助,比如子activity有一个OK按钮及一个Cancel按钮。

Intent intent = new Intent();
int resultCode = RESULT_OK;
setResult(resultCode, intent);

在桌面点击app图标时,os只是启动了系统的一个activity,即launcher activity。使用向导创建的activity默认被设置为launcher activity,在manifest中的定义:

<activity
    android:name=""
    android:label="@string/app_name" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

整理笔记时参考了如下资料:

  • 《Android编程权威指南》Bill Phillips Brian Hardy著,王明发 译。人民邮电第1版。
    英文版书名《Android Programming - The Big Nerd Ranch Guide》

知识共享许可协议
li2的博客WeiYi.Li 创作,采用 知识共享 署名-非商业性使用 4.0 国际 许可协议进行许可。
© 2011-2022. All rights reserved by WeiYi.Li. Powerd by Jekyll & LinAnYa's Theme