首页 > 其他分享 >Android中Fragment的最佳实践—简易版的新闻应用

Android中Fragment的最佳实践—简易版的新闻应用

时间:2024-09-07 09:54:47浏览次数:15  
标签:title Fragment content 新建 简易版 news Android public view

文章目录

Android中Fragment的最佳实践—简易版的新闻应用

现在你已经将关于碎片的重要知识点都掌握得差不多了,不过在灵活运用方面可能还有些欠缺,因此下面该进入我们本章的最佳实践环节了。

前面有提到过,碎片很多时候都是在平板开发当中使用的,主要是为了解决屏幕空间不能充分利用的问题。那是不是就表明,我们开发的程序都需要提供一个手机版和一个Pad版呢?确实有不少公司都是这么做的,但是这样会浪费很多的人力物力。因为维护两个版本的代码成本很高,每当增加什么新功能时,需要在两份代码里各写一遍,每当发现一个bug时,需要在两份代码里各修改一次。因此今天我们最佳实践的内容就是,教你如何编写同时兼容手机和平板的应用程序

还记得在本章开始的时候提到过的一个新闻应用吗?现在我们就将运用本章中所学的知识来编写一个简易版的新闻应用,并且要求它是可以同时兼容手机和平板的。新建好一个FragmentBestPractice项目,然后开始动手吧!

app/build.gradle当中添加依赖库

由于待会在编写新闻列表时会使用到RecyclerView,因此首先需要在app/build.gradle当中添加依赖库,如下所示:

dependencies {
    implementation 'androidx.appcompat:appcompat:1.4.1'
    implementation 'com.google.android.material:material:1.5.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}

新建新闻实体类News

接下来我们要准备好一个新闻的实体类,新建类News,代码如下所示:

public class News {
private String title;
private String content;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}

新建布局文件news_content_frag.xml

News类的代码还是比较简单的,title字段表示新闻标题,content字段表示新闻内容。接着新建布局文件news_content_frag.xml,用于作为新闻内容的布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/visibility_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="invisible" >
<TextView
android:id="@+id/news_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:textSize="20sp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#000" />
<TextView
android:id="@+id/news_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="15dp"
android:textSize="18sp" />
</LinearLayout>
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:background="#000" />
</RelativeLayout>

新闻内容的布局主要可以分为两个部分,头部部分显示新闻标题,正文部分显示新闻内容,中间使用一条细线分隔开。这里的细线是利用View来实现的,将View的宽或高设置为1dp,再通过background属性给细线设置一下颜色就可以了。这里我们把细线设置成黑色。

新建NewsContentFragment类

然后再新建一个NewsContentFragment类,继承自Fragment,代码如下所示:

public class NewsContentFragment extends Fragment {
private View view;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.news_content_frag, container, false);
return view;
}
public void refresh(String newsTitle, String newsContent) {
View visibilityLayout = view.findViewById(R.id.visibility_layout);
visibilityLayout.setVisibility(View.VISIBLE);
TextView newsTitleText = (TextView) view.findViewById (R.id.news_title);
TextView newsContentText = (TextView) view.findViewById(R.id.news_content);
newsTitleText.setText(newsTitle); //刷新新闻的标题
newsContentText.setText(newsContent); //刷新新闻的内容
}
}

首先在onCreateView()方法里加载了我们刚刚创建的news_content_frag布局,这个没什么好解释的。接下来又提供了一个refresh()方法,这个方法就是用于将新闻的标题和内容显示在界面上的。可以看到,这里通过findViewById()方法分别获取到新闻标题和内容的控件,然后将方法传递进来的参数设置进去。

单页模式需新建NewsContentActivity

这样我们就把新闻内容的碎片和布局都创建好了,但是它们都是在双页模式中使用的,如果想在单页模式中使用的话,我们还需要再创建一个活动。右击com.example.fragmentbestpractice包→New→Activity→Empty Activity,新建一个NewsContentActivity,并将布局名指定成news_content,然后修改news_content.xml中的代码,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/news_content_fragment"
android:name="com.example.fragmentbestpractice.NewsContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>

这里我们充分发挥了代码的复用性,直接在布局中引入NewsContentFragment,这样也就相当于把news_content_frag布局的内容自动加了进来。

然后修改NewsContentActivity中的代码,如下所示:

public class NewsContentActivity extends AppCompatActivity {
public static void actionStart(Context context, String newsTitle, String
newsContent) {
Intent intent = new Intent(context, NewsContentActivity.class);
intent.putExtra("news_title", newsTitle);
intent.putExtra("news_content", newsContent);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_content);
String newsTitle = getIntent().getStringExtra("news_title"); //获取传入的新
闻标题
String newsContent = getIntent().getStringExtra("news_content"); //获取传入
的新闻内容
NewsContentFragment newsContentFragment = (NewsContentFragment)
getSupportFragmentManager().findFragmentById(R.id.news_content_fragment);
newsContentFragment.refresh(newsTitle, newsContent); //刷新NewsContentFragment界面
}
}

可以看到,在onCreate()方法中我们通过Intent获取到了传入的新闻标题和新闻内容,然后调用FragmentManager的findFragmentById()方法得到了NewsContentFragment的实例,接着调用它的refresh()方法,并将新闻的标题和内容传入,就可以把这些数据显示出来了。注意这里我们还提供了一个actionStart()方法,启动活动的最佳写法。

新建news_title_frag.xml

接下来还需要再创建一个用于显示新闻列表的布局,新建news_title_frag.xml,代码如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/news_title_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</LinearLayout>

这个布局的代码就非常简单了,里面只有一个用于显示新闻列表的RecyclerView。

新建news_item.xml

既然要用到RecyclerView,那么就必定少不了子项的布局。新建news_item.xml作为RecyclerView子项的布局,代码如下所示:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/news_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="true"
android:ellipsize="end"
android:textSize="18sp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="15dp"
android:paddingBottom="15dp" />

子项的布局也非常简单,只有一个TextView。仔细观察TextView,你会发现其中有几个属性是我们之前没有学过的。android:padding表示给控件的周围加上补白,这样不至于让文本内容会紧靠在边缘上。android:maxLines设置为true表示让这个TextView只能单行显示。android:ellipsize用于设定当文本内容超出控件宽度时,文本的缩略方式,这里指定成end表示在尾部进行缩略。

新建NewsTitleFragment

既然新闻列表和子项的布局都已经创建好了,那么接下来我们就需要一个用于展示新闻列表的地方。这里新建NewsTitleFragment作为展示新闻列表的碎片,代码如下所示:

public class NewsTitleFragment extends Fragment {
private boolean isTwoPane;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.news_title_frag, container, false);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getActivity().findViewById(R.id.news_content_layout) != null) {
isTwoPane = true; //可以找到news_content_layout布局时,为双页模式
} else {
isTwoPane = false; //找不到news_content_layout布局时,为单页模式
}
}
}

可以看到,NewsTitleFragment中并没有多少代码,在onCreateView()方法中加载了news_title_frag布局,这个没什么好说的。我们注意看一下onActivityCreated()方法,这个方法通过在活动中能否找到一个id为news_content_layout的View来判断当前是双页模式还是单页模式,因此我们需要让这个id为news_content_layout的View只在双页模式中才会出现。

那么怎样才能实现这个功能呢?其实并不复杂,只需要借助我们刚刚学过的限定符就可以了。

修改activity_main.xml

首先修改activity_main.xml中的代码,如下所示:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/news_title_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="@+id/news_title_fragment"
android:name="com.example.fragmentbestpractice.NewsTitleFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>

上述代码表示,在单页模式下,只会加载一个新闻标题的碎片。

使用限定符新建layout-sw600dp文件夹再新建一个activity_main.xml

然后新建layout-sw600dp文件夹,在这个文件夹下再新建一个activity_main.xml文件,代码如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="@+id/news_title_fragment"
android:name="com.example.fragmentbestpractice.NewsTitleFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<FrameLayout
android:id="@+id/news_content_layout"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3" >
<fragment
android:id="@+id/news_content_fragment"
android:name="com.example.fragmentbestpractice.NewsContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</LinearLayout>

可以看出,在双页模式下我们同时引入了两个碎片,并将新闻内容的碎片放在了一个FrameLayout布局下,而这个布局的id正是news_content_layout。因此,能够找到这个id的时候就是双页模式,否则就是单面模式。

现在我们已经将绝大部分的工作都完成了,但还剩下至关重要的一点,就是

在NewsTitleFragment中通过RecyclerView将新闻列表展示出来。我们

新建一个内部类NewsAdapter

在NewsTitleFragment中新建一个内部类NewsAdapter来作为RecyclerView的适配器,如下所示:

public class NewsTitleFragment extends Fragment {
private boolean isTwoPane;
...
class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
private List<News> mNewsList;
class ViewHolder extends RecyclerView.ViewHolder {
TextView newsTitleText;
public ViewHolder(View view) {
super(view);
newsTitleText = (TextView) view.findViewById(R.id.news_title);
}
}
public NewsAdapter(List<News> newsList) {
mNewsList = newsList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.news_item, parent, false);
final ViewHolder holder = new ViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
News news = mNewsList.get(holder.getAdapterPosition());
if (isTwoPane) {
//如果是双页模式,则刷新NewsContentFragment中的内容
NewsContentFragment newsContentFragment =
(NewsContentFragment) getFragmentManager()
.findFragmentById(R.id.news_content_fragment);
newsContentFragment.refresh(news.getTitle(),
news.getContent());
} else {
//如果是单页模式,则直接启动NewsContentActivity
NewsContentActivity.actionStart(getActivity(),
news.getTitle(), news.getContent());
}
}
});
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
News news = mNewsList.get(position);
holder.newsTitleText.setText(news.getTitle());
}
@Override
public int getItemCount() {
return mNewsList.size();
}
}
}

RecyclerView的用法你已经相当熟练了,因此这个适配器的代码对你来说应该没有什么难度吧?需要注意的是,之前我们都是将适配器写成一个独立的类,其实也是可以写成内部类的,这里写成内部类的好处就是可以直接访问NewsTitleFragment的变量,比如isTwoPane。

观察一下onCreateViewHolder()方法中注册的点击事件,首先获取到了点击项的News实例,然后通过isTwoPane变量来判断当前是单页还是双页模式,如果是单页模式,就启动一个新的活动去显示新闻内容,如果是双页模式,就更新新闻内容碎片里的数据。

向RecyclerView中填充数据,修改NewsTitleFragment

现在还剩最后一步收尾工作,就是向RecyclerView中填充数据了。修改NewsTitleFragment中的代码,如下所示:

public class NewsTitleFragment extends Fragment {
...
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.news_title_frag, container, false);
RecyclerView newsTitleRecyclerView = (RecyclerView) view.findViewById
(R.id.news_title_recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
newsTitleRecyclerView.setLayoutManager(layoutManager);
NewsAdapter adapter = new NewsAdapter(getNews());
newsTitleRecyclerView.setAdapter(adapter);
return view;
}
private List<News> getNews() {
List<News> newsList = new ArrayList<>();
for (int i = 1; i <= 50; i++) {
News news = new News();
news.setTitle("This is news title " + i);
news.setContent(getRandomLengthContent("This is news content " + i + ". "));
newsList.add(news);
}
return newsList;
}
private String getRandomLengthContent(String content) {
Random random = new Random();
int length = random.nextInt(20) + 1;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; i++) {
builder.append(content);
}
return builder.toString();
}
...
}

可以看到,onCreateView()方法中添加了RecyclerView标准的使用方法,在碎片中使用RecyclerView和在活动中使用几乎是一模一样的,相信没有什么需要解释的。另外,这里调用了getNews()方法来初始化50条模拟新闻数据,同样使用了一

个getRandomLengthContent()方法来随机生成新闻内容的长度,以保证每条新闻的内容差距比较大,相信你对这个方法肯定不会陌生了。

这样我们所有的编写工作就已经完成了,赶快来运行一下吧!首先在手机模拟器上运行,效果如图所示:

在这里插入图片描述

可以看到许多条新闻的标题,然后点击第一条新闻,会启动一个新的活动来显示新闻的内容。

接下来将程序在平板模拟器上运行,同样点击第一条新闻,效果如图所示:

在这里插入图片描述

怎么样?同样的一份代码,在手机和平板上运行却分别是两种完全不同的效果,说明我们程序的兼容性已经相当不错了。通过这个例子,我相信你对碎片的理解一定又加深了很多。

如果对你有帮助,就一键三连呗(关注+点赞+收藏),我会持续更新更多干货~~

标签:title,Fragment,content,新建,简易版,news,Android,public,view
From: https://blog.csdn.net/m0_63526467/article/details/141989071

相关文章

  • Android中Fragment的生命周期
    文章目录Android中Fragment的生命周期碎片的状态和回调碎片完整的生命周期Android中Fragment的生命周期和活动一样,碎片也有自己的生命周期,并且它和活动的生命周期实在是太像了,我相信你很快就能学会,下面我们马上就来看一下。碎片的状态和回调还记得每个活动在其生......
  • Android 开发避坑经验(2):深入理解Fragment与Activity交互
    在Android开发过程中,Fragment和Activity之间的交互是一个常见的难题,处理不当会引发UI更新问题、生命周期混乱、数据丢失等问题。这篇文章将深入探讨如何避免这些常见坑点,提供可靠的解决方案,并通过示例代码展示最佳实践。1.坑点:Fragment和Activity的生命周期差异......
  • android利用jni读取assets文件夹下的文件
    一、概述在jni的开发中,有时候会在c/c++层读取assets文件夹下的图片。有两种方式可以选择:方式一:在java/kotlin层把文件读取出来,然后以字符串的形式传递给jni层。方式二:java/kotlin层传递一个文件名,jni利用AAssetManager读取文件内容目前介绍的是第二种方......
  • android从java/kotlin层传递bitmap给jni并使用其像素
    一、概述在做jni开发的时候,有些情况下会直接通过java/kotlin层传递bitmap给jni,并取出其数据进行利用。例如:OpenGLES绘制纹理、保存像素图片等。二、代码示例1.在cmake中引入可以操作jni层BitmapInfo的libjnigraphics-landroid2.导入头文件#in......
  • Android 11.0 FolderIcon文件夹图标内预览图标超出边距解决方案
    1.前言在11.0的系统rom定制化产品开发中,在进行Launcher3的功能定制化过程中,在实现文件夹功能的时候,由于产品分辨率等原因在拖拽图标进文件夹的时候,在3*3的布局中,会发现图标出了folder边距,所以就需要分析相关的功能,然后实现解决这个问题2.FolderIcon文件夹图标内预览图标超......
  • 基于Android的B2B电影电商平台系统: 电影管理系统:基于Android的电影平台系统
     目录一.研究目的1.1研究背景1.2研究目的二.系统需求分析三.​​​​​​整体架构设计四.页面展示五.源码获取方式一.研究目的1.1研究背景据了解,以美国为首的国外电影产业早已形成机制健全、信息充分流通的产业链生态圈,其行业利润不仅仅依靠票房,而是通过衍生品......
  • 使用 Android Lua Helper 在VSCODE中调试安卓Lua应用
    一、VSCODE与AndroidLuaHelper的功能特点VisualStudioCode(VSCODE)是一款功能强大的代码编辑器,它以其高度可定制的界面、强大的扩展生态系统、流畅的性能表现以及对众多编程语言的天然支持而备受开发者青睐。在众多的开发场景中,VSCODE都展现出了卓越的性能和灵活性。Lua......
  • 驱动编写——《Android深度探索(卷1):HAL与驱动开发》笔记
    设备驱动大致骨架驱动代码.c文件#include<linux/module.h>#include<linux/init.h>#include<linux/slab.h>//使用kmalloc就需要includestaticunsignedcharmen[100000];//设备文件file,buf数据位置,count可读字节数,ppos偏移量staticssize_t驱动读函数(structfile*......
  • Android平台通过RTSP服务实现摄像头麦克风共享
    技术背景前些年,我们在完成Android平台RTMP直播推送模块后,遇到这样的技术需求,好多开发者希望在Android平台,实现摄像头和麦克风音视频数据采集编码打包后,对外提供RTSP(RealTimeStreamingProtocol)服务。通常,这样的技术需求,需要通过集成支持RTSP服务功能的库或自己实现轻量级的RTSP服......
  • Android开发 - Matrix 处理图像变换解析
    Matrix是什么Matrix是一个用于处理图像变换的类,它可以对图像进行缩放、旋转、平移和倾斜等操作。通俗来讲,Matrix就像是一个数学公式,用来定义如何改变图像的位置、形状或者方向Matrix的主要功能缩放(Scale):可以改变图片的大小,比如放大或缩小旋转(Rotate):可以将图片绕某个......