Kitek's Page Blog programisty / webdeveloper'a

Android - własne czcionki

W przypadkach gdy nadworny grafik wymyśli sobie fantazyjne napisy na wizualizacji aplikacji lub domyślny systemowy font nam się znudził możemy wgrać własną czcionkę i trochę poszaleć. Poniżej przedstawiam prosty sposób na zastosowanie dowolnych czcionek z TextView.

  1. Nasze fonty umieszczamy w katalogu assets/fonts (jeżeli nie mamy takiego tworzymy go)
  2. Na wybranym TextView ustawiamy Typeface z naszą czcionką:
Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/GloriaHallelujah.ttf");
		
TextView tx1 = (TextView) findViewById(R.id.tx1);
tx1.setTypeface(tf);

Czcionki możemy ściągnąć ze strony Google Fonts.

Android TextView - Przykład zastosowania różnych fontów Przykład zastosowania różnych czcionek

Redis - ograniczone kolekcje

Pracując nad aplikacją wykorzystującą Redis’a potrzebowałem prostego mechanizmu umożliwiającego przechowywanie kilkuset ostatnich logów. Istotne było ograniczenie maksymalnej ich liczby, a także zapewnienie odpowiedniej rotacji. Dzięki zastosowaniu list i poleceń: lpush i ltrim możliwe jest stworzenie ograniczonej kolekcji.

var rc = redis.createClient("host", "port"),
    cacheName = "my-logs",
    maxLogSize = 100,
    logData = {"key":"value"};

rc.lpush(cacheName, JSON.stringify(logData));
rc.ltrim(cacheName, 0, maxLogSize);

Async.js

Programując w języku JavaScript prędzej czy później natkniemy się na asynchroniczne callback’i, które w dużych ilościach mogą tworzyć swojego rodzaju “wodospady”. Poniższy kod w dużym uproszczeniu obrazuje omawiany przypadek:

function doSomething(id, callback) {
	var cacheName = "someCache-"+id;
	// Check cache first
	getFromCache(cacheName, function(results) {
		if(null === results) {
			// if null get from database
			getFromDb("SELECT * FROM t WHERE id = "+id,function(rows) {
				// set cache 
				setToCache(cacheName, rows, function(err) {
					// return values
					callback(rows);
				});
			});
		} else {
			// return cached values
			callback(results);
		}
	});
}

Przedstawiony kod jest po pierwsze mało czytelny, po drugie posiada wiele zagnieżdżeń, a po trzecie można łatwo nadpisac wyniki poprzednich funkcji. Powyższy kod w łatwy sposób możemy zrefaktoryzować przy pomocy biblioteki Async.js.

Async.js jest biblioteką początkowo zaprojetktowaną dla Node.js ,jednak działa również w nowoczesnych przeglądarkach. Oferuje szereg ciekawych możliwości, około 20 funkcji usprawniających m.in. tworzenie asynchronicznych bloków kodu. Poniżej zostały opisane tylko wybrane z nich:

.series(tasks, [callback])

Uruchamia funkcje w podanej kolejności. Po zakończeniu jednej funkcji uruchamiana jest następna. Jeżeli któryś z podanych bloków zwróci błąd do callback’a przerywane jest wykonywanie całej kolejki. W przypadku poprawnego wykonania wszystkich kroków wyniki zwracane są jako tablica.

function doSomethingOther(params, results) {
	async.series([
		function checkIfUserExists(callback) {
			// do something
			callback(null, 'exists');
		},
		function checkIfUserIsBanned(callback) {
			// do something
			if(isBanned) {
				// fail, break queue
				callback('User is banned');
				return;
			}
			callback(null, 'notBanned');
		},
		function checkIfUserHasPrivileges(callback) {
			// do something
			callback(null, 'hasprivileges');
		}
	], 
	function result(err, results){
		if(err) {
			// something went wrong
		} else {
			// results = ['exists','notBanned','hasprivileges'];
		}
	});
}

Pierwszym parametrem funkcji result jest err, który zawiera informację o ewentualnym błędzie. Domyślna wartość (w przypadku braku błedu) err to undefined, warto o tym pamiętać tworząc porównania.

.waterfall(tasks, [callback])

Funkcja podoba do wcześniej omówionej series z tą różnicą, że dodatkowo umożliwia przekazywanie wyników do następnego kroku.

async.waterfall([
	function step1(callback) {
		callback(null, 'result 1');
	},
	function step2(arg1, callback) {
		// arg1 = 'result 1'
		callback(null, 'result 2', 'result 3');
	},
	function step3(arg1, arg2, callback) {
		callback(null, 'result 4');
	}],
	function result(err, lastResult) {
		// lastResult = 'result 4'
	}
);

W tym przypadku domyślna wartość err to null.

.parallel(tasks, [callback])

async.parallel([
	function step1(callback) {
		setTimeout(function() {
			console.log('step1');
			callback(null, 'result 1');	
		}, 8000);
	},
	function step2(callback) {
		setTimeout(function() {
			//callback(null, 'result 2');
			console.log('step2');
			callback('Error!');
		}, 50);
	},
	function step3(callback) {
		setTimeout(function() {
			console.log('step3');
			callback(null, 'result 3');
		}, 100);
	}],
	function result(err, results) {
		console.log(err);
		console.log(results);
	}
);

Umożliwia uruchomienie kilku funkcji jednocześnie. W przypadku poprawnego wykonania się każdej funkcji wyniki zwracane są w odpowiednio posortowanej tablicy results. Gdy wystąpi bład to główny callback wywoływany jest natychmiast. Uruchomione wcześniej funkcje nie zostaną przerwane. Domyślna wartość (w przypadku braku błedu) err to undefined.