{"id":1319,"date":"2026-09-14T16:06:38","date_gmt":"2026-09-14T16:06:38","guid":{"rendered":"https:\/\/boochlin.com\/?page_id=1319"},"modified":"2026-09-14T16:06:38","modified_gmt":"2026-09-14T16:06:38","slug":"funnyvote-evolution-guide","status":"publish","type":"page","link":"https:\/\/boochlin.com\/?page_id=1319","title":{"rendered":"Funny Vote \u5341\u5e74\u6f14\u9032\uff1a\u5f9e Java MVP \u5230 Compose \u8207\u96f2\u539f\u751f\u67b6\u69cb\uff08\u5168\u7cfb\u5217\u5c0e\u89bd\uff09"},"content":{"rendered":"<style>\n\/* Boochlin Tech Blog \u00b7 FunnyVote Series Navigation Dashboard *\/\n.guide-wrap {\n  overflow-wrap: anywhere;\n  word-break: break-word;\n  max-width: 100%;\n  color: #0F172A;\n  line-height: 1.65;\n  font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Noto Sans TC\", \"Helvetica Neue\", sans-serif;\n  box-sizing: border-box;\n}\n.guide-wrap * { box-sizing: border-box; }\n.overview-hero-fv {\n  background: #0F172A;\n  color: #FFFFFF;\n  border-radius: 12px;\n  padding: 28px 24px;\n  margin-bottom: 32px;\n  box-shadow: 0 4px 20px rgba(15,23,42,0.15);\n  border-top: 4px solid #F59E0B;\n}\n.overview-title {\n  font-size: 1.45em;\n  font-weight: 800;\n  margin: 0 0 10px 0;\n  color: #FFFFFF;\n  letter-spacing: -0.01em;\n}\n.overview-desc {\n  font-size: 0.92em;\n  color: #94A3B8;\n  margin: 0 0 18px 0;\n  line-height: 1.6;\n}\n.overview-stats {\n  display: flex;\n  flex-wrap: wrap;\n  gap: 10px;\n  margin-bottom: 20px;\n}\n.stat-pill {\n  background: #1E293B;\n  border: 1px solid #334155;\n  border-radius: 6px;\n  padding: 6px 14px;\n  font-size: 0.82em;\n  color: #E2E8F0;\n  display: flex;\n  align-items: center;\n  gap: 6px;\n}\n.stat-num-fv {\n  color: #FBBF24;\n  font-weight: 700;\n  font-family: ui-monospace, monospace;\n}\n.timeline-container {\n  position: relative;\n  margin-bottom: 36px;\n}\n.stage-block {\n  margin-bottom: 28px;\n}\n.stage-header {\n  border-bottom: 2px solid #E2E8F0;\n  padding-bottom: 8px;\n  margin-bottom: 16px;\n  display: flex;\n  justify-content: space-between;\n  align-items: baseline;\n  flex-wrap: wrap;\n}\n.stage-title {\n  font-size: 1.15em;\n  font-weight: 700;\n  color: #0F172A;\n  margin: 0;\n}\n.stage-badge-fv {\n  font-size: 0.75em;\n  background: #FEF3C7;\n  color: #B45309;\n  padding: 3px 10px;\n  border-radius: 9999px;\n  font-weight: 600;\n}\n.card-grid {\n  display: grid;\n  grid-template-columns: 1fr;\n  gap: 14px;\n}\n@media (min-width: 768px) {\n  .card-grid { grid-template-columns: 1fr 1fr; }\n}\n.nav-card-fv {\n  background: #FFFFFF;\n  border: 1px solid #E2E8F0;\n  border-left: 4px solid #F59E0B;\n  border-radius: 8px;\n  padding: 18px 20px;\n  box-shadow: 0 2px 4px rgba(0,0,0,0.03);\n  transition: transform 0.15s ease, box-shadow 0.15s ease;\n  display: flex;\n  flex-direction: column;\n  justify-content: space-between;\n}\n.nav-card-fv:hover {\n  transform: translateY(-2px);\n  box-shadow: 0 6px 14px rgba(0,0,0,0.07);\n  border-left-color: #D97706;\n}\n.card-title {\n  font-size: 1.0em;\n  font-weight: 700;\n  margin: 0 0 8px 0;\n  line-height: 1.45;\n}\n.card-title a {\n  color: #0F172A;\n  text-decoration: none;\n}\n.card-title a:hover {\n  color: #D97706;\n}\n.card-desc {\n  font-size: 0.85em;\n  color: #64748B;\n  margin: 0 0 14px 0;\n  line-height: 1.55;\n  flex-grow: 1;\n}\n.card-meta {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  font-size: 0.78em;\n  color: #94A3B8;\n  border-top: 1px dashed #F1F5F9;\n  padding-top: 10px;\n}\n.card-tag {\n  background: #FEF3C7;\n  color: #92400E;\n  padding: 2px 8px;\n  border-radius: 4px;\n  font-family: ui-monospace, monospace;\n  font-weight: 600;\n}\n.repo-box {\n  background: #F8FAFC;\n  border: 1px solid #E2E8F0;\n  border-radius: 8px;\n  padding: 16px 20px;\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  flex-wrap: wrap;\n  gap: 12px;\n  margin-top: 24px;\n}\n.repo-text {\n  font-size: 0.9em;\n  color: #334155;\n}\n.repo-btn {\n  background: #0F172A;\n  color: #FFFFFF;\n  padding: 8px 16px;\n  border-radius: 6px;\n  text-decoration: none;\n  font-size: 0.85em;\n  font-weight: 600;\n  display: inline-block;\n}\n.repo-btn:hover {\n  background: #1E293B;\n  color: #FFFFFF;\n}\n<\/style>\n<div class=\"guide-wrap\">\n<div class=\"overview-hero-fv\">\n<h1 class=\"overview-title\">Funny Vote \u5341\u5e74\u6f14\u9032\uff1a\u5f9e Java MVP \u5230 Compose \u8207\u96f2\u539f\u751f\u67b6\u69cb<\/h1>\n<p class=\"overview-desc\">\u8de8\u8d8a\u5341\u5e74\u7684\u771f\u5be6\u8edf\u9ad4\u5de5\u7a0b\u6f14\u9032\u5168\u7d00\u9304\u3002\u5f9e 2016 \u5e74\u624b\u6572 ButterKnife \u8207\u96dc\u4e82 MVC\uff0c\u5230 2018 \u5e74 Kotlin 1.2 \u7684\u9072\u4f86\u6551\u8d16\uff1b2024 \u5e74\u8df3\u5165 Compose \u5ba3\u544a\u5f0f UI \u8207 MVI \u55ae\u5411\u6d41\uff1b\u76f4\u5230 2026 \u5e74\u4ee5 Material 3 \u5168\u91cf\u5fa9\u523b\u3001Firebase \u63db\u5fc3\u624b\u8853\uff0c\u4e26\u4ee5\u4e3b\u6d41 Vibe Coding \u914d\u5408 OWASP MASVS \u6253\u9020\u51fa 100 \u5206\u751f\u7522\u7d1a\u9632\u79a6\u7684\u65d7\u8266\u5168\u8c8c\u3002<\/p>\n<div class=\"overview-stats\">\n<div class=\"stat-pill\">\u5168\u7cfb\u5217\u7ae0\u7bc0\uff1a<span class=\"stat-num-fv\">\u5168\u4e03\u90e8\u66f2<\/span><\/div>\n<div class=\"stat-pill\">\u6642\u7a7a\u8de8\u5ea6\uff1a<span class=\"stat-num-fv\">2016 \u2794 2026\uff08\u6574\u6574\u5341\u5e74\uff09<\/span><\/div>\n<div class=\"stat-pill\">\u6280\u8853\u68e7\u66f4\u8fed\uff1a<span class=\"stat-num-fv\">Java\/XML \u2794 Kotlin\/Compose\/MVI \u2794 Firebase Serverless<\/span><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"stage-block\">\n<div class=\"stage-header\">\n<h2 class=\"stage-title\">\u7b2c\u4e00\u7d00\u5143\uff1a\u820a\u77f3\u5668\u6642\u4ee3\u7684\u67b6\u69cb\u6478\u7d22\uff082016 &#8211; 2018\uff09<\/h2>\n<p>      <span class=\"stage-badge-fv\">Era 1 \u00b7 Java, MVP &amp; Kotlin 1.2<\/span>\n    <\/div>\n<div class=\"card-grid\">\n<div class=\"nav-card-fv\">\n<div class=\"card-title\"><a href=\"https:\/\/boochlin.com\/?p=320\">Funny vote APP -MVP \u66f4\u65b0\u96dc\u8a18\uff08\u4e00\uff09<\/a><\/div>\n<div class=\"card-desc\">\u5341\u5e74\u524d\u7684\u8d77\u9ede\u3002\u56de\u9867 2016 \u5e74\u5f9e\u6e3e\u6c8c\u6ce5\u6f6d\u7684 MVC \u67b6\u69cb\uff0c\u4e00\u6b65\u6b65\u624b\u6572\u4ecb\u9762\u3001\u62bd\u96e2 Presenter\u3001\u9081\u5411 MVP \u67b6\u69cb\u7684\u521d\u557c\u3002<\/div>\n<div class=\"card-meta\">\n          <span class=\"card-tag\">Post #320 \u00b7 2016 \u59cb\u7956\u7bc7<\/span><br \/>\n          <a href=\"https:\/\/boochlin.com\/?p=320\" style=\"color:#D97706;font-weight:600;text-decoration:none;\">\u95b1\u8b80\u672c\u7bc7 \u2794<\/a>\n        <\/div>\n<\/p><\/div>\n<div class=\"nav-card-fv\">\n<div class=\"card-title\"><a href=\"https:\/\/boochlin.com\/?p=1284\">Funny vote APP \u2013 Kotlin \u8207 RxJava \u7684\u9072\u4f86\u6551\u8d16\uff08\u4e8c\uff09<\/a><\/div>\n<div class=\"card-desc\">\u9032\u5165 2018 \u5e74\u3002Kotlin 1.2 \u5ba3\u544a\u300c\u6211\u6c92\u6709 NPE\u300d\uff0c\u642d\u914d RxJava 2 \u6574\u7406\u975e\u540c\u6b65\u56de\u547c\uff1b\u6d88\u6ec5 JavaBean \u6a23\u677f\uff0c\u544a\u5225\u8001\u820a Java 7\/8 \u8a9e\u6cd5\u3002<\/div>\n<div class=\"card-meta\">\n          <span class=\"card-tag\">Post #1284 \u00b7 2018 \u73fe\u4ee3\u5316\u7bc7<\/span><br \/>\n          <a href=\"https:\/\/boochlin.com\/?p=1284\" style=\"color:#D97706;font-weight:600;text-decoration:none;\">\u95b1\u8b80\u672c\u7bc7 \u2794<\/a>\n        <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"stage-block\">\n<div class=\"stage-header\">\n<h2 class=\"stage-title\">\u7b2c\u4e8c\u7d00\u5143\uff1a\u5ba3\u544a\u5f0f UI \u8207\u55ae\u5411\u6d41\u9769\u547d\uff082024\uff09<\/h2>\n<p>      <span class=\"stage-badge-fv\">Era 2 \u00b7 Compose &amp; MVI Architecture<\/span>\n    <\/div>\n<div class=\"card-grid\">\n<div class=\"nav-card-fv\">\n<div class=\"card-title\"><a href=\"https:\/\/boochlin.com\/?p=1288\">Funny vote APP \u2013 \u544a\u5225 XML \u8fce\u4f86 Compose \u7684\u75db\u82e6\u8207\u751c\u871c\uff1a\u5f9e\u523b\u756b\u9762\u5230\u649e\u4e0a\u91cd\u7d44\u5730\u7344\uff08\u4e09\uff09<\/a><\/div>\n<div class=\"card-desc\">\u5168\u9762\u62c6\u9664 30 \u4efd XML\uff0cMainActivity \u7e2e\u7de8\u81f3 32 \u884c\u7d14\u5c0e\u822a\u3002\u7136\u800c\uff0cKotlin \u6a19\u6e96 List \u7adf\u88ab\u5224\u5b9a\u70ba Unstable \u5f15\u767c\u6efe\u52d5\u6389\u5e40\uff01@Immutable \u99b4\u670d\u91cd\u7d44\u8a08\u6578\u5668\u5be6\u9304\u3002<\/div>\n<div class=\"card-meta\">\n          <span class=\"card-tag\">Post #1288 \u00b7 2024 Compose\u7bc7<\/span><br \/>\n          <a href=\"https:\/\/boochlin.com\/?p=1288\" style=\"color:#D97706;font-weight:600;text-decoration:none;\">\u95b1\u8b80\u672c\u7bc7 \u2794<\/a>\n        <\/div>\n<\/p><\/div>\n<div class=\"nav-card-fv\">\n<div class=\"card-title\"><a href=\"https:\/\/boochlin.com\/?p=1297\">Funny vote APP \u2013 \u70ba\u4e86\u89e3\u6c7a\u72c0\u614b\u6253\u67b6\uff1a\u76f4\u4e0a MVI \u55ae\u5411\u6d41\u8207\u62ef\u6551\u767d\u5c4f\u707d\u96e3\uff08\u56db\uff09<\/a><\/div>\n<div class=\"card-desc\">MVVM \u591a\u500b StateFlow \u5c0e\u81f4\u756b\u9762\u6495\u88c2\uff01\u6279\u99c1\u516c\u7248\u6559\u7a0b Sealed Class \u9020\u6210\u4e0b\u62c9\u5237\u65b0\u767d\u5c4f\u7684\u73a9\u5177\u67b6\u69cb\uff1b\u4ee5\u55ae\u4e00\u4e0d\u53ef\u8b8a\u5feb\u7167\u8207 Channel.BUFFERED \u9054\u6210\u65cb\u8f49\u87a2\u5e55\u96f6\u907a\u5931\u3002<\/div>\n<div class=\"card-meta\">\n          <span class=\"card-tag\">Post #1297 \u00b7 2024 MVI\u67b6\u69cb\u7bc7<\/span><br \/>\n          <a href=\"https:\/\/boochlin.com\/?p=1297\" style=\"color:#D97706;font-weight:600;text-decoration:none;\">\u95b1\u8b80\u672c\u7bc7 \u2794<\/a>\n        <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"stage-block\">\n<div class=\"stage-header\">\n<h2 class=\"stage-title\">\u7b2c\u4e09\u7d00\u5143\uff1a\u7121\u640d\u5fa9\u523b\u3001\u96f2\u539f\u751f\u63db\u5fc3\u8207 Vibe Coding \u7d42\u5c40\uff082026\uff09<\/h2>\n<p>      <span class=\"stage-badge-fv\">Era 3 \u00b7 Material 3, Firebase &amp; Vibe Coding<\/span>\n    <\/div>\n<div class=\"card-grid\">\n<div class=\"nav-card-fv\">\n<div class=\"card-title\"><a href=\"https:\/\/boochlin.com\/?p=1299\">Funny vote APP \u2013 \u5f37\u8feb\u75c7\u7684 100% \u756b\u9762\u5fa9\u523b\uff1a\u628a\u5341\u5e74\u524d\u7684\u9752\u6625\u642c\u9032 Material 3\uff08\u4e94\uff09<\/a><\/div>\n<div class=\"card-desc\">\u539f\u5275\u8005\u7684\u60c5\u611f\u6f54\u7656\uff1a\u628a 6 \u9801\u5c0e\u89bd\u3001\u81ea\u8a02\u5206\u4eab\u8207\u689d\u6b3e\u7121\u640d\u642c\u56de Material 3\u3002\u5728 Samsung S23 \u5be6\u6a5f\u8dd1\u51fa 120fps \u4e00\u689d\u7da0\u7dda\uff0c\u537b\u731b\u7136\u767c\u73fe\u4e94\u7f8e\u5143 VPS \u65e9\u5c31\u505c\u6a5f\u5165\u571f\u7684\u5de8\u5927\u5c37\u5c2c\uff01<\/div>\n<div class=\"card-meta\">\n          <span class=\"card-tag\">Post #1299 \u00b7 2026 \u756b\u9762\u5fa9\u523b\u7bc7<\/span><br \/>\n          <a href=\"https:\/\/boochlin.com\/?p=1299\" style=\"color:#D97706;font-weight:600;text-decoration:none;\">\u95b1\u8b80\u672c\u7bc7 \u2794<\/a>\n        <\/div>\n<\/p><\/div>\n<div class=\"nav-card-fv\">\n<div class=\"card-title\"><a href=\"https:\/\/boochlin.com\/?p=1313\">Funny vote APP \u2013 \u4e94\u7f8e\u5143\u4f3a\u670d\u5668\u9663\u4ea1\u5f8c\uff1a\u7528 Firebase \u8207\u8001\u5206\u652f\u7e8c\u547d\u7684\u96f2\u7aef\u63db\u5fc3\u96dc\u8a18\uff08\u516d\uff09<\/a><\/div>\n<div class=\"card-desc\">Serverless \u96f2\u539f\u751f\u63db\u5fc3\uff1aFirestore \u53cd\u6b63\u898f\u5316\u5feb\u53d6\u7701\u9322\u8a08\u8cbb\u3001\u4e00\u4eba\u4e00\u7968\u60b2\u89c0\u9396\u4e8b\u52d9\u3001\u5169\u968e\u6bb5 Bi-gram \u4e2d\u6587\u641c\u5c0b\u3002\u4e26\u70ba 4 \u500b\u5341\u5e74\u524d\u8001\u5206\u652f\u7e8c\u547d\uff0c\u898b\u8b49\u8de8\u8d8a\u5341\u5e74\u7684\u4e09\u4ee3\u4ee3\u78bc\u5c0d\u6bd4\u3002<\/div>\n<div class=\"card-meta\">\n          <span class=\"card-tag\">Post #1313 \u00b7 2026 \u96f2\u7aef\u63db\u5fc3\u7bc7<\/span><br \/>\n          <a href=\"https:\/\/boochlin.com\/?p=1313\" style=\"color:#D97706;font-weight:600;text-decoration:none;\">\u95b1\u8b80\u672c\u7bc7 \u2794<\/a>\n        <\/div>\n<\/p><\/div>\n<div class=\"nav-card-fv\" style=\"border-left-color: #E11D48;\">\n<div class=\"card-title\"><a href=\"https:\/\/boochlin.com\/?p=1315\">Funny vote APP \u2013 \u5f9e\u96f6\u958b\u59cb\u7684 Vibe Coding \u5be6\u6230\u6307\u5357\uff1a\u4ee5 Codex \u8996\u89d2\u770b AI \u5354\u540c\u3001\u7ffb\u8eca\u73fe\u5834\u8207\u8cc7\u5b89\u52a0\u56fa\uff08\u4e03\u00b7\u7d42\u5c40\u7bc7\uff09<\/a><\/div>\n<div class=\"card-desc\">\u7cfb\u5217\u7d42\u5c40\uff01Codex \u9996\u5e2d\u5be9\u67e5\u54e1\u64cd\u5200\uff1a\u63ed\u9732\u4e3b\u6d41\u8b77\u6b04\u9a45\u52d5\u958b\u767c\uff08Harness-Driven\uff09\uff1b\u6293\u51fa AI \u5047\u96e2\u7dda SSOT \u7834\u7dbb\uff1b\u5256\u6790\u4e09\u5927\u7834\u7522\u8cc7\u5b89\u5730\u96f7\u8207\u771f\u5be6 Git Diff\uff0c\u4ee5 OWASP MASVS 100 \u5206 A+ \u5b8c\u7f8e\u9589\u74b0\u3002<\/div>\n<div class=\"card-meta\">\n          <span class=\"card-tag\" style=\"background:#FFE4E6;color:#BE123C;\">Post #1315 \u00b7 \u7d42\u5c40\u5927\u6210\u7bc7<\/span><br \/>\n          <a href=\"https:\/\/boochlin.com\/?p=1315\" style=\"color:#E11D48;font-weight:600;text-decoration:none;\">\u95b1\u8b80\u672c\u7bc7 \u2794<\/a>\n        <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"repo-box\">\n<div class=\"repo-text\">\n      <strong>\u5168\u5c08\u6848\u958b\u6e90\u5009\u5eab\uff1a<\/strong>\u5305\u542b\u5341\u5e74\u9593\u6240\u6709\u6f14\u9032\u6b77\u53f2\u5206\u652f\uff08<code>mvp<\/code>\u3001<code>mvp_rxjava<\/code>\u3001<code>kotlin-rewrite<\/code>\u3001<code>mvi-rewrite<\/code>\u3001<code>modern-android<\/code>\u3001<code>feature\/firebase-backend<\/code> \u8207\u8001\u67b6\u69cb Firebase \u7e8c\u547d\u5206\u652f\uff09\u3002\n    <\/div>\n<p>    <a href=\"https:\/\/github.com\/boochlin06\/FunnyVote\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"repo-btn\">\u524d\u5f80 GitHub \u5009\u5eab \u2794<\/a>\n  <\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Funny Vote \u5341\u5e74\u6f14\u9032\uff1a\u5f9e Java MVP \u5230 Compose \u8207\u96f2\u539f\u751f\u67b6\u69cb \u8de8\u8d8a\u5341\u5e74\u7684\u771f\u5be6\u8edf\u9ad4\u5de5\u7a0b [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"_links":{"self":[{"href":"https:\/\/boochlin.com\/index.php?rest_route=\/wp\/v2\/pages\/1319"}],"collection":[{"href":"https:\/\/boochlin.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/boochlin.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/boochlin.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/boochlin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1319"}],"version-history":[{"count":0,"href":"https:\/\/boochlin.com\/index.php?rest_route=\/wp\/v2\/pages\/1319\/revisions"}],"wp:attachment":[{"href":"https:\/\/boochlin.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1319"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}