ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

经典的ViewPager+Fragment界面:用TaoToken统一Key打通AI辅助开发链路

经典的ViewPager+Fragment界面:用TaoToken统一Key打通AI辅助开发链路 1. 经典 ViewPagerFragment 多页滑动架构为什么还要接 AI 辅助开发链路ViewPager 配合 Fragment 做多页滑动是 Android 里非常经典的一套界面结构顶部一排可点击的标题下面一个可以左右滑动的容器每个页面是一个独立的 Fragment。它适合做资产页、订单页、设置页这类「同一层级、多个平级子页」的场景。你只要把标题数量、Fragment 数量对上滑动和点击就能联动起来。但真正写起来麻烦的地方不在 ViewPager 本身而在周边FragmentPagerAdapter 和 FragmentStateAdapter 该选哪个、Fragment 生命周期怎么和 ViewPager 对齐、光标动画怎么跟着页面走、依赖版本冲突怎么排。这些细节一旦卡住搜索答案又散落在各种老帖子里效率很低。我这次的做法是把 Android Studio 里的 AI 补全请求统一走 TaoToken 的 Key让代码建议、报错解释、依赖版本确认都在同一个工程里完成。这样做的价值很直接——你在写 ViewPager2 FragmentStateAdapter 的时候AI 能基于你当前文件给出更贴近上下文的补全而不是每次都要把整段代码复制到网页对话框里。这篇会交付三样东西可直接复制的 Gradle 依赖、ViewPager2 FragmentStateAdapter 的完整配置片段、以及在 Android Studio 里把 AI 请求 Base URL 改到 TaoToken 的验证动作。目标是页面切换和 AI 代码建议在同一个工程内跑通。适合谁看正在用 ViewPager/Fragment 做多页界面、想顺手把 AI 补全接进 IDE、又不想在多个工具之间来回切换的 Android 开发者。下面从环境准备开始一步步来。2. TaoToken 前置准备拿到统一 Key 并确认 Base URL在动 Android 工程之前先把 TaoToken 这边的信息准备好。你需要的是一个 API Key 和一个 Base URL后面在 Android Studio 的 AI 插件里填的就是这两个值。先访问官网了解整体能力https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content然后进入控制台创建 Key。控制台地址https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content在控制台里找到 API Keys 页面新建一个 Key复制出来先存到安全的地方。API Keys 直达https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentBase URL 统一用这个注意 API 地址不加 UTM 参数https://taotoken.net/api这里有个容易踩的点Base URL 填的是根路径不要自己拼/v1/chat/completions之类的后缀具体路径由插件或 SDK 自己补。我试过手动拼后缀结果 404排查了半天才发现是多写了。关于模型 IDTaoToken 支持多种模型你在控制台或文档里能看到当前可用的模型列表。写配置的时候Model ID 要和你实际调用的模型对上比如常见的claude-sonnet-4-5、gpt-4o这类命名。文档入口https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content如果你后面要接 Claude Code 做长期编码可以看 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentClaude Code 的 Anthropic 接入说明在这里https://taotoken.net/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content准备阶段就三件事Key、Base URL、Model ID。这三个值后面在配置片段里会反复出现先记牢。下面进入 Android 工程本身。3. 可复制配置Gradle 依赖与 ViewPager2FragmentStateAdapter 片段这一节是全文的核心所有片段都可以直接复制。先看 Gradle 依赖。3.1 Gradle 依赖片段在app/build.gradleKotlin DSL 则是build.gradle.kts里加入 ViewPager2 和 Fragment 相关依赖。ViewPager2 已经包含在 AndroidX 里不需要单独引 support 库dependencies { implementation androidx.appcompat:appcompat:1.6.1 implementation androidx.constraintlayout:constraintlayout:2.1.4 implementation androidx.viewpager2:viewpager2:1.1.0 implementation androidx.fragment:fragment-ktx:1.6.2 implementation com.google.android.material:material:1.11.0 }如果你用的是 Kotlin DSLdependencies { implementation(androidx.appcompat:appcompat:1.6.1) implementation(androidx.constraintlayout:constraintlayout:2.1.4) implementation(androidx.viewpager2:viewpager2:1.1.0) implementation(androidx.fragment:fragment-ktx:1.6.2) implementation(com.google.android.material:material:1.11.0) }注意viewpager2:1.1.0这个版本它修复了早期 1.0.x 里嵌套滑动的一些问题。如果你项目里已经有旧版 support 库的 ViewPager建议新页面直接用 ViewPager2不要混用。3.2 布局文件activity_main.xml顶部标题栏加 ViewPager2?xml version1.0 encodingutf-8? LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/android android:orientationvertical android:layout_widthmatch_parent android:layout_heightmatch_parent android:background#eeeeee RelativeLayout android:layout_widthmatch_parent android:layout_height50dp LinearLayout android:idid/title_container android:layout_widthmatch_parent android:layout_heightmatch_parent android:background#ffffff android:orientationhorizontal TextView android:idid/tx_title_left android:layout_weight1 android:layout_width0dp android:layout_heightmatch_parent android:gravitycenter android:text当前资产 android:textSize16sp android:textColor#ff9600/ TextView android:idid/tx_title_right android:layout_weight1 android:layout_width0dp android:layout_heightmatch_parent android:gravitycenter android:text历史资产 android:textSize16sp android:textColor#666666/ /LinearLayout View android:idid/cursor android:layout_width60dp android:layout_height3dp android:background#ff9600 android:layout_alignParentBottomtrue/ /RelativeLayout androidx.viewpager2.widget.ViewPager2 android:idid/fragment_view_pager android:layout_widthmatch_parent android:layout_heightmatch_parent/ /LinearLayout3.3 FragmentStateAdapter 配置新建一个 Adapter继承FragmentStateAdapterclass MainPagerAdapter( fragmentActivity: FragmentActivity, private val fragments: ListFragment ) : FragmentStateAdapter(fragmentActivity) { override fun getItemCount(): Int fragments.size override fun createFragment(position: Int): Fragment fragments[position] }在 Activity 里组装class MainActivity : AppCompatActivity() { private lateinit var viewPager: ViewPager2 private lateinit var cursor: View private lateinit var txLeft: TextView private lateinit var txRight: TextView private var currentIndex 0 private var cursorOffset 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) viewPager findViewById(R.id.fragment_view_pager) cursor findViewById(R.id.cursor) txLeft findViewById(R.id.tx_title_left) txRight findViewById(R.id.tx_title_right) val fragments listOf(FirstFragment(), SecondFragment()) viewPager.adapter MainPagerAdapter(this, fragments) val dm resources.displayMetrics cursorOffset dm.widthPixels / fragments.size txLeft.setOnClickListener { viewPager.setCurrentItem(0, true) } txRight.setOnClickListener { viewPager.setCurrentItem(1, true) } viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { moveCursor(position) updateTitleColor(position) currentIndex position } }) } private fun moveCursor(position: Int) { val anim TranslateAnimation( currentIndex * cursorOffset.toFloat(), position * cursorOffset.toFloat(), 0f, 0f ) anim.fillAfter true anim.interpolator DecelerateInterpolator() anim.duration 300 cursor.startAnimation(anim) } private fun updateTitleColor(position: Int) { txLeft.setTextColor(if (position 0) 0xffff9600.toInt() else 0xff666666.toInt()) txRight.setTextColor(if (position 1) 0xffff9600.toInt() else 0xff666666.toInt()) } }3.4 AI 补全请求配置片段在 Android Studio 的 AI 插件设置里把 Base URL 改成 TaoToken。以常见的 settings JSON 形式为例{ ai.provider: openai-compatible, ai.baseUrl: https://taotoken.net/api, ai.apiKey: sk-你的TaoTokenKey, ai.model: claude-sonnet-4-5, ai.timeoutMs: 60000 }如果你用的是 TOML 配置部分插件支持[ai] provider openai-compatible base_url https://taotoken.net/api api_key sk-你的TaoTokenKey model claude-sonnet-4-5 timeout_ms 60000三件套记牢Base URL 是https://taotoken.net/apiKey 是控制台生成的Model ID 要和你实际调用的模型一致。这三个值缺一个都跑不通。4. 验证请求在 Android Studio 里确认 AI 补全真的走通了配置填完不代表生效得实际验证一次。这一步很多人跳过结果后面报错不知道从哪查。4.1 触发一次补全打开你刚写好的MainActivity.kt在moveCursor方法下面新起一行输入注释// 根据 position 更新标题文字颜色然后等 AI 补全弹出建议。如果配置正确几秒内会出现补全内容。如果没反应先检查插件是否启用了 AI 补全功能。4.2 用模型对话做一次独立验证除了 IDE 补全你也可以直接在模型对话页面发一条请求确认 Key 和 Base URL 本身没问题https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content在对话里输入「用 Kotlin 写一个 ViewPager2 的 FragmentStateAdapter」看是否正常返回。这一步能帮你区分问题出在 Key 上还是 IDE 插件上。4.3 成功结果长什么样补全成功时你会看到 AI 给出的代码片段比如private fun updateTitleColor(position: Int) { val activeColor 0xffff9600.toInt() val normalColor 0xff666666.toInt() txLeft.setTextColor(if (position 0) activeColor else normalColor) txRight.setTextColor(if (position 1) activeColor else normalColor) }同时页面滑动时顶部光标会跟着平移标题颜色同步切换。这两件事同时成立说明页面切换和 AI 补全都在同一工程里跑通了。4.4 用 curl 做一次底层验证如果你想确认网络层没问题可以在终端里直接发一次请求curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的TaoTokenKey \ -H Content-Type: application/json \ -d { model: claude-sonnet-4-5, messages: [{role: user, content: ping}] }返回里有choices字段就说明链路通了。这一步能排除 IDE 插件本身的干扰。5. 本篇常见错误排查401、local proxy failed、reading choices、OAuth这一节按真实报错来对照遇到问题直接查。5.1 401 Unauthorized最常见。原因通常是 Key 填错、Key 前后有空格、或者 Key 已经失效。检查顺序先确认ai.apiKey字段里没有多余空格再去控制台确认这个 Key 还在有效期内。如果 Key 是从网页复制的注意别把换行符也带进去。5.2 local proxy failed这个报错一般出现在插件尝试走本地代理时。检查你的 IDE 网络设置里有没有配置 HTTP 代理如果有先关掉再试。TaoToken 的 Base URL 是直连的不需要额外代理配置。另外确认ai.baseUrl填的是https://taotoken.net/api不要写成http。5.3 reading choices 报错这个通常意味着请求发出去了但返回体里没有choices字段。可能原因Model ID 写错了或者请求路径不对。确认ai.model和你实际调用的模型一致Base URL 不要自己拼后缀。如果用的是 curl 验证检查-d里的 JSON 格式是否合法。5.4 OAuth 相关报错如果你接的是 Claude Code 这类工具可能会遇到 OAuth 报错。这时候不要走 OAuth 流程改用 API Key 方式接入。Claude Code 的 Anthropic 接入说明在https://taotoken.net/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content按文档里的方式填 Base URL、Key、Model ID 三件套不要混用 OAuth 和 API Key 两种模式。5.5 依赖冲突报错如果 Gradle 同步时报Duplicate class或Conflict with dependency大概率是旧版 support 库和 AndroidX 混用了。检查gradle.properties里有没有android.useAndroidXtrue和android.enableJetifiertrue然后确认没有同时引入com.android.support和androidx的同类库。5.6 Fragment 不显示或空白ViewPager2 的 Fragment 空白常见原因是 Adapter 的getItemCount返回 0或者 Fragment 列表在设置 Adapter 之后才填充。确认fragments列表在viewPager.adapter ...之前就已经有数据。另外 FragmentStateAdapter 要求传入的是FragmentActivity如果你传的是普通 Activity 会报类型错误。6. 把 AI 补全接进日常 Android 开发从 ViewPager 到长期编码ViewPager2 FragmentStateAdapter 这套结构跑通之后你会发现它只是一个起点。真正提升效率的地方在于AI 补全能基于你当前工程的文件结构、依赖版本、命名习惯给出建议而不是每次都要重新描述上下文。如果你只是偶尔用一下 AI 补全按第 3 节的配置填好 Base URL、Key、Model ID 就够了。验证模型是否可用可以直接去模型对话页面试https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content如果你打算长期在 Android 工程里用 AI 辅助编码比如让它帮你写 Adapter、排查 Gradle 冲突、生成单元测试那 Coding Plan 会更合适https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content接入文档和 API Keys 页面建议收藏后面换模型或加新工程时会反复用到https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content最后说一个实际经验ViewPager2 的setCurrentItem(position, true)第二个参数控制是否平滑滚动做标题点击跳转时建议传true体验更自然。而registerOnPageChangeCallback里的onPageSelected是更新光标和标题颜色的正确位置不要放在onPageScrolled里否则滑动过程中颜色会频繁闪烁。这些细节 AI 补全不一定每次都能给对但你把配置接好之后至少排查和验证的链路是通的。
返回列表