Данная статься познакомит вас с разработкой простого приложения для Android TV. В первую очередь она ориентированна на тех, кто уже имел какой-либо опыт в разработке приложений для Android, поэтому я не буду здесь объяснять что такое Activity, Fragments и т.д.
В интернете есть много русскоязычной информации по разработке приложений для Android и не мало статей по написанию HelloWord для него же. Заинтересовавшись разработкой приложений для Android TV, я сразу же начал изучать эту тему на англоязычных сайтах. К моему удивлению материала оказалось не так уж и много, и я решил посмотреть что же есть на русском. На русском ничего найти не удалось (возможно плохо искал). В общем я намерен исправить эту ситуацию.
Так как интерфейс приложений для телефонов и Android TV имеет существенные различия, то мы должны создать интерфейс приложения, подходящий для взаимодействия на TV. Например, нам следует создавать приложения с которыми можно взаимодействовать, используя только клавиши — ↑ ↓ → ←. В реализации такого интерфейса нам может помочь библиотека LeanbackSupport, позволяющая вполне легко создавать UI, который будет удобен при работе с приложениями на Android TV.
Создание проекта в Android Studio
Запустив Android Studio, необходимо создать новый проект. При создании выбрать платформу TV и указать минимальную версию SDK. Android Studio предложит нам создать «Android TV Activity», однако на данный момент следует выбрать «Add No Activity», т.к. если вы выберите создание Activity, то AS создаст много классов и файлов, в которых изначально сложнее разобраться.
Создание Activity
Для начала необходимо создать новый XML файл под именем activity_main.xml, который будет содержать разметку для нашей Activity. Код разметки мы изменим позже.
Теперь следует создать класс унаследованный от Activity. Для этого нужно создать новый класс с именем MainActivity и унаследовать его от класса Activty. Предопределить метод onCreate(Bundle SIS) и установить в нем содержимое для Activity из созданного файла разметки.
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Объявление Activity в файле манифеста приложения
Если вы попытаетесь запустить приложение на данном этапе, то оно естественно не запустится, так как в файле AndroidManifest.xml у нас не объявлено ни одной Activity.
В файл манифеста нужно добавить следующий код.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.simpletvapp">
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<uses-feature
android:name="android.software.leanback"
android:required="true" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Leanback">
<activity
android:name=".MainActivity"
android:icon="@drawable/app_icon_your_company"
android:label="@string/app_name"
android:logo="@drawable/app_icon_your_company" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Теперь разберем некоторые моменты. Часть кода приведенная ниже отключает тач.
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
В этой части вы указываете, что приложение должно запускаться только на Android TV. Если вы разрабатываете приложение не только для TV, то вам следует установить значение false.
<uses-feature
android:name="android.software.leanback"
android:required="true" />
При объявлении Activity мы указываем в intent-filter, что Activity должна запускаться на Android TV.
<category android:name=”android.intent.category.LEANBACK_LAUNCHER/>
Создание фрагмента
Сейчас нужно создать класс Java с именем MainFragment и унаследовать от класса BrowseFragment из библиотеки LeanbackSupport. BrowseFragment позволяет создавать стандартный интерфейс приложений для Android TV.
Теперь мы можем привязать созданный фрагмент к нашей Activity, для этого в файл разметки Activity (в моем случае это activity_main.xml) следует поместить следующий код разметки.
<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_browse_fragment"
android:name="com.simpletvapp.MainFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Запуск приложения
Чтобы запустить приложение, нужно создать эмулятор Android TV. Его можно создать в Android Virtual Device Manager.
После создания эмулятора можно запустить на нем наше приложение. На данный момент оно имеет следующий вид.
Здесь вы видите пустой BrowseFragment. Вы можете увидеть RowsFragment в левой части приложения (фрагмент отвечает за отображение списка заголовков) и HeaderFragment в правой части экрана (отвечает за отображение контента заголовков).
Далее мы заполним HeaderFragment, RowsFragment и рассмотрим их подробнее. Перед этим установим основные цвета UI и заголовок для приложения.
Настройка стиля приложения
Здесь я добавил метод setupUI() в MainFragment.java и вызвал его в предопределенном методе onActivityCreated.
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setupUI();
}
private void setupUI() {
setTitle("Hello Android TV!");
int color = ContextCompat.getColor(getActivity(), R.color.fastlane_background);
setBrandColor(color);
}
Если вы запустите приложение на данном этапе, то вы должны увидеть вот такой UI.
Заполнение BrowseFragment
Давайте сначала разберемся на примере готового приложения Android TV содержание BrowseFragment. Каждый заголовок в левой части фрагмента (HeaderItem) имеет ряд с контентом в правой части. Комбинацию «заголовок (HeaderItem) + контент в правой части приложения», содержит класс ListRow. Содержание BrowseFragment представляет собой список из ListRow. Заголовок и список с контентом в правой части имеет отношение один к одному.
Рассмотрим ListRow детальнее. За список с контентом отвечает ArrayObjectAdapter. В данном случае CardInfo это элемент контента. CardInfo может быть любым объектом. Как создать и отобразить CardInfo мы рассмотри позже.
Сейчас мы можем сделать следующие выводы:
ArrayObjectAdapter — отвечает за список из ListRow
ListRow = HeaderItem (заголовок) + ArrayObjectAdapter (список контента в правой части)
Класс Presenter
Заполнение элементов контента определяется при помощи класса Presenter из библотеки LeanbackSupport. Он определяет отображение элемента контента. Presenter является абстрактным классом, поэтому мы должны создать новый класс и унаследовать его от Presenter. Когда вы создадите новый класс, вы должны предопределить как минимум 3 метода:
onCreateViewHolder(ViewGroup parent);
onBindViewHolder(ViewGolder, viewHolder, Object item);
onUnbindViewHolder(ViewHolder viewHolder);
Presenter содержит внутренний класс ViewHolder, который позволяет ссылаться к View (элемент контента). Мы можем получить доступ к View через ViewHolder при конкретных событиях, например в методах класса Presenter onBind() или onUnbind()
Заполнение HeadersFragment и RowsFragment
Давайте перейдем к делу. Здесь мы создаем класс GridItemPresenter унаследованный от класса Presenter. В этом приложении Object (элемент контента) отображает строку, а ViewHolder содержит в себе TextView для отображения этой строки. View создается в методе onCreateViewHolder(), а ее заполнение производится в методе onBindViewHolder().
public class GridItemPresenter extends Presenter {
private static final int WIDTH_ITEM = 300;
private static final int HEIGHT_ITEM = 200;
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent) {
TextView view = new TextView(parent.getContext());
view.setLayoutParams(new ViewGroup.LayoutParams(WIDTH_ITEM, HEIGHT_ITEM));
view.setFocusable(true);
view.setFocusableInTouchMode(true);
view.setGravity(Gravity.CENTER);
view.setBackgroundColor(ContextCompat.getColor(parent.getContext(), R.color.default_background));
view.setTextColor(Color.WHITE);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, Object item) {
TextView textView = (TextView) viewHolder.view;
String str = (String) item;
textView.setText(str);
}
@Override
public void onUnbindViewHolder(ViewHolder viewHolder) {
}
}
В класс MainFragment добавляем метод loadRows() и вызываем его в предопределенном методе onActivityCreated()
private void loadRows() {
// адаптер, отвечающий за ListRow (ListRow = заголовок + контент)
ArrayObjectAdapter rowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
// класс отчечает за заголовок, в конструкторе указываем что это первый заголовок в списке,
// и сам заголовок содерэит текст "Заголовок 1"
HeaderItem headerItem = new HeaderItem(0, "Заголовок 1");
// наш класс, отвечающий за заполнение элементов контента
GridItemPresenter itemPresenter = new GridItemPresenter();
// адаптер, отвечает за отображение контента в правой части
ArrayObjectAdapter gridAdapter = new ArrayObjectAdapter(itemPresenter);
// добавление трех элементов контента
gridAdapter.add(0, "Эемент 1");
gridAdapter.add(1, "Эемент 2");
gridAdapter.add(2, "Эемент 3");
// в адаптер, отвечающий за ListRows, добавляем ListRow.
// в конструктор передаем класс, отвечающий за заголовок и адаптер, отвечающий за
// отображение списка контента
rowsAdapter.add(new ListRow(headerItem, gridAdapter));
setAdapter(rowsAdapter);
}
Теперь вы можете запустить приложение и увидеть экран представленный ниже.
На этом все. В этой статье я попытался объяснить некоторые из основных принципов создания приложения для Android TV.
За основу данной статьи были взяты этот и этот туториалы.
Автор: b0ot