文章目錄
概述
今日學習內容如下:
- 瞭解 Miwok 語言應用的結構,在該應用中創建多屏,並使用 Intents 將多個 Activity 連接起來。
- 視圖回收
- 使用 LinearLayout 和 TextView 展示數據
- 改用 ListView 和 ArrayAdapeter 展示數據
- Memory Profiler 使用
- ……
Miwok應用構建
應用概述
Miwok 是一個用來學習 Miwok語言的應用,應用打開後應該有四個可選的類別,分別爲Numbers、Family Members、Colors、Phrases。當點擊任意一個類別所在的區域時,將跳轉到該類別所在的頁面。
結構大概像下面這樣:
添加Activity
分別爲四個類別新建 Activity,鼠標右擊 --> New --> Activity --> EmptyActivity
在首頁中爲每個類別創建選項,這裏使用 LinearLayout 和 TextView:
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
中:
想要自定義 Activity 的名稱,可以更改 activity 標籤中的屬性來實現,如 指定 label 屬性的值即可更改相應的 Activity 顯示的名稱
視圖回收
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);
}
- 首先創建了一個包含了 10000 個數字的 列表作爲數據來源
- 創建一個 ArrayAdapter 用於管理字符串數據(這裏是泛型),
this
參數指定上下文,android.R.layout.simple_list_item_1
是Android中一個列表項佈局,words
指定數據來源 findViewById(R.id.list)
獲取根視圖 ListView 的實例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
的佈局樣式
內存性能分析器使用
在 Android Studio 的工具欄中 View --> Tool Windows --> Profiler ,即可打開 Profiler,它顯示一個應用內存使用量的實時圖表,讓您可以捕獲堆轉儲、強制執行垃圾回收以及跟蹤內存分配。
使用 Memory Profiler 對比 視圖回收中,兩種方法 在頁面顯示 1000 個數字的內存消耗情況:
LinearLouyout + TextView 的方式大概佔用了 18mb 的內存 資源,ListView + ArrayAdapter 的方式則消耗了 8mb 資源,只使用到了前者的一半不到。
如果有更多的內容需要顯示,兩者的 內存消耗會更加明顯;比如在微博 App 的首頁用戶可以一直往下刷,查看 幾千上萬條 動態 ,就使用到了 視圖回收的機制。
並且 LinearLouyout 要想在屏幕中滾動查看更多內容,需要配合 ScrollView 實現;而 ListView 默認支持在屏幕中滾動瀏覽更多的效果。
總結
視圖回收 機制在日常使用的 App 中十分常見,如微博,CSDN 等。
今天學的 內容差不多就這些了, 步驟不多,但涵蓋的概念和知識點不少,慢慢來。
參考
ArrayAdapter --> BaseAdapter --> ListAdapter