本文所有代码均存放于https://github.com/MADMAX110/Starbuzz
开始构建一个应用时,你会考虑这个应用要包含什么,会有各种各样的很多想法,如何组织这些想法来建立一个直观、清晰的应用。
一、活动归类
要组织各种各样的活动,有一种方法很有效:可以把它们归类为3种不同类型的活动:顶级活动、类别活动和详细信息/编辑活动。
顶级活动:括对用户来说最重要的功能,要为用户提供便捷的途径,使他们能轻松地导航到这些功能。在大多是应用中,用户看到的第一个活动就是顶级活动。
类别活动:会显示某个特定类别的数据,通常会显示在一个列表中。这一类活动一般用于帮助用户导航到详细信息/编辑活动。
详细信息/编辑活动:会显示某个特定记录的详细信息,允许用户编辑这个记录,或者可以让用户输入新的记录。
很显然以上三种活动具有明显的层级关系,存在层层调用的关系。
二、构建一个菜单应用
在顶级活动中,包含一个logo,还会显示一个导航列表,其中包括饮料,食物和分店的入口。
在饮料类别活动中,会显示出售的所有饮料的一个清单。用户单击其中一种,可以查看其更多详细信息。
在饮料详细活动中,会显示饮料名,图片及描述。
由此看来,该应用的应用结构已经非常清晰了。包含三个活动,TopLevelActivity使应用的顶级活动,允许用户在应用中导航。DrinkCategoryActivity是一个类别活动,它包含所有饮料的一个列表。而DrinkActivity会显示某种饮料的详细信息。
应用的工作如下:
1、应用启动时,它会启动活动TopLevelActivity。
该活动使用布局activity_top_level.xml。它会显示一个选项列表,其中包括Drinks、Food和Stores。
2、用户单击TopLevelActivity中的Drinks。这会启动DrinkCategoryActivity。
这个活动使用布局activity_drink_category.xml,会显示一个饮料列表。从Drink.java类文件中获得饮料信息。
3、用户单击DrinkCategoryActivity中的饮料,这会启动DrinkActivity。
这个活动使用布局activity_drink.xml,他也从Drink.java类文件获得饮料的详细信息。
三、创建工程
如下图所示,创建一个名为Starbuzz的新的安卓工程。
工程目录如下:
其中包括一个Drink类,三个活动,三个布局,以及四张图片。
工程保存图像时,Android会为各个图像指定一个ID,形式为R.drawable.image_name,值是int类型。
四、Drink类
首先是Drink类,这是一个纯Java类,定义了一个包括3中饮料的数组,每种饮料包括饮料名,描述,以及图像资源ID。
Drink.java
package com.hfad.starbuzz;
public class Drink {
private String name;
private String description;
private int imageResourceId;
//drinks is an array of Drinks
public static final Drink[] drinks = {
new Drink("Latte", "A couple of espresso shots with steamed milk", R.drawable.latte),
new Drink("Cappuccino", "Espresso, hot milk, and a steamed milk foam", R.drawable.cappuccino),
new Drink("Filter", "Highest quality beans roasted and brewed fresh", R.drawable.filter)
};
//Each Drink has a name, description, and an image resource
private Drink(String name, String description, int imageResourceId) {
this.name = name;
this.description = description;
this.imageResourceId = imageResourceId;
}
public String getDescription() {
return description;
}
public String getName() {
return name;
}
public int getImageResourceId() {
return imageResourceId;
}
public String toString() {
return this.name;
}
}
五、顶级布局
TopLevelActivity时默认活动,其布局为activity_top_level.xml。顶级布局包含一个图像和一个列表
定义图像视图:
<ImageView
android:layout_width="200dp"
android:layout_height="100dp"
android:src="@drawable/starbuzz_logo"
android:contentDescription="@string/starbuzz_logo"
/>
在strings.xml中增加字符串
<string name="starbuzz_logo">Starbuzz logostring>
定义列表视图
<ListView
android:id="@+id/list_options"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@array/options" />
在strings.xml中增加一个字符串数组
<string-array name="options">
<item>Drinksitem>
<item>Fooditem>
<item>Storesitem>
string-array>
完整的activity_top_level.xml代码
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.hfad.starbuzz.TopLevelActivity"
>
<ImageView
android:layout_width="200dp"
android:layout_height="100dp"
android:src="@drawable/starbuzz_logo"
android:contentDescription="@string/starbuzz_logo"
/>
<ListView
android:id="@+id/list_options"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:entries="@array/options"
/>
LinearLayout>
六、在顶级活动中利用监听器让列表视图响应单击
可以实现一个事件监听器让列表视图中的列表项响应用户单击。
事件监听器允许你监听应用中发生的事件,例如单击视图、视图得到焦点或失去焦点,或者用户按下设备上的一个按键。通过事件监听器可以对用户某个特定的动作做出响应。
使用OnItemClickListener监听列表项的单击事件
下面是完整的TopActivity.java代码
package com.hfad.starbuzz;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
public class TopLevelActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_top_level);
//创建监听器
AdapterView.OnItemClickListener itemClickListener =
new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//Drink是列表视图中的第一项,所以位于位置0
if (position == 0) {
//这个意图来自TopLevelActivity,需要启动DrinkCategoryActivity
Intent intent = new Intent(TopLevelActivity.this, DrinkCategoryActivity.class);
startActivity(intent);
}
}
};
//为列表视图增加监听器
ListView listView = (ListView) findViewById(R.id.list_options);
listView.setOnItemClickListener(itemClickListener);
}
}
七、类别活动显示一个类别的数据
DrinkCategoryActivity是类别活动的一个例子。类别活动显示属于某个特定类别的数据,通常会显示在一个列表中。可以使用类别活动导航查看数据的详细信息。
需要注意的是:这里不使用android:entries属性,但是这样只能关联一个静态数组。这里我们需要把列表视图关联到Drink类中的drinks数组。
非静态数据要使用适配器
如果要在列表视图中显示数据,而数据来自strings.xml以外的其他数据源(如一个Java数组或数据库),就需要使用适配器。适配器就像数据源和列表视图之间的一座桥。这里主要使用数组适配器。数组适配器可以将数组和视图绑定,可以用于AdapterView类的任何子类,这说明这种适配器也可以用于列表视图和spinner,ArrayAdapter是一种专门用于处理数组的适配器。
用数组适配器连接列表视图和数组:
ArrayAdapter<Drink> listAdapter = new ArrayAdapter<>(
this,
android.R.layout.simple_list_item_1,
Drink.drinks);
数组适配器一般有三个参数,一个Context(通常是当前活动),一个布局资源以及数组本身。
然后关联到列表视图
ListView listDrinks = (ListView) findViewById(R.id.list_drinks);
listDrinks.setAdapter(listAdapter);
处理单击事件
AdapterView.OnItemClickListener itemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == 0) {
Intent intent = new Intent(DrinkCategoryActivity.this, DrinkCategoryActivity.class);
startActivity(intent);
}
}
};
将所单击列表项的ID增加到一个意图来传递ID
用类别活动在一个列表视图中显示列表项,通常会使用onItemClick方法启动另一个活动来显示用户单击的列表项的详细信息。为此,要创建一个意图启动第二个活动。然后为意图增加所单击列表项的ID作为额外信息,使得第二个活动启动时可以使用这个信息。在这里我们希望启动DrinkActivity并传入所选择饮料的ID。然后DrinActivity就能使用这个信息显示相应饮料的详细信息了。下面给出意图的代码:
Intent intent = new Intent(DrinkCategoryActivity.this, DrinkActivity.class);
//向意图增加所单击列表项的ID,第一个参数表示使用这个常量名表示意图中的额外信息名
//这样就能知道DrinkCategoryActivity和DrinkActivity在使用同一个字符串
//创建DrinkActivity活动时要增加这个常量。
intent.putExtra(DrinkActivity.EXTRA_DRINKID, (int)id);
startActivity(intent);
完整的DrinkCategoryActivity代码
package com.hfad.starbuzz;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class DrinkCategoryActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drink_category);
ArrayAdapter<Drink> listAdapter = new ArrayAdapter<>(
this,
android.R.layout.simple_list_item_1,
Drink.drinks);
ListView listDrinks = (ListView) findViewById(R.id.list_drinks);
listDrinks.setAdapter(listAdapter);
AdapterView.OnItemClickListener itemClickListener = new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == 0) {
Intent intent = new Intent(DrinkCategoryActivity.this, DrinkCategoryActivity.class);
startActivity(intent);
}
Intent intent = new Intent(DrinkCategoryActivity.this, DrinkActivity.class);
//向意图增加所单击列表项的ID,第一个参数表示使用这个常量名表示意图中的额外信息名
//这样就能知道DrinkCategoryActivity和DrinkActivity在使用同一个字符串
//创建DrinkActivity活动时要增加这个常量。
intent.putExtra(DrinkActivity.EXTRA_DRINKID, (int)id);
startActivity(intent);
}
};
listDrinks.setOnItemClickListener(itemClickListener);
}
}
八、详细信息活动显示一个记录的数据
activity_drink.xml
<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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DrinkActivity">
<ImageView
android:id="@+id/photo"
android:layout_width="190dp"
android:layout_height="190dp"/>
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
LinearLayout>
从意图获取数据
创建DrinkCategoryActivity时,将用户单击的饮料的ID作为额外信息增加到意图。为它指定一个标签DrinkActivity.EXTRA_DRINKID,要在DrinkActivity中把它定义一个常量:
public static final String EXTRA_DRINKID = "drinkId";
从意图中获取EXTRA_DRINKID值
int drinkId = (Integer)getIntent().getExtras().get(EXTRA_DRINKID);
再使用drinkID得到用户选择的饮料的详细信息,drinkID时饮料的ID。也就是drinks数组中这种饮料的索引,这说明可以使用以下代码得到用户单击的饮料:
Drink drink = Drink.drinks[drinkId];
使用数据更新视图
TextView name = (TextView) findViewById(R.id.name);
name.setText(drink.getName());
TextView description = (TextView) findViewById(R.id.description);
description.setText(drink.getDescription());
ImageView photo = (ImageView) findViewById(R.id.photo);
photo.setImageResource(drink.getImageResourceId());
photo.setContentDescription(drink.getName());
完整的DrinkActivity代码:
package com.hfad.starbuzz;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
public class DrinkActivity extends AppCompatActivity {
public static final String EXTRA_DRINKID = "drinkId";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drink);
int drinkId = (Integer)getIntent().getExtras().get(EXTRA_DRINKID);
Drink drink = Drink.drinks[drinkId];
TextView name = (TextView) findViewById(R.id.name);
name.setText(drink.getName());
TextView description = (TextView) findViewById(R.id.description);
description.setText(drink.getDescription());
ImageView photo = (ImageView) findViewById(R.id.photo);
photo.setImageResource(drink.getImageResourceId());
photo.setContentDescription(drink.getName());
}
}