ActivityManager

W pewnych przypadkach zachodzi potrzeba sprawdzenia czy w naszej aplikacji znajdują się inne “działające” Activity niż to, które obecnie jest na froncie. Można to osiągnąć za pomocą klas ActivityManager i RunningTaskInfo. Poniżej przedstawiono sposób użycia.

ActivityManager mngr = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<activitymanager.RunningTaskInfo> taskList = mngr.getRunningTasks(10);
if (taskList.get(0).numActivities == 1 
	&& taskList.get(0).topActivity.getClassName().equals(this.getClass().getName())) {
	// Tylko jedno activity, te które obecnie jest na froncie
}

Możliwe jest również pobranie szerszej informacji:

Iterator<runningtaskinfo> itr = taskList.iterator();
while (itr.hasNext()) {
	RunningTaskInfo runningTaskInfo = (RunningTaskInfo) itr.next();

	// Informacje
	int id = runningTaskInfo.id;
	CharSequence desc = runningTaskInfo.description;
	String topActivity = runningTaskInfo.topActivity.getShortClassName();
	int numOfActivities = runningTaskInfo.numActivities;
}

Do poprawnego uruchomienia powyższych przykładów wymagane jest zdefiniowania uprawnienia GET_TASKS.

<uses-permission android:name="android.permission.GET_TASKS"/>

Sprite Cow

Zawsze gdy mam do czynienia z potocznie zwanymi “sprajtami” sięgam po narzędzie Sprite Cow ułatwiające wygenerowanie odpowiednich klas w CSS. Użycie jest bardzo proste: ładujemy nasz plik, klikamy myszką na interesującą nas ikonkę i dostajemy wygenerowaną klasę CSS wraz ze współrzędnymi ikonki.Sprite Cow

Headless fragments

Android udostępnia świetne rozwiązanie w postaci fragmentów, które może zostać wykorzystane również jako narzędzie do obejścia “resetowania” naszego Activity przy zmianie orientacji/konfiguracji urządzenia. W sytuacjach gdy potrzebujemy wykonać pewne zadanie w tle (np. AsyncTask: autoryzujący użytkownika przez HTTP Api lub wysyłający duże dane do zewnętrznego serwera) każde obrócenie urządzenia wywoła naszego AsyncTask’a ponownie. Oczywiście możemy zablokować na stałe możliwość zmiany orientacji ekranu lub nadpisać metodę obsługującą zmiany w konfiguracji jednak w większości przypadków nie są to rozwiązania dobre lub odpowiadające naszym wymaganiom.
Z powodzeniem do takich zadań możemy wykorzystać fragmenty nie posiadające swoich widoków. Poniżej przedstawiam prosty przykład samego fragmentu jak i sposobu jego uruchamiania.

HeadlessFragments.java

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;

public class HeadlessFragments extends Fragment {

	public static final String TAG = "HeadlessFragments";

	// Pomocniczy interfejs do raportowania zdarzen AsyncTask'a
	public static interface TaskCallbacks {
		void onPreExecute();

		void onProgressUpdate(int percent);

		void onCancelled();

		void onPostExecute();
	}

	private TaskCallbacks mCallbacks;
	private MyTask myTask;

	@Override
	public void onAttach(Activity activity) {
		super.onAttach(activity);
		// W tym miejscu przypisujemy activity w ktorym nasz fragment zostal
		// utworzony.
		// Oczywiscie te Activity musi implementowac powyzej zdefiniowany
		// interfejs
		mCallbacks = (TaskCallbacks) activity;
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// Ta linijka jest bardzo istotna, dzieki niej nasz fragment zostanie
		// zachowany (a nie tworzony od nowa) przy zmianie orientacji ekranu
		setRetainInstance(true);
		// Uruchom nasze zadanie
		myTask = new MyTask();
		myTask.execute();
	}

	@Override
	public void onDetach() {
		super.onDetach();
		mCallbacks = null;
	}

	private class MyTask extends AsyncTask {

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			if (null != mCallbacks) {
				mCallbacks.onPreExecute();
			}
		}

		@Override
		protected Void doInBackground(Void... params) {
			// TODO Tutaj wykonuje zadanie
			return null;
		}

		@Override
		protected void onProgressUpdate(Void... values) {
			super.onProgressUpdate(values);
			if (null != mCallbacks) {
				// mCallbacks.onProgressUpdate(values[0]);
			}
		}

		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			if (null != mCallbacks) {
				mCallbacks.onPostExecute();
			}
		}

		@Override
		protected void onCancelled() {
			super.onCancelled();
			if (null != mCallbacks) {
				mCallbacks.onCancelled();
			}
		}
	}
}

MainActivity.java

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;

public class MainActivity extends FragmentActivity implements
		HeadlessFragments.TaskCallbacks {

	public static final String TAG = "MainActivity";

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		FragmentManager fragmentManager = getSupportFragmentManager();
		HeadlessFragments taskFragment = (HeadlessFragments) fragmentManager
				.findFragmentByTag(HeadlessFragments.TAG);
		if (taskFragment == null) {
			taskFragment = new HeadlessFragments();
			fragmentManager.beginTransaction()
					.add(taskFragment, HeadlessFragments.TAG).commit();
		}
	}

	@Override
	public void onPreExecute() {
		// TODO Auto-generated method stub
	}

	@Override
	public void onProgressUpdate(int percent) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onCancelled() {
		// TODO Auto-generated method stub

	}

	@Override
	public void onPostExecute() {
		// TODO Auto-generated method stub
	}

}

“Szybszy” emulator Androida

Jakiś czas temu przerzuciłem się z domyślnego emulatora dostarczonego przez Google’owe SDK na narzędzie przygotowane przez genymotion.com. Nowy emulator podobno miał szybciej działać i sprawniej uruchamiać aplikacje… no i się nie zawiodłem. Różnice w szybkości widać szczególnie na komputerach, które nie posiadają możliwości sprzętowego przyśpieszenia emulatora (Intel HAXM). Jedyną aktualną wadą jest mała liczba dostępnych obrazów z wersjami Androida. Emulator jest darmowy, a do jego pobrania wymagane jest założenie konta na genymotion.com.

Sublime Text 2

Po online’owej liście ToDo przyszedł czas na świetny edytor Sublime Text 2. Napisany w Pythonie, dostępny praktycznie na wszystkie platformy, z bardzo dużą bazą plugin’ów.

Kilka podstawowych zalet edytora:

  • Szybki, nawet przy dużych projektach
  • Praca z wykorzystaniem wielu kursorów
  • Fuzzy Search dla otwierania plików i komend
  • Możliwość integracji z Git’em i SVN
  • “Mapa kodu” ułatwiająca przewijanie długich plików
  • Wyszukiwanie/zamiana z wykorzystaniem Regexpa z podglądem na żywo
  • Wsparcie większości języków programowania
  • Możliwość sprawdzania poprawności składni “live” np.: PHP, JS
  • Wygodny “Package Control” – umożliwiający przeglądanie i instalację pluginów

Program można ściągnąć i korzystać z niego za darmo (pełna wersja to koszt 59$). Jedyne “nieudogodnienie” wersji free to wyskakujące co pewien czas (co któryś zapis dokumentu) okno z informacją zachęcającą do zakupu programu.

Polecam zapoznanie się z features’ami na stronie samego programu jak również obejrzenie kliku video tutoriali.