尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

移动应用开发期末复习:Android核心知识点与备赛攻略

移动应用开发期末复习:Android核心知识点与备赛攻略 考前先聊几句这门课为什么让人又爱又恨移动应用开发听名字就觉得很“能打”——能自己写App、能参加技能大赛、毕业还能找份移动开发的工作。但真正到了期末复习很多同学的表情就逐渐凝固了知识点零零碎碎光一个Android就有Activity、Service、BroadcastReceiver、ContentProvider四大组件要背还有布局、适配、数据存储、网络请求、异步任务……复习资料打开一堆合上脑子空空。我当年复习这门课的时候也是硬啃了不少文档、踩了不少坑。后来帮学弟学妹梳理备考重点、带过几轮省赛培训之后才慢慢把这条“复习主线”摸清楚。这篇内容就是面向期末复习场景的移动应用开发核心梳理既覆盖考试高频考点也兼顾技能大赛“移动应用设计与开发”这类赛项里常考的实战技能。不管是期末突击还是备赛冲刺你都能在里面找到可以直接拿来用的知识框架和复习思路。先说清楚这篇不是教科书式的全面罗列而是按“考试怎么考、比赛怎么用、上手怎么做”三个角度精选出来的重点自用可以也欢迎转发给一起复习的小伙伴。1. 整体复习框架先打通“一条主线、四个支线”移动应用开发的知识点看起来散其实骨架非常清晰。我把整个复习体系归纳为一条主线是“页面 → 逻辑 → 数据 → 网络”四个支线分别是系统组件、UI布局与适配、数据持久化、网络与异步。这个框架不光应付期末考试做比赛项目时也一样适用。1.1 主线逻辑一个App从打开到运行到底发生了什么移动应用以Android为例的基本运行路径是用户点击图标 → 系统创建并启动一个Activity → Activity加载布局文件 → 布局中的控件被填充到屏幕上 → 用户交互触发事件 → 逻辑代码处理事件并读写数据本地存储或远程服务器→ 数据变化反馈到界面。把这条链路拆开就对应了复习的几个大块页面长什么样 → 布局与控件XML页面怎么切换 → Activity/Intent/Fragment数据存哪里 → SharedPreferences、文件、SQLite数据怎么来 → 网络请求、JSON解析耗时操作怎么做 → 线程、Handler、异步任务考试也好、比赛也好本质上都是围绕这条线在出题。你拿到一张试卷或一个赛题第一件事不要慌先判断它考的是这条主线的哪一段是布局设计是页面跳转传参还是数据入库判断对了再去调对应的知识点。1.2 支线拆解每门课都绕不开的高频考区四个支线是每年期末和技能大赛的“稳定出题区”系统组件Activity的生命周期、Service的启动与绑定、BroadcastReceiver的动态与静态注册、ContentProvider的基本使用。UI与适配五大布局LinearLayout、RelativeLayout、FrameLayout、TableLayout、ConstraintLayout的特性与嵌套常用控件TextView、Button、EditText、ListView、RecyclerViewdp/sp与px的区别屏幕适配方案。数据持久化三种轻量级方案的适用场景SQLite的增删改查SQLiteOpenHelper的使用升级时onUpgrade的处理。网络与异步HTTP协议基础HttpURLConnection与OkHttp的对比JSON格式与解析JSONObject与GsonHandler消息机制AsyncTask的历史与局限线程池入门。有同学会问是不是把这些背下来就能考好我的答案是背只是基础动手才能在考试和比赛中真正得分。尤其到了综合题或比赛实操环节光知道概念不知道怎么落地很容易在细节上翻车。后面几个部分我会把每个支线里的核心考点和实操要点掰开揉碎讲一遍。2. 系统组件核心考点生命周期、Intent传参、四大组件对比系统组件这部分是移动应用开发的“地基”也是期末考试简答题、填空题的“最喜欢”区域。技能大赛里虽然不会直接让你默写生命周期但你在做页面跳转、数据回传、服务绑定这些操作时每一步其实都在和组件打交道。2.1 Activity生命周期背图只是入门关键在“场景题”Activity生命周期几乎是每年必考而且出题方式越来越活。常见的考法有两种一种是直接画图填空另一种是给一个场景让你判断执行了哪些回调方法。比如最经典的“屏幕旋转”场景Activity从竖屏切到横屏会走一遍 onPause → onStop → onDestroy → onCreate → onStart → onResume。为什么不是直接旋转因为系统默认配置变化时会销毁并重建Activity。这个知识点单独背没意思你把它理解成“系统觉得当前的Activity配不上新屏幕所以重新生成了一个”就好记多了。再比如“按Home键回到桌面”走 onPause → onStop但不会走 onDestroy因为Activity实例还在后台存活着。所以如果你在 onStop 里释放了某些资源重新回到应用时要在 onStart 或 onRestart 里重新初始化。我复习时发现一个很有用的记忆方法把生命周期分成“前台可见期”onStart → onResume、“部分可见期”onPause、“后台不可见期”onStop、“销毁期”onDestroy四个阶段然后针对每个阶段去想一想“此时用户能看到什么能操作什么系统内存紧张时会不会杀我”只要想明白这三个问题绝大多数生命周期选择题都能秒答。还有一个复习时容易忽略的考点onSaveInstanceState。当Activity被系统回收前系统会调用它来保存状态你可以在里面用Bundle保存临时数据。注意它只在“非主动销毁”时才会被调用——如果你按返回键退出是不会触发 onSaveInstanceState 的。这个细节考选择题的话迷惑性特别大。2.2 Intent与页面跳转显式、隐式与传参回传的完整写法Intent是组件之间通信的“信使”期末笔试爱考概念上机考试则实打实要写代码。复习时不要只背“显式Intent指定组件名隐式Intent指定Action/Category”要能默写出一段完整的跳转代码。显式跳转很简单Intent intent new Intent(MainActivity.this, SecondActivity.class); startActivity(intent);如果需要传参用putExtra/putExtrasintent.putExtra(user_id, 1001); intent.putExtra(user_name, 张三); startActivity(intent);接收端在onCreate里取String name getIntent().getStringExtra(user_name); int id getIntent().getIntExtra(user_id, 0);如果需要“从B页面回传结果给A页面”就得用 startActivityForResult新版本用 ActivityResultLauncher但考试和很多旧项目里写 startActivityForResult 更多// A页面发起 Intent intent new Intent(MainActivity.this, SelectActivity.class); startActivityForResult(intent, 1); // A页面接收 Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode 1 resultCode RESULT_OK) { String result data.getStringExtra(result); } } // B页面返回 Intent data new Intent(); data.putExtra(result, 选了A); setResult(RESULT_OK, data); finish();这段代码我是要求自己默写三遍以上的。因为考试卷子上不会给你IDE的自动补全少写一个super调用、少判一个requestCode整道题可能就白做了。关于隐式Intent复习重点在于理解Action与Category的配对规则。系统会根据你设定的Action比如Intent.ACTION_VIEW和Category比如Intent.CATEGORY_DEFAULT通过IntentFilter匹配找到对应的组件。考试常考的一个点是隐式Intent至少需要一个Action和一个Category默认是DEFAULT缺少任何一个都可能导致匹配失败或抛ActivityNotFoundException。2.3 Service与BroadcastReceiver背概念之外要会的两件事Service是“后台运行”的代名词考试爱考“启动方式有哪两种、有什么区别”。这里一定要区分清楚startService()启动服务服务在后台无限期运行即使启动它的组件销毁了服务依然存在。需要调用stopService()或stopSelf()来停止。bindService()绑定服务服务与绑定者“同生共死”绑定者销毁时服务自动解绑销毁。绑定后还能调用服务内部的方法实现进程内通信。笔试可能会问“Service是否运行在主线程”答案是默认运行在主线程UI线程所以Service里不能直接做网络请求或大量耗时操作需要另开子线程。很多同学以为Service就等于子线程这是考试常埋的坑。BroadcastReceiver的复习重点则是两种注册方式的区别静态注册在AndroidManifest.xml里写 标签即使应用没启动也能收到广播动态注册在代码里 registerReceiver() 注册必须在onDestroy里 unregisterReceiver() 注销否则会内存泄漏。新版Android对静态注册加了限制部分隐式广播不再支持静态注册这个在选择题里容易成为陷阱复习时可以留意一下。2.4 四大组件横向对比这样记比较不容易混很多同学容易把四大组件的职责搞混我建议用一句话总结Activity负责“看得见的界面”一切用户看到和交互的内容都源于它。Service负责“后台任务”没有界面但可以在后台持续运行。BroadcastReceiver负责“消息收听”接收系统或应用发出的广播。ContentProvider负责“数据共享”为其他应用提供统一的数据访问接口。记法可以这样Activity是前台演员Service是后台工作人员BroadcastReceiver是电台听众ContentProvider是数据仓库管理员。这四个角色各管一摊考试问“哪个组件没有界面”马上想到Service和BroadcastReceiver后者可以有界面但不必须有实际开发中一般无界面。3. UI布局与列表从XML基础到RecyclerView实战UI这块是移动应用开发的“门面”也是期末考试上机题和技能大赛里最拉分的地方。很多项目组队时UI做得好的同学永远不愁找不到队友。复习UI不能只盯着“认识控件”要把布局嵌套、尺寸单位、列表适配这些硬功夫练到位。3.1 五大布局的选用原则什么时候用哪个心里要有数线性布局LinearLayout是最基础、最容易理解的布局适合从上到下或从左到右排布控件考试上机写界面时优先用它。但要注意它的性能问题嵌套过深会导致measure和layout阶段计算量成倍增长布局层级越多渲染越慢。比赛项目讲究界面流畅度尽量把层级控制在3层以内。相对布局RelativeLayout适合“控件之间相对定位”的场景比如“图片在文字左边”“按钮在父容器右下角”。它比线性布局灵活但约束关系写多了以后可读性会变差。帧布局FrameLayout最简单所有子控件默认堆叠在左上角。它通常用来做“层叠效果”比如一个界面上浮着一个悬浮按钮。帧布局也是Fragment容器最常用的宿主布局。表格布局TableLayout适合规整的表格型界面但实际App开发中用得已经很少了考试一般只是要求认识。约束布局ConstraintLayout是Android官方现在主推的布局它既能像相对布局那样设置约束又能做到扁平化不嵌套。比赛项目里如果对性能有要求优先选它。复习时至少要掌握常见的约束属性layout_constraintTop_toTopOf、layout_constraintStart_toEndOf等并理解“把控件A的左边约束到控件B的右边”这种写法。3.2 dp、sp与px选择题爱考的单位换算dpdensity-independent pixel是“密度无关像素”用来保证在不同密度的屏幕上显示出来的物理尺寸大致一致。spscale-independent pixel在dp的基础上还会跟随系统字体缩放所以文字大小用sp控件尺寸用dp。px是实际像素点一般不要在布局里直接指定px否则小屏大屏显示效果会差异很大。考试可能给一个换算题假设设备密度为2x即density2.0那么1dp等于多少px答案2px。换算公式是 px dp × density。还有一个常见考点是“wrap_content和match_parent的区别”。wrap_content是“包裹内容”控件有多大就显示多大match_parent是“填满父容器”占满父布局剩余的空间。这个虽然基础但考选择题时经常结合权重layout_weight一起考比如线性布局里两个按钮各设权重1它们就平分剩余空间。要记住权重是在剩余空间分配不是按固定比例划分整个布局所以如果有一个控件没设权重它先占据自身需要的大小剩下的空间才按权重分配。3.3 列表控件ListView与RecyclerView的复用机制与适配器列表是移动应用里出现频率最高的界面形态。考试和比赛都绕不开ListView或RecyclerView。ListView是老牌列表控件复习时重点理解“适配器模式”。ArrayAdapter适合纯文本列表SimpleAdapter适合简单图文列表BaseAdapter则适合完全自定义的列表项。写出高效的BaseAdapter核心就是convertView的复用和ViewHolder的缓存Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; if (convertView null) { convertView LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_student, parent, false); holder new ViewHolder(); holder.tvName convertView.findViewById(R.id.tv_name); holder.tvScore convertView.findViewById(R.id.tv_score); convertView.setTag(holder); } else { holder (ViewHolder) convertView.getTag(); } Student s dataList.get(position); holder.tvName.setText(s.getName()); holder.tvScore.setText(s.getScore() 分); return convertView; } static class ViewHolder { TextView tvName; TextView tvScore; }这段代码面试也爱考它的核心是convertView为空时才去加载布局并创建ViewHolder之后直接复用避免重复inflate和findViewById带来的性能损耗。RecyclerView是ListView的“加强版”熟练掌握它几乎是比赛项目的标配。复习时至少要把三件套弄明白LayoutManager线性、网格、瀑布流、Adapter需要继承RecyclerView.Adapter和ItemDecoration分隔线。RecyclerView的条目点击事件没有内置接口需要自己在Adapter里写接口回调public interface OnItemClickListener { void onItemClick(int position); } private OnItemClickListener mListener; public void setOnItemClickListener(OnItemClickListener listener) { this.mListener listener; } // 在onBindViewHolder中设置 holder.itemView.setOnClickListener(v - { if (mListener ! null) { mListener.onItemClick(position); } });笔试里可能会问“为什么RecyclerView点击事件不直接像ListView那样setOnItemClickListener”回答要点是RecyclerView的布局方式多样条目位置计算比较复杂官方把点击事件交给开发者自己处理这样更灵活。3.4 上机实操时的UI细节布局预览与真机适配上机写界面时我踩过不少坑总结几个经验先画草图再写XML哪怕只是在草稿纸上画个方框都能节约大量调试时间。单位用dp/sp不要用px字体颜色、背景色尽量抽到colors.xml里方便统一修改。布局写完先开Design预览再看真机效果。比赛用机屏幕尺寸不定建议用“小屏手机大屏平板”两种设备各预览一次。如果文字和图片混排注意ImageView的scaleType属性。设置为fitCenter可以按比例缩放并居中显示设置为centerCrop会裁剪填满控件适合做头像这类固定尺寸的图。这些细节看着小但上机考试时界面跑飞了、字被截断、按钮位置不对一连串问题下来心态很容易崩。提前把这些坑踩平考试时才能稳得住。4. 数据存储与SQLite三种方案怎么选、增删改查怎么写数据持久化是移动应用开发里另一大核心模块。期末笔试常考“三种持久化方式的区别”上机和比赛则会让你实际操作存数据、读数据。复习的关键是分清“不同场景用不同方案”别一上来就上数据库。4.1 SharedPreferences、文件存储与SQLite的适用场景SharedPreferences适合存“键值对”形式的简单配置数据比如用户登录状态的标记、设置的开关项、上次保存的草稿时间等。它的本质是生成一个XML文件用Map键值对的方式读写使用非常简单// 写入 SharedPreferences sp getSharedPreferences(user_config, MODE_PRIVATE); SharedPreferences.Editor editor sp.edit(); editor.putString(username, zhangsan); editor.putBoolean(is_login, true); editor.apply(); // 读取 String name sp.getString(username, 默认值); boolean isLogin sp.getBoolean(is_login, false);注意两点一是写入后要调用apply()或commit()apply()异步写盘、效率高commit()同步返回boolean、有结果反馈但会阻塞主线程二是从Android 7.0开始MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE已经被废弃不要再用了。文件存储适合存“流式数据”比如图片、日志、导出文件。内部存储路径通过 getFilesDir() 获取外部存储需要考虑权限申请。比赛项目里如果要导出Excel、保存日志文本通常是文件存储的活。SQLite是移动端最常用的嵌入式关系型数据库适合存结构化数据比如用户表、订单表、消息列表。它不需要独立的数据库服务数据就是一个.db文件但增删改查的SQL语句和后台数据库几乎一致所以学好SQLite对未来学MySQL、SQL Server也有帮助。三个方案的选择逻辑很简单数据很零碎且只是配置 → SharedPreferences数据是文件流 → 文件存储数据条数多、有结构、需要查询统计 → SQLite。考试问“什么场景用哪种存储”按这个思路答一般不会跑偏。4.2 SQLiteOpenHelper与数据库升级考试与项目的双热点SQLiteOpenHelper是管理数据库创建和版本升级的核心类。复习时要能默写一个最小实现public class DBHelper extends SQLiteOpenHelper { private static final String DB_NAME student.db; private static final int DB_VERSION 1; public DBHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); } Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE TABLE student( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, score INTEGER DEFAULT 0)); } Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // 版本升级时处理比如加字段、加表 db.execSQL(ALTER TABLE student ADD COLUMN grade TEXT); } }onCreate在数据库第一次创建时调用onUpgrade在数据库版本号变大时调用。考试简答题经常问“数据库升级时怎么处理”回答要点是在onUpgrade里写ALTER TABLE语句或重新建表并做好旧数据迁移不能直接drop表除非数据无所谓。实际操作中我建议在helper构造方法里传入一个静态常量DB_VERSION每次表结构变化时把版本号加1然后同步修改onUpgrade里的逻辑。这样既清晰又好维护比赛项目里多人协作也不容易踩坑。4.3 数据库增删改查的标准写法与游标处理SQLiteDatabase提供两类操作API一是execSQL()执行无返回值的SQL语句适合insert/update/delete二是rawQuery()执行查询语句返回Cursor游标。但实际开发中更推荐使用系统封装好的insert/query/update/delete方法避免SQL注入代码也更简洁// 插入 ContentValues values new ContentValues(); values.put(name, 李四); values.put(score, 95); long id db.insert(student, null, values); // 查询 Cursor cursor db.query(student, null, score ?, new String[]{90}, null, null, score DESC); while (cursor.moveToNext()) { String name cursor.getString(cursor.getColumnIndexOrThrow(name)); int score cursor.getInt(cursor.getColumnIndexOrThrow(score)); } cursor.close(); // 更新 ContentValues updateValues new ContentValues(); updateValues.put(score, 100); db.update(student, updateValues, name ?, new String[]{李四}); // 删除 db.delete(student, id ?, new String[]{1});用Cursor读取数据时有三点需要注意一是用完一定要cursor.close()否则会内存泄漏二是查询时尽量只取需要的字段不要一味select *三是用getColumnIndexOrThrow()代替getColumnIndex()能在列名写错时快速报错方便排查问题。4.4 上机实操避坑ID自增、中文乱码与主线程ANR写数据库代码时有几个实战中很容易踩的坑建表语句里主键自增要写成 INTEGER PRIMARY KEY AUTOINCREMENT注意“INTEGER”不能写成“INT”否则自增可能不生效。中文乱码大多出现在读写编码不一致。Android默认UTF-8一般不会乱码但如果你在Windows下手动改了数据库文件很容易出现乱码。解决办法是统一使用UTF-8别用GBK。不要把数据库操作放在主线程里做。数据库写入慢、数据量大时主线程会被阻塞超过5秒就会抛出ANRApplication Not Responding提示。比赛项目里数据库操作一定要放到子线程或使用线程池。我在备赛和带比赛队伍时见过不少选手在数据库读写上“翻车”。原因往往不是不会写SQL而是没考虑好线程和生命周期。数据读写放到子线程后记得通过runOnUiThread或Handler把结果回调到UI线程更新界面这样既流畅又安全。5. 网络请求与JSON解析从HTTP基础到OkHttpGson组合现在的移动应用几乎都要联网网络请求和JSON解析是期末上机考试、技能大赛的重头戏。这块内容不算难但知识点非常碎权限、主线程限制、超时处理、解析异常、线程切换……任何一环出问题程序就“崩给你看”。5.1 HTTP协议基础与Android联网前的“三件套”准备在写代码之前先把HTTP复习到位HTTP是应用层协议基于请求-响应模型。请求行里包含请求方法GET/POST/PUT/DELETE、请求URL、协议版本。请求头用键值对携带额外信息比如Content-Type、Authorization。请求体是POST等方式携带的数据正文。响应包含状态行状态码如200成功、404资源不存在、500服务器内部错误、响应头和响应体。很多笔试题目从后端接口给你一段JSON让你判断“用GET还是POST合适”——记住经验法则查询操作且不涉及敏感数据用GET创建/修改/删除或携带敏感信息用POST。Android联网前有三件事必须做漏一个程序就跑不起来在AndroidManifest.xml里添加网络权限如果访问HTTP明文流量Android 9.0及以上需要在manifest里设置 android:usesCleartextTraffictrue或配置networkSecurityConfig否则会报“Cleartext HTTP traffic not permitted”。API 30及以上需要在manifest里声明android:usesCleartextTraffictrue之外还可能需处理网络权限的一些限制。最稳妥的方式是直接用HTTPS接口。上机考试时第一件丢分的事就是忘了加网络权限代码写对了但一运行就崩。备考时建议把它写进自己的“代码启动模板”里每次新建项目先补齐。5.2 HttpURLConnection与OkHttp两种写法的对比与选择HttpURLConnection是JDK自带的网络请求类轻量、无需三方依赖适合考试和简单请求。一个最小GET请求如下URL url new URL(https://api.example.com/student/list); HttpURLConnection conn (HttpURLConnection) url.openConnection(); conn.setRequestMethod(GET); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); int code conn.getResponseCode(); if (code 200) { InputStream is conn.getInputStream(); BufferedReader reader new BufferedReader(new InputStreamReader(is, UTF-8)); StringBuilder sb new StringBuilder(); String line; while ((line reader.readLine()) ! null) { sb.append(line); } String response sb.toString(); // 解析response reader.close(); is.close(); } conn.disconnect();POST请求则要设置setDoOutput(true)并写入请求体比如JSON格式的bodyconn.setRequestMethod(POST); conn.setDoOutput(true); conn.setRequestProperty(Content-Type, application/json;charsetUTF-8); String body {\name\:\张三\,\score\:90}; conn.getOutputStream().write(body.getBytes(UTF-8));OkHttp是目前Android项目主流的三方网络库由Square公司开源。它支持连接池复用、GZIP压缩、请求取消、拦截器等高级特性代码也更简洁。最小用法OkHttpClient client new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS) .build(); RequestBody requestBody RequestBody.create( MediaType.parse(application/json;charsetUTF-8), jsonString); Request request new Request.Builder() .url(https://api.example.com/student/add) .post(requestBody) .build(); client.newCall(request).enqueue(new Callback() { Override public void onFailure(Call call, IOException e) { // 网络失败e.getMessage()查看原因 } Override public void onResponse(Call call, Response response) throws IOException { if (response.isSuccessful()) { String result response.body().string(); // UI更新记得切回主线程 } } });考试如果允许引用三方库优先用OkHttp如果纯粹笔试手写代码HttpURLConnection的写法必须会。两种都要练因为笔试可能规定“不准使用第三方库”上机则可能要求“必须使用OkHttpGson”。5.3 Gson解析JSON对象、数组与嵌套结构的处理服务端返回的JSON数据通常有两种结构简单对象和数组。用Gson解析时核心是先定义好对应的JavaBean实体类。简单JSON对象String json {\name\:\张三\,\score\:90}; Student s new Gson().fromJson(json, Student.class);JSON数组String jsonArray [{\name\:\张三\,\score\:90},{\name\:\李四\,\score\:95}]; ListStudent list new Gson().fromJson(jsonArray, new TypeTokenListStudent(){}.getType());注意这里 TypeToken 必须加上因为泛型在运行时会被擦除不传TypeToken的话Gson无法获知List的元素类型。比赛项目的接口返回往往是带状态码和消息的统一格式{ code: 200, message: success, data: { total: 2, list: [ {name: 张三, score: 90}, {name: 李四, score: 95} ] } }对应实体类可以写一个通用Result类public class ResultT { private int code; private String message; private T data; // getter/setter省略 }解析时ResultPageData result new Gson().fromJson(json, new TypeTokenResultPageData(){}.getType());这样写的好处是一套Result类可以复用很多接口比赛现场写代码时效率特别高。我带队时一直强调先定义好“返回结构”再写具体的解析逻辑别一个个接口硬编码解析否则改一个字段就要改好几处。5.4 主线程不能联网理解Android的线程限制与Handler这是Android开发里最“经典”的报错之一NetworkOnMainThreadException。系统强制要求网络请求不能放在主线程执行因为网络操作不可控如果大量请求阻塞主线程界面就会卡顿甚至ANR。解决方案主要有几种ThreadHandler、AsyncTask已过时不推荐新项目用、线程池、协程。在期末复习阶段重点是理解Handler消息机制——它是Android异步消息处理的核心也是笔试高频考点。Handler的工作机制可以理解为主线程里有一个Looper在不停轮询消息队列子线程通过Handler发送Message到队列Looper取出消息后交给Handler的handleMessage方法处理。这样就实现了“子线程干活主线程更新UI”的效果。// 主线程创建Handler Handler handler new Handler(Looper.getMainLooper()) { Override public void handleMessage(Message msg) { if (msg.what 1) { String result (String) msg.obj; tvResult.setText(result); } } }; // 子线程中发送消息 new Thread(() - { String result doNetworkRequest(); // 模拟网络请求 Message msg new Message(); msg.what 1; msg.obj result; handler.sendMessage(msg); }).start();也可以直接使用 runOnUiThread runOnUiThread(() - tvResult.setText(result));笔试里如果问“为什么不能在子线程直接更新UI”回答思路是Android的UI访问不是线程安全的主线程通过Looper机制维护UI队列子线程直接改UI会导致状态不一致所以系统只允许UI线程对界面进行修改。5.5 实战中JSON解析与网络请求的常见“翻车”点网络这块踩坑率非常高我把高频问题列出来复习时直接对照排查超时连不上服务器或请求太久需要设置connectTimeout和readTimeout。真实场景里服务器慢是常态超时时间设5-10秒比较合理。JSON解析报错最常见的是字段类型不匹配。比如服务端返回的是字符串90你实体类里写成intGson就会抛JsonSyntaxException。解决方法是确认接口文档或者把字段类型改用String接收再手动转int。返回空数据注意判空。解析之前先判断response是否为空解析出List后也要判断list.size()是否大于0避免空指针。访问http明文被拦高版本Android默认禁止明文流量比赛现场的测试接口经常是http的记得在manifest里开usesCleartextTraffic。线程问题onResponse回调是后台线程直接在里面操作TextView会崩溃必须切到主线程。复习时我建议把网络请求做成一个“标准流程”来练封装OkHttpClient → 构建Request → enqueue异步回调 → 判空 → 用Gson解析 → 切主线程更新UI → 失败时Toast提示。练到肌肉记忆考试时就不容易慌了。6. 期末复习与备赛冲刺我的实操经验与最后叮嘱到了最后一部分我想把真正“落地”的复习方法和比赛经验分享给你。这部分不是知识点但我觉得比知识点更重要——因为方法对了复习效率能翻倍。6.1 三轮复习法第一轮搭框架、第二轮刷题、第三轮做项目很多同学期末复习是一遍过结果前面背了后面忘。我带过的备考小组里用的最多且效果最好的是“三轮复习法”第一轮约占总时间40%搭框架。沿着“页面→逻辑→数据→网络”这条主线把每个模块的核心概念和代码模板过一遍。这轮不追求背熟追求的是“知道考什么、知识点在哪一章”。第二轮约占总时间30%刷题。把历年期末考试题、比赛样题拿出来做。做题时不要看笔记先自己回忆、自己写写不出来再翻书。这轮的核心是查漏补缺把“我以为我会”的地方揪出来。第三轮约占总时间30%做项目。期末考试如果有上机题或者你要参加技能大赛这轮几乎决定成败。找一个小而完整的项目比如“学生成绩管理系统”App把布局、列表、SQLite增删改查、网络请求、JSON解析全部串起来做一遍。项目不在大在完整。做完一个你对整个知识体系的掌握程度会上一个台阶。6.2 比赛项目备赛的三条经验分工、版本控制、模拟现场省赛类的移动应用开发赛项平时训练时我注意到三个关键点分享给你第一团队分工要按“界面逻辑数据”来切不要按“你的页面、我的页面”来切。因为比赛的评分维度中整体功能完整度往往比单页面精美更重要。界面负责人统一管理布局样式和颜色规范逻辑负责人统一处理页面跳转与数据传递数据负责人统一封装网络层和数据库层这样整合时不会出现各写各的、接口对不上。第二一定要用版本控制工具Git。哪怕只有一个人写代码也要养成每次改完一个小功能就commit的习惯。比赛现场时间紧如果改了界面后功能坏了能用Git快速回滚节省大量排查时间。第三每周至少做一次“模拟现场”训练。严格按照比赛的时间限制和题目要求关掉手机、不看笔记连续几个小时独立完成一个功能模块。很多选手平时写代码没问题一到比赛就紧张得连页面跳转都写不顺就是因为缺少这种限时训练。6.3 最后的经验之谈代码量才是硬道理期末复习也好、比赛备赛也罢我的个人体会是移动应用开发这门课看十遍书不如写一遍代码。很多同学喜欢把时间花在“看视频”“背重点”上但一上机就写不出来原因很简单——写代码是“手部记忆”驱动的技能只有手指敲过一遍才知道哪里容易漏分号、哪里容易写错类名、哪里容易忘了注册权限。所以我最后给你一个可量化的建议考前至少独立完成三个小项目比如一个“待办事项App”、一个“新闻列表App”、一个“登录注册个人中心App”。每个项目强制覆盖至少三个核心模块Activity跳转与传参、列表展示、数据存储或网络请求。这三个项目做完要是还觉得没底就再往里加功能——加一个图片加载、加一个下拉刷新、加一个按条件查询。复习资料再多最终都要落到这一行行代码上。希望这份整理能帮你把知识体系串起来也祝你在期末考试和技能大赛里拿到自己满意的成绩。如果你在复习过程中遇到具体报错或某个知识点卡住了回头看看正文里对应的章节或者自己动手跑一遍代码——大多数问题敲一敲就通了。
返回列表