Skip to content

Android 移动应用开发 · 期末复习

Android 四大组件(四大金刚)

这个比较重要,主要老师第一节课就说了四大金刚,肯定会有所考察

组件英文简单描述活动Activity与用户交互的界面容器,用户「看得见」的页面,负责 UI 展示和交互服务Service在后台长时间运行、无界面的组件,如播放音乐、下载文件广播接收器BroadcastReceiver接收并响应系统或应用发出的广播消息,如开机、电量低、网络变化内容提供者ContentProvider在不同应用间共享数据的统一接口,如读取通讯录、相册

活动(Activity)

Activity 是一个应用组件,它提供一个窗口,应用通过该窗口绘制 UI。通常,一个 Activity 对应一个屏幕界面。

这玩意翻译叫活动,实际上也就是你打开应用后看到的界面,就叫Activity,你看他能动,那不就是活动嘛

Activity 类定义了下面的回调,
回调说白了就是你把一个函数(一串代码)提前写好,但不主动调用它,而是把它交给系统或框架,让触发了某个动作的时候,自动帮你调用(运行)这个函数,下面是 Activity 类定义的回调。

回调描述onCreate()这是第一个回调,在活动第一次创建时调用onStart()这个回调在活动为用户可见时被调用onResume()这个回调在应用程序与用户开始可交互的时候调用onPause()被暂停的活动无法接受用户输入,不能执行任何代码。当前活动将要被暂停,上一个活动将要被恢复时调用onStop()当活动不在可见时调用onDestroy()当活动被系统销毁之前调用onRestart()当活动被停止以后重新打开时调用

服务(Service)

服务是一个后台运行的组件,执行长时间运行且不需要用户交互的任务。

说白了就是,在后台运行的程序,例如微信的消息接受、音乐播放等,你看不到,但他会在运行。

状态描述StartedAndroid的应用程序组件,如活动,通过startService()启动了服务,则服务是Started状态。一旦启动,服务可以在后台无限期运行,即使启动它的组件已经被销毁。Bound当Android的应用程序组件通过bindService()绑定了服务,则服务是Bound状态。Bound状态的服务提供了一个客户服务器接口来允许组件与服务进行交互,如发送请求,获取结果,甚至通过IPC来进行跨进程通信。

广播接收器(Broadcast Receivers)

广播接收器用于响应来自其他应用程序或者系统的广播消息。这些消息有时被称为事件或者意图。例如,应用程序可以初始化广播来让其他的应用程序知道一些数据已经被下载到设备,并可以为他们所用。

说白了,这个是一个专门听命令来干活的,比如你开关Wi-Fi,调整亮度,或者你到固定的位置,你的系统会“广而告知”这个事件,这家伙听到之后就开始运行任务。

内容提供者(Content Provider)

内容提供者组件通过请求从一个应用程序向其他的应用程序提供数据。这些请求由类 ContentResolver 的方法来处理。内容提供者可以使用不同的方式来存储数据。数据可以被存放在数据库,文件,甚至是网络。

这玩意是提供内容的,例如照片选择器、通讯录等等,触发这玩意之后,系统会把这些信息返回给软件,软件就拿到你的照片、通讯录等存在系统的信息了。


第二章:布局 + 基本控件

控件 是用户能看到并与之交互的 UI 元素,比如你看到的界面上的按钮,界面上的各个文字,这个就是控件。

布局 定义了应用界面的结构——它告诉 Android的控件怎么摆,比如这个按钮应该放在最顶上,最底下什么的。

控件 ID(最重要)

xml
<!-- 给控件唯一标识,方便 Java 代码 findViewById 查找 -->
<!-- 同一 xml 内 ID 不能重复;不同 xml 页面可用相同 ID -->
android:id="@+id/text_view"
java
// Java 中根据 ID 查找控件
TextView tv = findViewById(R.id.text_view);

基本控件速记(作用 / 英文名 / 标签名)

控件英文名作用关键属性文本框TextView显示文字text / textSize / textColor输入框EditText接收输入(继承 TextView)hint / inputType / maxLength按钮Button点击触发事件(继承 TextView)text / onClick单选RadioButton + RadioGroup同组互斥单选checked / orientation多选CheckBox可多选text / checked图像ImageView显示图片src / scaleType

三种重点布局

xml
<!-- 1. 线性布局:单方向排列 -->
<LinearLayout
    android:orientation="vertical"   <!-- vertical 垂直 / horizontal 水平 -->
    android:gravity="center"         <!-- 子控件对齐方式 -->
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button android:layout_weight="1" .../>  <!-- weight 权重 -->
</LinearLayout>
xml
<!-- 2. 相对布局:参照其他控件/父容器定位 -->
<RelativeLayout ...>
    <Button android:id="@+id/btn_center"
        android:layout_centerInParent="true"/>        <!-- 父容器居中 -->
    <Button android:layout_above="@id/btn_center"/>   <!-- 在目标控件上方 -->
    <Button android:layout_below="@id/btn_center"/>   <!-- 在目标控件下方 -->
    <!-- 类推:layout_toLeftOf / toRightOf / alignParentTop ... -->
</RelativeLayout>
xml
<!-- 3. 表格布局:按行列排列 -->
<TableLayout android:stretchColumns="1">  <!-- 可拉伸列,索引从0开始 -->
    <TableRow>
        <TextView android:text="姓名"/>
        <TextView android:text="张三"/>
    </TableRow>
</TableLayout>

Button 点击事件三种写法

java
// 写法1:XML 中 android:onClick="click",Java 写同名方法
public void click(View v) { ... }

// 写法2:匿名内部类
btn.setOnClickListener(new View.OnClickListener() {
    @Override public void onClick(View v) { ... }
});

// 写法3:公共监听器(Activity implements View.OnClickListener)
@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btn1: ...; break;
        case R.id.btn2: ...; break;
    }
}

第三章:高级控件 ListView / RecyclerView

ListView 三要素

这玩意说白了就是“列表视图”,当你需要一个长长的列表的时候,这个东西就有用了,比如说你做任务清单,或者是聊天列表,只要是有设计到列表的,那可能都要用这个。

老师强调了一个点,ListView中如果有1000个元素,那可能不会有1000个组件去注册,而可能只有十几二十个来复用,这样可以提高性能。你可以想象成,有20个卡片,你向上滑动,上面的卡片不在屏幕里面了,会回收起来,擦掉内容,把下面的内容贴到卡片上,接在下面。

ListView 的三个核心要素:

  1. ListView 控件
    负责显示列表,是列表的容器。
  2. 数据源
    要展示的数据,可以来自数组、集合、数据库等。
  3. 适配器 Adapter
    负责把数据源中的数据按照一定规则显示到 ListView 中。

三种适配器(从简单到复杂)

适配器适用场景ArrayAdapter简单文本列表,每项只有文字SimpleAdapter每项多个控件(图片+文字),功能简单BaseAdapter最灵活,复杂列表,需重写 4 个方法

java
// BaseAdapter:重写四个方法
class MyAdapter extends BaseAdapter {
    @Override public int getCount() { return dataList.size(); }
    @Override public Object getItem(int position) { return dataList.get(position); }
    @Override public long getItemId(int position) { return position; }
    @Override public View getView(int position, View convertView, ViewGroup parent) {
        View view = LayoutInflater.from(context).inflate(R.layout.item, parent, false);
        TextView tv = view.findViewById(R.id.tv);
        tv.setText(dataList.get(position));
        return view;
    }
}

BaseAdapter 中常见需要重写的方法:

  1. getCount():返回数据总数
  2. getItem():返回指定位置的数据
  3. getItemId():返回指定位置的 id
  4. getView():返回每一行列表项的视图,是最重要的方法

RecyclerView

RecyclerView 是 Android Jetpack 中的列表控件。他更灵活更高效,Android 5.0+ 适用。

RecyclerView 相比 ListView,最大的提升是它强制使用 ViewHolder 模式来回收复用 View、通过 LayoutManager 解耦了布局方式从而支持纵向/横向/网格/瀑布流多种排列、并且原生支持局部刷新和 item 动画,在性能、灵活性和扩展性上都全面超越 ListView。RecyclerView 也是用于展示列表数据,比 ListView 更强大。

RecyclerView 的几个角色:

  1. RecyclerView
    列表容器。
  2. 数据源
    要展示的数据。
  3. Adapter
    适配器,负责把数据绑定到列表项。
  4. ViewHolder
    保存列表项中控件的引用。
  5. LayoutManager
    布局管理器,决定列表如何排列。

下面表格简单了解下既可,不用背

对比点ListViewRecyclerView出现时间老控件新控件,Jetpack 组件性能可优化,但依赖手写 ViewHolder默认强制使用 ViewHolder,复用机制更规范布局能力主要是垂直列表支持纵向、横向、网格、瀑布流动画支持较弱原生支持 item 增删改动画分割线内置 divider 比较方便通过 ItemDecoration 实现点击事件有 setOnItemClickListener需要自己在 Adapter/ViewHolder 中处理局部刷新能力较弱支持 notifyItemChanged()notifyItemInserted() 等局部刷新扩展性一般很强推荐程度老项目/简单列表可用新项目更推荐

关键代码(强制 ViewHolder 复用)

java
// ① ViewHolder:缓存控件引用,避免重复 findViewById
public class BookViewHolder extends RecyclerView.ViewHolder {
    TextView tvTitle, tvAuthor;
    public BookViewHolder(@NonNull View itemView) {
        super(itemView);
        tvTitle = itemView.findViewById(R.id.tv_title);
        tvAuthor = itemView.findViewById(R.id.tv_author);
    }
}

// ② Adapter:三个核心方法
public class BookAdapter extends RecyclerView.Adapter<BookViewHolder> {
    private List<Book> bookList;
    public BookAdapter(List<Book> bookList) { this.bookList = bookList; }

    @Override  // 创建 ViewHolder,inflate 布局
    public BookViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_book, parent, false);
        return new BookViewHolder(view);
    }
    @Override  // 绑定数据
    public void onBindViewHolder(BookViewHolder holder, int position) {
        Book book = bookList.get(position);
        holder.tvTitle.setText(book.getTitle());
        holder.tvAuthor.setText(book.getAuthor());
    }
    @Override  // 返回数据总数
    public int getItemCount() { return bookList.size(); }
}

// ③ 设置 LayoutManager 并绑定 Adapter
RecyclerView rv = findViewById(R.id.recycler_view);
rv.setLayoutManager(new LinearLayoutManager(this));
rv.setAdapter(new BookAdapter(bookList));

ListView vs RecyclerView(高频对比)

对比项ListViewRecyclerViewViewHolder 复用手动优化(convertView + getTag)强制 ViewHolder 模式布局管理器无有 LayoutManager适配器方法getView 等 4 个onCreateViewHolder / onBindViewHolder / getItemCount排列方式仅纵向列表线性 / 网格 / 瀑布流

三种 LayoutManager:LinearLayoutManager(线性)、GridLayoutManager(网格)、StaggeredGridLayoutManager(瀑布流)。


第四章:菜单 + Activity + Intent

三种菜单(重点中的重点)

菜单英文简述涉及方法选项菜单OptionsMenu选项菜单是 Activity 主界面上的菜单,一般是右上角的三个点2 个:创建 + 点击上下文菜单ContextMenu长按控件弹出,例如微信长按对话框之后弹出来的“复制\粘贴”那一条,就是他所控制的3 个:注册 + 创建 + 点击弹出菜单PopupMenu点击控件,在其上方/下方弹出例如说,你在看抖音,点击气泡按钮弹出的评论区,点收藏按钮弹出的收藏夹选择页,这个都是弹出菜单发力的先 new 对象,步骤不同

java
// 1. 选项菜单 OptionsMenu —— 两个回调方法
@Override  // 创建菜单(生命周期回调)
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.options_menu, menu);
    return true;
}
@Override  // 点击菜单项
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();
    if (id == R.id.menu_add) { ...; return true; }
    return super.onOptionsItemSelected(item);
}
java
// 2. 上下文菜单 ContextMenu —— 三个方法(多一个注册,因要绑定被操作控件)
registerForContextMenu(textView);          // ① 注册(onCreate 中)
@Override  // ② 创建
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo info) {
    getMenuInflater().inflate(R.menu.context_menu, menu);
}
@Override  // ③ 点击
public boolean onContextItemSelected(MenuItem item) { ... }
java
// 3. 弹出菜单 PopupMenu —— 手动 new 对象,步骤与前两种不同
PopupMenu popup = new PopupMenu(this, v);                          // ① 创建对象
popup.getMenuInflater().inflate(R.menu.popup_menu, popup.getMenu()); // ② 加载资源
popup.setOnMenuItemClickListener(item -> { ... });                 // ③ 设置点击
popup.show();                                                      // ④ 显示

记忆要点:选项菜单、上下文菜单都是「创建时回调 + 点击时回调」的生命周期方法;上下文菜单因为要和被操作控件绑定,所以多一个注册方法(共 3 个)。弹出菜单是手动 new 对象,步骤不一样。

Activity 基础

Activity 就是你打开一个 App 时看到的每一个"页面",比如微信的聊天列表页、朋友圈页、设置页,每个页面对应一个 Activity。

这是 Android 设计上很特别的一点:

当一个应用调用另一个应用时,调用方应用会调用另一个应用中的 Activity,而不是整个应用。1

举个例子:你在笔记 App 里点"分享",弹出了微信。实际上是你 App 里的一个 Activity 请求启动微信里的某个 Activity(比如分享页),不是启动整个微信 App

Activity 的启动和关闭:

启动 Activity 使用:

startActivity(intent);

关闭 Activity 使用:

finish();
java
// 四大组件之一,用户看得见的界面容器
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);  // 加载布局
    }
}
// 创建步骤:① 继承 AppCompatActivity ② onCreate 中 setContentView 加载布局
//           ③ 在 AndroidManifest.xml 中注册

Activity 四种状态与生命周期

状态对应生命周期说明活动状态onResume() 已执行最上层,可见可交互,拥有焦点暂停状态onPause() 已执行、onStop() 未执行部分可见但失去焦点,仍存活停止状态onStop() 已执行完全不可见非活动状态onDestroy() 已执行已销毁或尚未创建

Activity 启动与关闭

java
// 启动
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);

// 关闭:① finish()   ② 按系统返回键
finish();

Intent 两种类型(必考区别)

这个启动方式有必要记一下,老师上课特意强调了

Activity有两种启动方式,Activity之间通过Intent通信跳转,分两种:

类型特点使用场景显式 Intent直接指定目标组件类名应用内部页面跳转隐式 Intent只描述要做什么,由系统匹配组件跨应用调用,例如我需要微信登录或者微信支付,那么就和系统说请求,系统帮你找微信的相关activity

java
// 显式 Intent:直接指定目标类名
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);

// 隐式 Intent:只描述动作,由系统匹配(看有没有指定目标组件来判定)
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("http://www.baidu.com"));
startActivity(intent);

判定方法:有没有直接指定目标组件类名——指定了就是显式;没指定(靠 Action / Category / Data 三要素匹配)就是隐式。IntentFilter 在 AndroidManifest.xml 中配置,告诉系统组件能响应哪些隐式 Intent。

Activiy 数据传递(两种方式)

java
// 方式一:putExtra() 逐个传 —— 适合数据量少
intent.putExtra("name", "张三");
intent.putExtra("age", 20);
// 接收方
String name = intent.getStringExtra("name");
int age = intent.getIntExtra("age", 0);

// 方式二:Bundle 打包 —— 适合数据量大(底层走 Binder)
Bundle bundle = new Bundle();
bundle.putString("name", "张三");
bundle.putInt("age", 20);
intent.putExtras(bundle);
// 接收方
Bundle b = getIntent().getExtras();
String name = b.getString("name");

数据回传(Activity Result API)仅做了解

数据回传指的是:

A 页面跳转到 B 页面,B 页面关闭或返回时,把数据再传回 A 页面,也就是数据方向从 B 回到 A。现在常用的方式是通过新的 Activity Result API 来实现页面之间的数据回传。

Fragment 碎片

Fragment 是 Activity 中的一个子界面,也可以理解为页面片段。特点:

  1. 不能独立存在
    Fragment 必须依赖 Activity。
  2. 生命周期依赖 Activity
    如果 Activity 销毁,Fragment 也会被销毁。
  3. 模块化
    一个 Activity 可以拆分成多个 Fragment。
  4. 复用性
    一个 Fragment 可以被多个 Activity 使用。

Fragment 的加载方式有两种:

  1. 静态加载
    页面内容固定不变时使用。
  2. 动态加载
    页面内容需要切换或变化时使用,实际开发中更常用。

动态加载 Fragment 的步骤:

  1. 创建 Fragment 实例。

  2. 获取 FragmentManager。

  3. 开启事务 beginTransaction()

  4. 添加或替换 Fragment:

  5. add()

  6. replace()

  7. 提交事务 commit()

老师强调,如果是第一次添加可以用 add(),如果是切换页面内容一般用 replace()


第五章 事件处理与消息机制(重点:5.1、5.4)

1. 两类事件处理方式

(1)基于监听的事件处理(开发常用,委派式)

  1. 核心三要素:

  2. 事件源:用户操作的控件(按钮、列表项等)

  3. 事件:用户操作(点击、长按、触摸等)

  4. 事件监听器:负责处理事件、响应操作

  5. 处理流程:注册监听器 → 用户操作触发事件 → 生成事件对象 → 监听器接收并处理事件

  6. 监听器实现方式(3种):

  7. 自定义内部类实现监听接口

  8. 匿名内部类实现(最常用,代码简洁)

  9. 当前Activity实现接口(适合多按钮共用同一个监听器,通过控件id区分点击事件)

(2)基于回调的事件处理

  1. 特点:事件源与监听器统一,控件自己处理事件,回调特定方法
  2. 实现方式:自定义类继承GUI组件类,重写对应回调方法(如onClickonLongClick等)

2. Handler消息传递机制

背景

安卓规定仅UI主线程可修改界面组件,耗时任务需在子线程执行,子线程需更新UI时通过Handler传递消息

四大核心要素

  1. Message:主线程与子线程之间传递的消息对象
  2. MessageQueue:消息队列,采用先进先出的数据结构存储消息
  3. Handler:处理器,负责发送消息( sendMessage方法)和处理消息( handleMessage方法)
  4. Looper:循环器,负责依次从消息队列取出消息交给Handler处理

3. Fragment/Configuration类(了解)

  1. Fragment:了解作用即可
  2. Configuration类:用于获取设备配置信息,通过getConfiguration方法获取对象

第六章 数据存储

安卓提供5种存储方式,重点掌握前3种

1. 文件存储

  1. 原理:通过IO流(输入流/输出流)将数据存为TXT格式文件

(1)内部存储

  1. 特点:存储在应用私有固定目录,数据仅当前应用可访问,空间有限

  2. 核心方法:

  3. openFileOutput():打开输出流,写入数据,两个参数(文件名、操作模式)

  4. openFileInput():打开输入流,读取数据,参数为文件名

  5. 操作模式:

  6. MODE_PRIVATE:私有模式,覆盖写入(替换原有内容)

  7. MODE_APPEND:追加写入(在文件末尾添加内容)

  8. 其余模式已弃用,不安全

(2)外部存储

  1. 特点:存储在外部设备(SD卡、内嵌存储等),数据可被其他应用访问,读写前需检查设备是否可用

  2. 核心工具类: Environment

  3. getExternalStorageState():检查外部设备是否可用

  4. getExternalStorageDirectories():获取外部存储根目录路径

  5. 读写方式:通过FileInputStream/FileOutputStream操作文件

2. SharedPreferences轻量存储

  1. 特点:适合存储小体量配置信息(用户名、设置项等),以XML格式存储在固定目录,通过键值对(key-value)读写
  2. 操作注意:读取数据直接调用get方法,增删改数据需通过Editor对象操作

3. SQLite数据库

  1. 特点:安卓自带轻量级关系型数据库,存储结构化数据,文件后缀为.db

核心操作类/接口

  1. SQLiteOpenHelper抽象类:数据库帮助类,用于创建数据库与版本更新

  2. 核心方法: 1. 构造方法:参数包括上下文、数据库名、游标工厂、版本号(最小从1开始) 1. onCreate():数据库创建时调用 1. onUpgrade():数据库版本更新时调用,参数包含旧版本号与新版本号

  3. Cursor游标接口:查询结果的返回值,可看作指针遍历查询结果

  4. 核心方法: 1. moveFirst():移动光标到第一行 1. moveToNext():移动光标到下一行,用于循环遍历 1. getInt()/ getString():根据列索引获取字段值(列索引从0开始)

增删改查操作

  1. 增/删/改:需获取可读写数据库对象( getWritableDatabase()),操作完成后调用close()关闭数据库
  2. 查询:仅需获取可读数据库对象( getReadableDatabase()),查询结果返回Cursor对象,遍历后关闭数据库

4. 其余存储(了解)

  1. ContentProvider:用于应用间数据共享,第七章详细讲解
  2. 网络存储:数据存储在云端

大题示例:Fragment 动态加载(最可能考的核心方法)

老师明确说:程序题考的是「实现特定功能时用到的关键方法」,并专门点名 Fragment 动态加载的 5 个步骤。

五步流程图

完整示例代码

① Fragment 类

java
public class TestFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // 加载 Fragment 自己的布局
        return inflater.inflate(R.layout.fragment_test, container, false);
    }
}

② Activity 布局中放容器

xml
<!-- activity_main.xml 中放一个容器用于承载 Fragment -->
<FrameLayout
    android:id="@+id/ll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

③ Activity 中动态加载(5 个核心步骤)

java
// 1. 创建 Fragment 实例对象
TestFragment testFragment = new TestFragment();

// 2. 获取 FragmentManager
FragmentManager fm = getSupportFragmentManager();

// 3. 开启事务
FragmentTransaction transaction = fm.beginTransaction();

// 4. 替换容器中的 Fragment
transaction.replace(R.id.ll, testFragment);

// 5. 提交事务
transaction.commit();

Fragment 与 Activity 通信(可能追问)

java
// Activity 中获取 Fragment 实例
FragmentManager fm = getSupportFragmentManager();
Fragment f = fm.findFragmentById(R.id.ll);   // 或 findFragmentByTag()

// Fragment 中获取 Activity 实例
getActivity();   // 拿到依附的 Activity,再调用其方法

静态加载 vs 动态加载

方式操作适用静态加载XML 中写 <fragment> 标签固定不动的 Fragment动态加载Java 中用 FragmentTransaction需要切换的 Fragment


大题示例:ListView + 适配器(高频核心,重点掌握)

评分第 2、三种题型全覆盖。客观题只考了 setAdapter、适配器名字,大题极可能要求手写 BaseAdapter 完整实现 + 在 Activity 中绑定。下面按「四步实现一个列表」的完整流程整理。

实现流程图

完整示例代码

① Activity 布局放 ListView

xml
<!-- activity_main.xml -->
<ListView
    android:id="@+id/list_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

② 列表项布局

xml
<!-- item.xml:每一行长什么样 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="12dp">
    <ImageView
        android:id="@+id/iv_icon"
        android:layout_width="40dp"
        android:layout_height="40dp"/>
    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"/>
</LinearLayout>

③ 自定义 BaseAdapter(核心,重写 4 个方法)

java
public class MyAdapter extends BaseAdapter {
    private Context context;
    private List<String> dataList;   // 数据源

    public MyAdapter(Context context, List<String> dataList) {
        this.context = context;
        this.dataList = dataList;
    }

    @Override  // 方法1:返回数据总条数
    public int getCount() { return dataList.size(); }

    @Override  // 方法2:返回指定位置的数据
    public Object getItem(int position) { return dataList.get(position); }

    @Override  // 方法3:返回指定位置的 id
    public long getItemId(int position) { return position; }

    @Override  // 方法4:返回每一项的 View(最核心)
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            // 复用优化:convertView 为空才 inflate 新布局
            convertView = LayoutInflater.from(context)
                    .inflate(R.layout.item, parent, false);
            holder = new ViewHolder();
            holder.tvName = convertView.findViewById(R.id.tv_name);
            convertView.setTag(holder);   // 把控件引用存进 tag
        } else {
            holder = (ViewHolder) convertView.getTag();  // 复用时直接取出
        }
        // 给控件设置数据
        holder.tvName.setText(dataList.get(position));
        return convertView;
    }

    // ViewHolder:缓存控件引用,避免重复 findViewById
    static class ViewHolder {
        TextView tvName;
    }
}

④ Activity 中绑定(3 步:找控件 → 准备数据 → setAdapter)

java
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 1. 找到 ListView
        ListView listView = findViewById(R.id.list_view);

        // 2. 准备数据源
        List<String> data = new ArrayList<>();
        data.add("张三");
        data.add("李四");
        data.add("王五");

        // 3. 创建适配器并绑定(setAdapter 是填充数据的关键方法)
        MyAdapter adapter = new MyAdapter(this, data);
        listView.setAdapter(adapter);

        // 4.(可选)设置条目点击事件
        listView.setOnItemClickListener((parent, view, position, id) -> {
            Toast.makeText(this, "点击了:" + data.get(position),
                    Toast.LENGTH_SHORT).show();
        });
    }
}

如果用简单适配器(ArrayAdapter,了解即可)

java
// 每项只有一行文字时,用系统自带布局,不用写 item.xml 和适配器类
ArrayAdapter<String> adapter = new ArrayAdapter<>(
        this, android.R.layout.simple_list_item_1, data);
listView.setAdapter(adapter);

答题要点速记

  1. 三要素:数据源 → 适配器 Adapter → ListView,缺一不可(不设 Adapter 不显示数据)。
  2. BaseAdapter 必背 4 方法getCount / getItem / getItemId / getView
  3. getView 是核心convertView 复用 + ViewHolder(setTag/getTag)做性能优化,这是失分重灾区,务必写出。
  4. 绑定关键方法listView.setAdapter(adapter)

其它大题易考方向(简答 / 程序)

  1. Intent:显式(指定目标类名,应用内跳转)vs 隐式(描述动作,系统匹配,跨应用)。
  2. 数据传递:少用 putExtra();多用 Bundle 打包(底层 Binder)。
  3. 三种菜单:选项菜单(2 方法)、上下文菜单(3 方法,多一个 registerForContextMenu 注册)、弹出菜单(new PopupMenu 对象)。
  4. 数据存储:内部存储 openFileInput/openFileOutput;外部存储先查设备状态、再取根目录;数据库帮助类 + 访问类 + 接口。

复习提示:老师反复强调「对着那两张图再看」——重点看 ListView 三要素图、RecyclerView 各角色关系图,以及数据库帮助类/访问类/接口关系图。


各部分核心总结

第二章 · 布局与基本控件

  1. 控件 ID 是核心:唯一标识,方便 findViewById;同页面不可重复,不同页面可重复。
  2. 6 个基本控件:TextView、EditText、Button、RadioButton、CheckBox、ImageView——记作用 + 英文名 + 标签名。
  3. 三种重点布局:线性(单方向,weight 权重)、相对(参照定位)、表格(行列)。
  4. Button 点击三写法:XML onClick、匿名内部类、公共监听器。

第三章 · 列表控件

  1. ListView 三要素:数据源 → 适配器 → ListView。
  2. 三种适配器(简单到复杂):ArrayAdapter → SimpleAdapter → BaseAdapter(重写 4 方法)。
  3. RecyclerView 优势:强制 ViewHolder 复用 + LayoutManager(线性/网格/瀑布流),Adapter 三方法。
  4. 核心区别:ListView 手动复用、无布局管理器;RecyclerView 强制复用、有 LayoutManager。

第四章 · 菜单与 Activity

  1. 三种菜单:选项菜单(2 方法)、上下文菜单(3 方法,多一个注册)、弹出菜单(new 对象)。
  2. Activity 四状态:活动(onResume) → 暂停(onPause) → 停止(onStop) → 非活动(onDestroy)。
  3. Intent 两类型:显式(指定类名,内部跳转)vs 隐式(描述动作,系统匹配,跨应用)。
  4. 数据传递:少用 putExtra 逐个传;多用 Bundle 打包(Binder)。

第五章 · 数据存储

  1. 五种方式:文件、SharedPreferences、SQLite 数据库、ContentProvider、网络。
  2. 文件存储:内部 openFileInput/openFileOutput;外部先查设备状态、再取根目录。
  3. 数据库:帮助类(SQLiteOpenHelper)+ 访问类(SQLiteDatabase)+ 接口。

大题应对

  1. 程序题考「实现特定功能的核心方法」,不考弹 Toast 这类简单操作。
  2. 必背:Fragment 动态加载 5 步、适配器核心方法、菜单创建+点击回调、Intent 跳转+传值、文件/数据库读写方法。
  3. 老师强调「对着那两张图复习」——ListView/RecyclerView 角色图、数据库帮助类/访问类/接口关系图。

考点频率分析与大题预测(基于 1-4 章真题统计)

对 37 道客观题(单选18/判断12/填空7)做考点频率 + 题型覆盖加权统计,反推老师命题偏好。注意:以下仅基于 1-4 章真题,第 5 章(数据存储)题目缺失,需单独准备。

章节分布

考点偏好评分(频次 + 题型覆盖加权)

排名考点评分题型覆盖信号解读1布局14.0选/判/填 全覆盖老师最在意,反复换角度考2ListView12.0选/判/填 全覆盖同样全题型轰炸3Intent9.0选+判显隐式、传值是热点4RecyclerView8.0选+判与 ListView 成对考5对话框/菜单/控件/生命周期7.0选+判或选+填中等热度—Fragment3.0仅 1 次客观题几乎没考(见下方反差信号)

关键洞察:布局、ListView 是仅有的两个「三种题型全覆盖」考点,说明老师反复从不同角度挖掘,是最真实的核心偏好。

大题命题方向预测

逻辑:客观题已密集覆盖的记忆性细节(属性名、目录名、方法名)一般不原样搬进大题;但客观题反复触碰的核心主题,大题会以「写区别 / 写核心方法」的形式深化。

程序分析/设计题(2 道)最可能:

  1. ListView + 适配器:客观题只考了 setAdapter、适配器名字,大题极可能要求手写 BaseAdapter 的 getView() 或完整适配器
  2. RecyclerView:要求写 Adapter 三方法 + ViewHolder + LayoutManager 绑定。
  3. ⚠️ Fragment 动态加载:客观题仅出现 1 次(评分垫底),但老师录音专门点名 5 步。这种「客观题几乎没考 + 口头强调」的反差,强烈暗示它被留给了程序大题(步骤类不适合客观题)——最需警惕。

简答题最可能:

  1. Intent 显式 vs 隐式的区别 + 如何判定
  2. ListView vs RecyclerView 的区别(两大高频点天然对比)
  3. 三种适配器 / 三种菜单的区别与适用场景

第 5 章单独提醒

本次真题不含第 5 章,无法用频率反推。结合录音,第 5 章重点自行准备:

  1. 五种数据存储方式的定义
  2. 文件存储内部 vs 外部的区别与方法(openFileInput/openFileOutput)
  3. 数据库帮助类 + 访问类 + 接口的关系图

分析脚本:exam_analysis.py(本地,uv 环境可重跑)。