Android编程权威指南(第2版)读书笔记

本文介绍了Android开发中的多种实用技巧,包括按键监听器的正确使用、脱离Android Studio编译代码的方法、设置自动识别前缀、控件继承关系、Activity生命周期管理、处理设备旋转引起的界面重建、Intent的使用、Fragment的创建及优化、布局属性详解、日期格式化、指定登录界面、RecyclerView的优化、单例的应用场景、Fragment的保留策略、任务与后退栈的管理、进程与任务的区别、线程管理等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.按键监听器

在按键监听器注册时匿名内部类中使用toast时注意,此时this是View.OnClickListener,而不是activity

2.有时,出于种种原因,可能需要脱离Android Studio编译代码。

要使用Gradle,请切换到项目目录并执行以下命令:
$ ./gradlew tasks
如果是Windows系统,执行以下命令:
> gradlew.bat tasks
执行以上命令会显示一系列可用任务。你需要的是任务是installDebug,因此,再执行以下
命令:
$ ./gradlew installDebug
如果是Windows系统,执行以下命令。
> gradlew.bat installDebug
以上命令将把应用安装到当前连接的设备上,但不会运行它。要运行应用,需要在设备上手
动启动。

3.设置自动识别前缀

首先,配置Android Studio识别成员变量的m前缀。
打开
Android Studio首选项对话框(Mac用户选择Android Studio菜单,Windows用户选择File →
Settings
菜单)。分别展开EditorCode Style选项,在Java选项下选择Code Generation选项页。
Naming表单中,选择Fields行,添加m作为fields的前缀,然后添加s作为StaticFields的前缀

4.控件继承关系

View->TextView->Button

View->ImageView->ImageButton

5.onCreate()方法生命周期相关

通常, activity通过覆盖onCreate(...)方法来准备以下用户界面相关的工作:
实例化组件并将组件放置在屏幕上(调用setContentView(int)方法);
引用已实例化的组件;
为组件设置监听器以处理用户交互;
访问外部模型数据。
千万不要自己去调用
onCreate(...)方法或任何其他Activity生命周期方法,记住这一点
很重要。我们只需在
activity子类里覆盖这些方法,Android会适时去调用它们。 

另外,在onCreate(...)方法里,必须首先调用超类的实现方法,然后再调用
其他方法,这一点很关键。而在其他几个方法中,是否首先调用超类方法就不那么重要了。

需要注意的是,停止的activity能够存在多久,谁也无法保证。系统需要回收内存时,它将首
先销毁那些停止的
activity 

系统重启或长时间不使用activity时,暂存的activity记录通常也会被清除,此时的保存在activity中的bundle中的数据也会消失
和单击主屏幕键不一样的是,单击后退键后,无论是否启用Don’t keep activities选项,系统
总是会销毁当前
activity。单击后退键相当于通知系统“用户不再需要使用当前的activity

6.设备旋转导致界面回到初始

在应用运行中,只要设备配置发生了改变,Android就会销毁当前activity,然后再
创建新的
activity

设备旋转时,系统会销毁当前QuizActivity实例,然后创建一个新的QuizActivity实例,重新调用oncreate调用新的布局文件。再
次旋转设备,查看该销毁与再创建的过程。

横屏activity的创建:

  1. New Android resource directory
  2. 从资源类型(Resource type)列表中选择layout,保持Source Setmain选项不变。接下来选中待选资源特征列表中的Orientation然后单击>>按钮将其移动至已选资源特征区域
  3. 确认选中Screen Orientation下拉列表中的Landscape选项,并确保目录名显示为layout-land,如图3-10所示。点击OK按钮让Android Studio创建res/layout-land 
  4. 在project视图下,activity_quiz.xml文件从res/layout目录复制至res/layout-land目录,两个布局文件必须具有相同的文件名,这样它们才能以同一个资源ID被引用。
  5. 修改layout-land下的布局文件,修改成framelayout,这个帧布局是使用android:layout_gravity来指定位置,因此每个framelayout的直属子类需要添加这个值
  6. 在activity中覆盖onSaveInstanceState,put键值对,在oncreate中获取和设置键值。
7.显式intent

简单的方法是直接在数据目的activity中
Intent i = new Intent(QuizActivity.this, CheatActivity.class);
startActivity(i); 
带参数的intent
传递数据需要在数据目的activity加入
public static Intent newIntent(Context packageContext, boolean answerIsTrue) {
Intent i = new Intent(packageContext, CheatActivity.class);
i.putExtra(EXTRA_ANSWER_IS_TRUE, answerIsTrue);
return i;
} 
然后在数据源activity中调用这个方法,并且把数据answerIsTrue传递进去
Intent i = CheatActivity.newIntent(QuizActivity.this, answerIsTrue);
startActivityForResult(intent, REQUEST_CODE_CHEAT);
然后就可以在数据目的activity中获取
mAnswerIsTrue = getIntent().getBooleanExtra(EXTRA_ANSWER_IS_TRUE, false); 
处理返回值
发出返回值的activity首先设置数据isAnswerShown
private void setAnswerShownResult(boolean isAnswerShown) {
Intent data = new Intent();
data.putExtra(EXTRA_ANSWER_SHOWN, isAnswerShown);
setResult(RESULT_OK, data);
} 
其次设置静态解析方法
public static boolean wasAnswerShown(Intent result) {
return result.getBooleanExtra(EXTRA_ANSWER_SHOWN, false);
} 

接收返回值的activity覆盖onActivityResult
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) {
return;
}
if (requestCode == REQUEST_CODE_CHEAT) {
if (data == null) {
return;
}
mIsCheater = CheatActivity.wasAnswerShown(data);
}
} 


8.创建UI fragment

创建UI fragment的步骤与创建activity的步骤相同,具体如下:
 通过定义布局文件中的组件,组装界面;
 创建fragment类并设置其视图为定义的布局;
 通过代码的方式,组装在布局文件中实例化的组件 


9.布局属性

android:padding和android:margin的区别

android:layout_marginLeft指该控件距离边父控件的边距,指定视图组件间的距离;

android:paddingLeft指该控件内部内容,如文本距离该控件的边距。指定视图外边框与其内容间的距离。

如:
当按钮分别设置以上两个属性时,得到的效果是不一样的。
android:paddingLeft="30px":
按钮上设置的内容(例如图片)离按钮左边边界30个像素。
android:layout_marginLeft="30px"
整个按钮离左边设置的内容30个像素
这二个属性是相对的,假设B是A的子控件,设置B的margin和设置A的padding能达到相同的效果。


layout_开头的属性作用于组件 

layout_开头的属性则作用于组件的父组件

10 .日期SimpleDateFormat 

// SimpleDateFormat 类的格式化字符:
// G 年代指示符(AD) 
// y 年(yy:10 y/yyy/yyyy:2010)
// M 月(M:1 MM:01 MMM:Jan MMMM:January MMMMM:J) 
// L 独立月(L:1 LL:01 LLL:Jan LLLL:January LLLLL:J) 
// d 一个月中的第几日(只需此一个字符,输出如:10)
// h 时(只需此一个字符,输出如:上/下午 1 ~ 12) 
// H 时(只需此一个字符,输出如:0 ~ 23) 
// k 一天中的第几个小时(只需此一个字符,输出如:1 ~ 24)
// K 时(上/下午 0 ~ 11)
// m 一小时中的第几分(只需此一个字符,输出如:30)
// s 一分钟中的第几秒(只需此一个字符,输出如:55)
// S 毫秒(只需此一个字符,输出如:978)
// E 星期几(E/EE/EEE:Tue, EEEE:Tuesday, EEEEE:T)
// c 独立星期几(c/cc/ccc:Tue, cccc:Tuesday, ccccc:T)
// D 一年中的第几天(只需此一个字符,输出如:189)
// F 一月中的第几个星期几(只需此一个字符,输出如:2)
// w 一年中的第几个星期(只需此一个字符,输出如:27)
// W 一月中的第几个星期(只需此一个字符,输出如:1)
// a 上/下午标记符(只需此一个字符,输出如:AM/PM)
// Z 时区(RFC822)(Z/ZZ/ZZZ:-0800 ZZZZ:GMT-08:00 ZZZZZ:-08:00)
// z 时区(z/zz/zzz:PST zzzz:Pacific Standard Time)

11.指定app登陆界面

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


12.RecyclerView ViewHolder 和 Adapter 
RecyclerView 只创建刚好充满屏幕的12个视图,而不是100个视图。用户
滑动屏幕切换视图时,上一个视图会被回收利用。顾名思义, RecyclerView所做的就是回收再
利用,循环往复。 在oncreateview方法中会设置显示方式和绑定adapter和viewholder

adapter负责:
 创建必要的ViewHolder;
 绑定ViewHolder至模型层数据。 

ViewHolder只做一件事:容纳View视图


13.Android开发常用到单例的一大原因是

它们比fragment或activity活得久。例如,在设备旋转
或是在fragment和activity间跳转的场景下,单例不会受到影响,而旧的fragment或activity已经不
复存在了 

14.是否要保留fragment

首先,相比非保留fragment,保留fragment的显示非常复杂。一旦出现问题,排查起来非常
耗时。既然使用它会让程序复杂起来,能不用就不用吧。
其次,
fragment在使用保存实例状态savedInstanceState的方式处理设备旋转时,也能够应对所有生命周期场景;
但保留的
fragment只能处理activity因设备旋转而销毁的情况。如果activity是因操作系统需要回收
内存而被销毁,则所有保留的
fragment也会随之销毁,数据也就跟着丢失了。即使没有销毁,在activity实例进程关闭时,fragment也会被销毁,因此savedInstanceState保存的
时间更久一点。 

15.任务与后退栈

任务是用户比较关心的activity栈。栈底部的activity通常称为activity。用户可以看到栈顶的
activity。用户点击后退键时,栈顶activity会弹出栈外。如果当前屏幕上显示的是基activity,点击
后退键,系统会退回主屏幕。

在当前任务中启动activity的好处是,用户可以在任务内而不是在应用层级间导航返回
当前,从NerdLauncher启动的任何activity(可能是别的应用的)都会添加到NerdLauncher任务中

16.进程与任务
尽管存在未知的异常情况,但总的来说, Android世界里的每个应用组件都仅与一个进程相
关联。应用伴随着自己的进程一起完成创建,该进程同时也是应用中所有组件的默认进程。

(虽然组件可以指派给不同的进程,但我们推荐使用默认进程。如果确实需要在不同进程中
运行应用组件,通常也可以借助多线程来达到目的。相比多进程的使用,
Android多线程的使用
更加简单。)
每一个activity实例都仅存在于一个进程和一个任务中。这也是进程与任务的唯一相似之处。任
务只包含
activity,这些activity通常来自于不同的应用;而进程则包含了应用的全部运行代码和对象。
进程与任务很容易让人混淆,主要原因在于它们不仅在概念上有某种重叠,而且通常都是以
其所属应用的名称被人提及的。例如,从
NerdLauncher启动器中启动CriminalIntent应用时,操作
系统创建了一个
CriminalIntent进程以及一个以CrimeListActivity为基activity的新任务。在
overview screen中,我们可以看到标签为CriminalIntent的任务。

打开CriminalIntent应用,选择任何crime项,然后点击CHOOSE SUSPECT按钮。这会打开联
系人应用让我们选择目标联系人。随即,联系人
activity会被加入CriminalIntent应用任务。如果此
时点击后退键在不同
activity间切换的话,用户可能意识不到他们正在进程间切换。
然而,联系人
activity实例确实是在联系人应用进程的内存空间创建的,而且也是在该应用进
程里的虚拟机上运行的。这可以从图
22-13中看出。 

为进一步了解进程和任务的概念,让CriminalIntent应用处于运行状态,并打开联系人列表界
面。(继续之前,请确保联系人应用没有在overview screen出现。)点击主屏幕键回到主屏幕,从
中启动联系人应用。然后从联系人列表选取任意联系人,或添加新的联系人。
在这个操作过程中,会在联系人应用进程中创建新的联系人列表activity和联系人明细界面实
例。联系人应用新任务也会完成创建。这个新任务会引用联系人列表activity和联系人明细界面实
例,如图22-14所示。 


在发送crime消息时,你所选择发送消息应用的activity不会添加到
CriminalIntent应用任务中,而是添加到它自己的独立任务中
Lollipop设备上,对以android.intent.action.SENDaction.intent.action.SEND_
MULTIPLE
操作启动的activity,隐式intent选择器会创建独立的新任务。(在旧设备上,Gmail
activity是直接添加给CriminalIntent应用任务的。) 
Lollipop之前的设备上查看overview
screen
的话,你只能看到孤零零的一个任务。前面已说过, Lollipop之前的系统需要在manifest
提前定义应用任务,所以系统无法为单个应用动态创建多个任务。


17.线程
如果创建了大量的AsyncTask,或者长时间运行AsyncTask,那么很可能就是错用了它。
Android 3.2版本起,AsyncTask不再为每一个AsyncTask实例单独创建线程。相反,
它使用一个
Executor在单一的后台线程上运行所有AsyncTask后台任务。这意味着每个
AsyncTask都需要排队逐个运行。显然,长时间运行的AsyncTask会阻塞其他AsyncTask
时可使用Handler与主线程通信



第二遍总结:

1.Framelayout是最简单的layout,他是通过各个view的layout_gravity来确定位置。

2.startactivity并不是Activity的静态方法,他是通过交给操作系统的activityManager来启动别的应用,第一个参数指定要启动的activity在哪个包的content,并且通过getIntent() 获取startactivity传过来的intent。

3.显示intent主要用于同一应用中不同组件中。

4.调用Activity.finish()方法同样可以将CheatActivity从栈里弹出 。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值