Во время разработки игр и приложений часто возникают
ситуации, когда приходиться в каждом разработанном Activity писать один и тот же код. Потом
переносить его в другие проекты. В этой статье я хотел бы рассказать о том, как
можно облегчить жизнь при создании очередного Activity в приложении.
Теория
Что чаще всего мы используем при создании нового Activity? Конечно это
установка отображаемого View
(метод setContentView()),
отправка статистики, использование Wake Lock, логирование методов, запуск и остановка музыки и много
другое. Почему бы все эти методы не перенести в один класс, и затем
наследоваться от него в нашем Activity.
Практика
Разработаем абстрактный класс: SceletonActivity. Наследуемся
от android.app.Activity, чтобы можно было использовать соответствующие методы.
public abstract class SceletonActivity extends Activity { }
В этой статье я добавлю для нашего «скелета» возможность
отследить паузу приложения, использование Wake Lock, логирование и отправку статистики.
Добавим основные используемые методы в наш Activity. Для логирования я использую
класс, описанный мною в статье «Логирование в Android». Так же добавим атрибут protected
String tag. Он будет использоваться для хранения текущего имени класса.
protected String tag; // Имя класса для логирования @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); LogSystem.w(tag, "onCreate()"); } @Override protected void onPause() { super.onPause(); LogSystem.w(tag, "onPause()"); } @Override protected void onResume() { super.onResume(); LogSystem.w(tag, "onResume()"); } @Override protected void onDestroy() { super.onDestroy(); LogSystem.w(tag, "onDestroy()"); } @Override protected void onStart() { super.onStart(); LogSystem.w(tag, "onStart()"); } @Override protected void onStop() { super.onStop(); LogSystem.w(tag, "onStop()"); }
Следующий этап разработки нашего «скелета» - отслеживание
паузы в приложении. Для этого мы добавим атрибут protected boolean mPaused. И
немного изменим наши методы:
protected boolean mPaused; // отслеживание паузы в приложении @Override protected void onPause() { super.onPause(); LogSystem.w(tag, "onPause()"); this.mPaused = true; } @Override protected void onResume() { super.onResume(); LogSystem.w(tag, "onResume()"); this.mPaused = false; }
Для чего можно
использовать этот атрибут я покажу чуть позже в этой статье.
Теперь нам необходимо
установить для Activity соответствующее View и Tag,
а также инициализировать все элементы UI нашего Activity. Для этого у нас будут
использоваться абстрактные методы:
protected abstract void initInterface(); // Инициализация интерфейса protected abstract void setAttr(); // Установка атрибутов класса
Их реализация заложена в
тех Activity, которые
будут наследниками для SceletonActivity. Вызов этих методов необходимо
поместить в метод onCreate()
нашего «скелета»:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setAttr(); LogSystem.w(tag, "onCreate()"); setContentView(view); initInterface(); }
Так же мы хотим
отправлять статистику на используемый нами сервис (например, Google Analitics или Flurry).
Для этого мы добавим следующий метод:
public void trackSupportedApp(String activity, Mapmap) { LogSystem.w(tag, "trackSupportedApp(" + activity + ")"); }
Вместо логирования
необходимо добавит код отправки статистики для используемого вами сервиса.
Например, для Flurry
код может выглядеть следующим образом:
public static void trackSupportedApp(String activity, Mapmap) { if (activity == null || activity.length() == 0) return; if (map == null) FlurryAgent.logEvent(activity); else FlurryAgent.logEvent(activity, map); }
И на последок я добавлю WakeLock, чтобы наше
приложение не отключало экран во время работы.
Для этого нам необходимо
3 метода:
/** * Инициализация WakeLock */ private void initWl() { if (wl == null) { PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "org.snowpard.projects.five"); } } /** * Запускаем выполнение запрошенных функций WakeLock */ public void wlAsquire() { try { if (wl != null) wl.acquire(); }catch (Exception e) { } } /** * Останавливаем выполнение запрошенных функций WakeLock */ public void wlRelease() { try { if (wl != null) wl.release(); }catch (Exception e) { } }
Снова изменим наши
методы для использования новых функций:
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setAttr(); LogSystem.w(tag, "onCreate()"); setContentView(view); trackSupportedApp(tag, null); initWl(); initInterface(); } @Override protected void onPause() { super.onPause(); LogSystem.w(tag, "onPause()"); this.mPaused = true; wlRelease(); } @Override protected void onResume() { super.onResume(); LogSystem.w(tag, "onResume()"); this.mPaused = false; wlAsquire(); }
Использование SceletonActivity
Теперь я покажу, как
упростилась работы при разработке наших Activity. Разработаем приложение, содержащее 2 Activity и кнопки для перемещения между
ними.
Пример файла strings.xml
<resources>
<string name="btn_next">Следующее
Activity</string>
<string name="btn_previous">Предыдущее Activity</string>
<string name="app_name">Skeleton Example</string>
</resources>
Пример файлов макетов
для наших Activity:
first.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/btn_next"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/btn_next" />
</LinearLayout>
second.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/btn_previous"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/btn_previous" />
</LinearLayout>
И сами классы:
FirstActivity.java
public class FirstActivity extends SceletonActivity { @Override protected void initInterface() { Button btn = (Button)findViewById(R.id.btn_next); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(FirstActivity.this, SecondActivity.class); startActivity(intent); } }); } @Override protected void setAttr() { this.tag = FirstActivity.class.getSimpleName(); this.view = R.layout.first; } }>
SecondActivity.java
public class SecondActivity extends SceletonActivity { @Override protected void initInterface() { Button btn = (Button)findViewById(R.id.btn_previous); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { finish(); } }); } @Override protected void setAttr() { this.tag = SecondActivity.class.getSimpleName(); this.view = R.layout.second; } }
Как видите,
повторяющегося кода нет, сам код достаточно компактен, а наши Activity многофункциональны.
Не забудьте добавит
созданные Activity в AndroidManifest:
<activity
android:name=".FirstActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN"
/>
<category android:name="android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
<activity
android:name=".SecondActivity"
android:label="@string/app_name" >
</activity>
Атрибут mPaused
Как я и обещал, расскажу
немного об атрибуте mPaused, который используется для отслеживания паузы в
приложении. Как его можно использовать? Бывает, что при нажатии на кнопку,
действие происходит не сразу (девайсы разные бывают), и пользователь может
произвести повторное нажатие, которое, например, было бы в вашем приложении не желательно.
Для этого и используется mPaused. Пример использования:
btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (!mPaused) { Intent intent = new Intent(FirstActivity.this, SecondActivity.class); startActivity(intent); mPaused = true; } } });
Ссылки
Исходные коды данного проекта можно скачать отсюда: zip
Комментариев нет:
Отправить комментарий