如何在Android新闻App中用Fragment替代Activity展示新闻详情
新闻App转Fragment实现方案及学习指南
我开发了一款新闻App,使用Retrofit调用API,通过RecyclerView结合CardView展示新闻列表;用户点击新闻卡片时,会跳转至新的Activity,通过WebView展示完整新闻内容。现在我希望改用Fragment实现这一功能,但我对Fragment完全陌生,缺乏相关知识,恳请提供实现思路及Fragment的学习资源。以下是我的现有代码:
现有代码
MainActivity.kt
class MainActivity : AppCompatActivity() { lateinit var adapter: NewsAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) getNews() } private fun getNews() { val news :Call<News> = NewsSeversis.newsIntence.getHeadlines("in",1) news.enqueue(object :Callback<News>{ override fun onResponse(call: Call<News>, response: Response<News>) { //here response is a News response val news:News?=response.body() if (news!=null){ Log.d("response",news.toString()) adapter= NewsAdapter(news.articles) newsList.adapter=adapter newsList.layoutManager=LinearLayoutManager(this@MainActivity) Log.d("itemcount","${(newsList.layoutManager as LinearLayoutManager).itemCount}") Log.d("itemcount2", "${(newsList.layoutManager as LinearLayoutManager).findFirstVisibleItemPosition()}") } } override fun onFailure(call: Call<News>, t: Throwable) { Log.d("response","error occur",t) } }) } }
NewsAdapter.kt
class NewsAdapter (val artical: List<Artical>):RecyclerView.Adapter<NewsAdapter.articalViewHolder>(){ inner class articalViewHolder(itemView: View):RecyclerView.ViewHolder(itemView) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): articalViewHolder { val view:View=LayoutInflater.from(parent.context).inflate(R.layout.item_layout,parent,false) return articalViewHolder(view) } override fun onBindViewHolder(holder: articalViewHolder, position: Int) { val articals:Artical=artical[position] holder.itemView.apply { newsTitle.text=articals.title newsDescription.text=articals.description Glide.with(context).load(articals.urlToImage).into(newsImage) holder.itemView.setOnClickListener { val intent=Intent(context,DetailsWebview::class.java) intent.putExtra("EXTRA_URL",articals.url) Log.d("url",articals.url) context.startActivity(intent) } } } override fun getItemCount(): Int { return artical.size } }
详情页WebView Activity代码
class DetailsWebview : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_details_webview) val url :String?=intent.getStringExtra("EXTRA_URL") if (url !=null){ Log.d("DataFlow", "URL received: $url") detailsWebview.settings.javaScriptEnabled=true detailsWebview.settings.userAgentString="Mozilla/5.0 (Linux; Android 9; CPH1909) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.82 Mobile Safari/537.36" detailsWebview.webViewClient = object : WebViewClient() { override fun onPageFinished(view: WebView?, url: String?) { progressBar.visibility=View.GONE detailsWebview.visibility=View.VISIBLE } } detailsWebview.loadUrl(url) }else Log.d("DataFlow", "No URL received") } }
转Fragment实现思路
1. 拆分页面为两个Fragment
- 新闻列表Fragment:创建
NewsListFragment,将原MainActivity中获取新闻、初始化RecyclerView的逻辑全部迁移到该Fragment中,布局复用原activity_main的内容(单独抽成fragment_news_list.xml)。 - 新闻详情Fragment:创建
NewsDetailFragment,复用原DetailsWebview的布局逻辑,将布局改为fragment_news_detail.xml,通过Fragment的arguments传递URL参数,替代原Activity的Intent传参。
2. 改造主Activity作为Fragment容器
- 修改
activity_main.xml,替换为FragmentContainerView作为Fragment的承载容器。 - 主Activity仅负责在启动时加载
NewsListFragment,不再处理业务逻辑。
3. 修改Adapter的点击事件逻辑
- 给
NewsAdapter添加点击回调Lambda,当用户点击卡片时,通过FragmentManager执行事务,切换到NewsDetailFragment并传递URL,同时将事务加入回退栈,保证返回键能回到列表页。
关键代码修改示例
NewsListFragment.kt
class NewsListFragment : Fragment() { lateinit var adapter: NewsAdapter override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.fragment_news_list, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) getNews() } private fun getNews() { val news: Call<News> = NewsSeversis.newsIntence.getHeadlines("in", 1) news.enqueue(object : Callback<News> { override fun onResponse(call: Call<News>, response: Response<News>) { val newsData: News? = response.body() newsData?.let { adapter = NewsAdapter(it.articles) { url -> val detailFragment = NewsDetailFragment().apply { arguments = Bundle().apply { putString("EXTRA_URL", url) } } parentFragmentManager.beginTransaction() .replace(R.id.fragment_container, detailFragment) .addToBackStack(null) .commit() } newsList.adapter = adapter newsList.layoutManager = LinearLayoutManager(requireContext()) } } override fun onFailure(call: Call<News>, t: Throwable) { Log.d("response", "error occur", t) } }) } }
改造后的NewsAdapter.kt
class NewsAdapter( val articles: List<Artical>, private val onItemClick: (String) -> Unit ) : RecyclerView.Adapter<NewsAdapter.ArticleViewHolder>() { inner class ArticleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.item_layout, parent, false) return ArticleViewHolder(view) } override fun onBindViewHolder(holder: ArticleViewHolder, position: Int) { val article = articles[position] holder.itemView.apply { newsTitle.text = article.title newsDescription.text = article.description Glide.with(context).load(article.urlToImage).into(newsImage) setOnClickListener { onItemClick(article.url) } } } override fun getItemCount() = articles.size }
NewsDetailFragment.kt
class NewsDetailFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.fragment_news_detail, container, false) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val url = arguments?.getString("EXTRA_URL") url?.let { loadNewsUrl(it) } ?: Log.d("DataFlow", "No URL received") } private fun loadNewsUrl(url: String) { Log.d("DataFlow", "URL received: $url") detailsWebview.apply { settings.javaScriptEnabled = true settings.userAgentString = "Mozilla/5.0 (Linux; Android 9; CPH1909) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.82 Mobile Safari/537.36" webViewClient = object : WebViewClient() { override fun onPageFinished(view: WebView?, loadedUrl: String?) { progressBar.visibility = View.GONE detailsWebview.visibility = View.VISIBLE } } loadUrl(url) } } }
简化后的MainActivity.kt
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) if (savedInstanceState == null) { supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, NewsListFragment()) .commit() } } }
Fragment核心学习要点
- 生命周期:重点掌握
onCreateView、onViewCreated、onDestroyView等方法,理解Fragment和宿主Activity生命周期的联动关系。 - 事务管理:熟练使用
FragmentManager和FragmentTransaction的replace、addToBackStack等方法,掌握Fragment的添加、替换、移除逻辑。 - 数据传递:学习通过
arguments传递简单数据,通过ViewModel实现Fragment与Activity、Fragment间的复杂数据共享,避免内存泄漏。 - 上下文获取:在Fragment中优先使用
requireContext()、requireActivity()获取上下文,避免使用可能为空的context、activity。 - 状态保存:了解
onSaveInstanceState的用法,处理屏幕旋转等场景下的Fragment状态恢复。
内容的提问来源于stack exchange,提问作者Sumita Das
相关产品推荐
相关产品推荐

