Od dziś łamiemy tekst w htmlu

Jeśli kiedykolwiek przygotowywałeś tekst do druku i łamałeś manualnie tekst z przenoszeniem, polubisz to:

.dywiz {
	overflow-wrap: break-word;
	word-wrap: break-word;
	-webkit-hyphens: auto;
	-ms-hyphens: auto;
	-moz-hyphens: auto;
	hyphens: auto;
}

Niestety chrome nie robi…

caniuse

Więcej...

Prawdopodobieństwo wyrzucenia siódemki dwiema kostkami jest największe

Wyobraźmy sobie rzut kostką. Jedną kostką. Niech wynik rzutu nią będzie losowy. Oczywiście w przedziale od 1 do 6, mówimy o kostce sześciennej.

Wynik rzutu dwiema takimi kostkami (przedział 2 do 12) już losowy nie jest, mimo iż wydaje się to nielogiczne, skoro wynik rzutu jedną i drugą oddzielnie nadal losowy jest.

Prześledźmy wszystkie opcje… (więcej…)

Więcej...

AsyncTask i zakończona Aktywność na androidach

Na Androidach pre Honeycomb (api 11 czyli android 3.0) bez najmniejszych problemów można było wywołać dowolną procedurę typu pobierz dane (powiedzmy xml) z Internetu, obrób je, a następnie wyświetl. Wszystko w wątku UI.

Od czasu Honeycomb, przy próbie wykonania najprostszego pobrania danych metodą new URL().openStream() aplikacja się wywali zwracając NetworkOnMainThreadException.

Najprostszym sposobem na uniknięcie tego jest stworzenie nowego wątku i uruchomienie go, new Thread(new Runnable(){…}), bardziej zaawansowani programiści stworzą sobie klasę typu extends AsyncTask i użyją jej trzech metod: onPreExecute(), doInBackground(), oraz onPostExecute().

I tak powstanie kolejny problem, mianowicie, co jeśli w trakcie metody doInBackground() użytkownik (lub system) zamknie, czy zapauzuje naszą aplikację (na przykład do usera ktoś zadzwoni) a metoda onPostExecute() wykonuje coś na wątku UI, który w tej sytuacji jest albo w stanie pauzy (po onPause()) lub w ogóle go nie ma (po onDestroy())? Aplikacja także się wywali, w pierwszym wypadku zwracając tajemniczy BadTokenException, w drugim prawdopodobnie NullPointerException, choć to już zależne jest od innych czynników, bo może się zdarzyć, że aplikacja się zablokuje, ponieważ referencja do naszego AsyncTask, który jeszcze się wykonuje, nie mogła zostać wyczyszczona przez Garbage Collectora podczas onStop() ani onDestroy().

57[1]

Rozwiązanie jest dość proste, choć z ilości pytań na stackoverflow wynika, że niewielu je zna. Należy do konstruktora naszej klasy extends AsyncTask przesłać parametr zawierający naszą aktywność i na jego podstawie stworzyć obiekt klasy WeakReference:

public MyAsyncTask(MainActivity mainActivity) {
   super();
   this.mainActivityWeak = new WeakReference(mainActivity);
}

Następnie w onPreExecute() oraz w onPostExecute() we wszystkich operacjach odwołujących się do naszej mainActivity, która może się w międzyczasie zakończyć, odwołujemy się do WeakReference.get(), najlepiej po sprawdzeniu czy WeakReference.get() nie zakończyła się ani nie kończy się w danym momencie:

if (mainActivityWeak.get() != null &&
   !mainActivityWeak.get().isFinishing()) {
   mainActivityWeak.get().doSomethingOnUiThread();
}

Osobiście popieram z całego serca używanie klas extends AsyncTask do jak największej liczby zadań, które mogą być cięższe niż obliczenie SHA1 🙂 Nie blokują wątku UI i powodują, że aplikacja działa płynniej, a Androidowy MultiThreading cieszy się z kolejnej dobrze napisanej aplikacji.

Więcej...

Iteracja po tablicy i usuwanie wartości

W wielu językach programowania iteracja po tablicach odbywa się mniej więcej tak:

for (foo in arr) {
...
}

Dzięki takiej iteracji po wszystkich elementach, możemy łatwo przeczyścić całą tablicę podczas, na przykład, czyszczenia pamięci z obiektów.

var arr:Array= [];
for (i in 0...100) {
   arr.push(1);
}
for (foo in arr) {
   foo.somePreDisposeFunction();
   arr.remove(foo);
   foo = null;
}
trace(arr.length);

Po uruchomieniu takiego kodu okaże się, że tablica nadal zawiera w sobie obiekty, dokładnie połowę poprzedniej ilości. WAT.

Otóż funkcja remove() wykonana w trakcie pętli usunie obiekt na obecnej pozycji, przesunie tablicę w lewo, a pętla for przesunie obecną pozycję w prawo, tak więc jeden obiekt zostanie pominięty. Dlatego też używaj poniższego:

var arr:Array= [];
for (i in 0...100) {
   arr.push(1);
}
while (arr.length > 0) {
   var foo = arr.pop();
   foo.somePreDisposeFunction();
   foo = null;
}
trace(arr.length);

W ten sposób iteracja i usuwanie (funkcja pop()) wykonywana jest od końca tablicy i nie zagraża w żaden sposób całej pętli.

Więcej...

Manualny recycling w javie na androidzie

Przestań bawić się w manualny recycling obiektów, przyprawi Cię to o potężny ból głowy.
Jeśli musisz uruchomić ponownie aktywność z nowym zestawem zasobów, zakończ obecną i uruchom ją ponownie z odpowiednimi extrami w intencie, zamiast pozbywać się i na nowo ładować obiekty i niech android wykona brudną robotę (garbage collection – you see what I did there?) za Ciebie.

Intent intent = new Intent(this, this.getClass());
intent.putExtra("level", level + 1);
finish();
startActivity(intent);

Polecam też dodać android:launchMode=”singleTask” w tagu w manifeście. Oczywiście do stosowania tylko w przypadkach gdy wiesz co robisz.

Więcej...
>