安卓学习日志 — Day02

文章目录

概述

今日学习内容如下:

  • 了解 Miwok 语言应用的结构,在该应用中创建多屏,并使用 Intents 将多个 Activity 连接起来。
  • 视图回收
    • 使用 LinearLayout 和 TextView 展示数据
    • 改用 ListView 和 ArrayAdapeter 展示数据
  • Memory Profiler 使用
  • ……

Miwok应用构建

应用概述

Miwok 是一个用来学习 Miwok语言的应用,应用打开后应该有四个可选的类别,分别为Numbers、Family Members、Colors、Phrases。当点击任意一个类别所在的区域时,将跳转到改类别所在的页面。

结构大概像下面这样:

安卓学习日志 — Day02

添加Activity

分别为四个类别新建 Activity,鼠标右击 --> New --> Activity --> EmptyActivity

安卓学习日志 — Day02

在首页中为每个类别创建选项,这里使用 LinearLayout 和 TextView:

安卓学习日志 — Day02

OnClickListener

现在需要,当在首页点击某个类别时跳转到该类别所在的页面,这就需要监听 视图的 Onclick事件,而监听事件需要用到监听器,官方已经定义好了事件的监听器。

下面直接使用,在首页源码(MainActivity)的 OnCreate 方法方法中添加:

        // Find the View that show the number category
        TextView numbers = (TextView) findViewById(R.id.numbers);
        // Set a clickListener on that View
        numbers.setOnClickListener(new View.OnClickListener() {
            // …………
        });

首先使用 findViewById(R.id.numbers) 获取到了 Numbers 类别的视图,然后调用 numbers.setOnClickListener() 方法为视图设置 OnClick 事件的监听器,它接收 一个 OnClickListener 的实例。

监听器是一个 interface(接口),因此我们需要按照接口中预定义的来实现这个接口,单击事件监听器 OnClickListener 接口中只包含一个方法 void onClick(View v);,因此单击跳转 Activity 的代码如下:

      numbers.setOnClickListener(new View.OnClickListener() {
            // The code in this method will be executed when the family category is clicked on.
            @Override
            public void onClick(View view) {
                // Create a new intent to open the {@link NumbersActivity}
                Intent numbersIntent = new Intent(MainActivity.this, NumbersActivity.class);
                // Start the new activity
                startActivity(numbersIntent);
            }
        });

首先在 OnClickListener 的实现类中 重写 onClick 方法,并在里面定义视图单击时需要执行的操作。

onClick 方法中一共两行代码,第一行创建了一个 Intent 实例,传入两个参数 上下文环境 Context 和 目标Activity(这是一个显式的 Intent),表示将要跳转到 NumbersActivity 页面;第二行代码 则启动这个 Intent 实例,执行真实的 跳转操作。

四个类别的页面跳转也是一样的,分别创建并设置 单击事件的监听器并 使用 Intent 让其跳转套不同的 页面即可,代码省略…………。

修改Activity显示的名称

有一个问题,在创建 Miwok 项目时指定 App Name 为 Miwok,而没有为每个Activity定义 显示的名称,所以默认采用了应用的名称,在 AndroidManifest.xml 中:

安卓学习日志 — Day02

想要自定义 Activity 的名称,可以更改 activity 标签中的属性来实现,如 指定 label 属性的值即可更改相应的 Activity 显示的名称

安卓学习日志 — Day02

视图回收

LinearLayout 和 TextView

在 Numbers 页面中需要显示 1 到 10 的语言列表,因此考虑使用 线性布局 加 TextView 来实现:

在 Numbers 页面的布局文件中定义一个 id 为 rootView 的 LinearLayout,它将用于垂直排列 1 到 10 的 TextView

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rootView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".NumbersActivity" />

在 Numbers 页面的 OnCreate 方法中 填加代码 实现,先通过 findViewById 方法获取到根视图LinearLayout的实例,然后 创建一个 TextView 实例传入 this (当前Activity)作为上下文并设置 Text,最后调用根视图的 addView 方法将 TextView 添加进去,循环10次就添加了10个数字。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_numbers);

        LinearLayout root = (LinearLayout) findViewById(R.id.rootView);
        for (int i = 0; i < 10; i++) {
            TextView t = new TextView(this);
            t.setText("" + i);
            root.addView(t);
        }

采用这种方法,如果有 几千个数字要显示,则要循环 几千次,在手机里创建几千个TextView并渲染在手机屏幕上,这会占用较大的内存空间,因为手机屏幕能显示的TextView可能只有几个或十多个,这取决于 TextView的高宽。

设备的内存资源 是有限的。

ListView 和 ArrayAdapeter

LinearLayout + TextView 的会造成资源的浪费。

ListView 和 ArrayAdapeter 则不会,ArrayAdapeter是一个适配器 ,用于管理 视图和 数据。

假如在手机屏幕中可以显示 10 条 TextView ,而我们有 10000 个 数字需要显示,用户在滑动屏幕查看更多的数字时(上面的数字会移出屏幕,下面的数字会进入排列),适配器就会回收 移出数字的视图资源,并将改视图资源用于显示新进入的数字。

代码:

Numbers 的 xml 布局文件:

<?xml version="1.0" encoding="utf-8"?>
    <ListView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".NumbersActivity" />

Numbers 页面 的 onCreate 函数:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_numbers);
        // Create a array list of words
        ArrayList<String> words = new ArrayList<String>();
        for (int i = 0; i < 10000; i++) {
            words.add("" + i);
        }
        
        // Create a ArrayAdapter
		ArrayAdapter<String> itemsAdapter =
                new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, words);
        // Get layout instance
        ListView listLayout = (ListView) findViewById(R.id.list);
        // Set adapter for the layout instance
        listLayout.setAdapter(itemsAdapter);
    }
  1. 首先创建了一个包含了 10000 个数字的 列表作为数据来源
  2. 创建一个 ArrayAdapter 用于管理字符串数据(这里是泛型),this 参数指定上下文,android.R.layout.simple_list_item_1 是Android中一个列表项布局,words 指定数据来源
  3. findViewById(R.id.list) 获取根视图 ListView 的实例
  4. listLayout.setAdapter(itemsAdapter) 为 根视图绑定适配器

这样适配器就可以管理 视图视图 和 数据来源了。

最后一步的 listLayout.setAdapter(itemsAdapter); 比较复杂,ListView 定义的 设置适配器方法为 public void setAdapter(ListAdapter adapter) 要求接收一个 ListAdapter 对象,而最终转入的却是 ArrayAdapter 对象。

原因是:

ArrayAdapter 继承自 抽象类 BaseAdapter ,BaseAdapter 实现了 ListAdapter 接口,所以 ArrayAdapter 也是 ListAdapter的实现。

运行效果,图片大,只截部分,:

横线是 android.R.layout.simple_list_item_1 的布局样式

安卓学习日志 — Day02

内存性能分析器使用

在 Android Studio 的工具栏中 View --> Tool Windows --> Profiler ,即可打开 Profiler,它显示一个应用内存使用量的实时图表,让您可以捕获堆转储、强制执行垃圾回收以及跟踪内存分配。

使用 Memory Profiler 对比 视图回收中,两种方法 在页面显示 1000 个数字的内存消耗情况:

安卓学习日志 — Day02

LinearLouyout + TextView 的方式大概占用了 18mb 的内存 资源,ListView + ArrayAdapter 的方式则消耗了 8mb 资源,只使用到了前者的一半不到。

如果有更多的内容需要显示,两者的 内存消耗会更加明显;比如在微博 App 的首页用户可以一直往下刷,查看 几千上万条 动态 ,就使用到了 视图回收的机制。

并且 LinearLouyout 要想在屏幕中滚动查看更多内容,需要配合 ScrollView 实现;而 ListView 默认支持在屏幕中滚动浏览更多的效果。

总结

视图回收 机制在日常使用的 App 中十分常见,如微博,CSDN 等。

今天学的 内容差不多就这些了, 步骤不多,但涵盖的概念和知识点不少,慢慢来。

参考

OnClickListener

<activity>

ListView | Android Developers

ArrayAdapter --> BaseAdapter --> ListAdapter

查看堆和内存分配

关于 ListView 和 ArrayAdapter 的 Codepath 教程。

关于 ListView 的 Google I/O 演讲 Youtube 视频。

上一篇:ListView


下一篇:跟我学Android之十一 列表和适配器