内容简介 · · · · · ·
本书被广大Android 开发者誉为“Android 学习第一书”。全书系统全面、循序渐进地介绍了Android软件开发的必备知识、经验和技巧。
第2版基于Android 7.0 对第1 版进行了全面更新,将所有知识点都在最新的Android 系统上进行重新适配,使用 全新的Android Studio 开发工具代替之前的Eclipse,并添加了对Material Design、运行时权限、Gradle、RecyclerView、百分比布局、OkHttp、Lambda 表达式等全新知识点的详细讲解。
本书内容通俗易懂,由浅入深,既是Android 初学者的入门必备,也是Android 开发者的进阶首选。
作者简介 · · · · · ·
郭霖
Android软件开发工程师。从事Android开发工作6年,有着丰富的项目实战经验,负责及参与开发过多款移动应用与游戏,对Android系统架构及应用层开发有着深入的理解。
2013年3月开始,在CSDN上发表Android技术相关博文,很快获得了大量网友的好评。目前博客访问量已超过500万次,评论超过10000条。荣获CSDN认证专家,并被连续评选为CSDN 2013、2014、2015年度博客之星。
目录 · · · · · ·
1.1 了解全貌——Android王国简介 2
1.1.1 Android系统架构 2
1.1.2 Android已发布的版本 3
1.1.3 Android应用开发特色 4
1.2 手把手带你搭建开发环境 5
· · · · · · (更多)
1.1 了解全貌——Android王国简介 2
1.1.1 Android系统架构 2
1.1.2 Android已发布的版本 3
1.1.3 Android应用开发特色 4
1.2 手把手带你搭建开发环境 5
1.2.1 准备所需要的工具 5
1.2.2 搭建开发环境 5
1.3 创建你的第一个Android项目 9
1.3.1 创建HelloWorld项目 9
1.3.2 启动模拟器 12
1.3.3 运行HelloWorld 15
1.3.4 分析你的第一个Android程序 16
1.3.5 详解项目中的资源 22
1.3.6 详解build.gradle文件 23
1.4 前行必备——掌握日志工具的使用 26
1.4.1 使用Android的日志工具Log 26
1.4.2 为什么使用Log而不使用System.out 27
1.5 小结与点评 29
第2章 先从看得到的入手——探究活动 30
2.1 活动是什么 30
2.2 活动的基本用法 30
2.2.1 手动创建活动 31
2.2.2 创建和加载布局 32
2.2.3 在AndroidManifest文件中注册 35
2.2.4 在活动中使用Toast 37
2.2.5 在活动中使用Menu 38
2.2.6 销毁一个活动 40
2.3 使用Intent在活动之间穿梭 41
2.3.1 使用显式Intent 41
2.3.2 使用隐式Intent 44
2.3.3 更多隐式Intent的用法 46
2.3.4 向下一个活动传递数据 50
2.3.5 返回数据给上一个活动 51
2.4 活动的生命周期 53
2.4.1 返回栈 53
2.4.2 活动状态 54
2.4.3 活动的生存期 55
2.4.4 体验活动的生命周期 56
2.4.5 活动被回收了怎么办 62
2.5 活动的启动模式 63
2.5.1 standard 64
2.5.2 singleTop 65
2.5.3 singleTask 67
2.5.4 singleInstance 68
2.6 活动的最佳实践 71
2.6.1 知晓当前是在哪一个活动 71
2.6.2 随时随地退出程序 72
2.6.3 启动活动的最佳写法 74
2.7 小结与点评 75
第3章 软件也要拼脸蛋——UI开发的点点滴滴 76
3.1 如何编写程序界面 76
3.2 常用控件的使用方法 77
3.2.1 TextView 77
3.2.2 Button 80
3.2.3 EditText 82
3.2.4 ImageView 86
3.2.5 ProgressBar 88
3.2.6 AlertDialog 91
3.2.7 ProgressDialog 93
3.3 详解4种基本布局 94
3.3.1 线性布局 94
3.3.2 相对布局 100
3.3.3 帧布局 103
3.3.4 百分比布局 105
3.4 系统控件不够用?创建自定义控件 108
3.4.1 引入布局 109
3.4.2 创建自定义控件 111
3.5 最常用和最难用的控件——ListView 113
3.5.1 ListView的简单用法 114
3.5.2 定制ListView的界面 115
3.5.3 提升ListView的运行效率 119
3.5.4 ListView的点击事件 120
3.6 更强大的滚动控件——RecyclerView 122
3.6.1 RecyclerView的基本用法 122
3.6.2 实现横向滚动和瀑布流布局 125
3.6.3 RecyclerView的点击事件 130
3.7 编写界面的最佳实践 132
3.7.1 制作Nine-Patch图片 132
3.7.2 编写精美的聊天界面 135
3.8 小结与点评 141
第4章 手机平板要兼顾——探究碎片 142
4.1 碎片是什么 142
4.2 碎片的使用方式 144
4.2.1 碎片的简单用法 144
4.2.2 动态添加碎片 147
4.2.3 在碎片中模拟返回栈 150
4.2.4 碎片和活动之间进行通信 151
4.3 碎片的生命周期 151
4.3.1 碎片的状态和回调 151
4.3.2 体验碎片的生命周期 153
4.4 动态加载布局的技巧 156
4.4.1 使用限定符 156
4.4.2 使用最小宽度限定符 159
4.5 碎片的最佳实践——一个简易版的新闻应用 160
4.6 小结与点评 169
第5章 全局大喇叭——详解广播机制 170
5.1 广播机制简介 170
5.2 接收系统广播 171
5.2.1 动态注册监听网络变化 171
5.2.2 静态注册实现开机启动 174
5.3 发送自定义广播 177
5.3.1 发送标准广播 177
5.3.2 发送有序广播 179
5.4 使用本地广播 183
5.5 广播的最佳实践——实现强制下线功能 185
5.6 Git时间——初识版本控制工具 192
5.6.1 安装Git 192
5.6.2 创建代码仓库 193
5.6.3 提交本地代码 195
5.7 小结与点评 195
第6章 数据存储全方案——详解持久化技术 196
6.1 持久化技术简介 196
6.2 文件存储 197
6.2.1 将数据存储到文件中 197
6.2.2 从文件中读取数据 201
6.3 SharedPreferences存储 203
6.3.1 将数据存储到SharedPreferences中 203
6.3.2 从SharedPreferences中读取数据 206
6.3.3 实现记住密码功能 208
6.4 SQLite数据库存储 211
6.4.1 创建数据库 211
6.4.2 升级数据库 216
6.4.3 添加数据 219
6.4.4 更新数据 222
6.4.5 删除数据 224
6.4.6 查询数据 225
6.4.7 使用SQL操作数据库 228
6.5 使用LitePal操作数据库 229
6.5.1 LitePal简介 229
6.5.2 配置LitePal 230
6.5.3 创建和升级数据库 231
6.5.4 使用LitePal添加数据 236
6.5.5 使用LitePal更新数据 237
6.5.6 使用LitePal删除数据 240
6.5.7 使用LitePal查询数据 241
6.6 小结与点评 243
第7章 跨程序共享数据——探究内容提供器 244
7.1 内容提供器简介 244
7.2 运行时权限 245
7.2.1 Android权限机制详解 245
7.2.2 在程序运行时申请权限 249
7.3 访问其他程序中的数据 254
7.3.1 ContentResolver的基本用法 254
7.3.2 读取系统联系人 256
7.4 创建自己的内容提供器 260
7.4.1 创建内容提供器的步骤 261
7.4.2 实现跨程序数据共享 265
7.5 Git时间——版本控制工具进阶 275
7.5.1 忽略文件 275
7.5.2 查看修改内容 276
7.5.3 撤销未提交的修改 278
7.5.4 查看提交记录 279
7.6 小结与点评 280
第8章 丰富你的程序——运用手机多媒体 281
8.1 将程序运行到手机上 281
8.2 使用通知 283
8.2.1 通知的基本用法 283
8.2.2 通知的进阶技巧 289
8.2.3 通知的高级功能 291
8.3 调用摄像头和相册 293
8.3.1 调用摄像头拍照 294
8.3.2 从相册中选择照片 298
8.4 播放多媒体文件 303
8.4.1 播放音频 303
8.4.2 播放视频 307
8.5 小结与点评 311
第9章 看看精彩的世界——使用网络技术 312
9.1 WebView的用法 312
9.2 使用HTTP协议访问网络 314
9.2.1 使用HttpURLConnection 315
9.2.2 使用OkHttp 319
9.3 解析XML格式数据 321
9.3.1 Pull解析方式 324
9.3.2 SAX解析方式 326
9.4 解析JSON格式数据 329
9.4.1 使用JSONObject 330
9.4.2 使用GSON 331
9.5 网络编程的最佳实践 334
9.6 小结与点评 338
第10章 后台默默的劳动者——探究服务 339
10.1 服务是什么 339
10.2 Android多线程编程 340
10.2.1 线程的基本用法 340
10.2.2 在子线程中更新UI 341
10.2.3 解析异步消息处理机制 345
10.2.4 使用AsyncTask 347
10.3 服务的基本用法 349
10.3.1 定义一个服务 349
10.3.2 启动和停止服务 352
10.3.3 活动和服务进行通信 355
10.4 服务的生命周期 359
10.5 服务的更多技巧 359
10.5.1 使用前台服务 359
10.5.2 使用IntentService 361
10.6 服务的最佳实践——完整版的下载示例 365
10.7 小结与点评 378
第11章 Android特色开发——基于位置的服务 379
11.1 基于位置的服务简介 379
11.2 申请API Key 380
11.3 使用百度定位 384
11.3.1 准备LBS SDK 384
11.3.2 确定自己位置的经纬度 386
11.3.3 选择定位模式 391
11.3.4 看得懂的位置信息 393
11.4 使用百度地图 395
11.4.1 让地图显示出来 395
11.4.2 移动到我的位置 397
11.4.3 让“我”显示在地图上 400
11.5 Git时间——版本控制工具的高级用法 402
11.5.1 分支的用法 403
11.5.2 与远程版本库协作 404
11.6 小结与点评 406
第12章 最佳的UI体验——MaterialDesign实战 407
12.1 什么是Material Design 407
12.2 Toolbar 408
12.3 滑动菜单 415
12.3.1 DrawerLayout 415
12.3.2 NavigationView 418
12.4 悬浮按钮和可交互提示 423
12.4.1 FloatingActionButton 424
12.4.2 Snackbar 427
12.4.3 CoordinatorLayout 428
12.5 卡片式布局 430
12.5.1 CardView 431
12.5.2 AppBarLayout 437
12.6 下拉刷新 440
12.7 可折叠式标题栏 443
12.7.1 CollapsingToolbarLayout 443
12.7.2 充分利用系统状态栏空间 453
12.8 小结与点评 456
第13章 继续进阶——你还应该掌握的高级技巧 457
13.1 全局获取Context的技巧 457
13.2 使用Intent传递对象 461
13.2.1 Serializable方式 461
13.2.2 Parcelable方式 463
13.3 定制自己的日志工具 464
13.4 调试Android程序 466
13.5 创建定时任务 469
13.5.1 Alarm机制 469
13.5.2 Doze模式 471
13.6 多窗口模式编程 472
13.6.1 进入多窗口模式 473
13.6.2 多窗口模式下的生命周期 475
13.6.3 禁用多窗口模式 479
13.7 Lambda表达式 481
13.8 总结 485
第14章 进入实战——开发酷欧天气 486
14.1 功能需求及技术可行性分析 486
14.2 Git时间——将代码托管到GitHub上 489
14.3 创建数据库和表 494
14.4 遍历全国省市县数据 499
14.5 显示天气信息 509
14.5.1 定义GSON实体类 509
14.5.2 编写天气界面 514
14.5.3 将天气显示到界面上 520
14.5.4 获取必应每日一图 526
14.6 手动更新天气和切换城市 532
14.6.1 手动更新天气 532
14.6.2 切换城市 535
14.7 后台自动更新天气 540
14.8 修改图标和名称 542
14.9 你还可以做的事情 543
第15章 最后一步——将应用发布到360应用商店 545
15.1 生成正式签名的APK文件 545
15.1.1 使用Android Studio生成 546
15.1.2 使用Gradle生成 548
15.1.3 生成多渠道APK文件 551
15.2 申请360开发者账号 554
15.3 发布应用程序 556
15.4 嵌入广告进行盈利 560
15.4.1 注册腾讯广告联盟账号 560
15.4.2 新建媒体和广告位 562
15.4.3 接入广告SDK 564
15.4.4 重新发布应用程序 569
15.5 结束语 570
· · · · · · (收起)
丛书信息
喜欢读"第一行代码:Android(第2版)"的人也喜欢的电子书 · · · · · ·
喜欢读"第一行代码:Android(第2版)"的人也喜欢 · · · · · ·
第一行代码:Android(第2版)的话题 · · · · · · ( 全部 条 )



第一行代码:Android(第2版)的书评 · · · · · · ( 全部 20 条 )



> 更多书评20篇
-
热心市民钟先生 (元気です。)
在AndroidManifest.xml中通过给<activity>标签指定android:launchMode属性来选择启动模式。 standard:默认的启动模式。每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于使用standard模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。 singleTop:在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。 si...2017-04-17 23:03
在AndroidManifest.xml中通过给<activity>标签指定android:launchMode属性来选择启动模式。 standard:默认的启动模式。每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于使用standard模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。
singleTop:在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。
singleTask:每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。
singleInstance:会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈,也就解决了共享活动实例的问题。
回应 2017-04-17 23:03 -
热心市民钟先生 (元気です。)
FirstActivity: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.first_layout); Button button1 = (Button) findViewById(R.id.button_1); button1.setOnClickListener((View v) -> startActivityForResult(new Intent(this, SecondActivity.class), 8034)); } @Override protected void onActivityResult(int requestCode, int resultCode...2017-04-16 16:33
FirstActivity: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.first_layout); Button button1 = (Button) findViewById(R.id.button_1); button1.setOnClickListener((View v) -> startActivityForResult(new Intent(this, SecondActivity.class), 8034)); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case 8034: if (resultCode == RESULT_OK) { Log.d("FirstActivity", data.getStringExtra("data_return")); } break; default: } }
SecondActivity: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.second_layout); Button button2 = (Button) findViewById(R.id.button_2); button2.setOnClickListener((View v) -> { setResult(RESULT_OK, new Intent().putExtra ("data_return", "Hello FirstActivity")); finish(); }); } //为了解决用户通过按Back键回到FirstActivity导致数据丢失的问题 @Override public void onBackPressed() { setResult(RESULT_OK, new Intent().putExtra ("data_return", "Hello FirstActivity")); finish(); }
回应 2017-04-16 16:33
-
热心市民钟先生 (元気です。)
打开HelloWorldActivity,在onCreate()方法中添加一行打印日志的语句,如下所示: protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.hello_world_layout); Log.d("HelloWorldActivity","onCreate execute"); } Log.d()方法中传入了两个参数:第一个参数是tag,一般传入当前的类名就好,主要用于对打印信息进行过滤;第二个参数是msg,即想要打印的具体的内...2017-04-08 23:36
打开HelloWorldActivity,在onCreate()方法中添加一行打印日志的语句,如下所示: protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.hello_world_layout); Log.d("HelloWorldActivity","onCreate execute"); }
Log.d()方法中传入了两个参数:第一个参数是tag,一般传入当前的类名就好,主要用于对打印信息进行过滤;第二个参数是msg,即想要打印的具体的内容。
快捷输入: 打印一条debug级别的日志:输入logd,然后按下Tab键 打印一条warn级别的日志:输入logw,然后按下Tab键 以此类推。 小技巧:在onCreate()方法的外面输入logt,然后按下Tab键。这时就会以当前的类名作为值自动生成一个TAG常量。
回应 2017-04-08 23:36 -
热心市民钟先生 (元気です。)
如果需要在XML中引用一个id,就使用@id/id_name这种语法,而如果你需要在XML中定义一个id,则要使用@+id/id_name这种语法。 项目中添加的任何资源都会在R文件中生成一个相应的资源id,因此刚才创建的first_layout.xml布局的id现在已经添加到R文件中了。只需要调用R.layout.first_layout就可以得到first_layout.xml布局的id,然后将这个值传入setContentView()方法即可。2017-04-09 15:58
-
热心市民钟先生 (元気です。)
<?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/AppTheme"> <activity android:...2017-04-09 16:35
<?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/AppTheme"> <activity android:name=".FirstActivity" android:label="This is FirstActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
由于在最外层的<manifest>标签中已经通过package属性指定了程序的包名是com.example.activitytest,因此在注册活动时这一部分就可以省略了,直接使用.FirstActivity就可以了。
配置主活动:在<activity>标签的内部加入<intent-filter>标签,并在这个标签里添加<action android:name="android.intent.action.MAIN"/>和 <category android:name="android.intent.category.LAUNCHER"/>这两句声明即可。
注意:给主活动指定的label不仅会成为标题栏中的内容,还会成为启动器(Launcher)中应用程序显示的名称。
回应 2017-04-09 16:35 -
热心市民钟先生 (元気です。)
public class FirstActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.first_layout); Button button1 = (Button) findViewById(R.id.button_1); button1.setOnClickListener((View v) -> Toast.makeText(this, "You clicked Button 1", Toast.LENGTH_SHORT).show()); } }2017-04-09 18:28
public class FirstActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.first_layout); Button button1 = (Button) findViewById(R.id.button_1); button1.setOnClickListener((View v) -> Toast.makeText(this, "You clicked Button 1", Toast.LENGTH_SHORT).show()); } }
回应 2017-04-09 18:28
-
热心市民钟先生 (元気です。)
在AndroidManifest.xml中通过给<activity>标签指定android:launchMode属性来选择启动模式。 standard:默认的启动模式。每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于使用standard模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。 singleTop:在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。 si...2017-04-17 23:03
在AndroidManifest.xml中通过给<activity>标签指定android:launchMode属性来选择启动模式。 standard:默认的启动模式。每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于使用standard模式的活动,系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。
singleTop:在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。
singleTask:每次启动该活动时系统首先会在返回栈中检查是否存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。
singleInstance:会有一个单独的返回栈来管理这个活动,不管是哪个应用程序来访问这个活动,都共用的同一个返回栈,也就解决了共享活动实例的问题。
回应 2017-04-17 23:03 -
热心市民钟先生 (元気です。)
FirstActivity: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.first_layout); Button button1 = (Button) findViewById(R.id.button_1); button1.setOnClickListener((View v) -> startActivityForResult(new Intent(this, SecondActivity.class), 8034)); } @Override protected void onActivityResult(int requestCode, int resultCode...2017-04-16 16:33
FirstActivity: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.first_layout); Button button1 = (Button) findViewById(R.id.button_1); button1.setOnClickListener((View v) -> startActivityForResult(new Intent(this, SecondActivity.class), 8034)); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case 8034: if (resultCode == RESULT_OK) { Log.d("FirstActivity", data.getStringExtra("data_return")); } break; default: } }
SecondActivity: @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.second_layout); Button button2 = (Button) findViewById(R.id.button_2); button2.setOnClickListener((View v) -> { setResult(RESULT_OK, new Intent().putExtra ("data_return", "Hello FirstActivity")); finish(); }); } //为了解决用户通过按Back键回到FirstActivity导致数据丢失的问题 @Override public void onBackPressed() { setResult(RESULT_OK, new Intent().putExtra ("data_return", "Hello FirstActivity")); finish(); }
回应 2017-04-16 16:33
电子版有售 · · · · · ·
在哪儿买这本书 · · · · · ·
这本书的其他版本 · · · · · · ( 全部2 )
- 人民邮电出版社版 2014-8 / 463人读过 / 有售
以下豆列推荐 · · · · · · ( 全部 )
- 信息安全从业者书单推荐(riusksk) (Superyin)
- 书单-❤️书 (再出发)
- appdev (不需往后看)
- 编程-要看 (紫焱先森09)
- Android (qiaojiamin)
谁读这本书?
二手市场
订阅关于第一行代码:Android(第2版)的评论:
feed: rss 2.0
2 有用 森邑 2017-11-02
比第一版好了不少,起码没打怪升级了
0 有用 十八哥 2017-08-18
简单易懂,粗略练习了
0 有用 darcy27149 2017-04-22
觉得讲的挺好的,
0 有用 云飞风起e 2018-05-07
高效入门
0 有用 清乐 2018-06-12
很棒的入门书
0 有用 黄冰 2019-01-19
第一本android书
0 有用 DEQDON 2019-01-17
讲解很细致,很好的入门书
2 有用 xmyyzy123 2019-02-10
很多地方讲的不细致,原理的东西都没讲。
0 有用 装作有方向 2019-01-20
入门好书,所举例子的力度恰到好处。 循序渐进,对于入门真是不错。
2 有用 罗生门 2019-01-11
通读一遍,让人这是一本很不值的书,这本书的最大问题是不系统,大家可以与android官方文档对比一下,就知道这本书差多少内容。而且在高级部分又讲不清楚,让人看的一头雾水,因为很多细节没讲清楚,都是直接拿来用的。