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

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

现在我们就讲运用所学的知识来编写一个简易版的新闻英语,并且要求它是可以同时兼容手机和平板的。新建好一个 FragmentBestPractice 项目,然后开始手动吧!

第一步我们要先准备好一个新闻的实体类,新建类 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 类的代码还是比较简单的,title 字段表示新闻标题,content 字段表示新闻内容。接着新建一个 news_item.xml 布局,用于作为新闻列表中子项的布局:

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

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

接下来需要创建新闻列表的适配器,让这个适配器继承自 ArrayAdapter,并将泛型指定为 News 类。新建类 NewsAdapter,代码如下所示:

public class NewsAdapter extends ArrayAdapter<News> {  private int resourceId;  public NewsAdapter(Context context, int textViewResourceId, List<News> objects) {  super(context, textViewResourceId, objects);  resourceId = textViewResourceId;  }  @Override  public View getView(int position, View convertView, ViewGroup parent) {  News news = getItem(position);  View view;  if (convertView == null) {  view = LayoutInflater.from(getContext()).inflate(resourceId, null);  } else {  view = convertView;  }  TextView newsTitleText = (TextView) view.findViewById(R.id.news_title);  newsTitleText.setText(news.getTitle());  return view;  }
} 

可以看到,在 getView() 方法中,我们获取到了相应位置上的 News 类,并让新闻的标题在列表中进行显示。

这样基本就把新闻列表部分的代码编写完了,接下来我们看一下如何编写新闻内容部分的代码。新建布局文件 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" />  <ImageView  android:layout_width="match_parent"  android:layout_height="1dp"  android:scaleType="fitXY"  android:src="@drawable/spilt_line" />  <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>  <ImageView  android:layout_width="1dp"  android:layout_height="match_parent"  android:layout_alignParentLeft="true"  android:scaleType="fitXY"  android:src="@drawable/spilt_line_vertical" />  </RelativeLayout>  

新闻内容的布局主要可以分为两个部分,头部显示完整的新闻标题,正文部分显示新闻内容,中间使用一条细线分割开。这里的细线是利用 ImageView 显示了一张很窄的图片来实现的,将 ImageView 的 android:scaleType 属性设置为 fitXY,表示让这张图片填充满整个控件的大小。

然后再新建一个 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() 方法分别获取到新闻的标题和内容控件,然后将方法传递进来的参数设置进去。

接着要创建一个在 Activity 中使用的新闻内容布局,新建 news_content.xml,代码如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical" >  <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,作为显示新闻内容的 Activity,代码如下所示:

public class NewsContentActivity extends Activity {  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);  requestWindowFeature(Window.FEATURE_NO_TITLE);  setContentView(R.layout.news_content);  String newsTitle = getIntent().getStringExtra("news_title");  String newsContent = getIntent().getStringExtra("news_content");  NewsContentFragment newsContentFragment = (NewsContentFragment) getFragmentManager()  .findFragmentById(R.id.news_content_fragment);  newsContentFragment.refresh(newsTitle, newsContent);  }
}

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

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

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

这个布局的代码就非常简单了,里面只有一个 ListView。不过想必你已经猜到了,这个布局并不是给 Activity 使用的,而是给碎片使用的,因此我们还需要创建一个碎片来加载这个布局。新建一个 NewsTitleFragment 类,继承自 Fragment,代码如下所示:

public class NewsTitleFragment extends Fragment implements OnItemClickListener {  private ListView newsTitleListView;  private List<News> newsList;  private NewsAdapter adapter;  private boolean isTwoPane;  @Override  public void onAttach(Activity activity) {  super.onAttach(activity);  newsList = getNews();  adapter = new NewsAdapter(activity, R.layout.news_item, newsList);  }  @Override  public View onCreateView(LayoutInflater inflater, ViewGroup container,  Bundle savedInstanceState) {  View view = inflater  .inflate(R.layout.news_title_frag, container, false);  newsTitleListView = (ListView) view  .findViewById(R.id.news_title_list_view);  newsTitleListView.setAdapter(adapter);  newsTitleListView.setOnItemClickListener(this);  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 布局时,为单页模式  }  }  @Override  public void onItemClick(AdapterView<?> parent, View view, int position,  long id) {  News news = newsList.get(position);  if (isTwoPane) {  // 如果是双页模式,则刷新 NewsContentFragment 中的内容  NewsContentFragment newsContentFragment = (NewsContentFragment) getFragmentManager()  .findFragmentById(R.id.news_content_fragment);  newsContentFragment.refresh(news.getTitle(), news.getContent());  } else {  // 如果是单页模式,则直接启动 NewsContent  NewsContentActivity.actionStart(getActivity(), news.getTitle(),  news.getContent());  }  }  private List<News> getNews() {  List<News> newsList = new ArrayList<News>();  News news1 = new News();  news1.setTitle("Succeed in College as a Learning Disabled Student");  news1.setContent("College freshmen will soon learn to live with a   roommate, adjust to a new social scene and survive less-than-stellar   dining hall food. Students with learning disabilities will face these   transitions while also grappling with a few more hurdles.");  newsList.add(news1);  News news2 = new News();  news2.setTitle("Google Android exec poached by China's Xiaomi");  news2.setContent("China's Xiaomi has poached a key Google executive   involved in the tech giant's Android phones, in a move seen as a coup   for the rapidly growing Chinese smartphone maker.");  newsList.add(news2);  return newsList;  }
} 

这个类的代码有点长,我来重点解释一下。根据碎片的生命周期,我们知道,onAttach() 方法会首先执行,因此在这里做了一些数据初始化操作,比如调用 getNews() 方法获取几条模拟的新闻数据,以及完成 NewsAdapter 的创建。然后在 onCreateView() 方法中加载了 news_title_frag 布局,并给新闻列表的 ListView 注册了点击事件。接下来在 onActivityCreated() 方法中,我们通过是否能够找到一个 id 为 news_content_layout 的 View 来判断当前是双页模式还是单页模式,这个 id 为 news_content_layout 的 View 只在双页模式中才会出现,在稍后的布局里你将会看到。然后在 ListView 的点击事件里我们就可以判断,如果当前是单页模式,就启动一个新的 Activity 去显示新闻内容,如果当前是双页模式,就更新新闻内容碎片里的数据。

剩下工作就非常简单了,修改 activity_main.xml 中的代码,如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  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"  />  </LinearLayout> 

上述代码表示,在单页模式下,只会加载一个新闻标题的碎片。然后新建 layout-sw600dp 文件夹,在这个 文件夹下再新建一个 activity_main.xml 文件,代码如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  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 的时候就是双页模式,否则就是单页模式。

最后再将 MainActivity 稍作修改,把标题栏去除掉,代码如下所示:

public class MainActivity extends Activity {  @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  requestWindowFeature(Window.FEATURE_NO_TITLE);  setContentView(R.layout.activity_main);  }
}

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

图  4.15

可以看到两条新闻的标题,并且超出屏幕部分的文字是在尾部使用省略号代替的。

然后点击第二条新闻,会启动一个新的 Activity 来显示新闻的内容,效果如图 4.16 所示。

图 4.16

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

图 4.17

怎么样?同样的一份代码,在手机和平板上运行却分别是两种完全不同的效果,说明我们程序的兼容性已经写得相当不错了。

摘自《第一行代码》

碎片的最佳实践——一个简易版的新闻应用相关推荐

  1. 一个简易版的新闻应用(同时兼容手机和平板)

    代码可能有点长,需要耐心看几遍.前前后后我看了5遍才把整个流程吃透,相信你一定比我聪明!!! 新建一个FragmentBestPractice项目 (让ADT帮我们自动创建活动--活动名:MainAc ...

  2. Android之Fragment应用——一个简易版的新闻应用

    内容: 1.准备工作 2.新建一个新闻的实体类News 3.新建布局文件news_content_frag.xml,作为新闻内容的布局 4.NewsContentFragment类,继承自Fragme ...

  3. 《碎片的最佳实践》读书笔记

    转载请注明出处:http://blog.csdn.net/chengbao315/article/details/50962716 最近学习了郭霖<第一行代码>的4.5章节<碎片的最 ...

  4. 深入理解java虚拟机 - jvm高级特性与最佳实践(第三版)_JVM虚拟机面试指南:年薪30W以上高薪岗位需求的JVM,你必须要懂!...

    JVM的重要性 很多人对于为什么要学JVM这个问题,他们的答案都是:因为面试.无论什么级别的Java从业者,JVM都是进阶时必须迈过的坎.不管是工作还是面试中,JVM都是必考题.如果不懂JVM的话,薪 ...

  5. 高性能网站建设进阶指南:Web开发者性能优化最佳实践 pdf扫描版

    高性能网站建设进阶指南:Web开发者性能优化最佳实践是<高性能网站建设指南>姊妹篇.作者Steve Souders是Google Web性能布道者和Yahoo!前首席性能工程师.在本书中, ...

  6. DFiddler:A HTTP Packets Listener一个简易版的手机端的Fiddler。

    Diddler A HTTP Packets Listener一个简易版的手机端的Fiddler. Android系统需要Root权限. PIC_20140121_220503_617.jpeg PI ...

  7. 肝一波 ~ 手写一个简易版的Mybatis,带你深入领略它的魅力!

    零.准备工作 <dependencies><dependency><groupId>mysql</groupId><artifactId>m ...

  8. 实现一个简易版的微博,包含 client 和 server 两部分,并实现四个基础功能:关注、取关、发微博、获取用户微博列表

    const assert = require('assert'); const question = '实现一个简易版的微博,包含 client 和 server 两部分,并实现四个基础功能:关注.取 ...

  9. 依赖注入[5]: 创建一个简易版的DI框架[下篇]

    为了让读者朋友们能够对.NET Core DI框架的实现原理具有一个深刻而认识,我们采用与之类似的设计构架了一个名为Cat的DI框架.在<依赖注入[4]: 创建一个简易版的DI框架[上篇]> ...

最新文章

  1. SET QUOTED_IDENTIFIER OFF语句的作用
  2. 百度网页分享js代码
  3. javascript学习(三) 内置对象
  4. QT实现绘制3D基本形状
  5. session机制详解以及session的相关应用
  6. 解决Windows 8系统假死的方法
  7. html5基础知识点文本标签
  8. malloc在函数内分配内存问题
  9. ​ ​微软Office新增实用功能允许用户在不同设备上轻松送同步字体
  10. 【Spring 5】响应式Web框架实战(上) 1
  11. 搞定 Linux Shell 文本处理工具,看完这篇集锦就够了
  12. python支持按指定字符串分割成数组_按固定元素数目分割数组- perl,python
  13. 禁掉win2003/2008服务 提高系统运行速度
  14. 图文并茂搭建STM32开发环境
  15. 稚晖君_瀚文机械键盘
  16. 任正非在持股员工代表会上讲:我的家人永不会进入接班人序列
  17. linux命令详解:tc
  18. Google 地图- 基本地图类型
  19. 上海亚商投顾:沪指逼近2900点 两市超4500股飘绿
  20. android仿百度地图悬浮式窗口,百度地图(bMap)实现浮动层、按钮等的方法及代码...

热门文章

  1. sqlite怎么转换mysql_Django如何把SQLite数据库转换为Mysql数据库
  2. SpringBoot实现登录注册
  3. Java面试 一篇就够[大量链接+图文]
  4. 5-(4-甲酰基苯基)-10,15,20-苯基卟啉(FPTPP)/Β-硝基四苯基卟啉[H2TP(NO2)]及其锌配合物[ZnTPP(NO2)]的合成方法/结构式
  5. 如何加速播放SWF格式文件——使用Enounce MySpeed轻松实现
  6. 硬件设备与软件交互加密方案
  7. 5G NR - 38.101-1协议笔记(一)
  8. Vue--Router--路由传参的方法
  9. iOS AppStore上架流程图文详解​
  10. 2019-04-07我破解了中国商标网