Android Programming - Bill Phillips

Android 开发经典教程,由 Big Nerd Ranch 团队编写。本书采用实践驱动的教学方法,通过构建真实应用来讲解 Android 核心概念,涵盖 Activity、Fragment、RecyclerView 等关键组件。
关于作者
Bill Phillips 是 Android 开发领域的知名教育者:
- Big Nerd Ranch 联合创始人:全球知名的移动开发培训机构
- Android 早期 adopter:从 Android 初期就开始从事开发和教育
- 技术作家:著有多本 Android 开发相关经典教程
- 培训师:培养了数千名专业 Android 开发者
Big Nerd Ranch 团队以其"沉浸式"教学方法著称,通过手把手构建真实应用,帮助开发者快速掌握 Android 开发技能。
核心内容
1. Activity 生命周期
class MainActivity : AppCompatActivity() {
private val TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d(TAG, "onCreate")
}
override fun onStart() {
super.onStart()
Log.d(TAG, "onStart")
}
override fun onResume() {
super.onResume()
Log.d(TAG, "onResume")
}
override fun onPause() {
super.onPause()
Log.d(TAG, "onPause")
}
override fun onStop() {
super.onStop()
Log.d(TAG, "onStop")
}
override fun onDestroy() {
super.onDestroy()
Log.d(TAG, "onDestroy")
}
override fun onRestart() {
super.onRestart()
Log.d(TAG, "onRestart")
}
}
2. Fragment 使用
// Fragment 定义
class DetailFragment : Fragment() {
private lateinit var textView: TextView
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_detail, container, false)
textView = view.findViewById(R.id.textView)
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
arguments?.let {
val text = it.getString("key")
textView.text = text
}
}
companion object {
fun newInstance(text: String): DetailFragment {
val fragment = DetailFragment()
val args = Bundle()
args.putString("key", text)
fragment.arguments = args
return fragment
}
}
}
// Fragment 事务
supportFragmentManager.beginTransaction()
.replace(R.id.container, DetailFragment.newInstance("Hello"), "TAG")
.addToBackStack(null)
.commit()
3. RecyclerView
// Adapter
class MyAdapter(private val items: List<String>) :
RecyclerView.Adapter<MyAdapter.ViewHolder>() {
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
val textView: TextView = view.findViewById(R.id.textView)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_layout, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.textView.text = items[position]
}
override fun getItemCount() = items.size
}
// 使用
val recyclerView: RecyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = MyAdapter(dataList)
// 不同布局
recyclerView.layoutManager = GridLayoutManager(this, 2) // 网格
recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.HORIZONTAL, false) // 横向
4. Intent 与导航
// 显式 Intent
val intent = Intent(this, DetailActivity::class.java).apply {
putExtra("KEY_ID", 123)
putExtra("KEY_NAME", "John")
}
startActivity(intent)
// 接收数据
val id = intent.getIntExtra("KEY_ID", 0)
val name = intent.getStringExtra("KEY_NAME")
// 隐式 Intent
val webIntent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("https://www.example.com")
}
startActivity(webIntent)
// 返回结果
val pickImageIntent = Intent(Intent.ACTION_PICK).apply {
type = "image/*"
}
startActivityForResult(pickImageIntent, REQUEST_CODE)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
val imageUri = data?.data
// 处理返回的图片
}
}
5. ViewModel 与 LiveData
// ViewModel
class MainViewModel : ViewModel() {
private val _items = MutableLiveData<List<String>>()
val items: LiveData<List<String>> = _items
private val _loading = MutableLiveData<Boolean>()
val loading: LiveData<Boolean> = _loading
fun loadData() {
viewModelScope.launch {
_loading.value = true
try {
val result = repository.getItems()
_items.value = result
} catch (e: Exception) {
// 处理错误
} finally {
_loading.value = false
}
}
}
}
// Activity/Fragment 中使用
val viewModel: MainViewModel by viewModels()
viewModel.items.observe(viewLifecycleOwner) { items ->
adapter.submitList(items)
}
viewModel.loading.observe(viewLifecycleOwner) { isLoading ->
progressBar.isVisible = isLoading
}
6. 协程 (Coroutines)
// 基本用法
lifecycleScope.launch {
// 主线程
val result = withContext(Dispatchers.IO) {
// 后台线程
repository.getData()
}
// 回到主线程
updateUI(result)
}
// async/await
lifecycleScope.launch {
val deferred1 = async { fetchData1() }
val deferred2 = async { fetchData2() }
val result1 = deferred1.await()
val result2 = deferred2.await()
updateUI(result1, result2)
}
// Flow
fun getDataStream(): Flow<List<Item>> = flow {
emit(repository.getItems())
}
lifecycleScope.launch {
viewModel.getDataStream()
.flowOn(Dispatchers.IO)
.collect { items ->
updateUI(items)
}
}
7. Room 数据库
// Entity
@Entity(tableName = "users")
data class User(
@PrimaryKey val id: Int,
@ColumnInfo(name = "first_name") val firstName: String,
@ColumnInfo(name = "last_name") val lastName: String
)
// DAO
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getAll(): List<User>
@Query("SELECT * FROM users WHERE id = :userId")
fun getById(userId: Int): User?
@Insert
fun insert(user: User)
@Update
fun update(user: User)
@Delete
fun delete(user: User)
}
// Database
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
@Volatile private var instance: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
return instance ?: synchronized(this) {
Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app_database"
).build()
}
}
}
}
8. 网络请求 (Retrofit)
// API 接口
interface ApiService {
@GET("users/{id}")
suspend fun getUser(@Path("id") userId: Int): Response<User>
@POST("users")
suspend fun createUser(@Body user: User): Response<User>
@GET("users")
fun getUsersStream(): Flow<List<User>>
}
// Retrofit 构建
object ApiClient {
private const val BASE_URL = "https://api.example.com/"
val apiService: ApiService by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(KotlinxCoroutinesCallAdapterFactory.create())
.build()
.create(ApiService::class.java)
}
}
// 使用
lifecycleScope.launch {
try {
val response = ApiClient.apiService.getUser(123)
if (response.isSuccessful) {
val user = response.body()
updateUI(user)
}
} catch (e: Exception) {
showError(e.message)
}
}
经典摘录
Android development is about understanding the Android lifecycle and building components that work together within that lifecycle.
Always do long-running operations (network, database) on a background thread.
ViewModel survives configuration changes. Use it to store UI-related data that shouldn't be lost on screen rotation.
RecyclerView is efficient because it recycles views. Always use ViewHolder pattern for smooth scrolling.
读书心得
《Android Programming》是 Big Nerd Ranch 的经典培训教材,采用"Learning by Doing"的方式,通过构建真实应用来讲解 Android 核心概念。
书中对我帮助最大的是Activity 生命周期的详细讲解。Android 的生命周期比 iOS 复杂得多,理解 onCreate、onStart、onResume、onPause、onStop、onDestroy 的执行时机和用途,是编写健壮 Android 应用的基础。
协程部分的讲解也非常出色。从基本的 launch/async 到 Flow 流式处理,书中通过大量示例展示了如何在 Android 中优雅地处理异步操作。相比传统的 Callback 和 AsyncTask,协程让代码更加简洁易读。
Room 和 Retrofit 的集成也是亮点之一。作为 Android 官方推荐的数据库和网络库,它们与协程、LiveData 的配合使用是现代 Android 开发的标准模式。
虽然 Jetpack Compose 正在改变 Android UI 开发方式,但书中的核心概念——生命周期、Fragment、ViewModel、协程——仍然是 Android 开发的基石。
对于想系统学习 Android 开发的开发者来说,这本书是很好的起点。它不仅能让你快速上手,更能帮助你建立 对 Android 架构的深入理解。