authors
;
isbn
;
pageCount
;
fiction
.
Это, конечно, не масса, но достаточно много. К тому же мы собираемся не
-
много расширить этот экран, но не будем забегать вперед и начнем с самого
простого.
Android
Если вы прочитали главы 2 и 15, многое, о чем рассказывается в этом разделе,
покажется вам знакомым.
Сначала определим макет XML. Как вы уже знаете, нам нужно показать каж
-
дое свойство, имеющееся в экземпляре
Book
, поэтому просто отобразим их
в виде вертикального списка и выполним оформление программно. И снова
заключим
LinearLayout
в
ScrollView
, чтобы информацию можно было отобра
-
зить на любом экране, с любыми размерами и любым разрешением, а также
с любыми настройками доступности, как, например, выбор крупного шрифта
для отображения текста.
310
Сохранность данных
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:id="@+id/textview_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:id="@+id/textview_authors"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:id="@+id/textview_isbn"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:id="@+id/textview_pagecount"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:id="@+id/textview_isfiction"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Сохраните этот XML-код в файле
res/layout/activity_detail.xml
.
Нам нужно, чтобы в этих текстовых представлениях отображались полные
метки, поэтому используем строки-заполнители, добавив их в файл
strings.
xml
. Строка-заполнитель – это строка, содержащая специальные символы фор
-
матирования, которые должны замещаться значениями переменных. Более
подробную информацию о строках-заполнителях ищите в документации Java
с описанием метода
String.format
.
Добавьте в
strings.xml
следующие строки:
Book Title: %s
Book Authors: %s
Book ISBN: %s
Book Page Count: %d
Book : %b
Детализация информации о книгах
311
Нам также необходим контроллер пользовательского интерфейса для
отобра жения макета, а также для управления поведением компонентов. В дан
-
ном случае эту роль будет играть
Ac ti vi ty
.
Мы должны передать этому контроллеру некоторую информацию о книге,
но сделать это в Android не так-то просто. Экземпляр
Ac ti vi ty
создается про
-
граммно и непрозрачно, но, как рассказывалось в главе 1, простые данные
можно передать в экземпляре
Bundle
с помощью намерения
Intent
, запускаю
-
щего контроллер.
В приложениях, подобных этому, можно встретить два разных подхода.
Иногда один из них подходит лучше, иногда другой, но в большинстве случаев
выбор от личных предпочтений разработчиков. И да, не стесняйтесь экспери
-
ментировать с другими подходами – наша команда, например, использует для
решения этой задачи совершенно другой и очень нестандартный подход, но
его обсуждение выходит за рамки данной главы.
Итак, подход № 1: сериализовать весь объект и передать его как строку
String
(или массив байтов
byte[]
), а затем десериализовать в контроллере. Все
это реализуется очень просто, но помните, что емкость экземпляра
Bundle
огра
-
ничена – она составляет 1 Мбайт – и распределяется между всеми операциями,
даже теми, о существовании которых вы можете и не подозревать.
Подход № 2: передать какой-то уникальный идентификатор, например
идентификационный номер или URI, а затем по этому идентификатору из
-
влечь информацию из другого источника, например из локальной базы дан
-
ных, хранилища JSON или даже удаленного сервера.
Пока для простоты мы используем первый подход. Этот экземпляр
Ac ti vi ty
будет принимать из своего объекта
Intent
строку в формате JSON, содержа
-
щую экземпляр
Book
в сериализованном виде. Присвоим этой строке иденти
-
фикатор BOOK_JSON и сохраним его в константе. Затем десериализуем стро
-
ку в методе
onCreate
и сохраним полученные значения в соответствующих
свойствах.
Java
public class BookDetailAc ti vi ty extends Ac ti vi ty {
public static final String BOOK_JSON = "BOOK_JSON";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
// получить экземпляр Book из сериализованной строки
String json = getIntent().getStringExtra(BOOK_JSON);
Book book = new Gson().fromJson(json, Book.class);
// заполнить поля представления
Resources resources = getResources();
String title = resources.getString(R.string.detail_title, book.getTitle());
((TextView) findViewById(R.id.textview_title)).setText(title);
String authors = TextUtils.join(", ", book.getAuthors());
312
Сохранность данных
authors = resources.getString(R.string.detail_authors, authors);
((TextView) findViewById(R.id.textview_authors)).setText(authors);
String isbn = resources.getString(R.string.detail_isbn, book.getIsbn());
((TextView) findViewById(R.id.textview_isbn)).setText(isbn);
String pageCount = resources.getString(R.string.detail_pagecount,
book.getPageCount());
((TextView) findViewById(R.id.textview_pagecount)).setText(pageCount);
String fiction = resources.getString(R.string.detail_isfiction, book.isFiction());
((TextView) findViewById(R.id.textview_isfiction)).setText(fiction);
}
}
Kotlin
class BookDetailAc ti vi ty : Ac ti vi ty() {
companion object {
val BOOK_JSON = "BOOK_JSON"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)
// получить экземпляр Book из сериализованной строки
val json = intent.getStringExtra(BOOK_JSON)
val book = Gson().fromJson(json, Book::class.java)
// заполнить поля представления
textview_title.text = resources.getString(R.string.detail_title, book.title)
textview_authors.text = resources.getString(R.string.detail_authors,
TextUtils.join(", ", book.authors))
textview_isbn.text = resources.getString(R.string.detail_isbn, book.isbn)
textview_pagecount.text = resources.getString(R.string.detail_pagecount,
book.pageCount)
textview_isfiction.text = resources.getString(R.string.detail_isfiction,
book.isFiction)
}
}
Не забудьте также зарегистрировать новый объект
Ac ti vi ty
в манифесте при
-
ложения:
Отлично! Мы создали
Ac ti vi ty
с пользовательским интерфейсом, отобра
-
жающим всю информацию, имеющуюся в экземпляре
Book
. Теперь вернемся
к представлению списка, созданному в главе 17, и реализуем обработку со
-
бытия касания, по которому будем передавать выбранный экземпляр
Book
из
BrowseContentAc ti vi ty
в новый
BookDetailAc ti vi ty
. Прежде всего мы должны до
-
бавить в элемент списка (на данный момент это экземпляр
TextView
) метод
View.OnClickListener
, который извлекает соответствующий экземпляр
Book
и за
-
пускает
BookDetailAc ti vi ty
. Это можно сделать только один раз, на этапе соз
-
дания – в методе
onCreateViewHolder
. Поскольку эти представления постоянно
Детализация информации о книгах
313
освобождаются и используются повторно, нужно своевременно обновлять
связь между элементом списка и соответствующей книгой, что можно сделать
в цикле связывания и обновления, представленного методом
onBindViewHolder
.
Вот как должна выглядеть обновленная версия
BrowseBooksAdapter
:
Java
public class
BrowseBooksAdapter extends RecyclerView.Adapter {
private final BookDataSource mSource;
public BrowseBookAdapter(BookDataSource source) {
super();
mSource = source;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(new TextView(parent.getContext()));
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Book book = mSource.get(position);
holder.mTextView.setTag(book);
holder.mTextView.setText(book.getTitle());
}
@Override
public int getItemCount() {
return mSource.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private TextView mTextView;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mTextView = (TextView) itemView;
mTextView.setOnClickListener(this::showBook);
}
private void showBook(View view) {
Book book = (Book) view.getTag();
String json = new Gson().toJson(book);
Intent intent = new Intent(view.context, BookDetailAc ti vi ty.class);
intent.putExtra(BookDetailAc ti vi ty.BOOK_JSON, json);
view.getContext().startAc ti vi ty(intent);
}
}
}
Kotlin
class BrowseBooksAdapter(private val source: BookDataSource) :
RecyclerView.Adapter() {
314
Сохранность данных
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(TextView(parent.context))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val book = source.get(position)
holder.textView.tag = book
holder.textView.text = book.title
}
override fun getItemCount(): Int {
return source.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val textView: TextView = itemView as TextView
init {
textView.setOnClickListener { v > showBook(v) }
}
private fun showBook(view: View) {
val book = view.tag as Book
val json = Gson().toJson(book)
val intent = Intent(view.context, BookDetailAc ti vi ty::class.java)
intent.putExtra(BookDetailAc ti vi ty.BOOK_JSON, json)
view.context.startAc
ti
vi
ty(intent)
}
}
}
Если теперь запустить приложение, то при каждом касании элемента списка
в каталоге должен открываться экран с подробной информацией о книге, име
-
ющейся у нас. Поздравляем, вы только что освоили один из шаблонов, широко
используемых в Android и вообще в программировании пользовательского ин
-
терфейса! Улучите момент и погладьте себя по голове!
Do'stlaringiz bilan baham: |