Przygody z Androidem doprowadziły mnie do momentu, w którym zmuszony zostałem zabawić się w tworzenie własnych elementów wyświetlanej listy. Oczywiście ani stworzenie własnego layoutu, ani adaptera nie jest czymś wielce trudnym... ale potrafi dostarczyć pewnych niemiłych doznań podczas procesu tworzenia. Generalnie problemem, który sprawił, że ten wpis powstał było zadanie generowania innego layoutu (w widoku dropdown) dla elementu obecnie zaznaczonego przez spinner.
Przykład, który tu zostanie przedstawiony można pobrać z chomika: (link)
niedziela, 3 czerwca 2012
niedziela, 20 maja 2012
UFO Afterlight
Kilka dni temu nabyłem UFO Afterlight po promocyjnej cenie 2zł (cała opowieść znajduje się tutaj) i tak się ucieszyłem z tej transakcji, że postanowiłem od razu go zainstalować :) Instalacja przebiegła bez problemów, więc tutaj zastrzeżeń nie mam. I na tym by się skończyła radość ma z bezproblemowego uruchamiania tej gry :(
Na początek ujrzałem magię paranoicznych zabezpieczeń, więc bez ociągania się rozpocząłem poszukiwania sposobu na obejście konieczności instalowania tego "przyjaznego użytkownikowi" oprogramowania. Efektem kilku minut poszukiwań były aż dwa patche (po instalacji dostajemy wersję 1.4)... 1.5 do pobrania ze strony Cenegi (link | mirror) oraz 1.7 ze strony twórców gry - studia ALTAR Games (link | mirror). Co ciekawe 1.7 jest przeznaczony dla wszystkich edycji (w tym dystrybucji cyfrowej) i generalnie nie posiada i nie wymaga żadnych uroczych zabezpieczeń typu STARFORCE.
Tak więc grę zaktualizowałem, wszystko pięknie (notabene wersja 1.7 dodaje menedżer językowy, więc bez trudu można zmieniać język gry :), aż do momentu próby odpalenia gry. Wtedy to pojawia się błąd o braku dllki...
Na szczęście proces patchowania nie usunął tego pliku, a jedynie zmienił jego nazwę na OpenAL32._dll - tak więc nazwę zmieniamy na OpenAL32.dll i już bez dalszych trudów możemy uruchamiać grę :D
Co jednak nie znaczy, że bez dalszych trudów się obędzie. Na mej drodze stanęła o zgrozo rozdzielczość mego monitora w laptopie (1366x768), która to okazała się niewystarczająca pod względem wysokości. Konkretniej część ekranu gry po prostu nie renderowała się i tak ekran ustawień zamiast wyglądać tak:
I żeby nie było, to te guziki były "renderowane", tylko poza ekranem - na co dowód dostarczył podgląd okna Windowsa :P
Na szczęście remedium na ten problem jest bardzo proste - wystarczy otworzyć grę w oknie (odpowiedni skrót z menu start), zmienić rozdzielczość na taką jaka nam odpowiada, a następnie możemy już uruchamiać grę na pełnym ekranie i będziemy widzieć wszystkie elementy gry ^.^ (poza tym okienkowy tryb gry automatycznie skaluje zawartość gry do rozmiaru okna, więc w oknie zawsze widzimy wszystko).
Na początek ujrzałem magię paranoicznych zabezpieczeń, więc bez ociągania się rozpocząłem poszukiwania sposobu na obejście konieczności instalowania tego "przyjaznego użytkownikowi" oprogramowania. Efektem kilku minut poszukiwań były aż dwa patche (po instalacji dostajemy wersję 1.4)... 1.5 do pobrania ze strony Cenegi (link | mirror) oraz 1.7 ze strony twórców gry - studia ALTAR Games (link | mirror). Co ciekawe 1.7 jest przeznaczony dla wszystkich edycji (w tym dystrybucji cyfrowej) i generalnie nie posiada i nie wymaga żadnych uroczych zabezpieczeń typu STARFORCE.
Tak więc grę zaktualizowałem, wszystko pięknie (notabene wersja 1.7 dodaje menedżer językowy, więc bez trudu można zmieniać język gry :), aż do momentu próby odpalenia gry. Wtedy to pojawia się błąd o braku dllki...
Na szczęście proces patchowania nie usunął tego pliku, a jedynie zmienił jego nazwę na OpenAL32._dll - tak więc nazwę zmieniamy na OpenAL32.dll i już bez dalszych trudów możemy uruchamiać grę :D
Co jednak nie znaczy, że bez dalszych trudów się obędzie. Na mej drodze stanęła o zgrozo rozdzielczość mego monitora w laptopie (1366x768), która to okazała się niewystarczająca pod względem wysokości. Konkretniej część ekranu gry po prostu nie renderowała się i tak ekran ustawień zamiast wyglądać tak:
wyglądał tak (nie miał m.in. guzików umożliwiających zmianę ustawień):
I żeby nie było, to te guziki były "renderowane", tylko poza ekranem - na co dowód dostarczył podgląd okna Windowsa :P
Na szczęście remedium na ten problem jest bardzo proste - wystarczy otworzyć grę w oknie (odpowiedni skrót z menu start), zmienić rozdzielczość na taką jaka nam odpowiada, a następnie możemy już uruchamiać grę na pełnym ekranie i będziemy widzieć wszystkie elementy gry ^.^ (poza tym okienkowy tryb gry automatycznie skaluje zawartość gry do rozmiaru okna, więc w oknie zawsze widzimy wszystko).
niedziela, 29 kwietnia 2012
WebBrowser i cieknąca pamięć
Jeśli kiedykolwiek używaliście domyślnego WebBrowsera w C# to za pewne zauważyliście, że ilość pamięci zużywanej przez wasz program rośnie wraz z użytkowaniem tej kontrolki w zasadzie w nieskończoność. Dlaczego tak się dzieje? Cóż dokładnie nie wiadomo, wiadomo jednak, że jest to spowodowane głównie cachowaniem zawartości odwiedzonych stron... dodajmy cachowaniem, którego nie można w całości wyłączyć/wyczyścić. Oczywiście można by sądzić, iż problem ten wynika z leciwości tej kontrolki, jednak ku memu wielkiemu zaskoczeniu to samo dzieje się z WebBrowserem dostępnym wewnątrz WPF (obie kontrolki używają tego samego silnika IE).
Ale po co w ogóle używać kontrolkę WebBrowser? Poza oczywistym zastosowaniem - umożliwienia "przeglądania" Internetu (klikania w łącza, oglądania obrazków, czytania tekstów) można również używać go do parsowania ściągniętych plików HTML, z którymi natywne parsery .NET nie dają sobie rady z racji niezgodnego ze standardem użycia tagów.
Oczywiście to do czego chcemy używać WebBrowser jest sprawą drugorzędną, gdyż wpływa jedynie na to czy istnieje jakieś rozwiązanie alternatywne, czy też skazani jesteśmy na WebBrowsera, który pożre przy sprzyjających dla siebie warunkach wszelkie ilości dostępnej pamięci nie dając w zamian absolutnie nic. W tym wpisie przedstawię kilka sposobów na ograniczenie ilości wyciekającej pamięci, więc jeśli ktoś liczy na to, że znajdzie tu sposób na całkowite zażegnanie tego problemu to spotka go rozczarowanie, gdyż takie sposobu nie znam, ani nigdzie nie mogłem znaleźć... Obalę również kilka mitów krążących po sieci związanych z "magicznymi sposobami" na ograniczenie używanej pamięci. Oczywiście zawsze można zaprzestać używania natywnych kontrolek i wykorzystać kontrolki stworzone w pocie czoła innych programistów (dla porównania w dalszej części przedstawię właśnie kontrolkę Awesomium):
Ale po co w ogóle używać kontrolkę WebBrowser? Poza oczywistym zastosowaniem - umożliwienia "przeglądania" Internetu (klikania w łącza, oglądania obrazków, czytania tekstów) można również używać go do parsowania ściągniętych plików HTML, z którymi natywne parsery .NET nie dają sobie rady z racji niezgodnego ze standardem użycia tagów.
Oczywiście to do czego chcemy używać WebBrowser jest sprawą drugorzędną, gdyż wpływa jedynie na to czy istnieje jakieś rozwiązanie alternatywne, czy też skazani jesteśmy na WebBrowsera, który pożre przy sprzyjających dla siebie warunkach wszelkie ilości dostępnej pamięci nie dając w zamian absolutnie nic. W tym wpisie przedstawię kilka sposobów na ograniczenie ilości wyciekającej pamięci, więc jeśli ktoś liczy na to, że znajdzie tu sposób na całkowite zażegnanie tego problemu to spotka go rozczarowanie, gdyż takie sposobu nie znam, ani nigdzie nie mogłem znaleźć... Obalę również kilka mitów krążących po sieci związanych z "magicznymi sposobami" na ograniczenie używanej pamięci. Oczywiście zawsze można zaprzestać używania natywnych kontrolek i wykorzystać kontrolki stworzone w pocie czoła innych programistów (dla porównania w dalszej części przedstawię właśnie kontrolkę Awesomium):
- Awesomium (strona główna | wraper .NET | licencja)
- geckofx (strona główna)
- WebKit .NET (strona projektu)
wtorek, 27 marca 2012
Jak sprawdzać istnienie używanych elementów?
Pytanie brzmi "jak", bo to, że jakoś weryfikować trzeba to mam nadzieję jest oczywiste :) Generalnie rozchodzi się o kilka sytuacji - np. gdy chcemy zinkludować jakiś plik, lub czytamy tablicę i nie jesteśmy pewni, czy jakiś określony klucz jest w niej ustawiony (choćby w przypadku $_POST/$_GET). Oczywiście PHP jako ten nowoczesny język udostępnia nam kilka możliwości sprawdzenia czy faktycznie mamy co czytać, toteż w tym wpisie spróbuję porównać wydajność tych metod.
Elementy tablicy
Na pierwszy ogień pójdzie sprawdzanie istnienia elementów tablicy. By jednak nie było tak całkiem prosto i by było o czym pisać to założymy, że tablica jest wielowymiarowa, czyli składa się z tablic, które składają się z innych tablic:
if(isset())
Dla każdego przykładu użycia dodałem zarówno wywołanie dla elementu w tablicy się znajdującego (Nested), jak i tego, którego w niej nie ma (Indo).
Jeden if, wiele isset()
Wydawać by się mogło, że sprawdzenie całej ścieżki w pojedynczym isset() jest o wiele lepszym rozwiązaniem niż wielokrotne wywołanie funkcji...
if i isset() dla każdego poziomu
Taki zapis jest jakby typowym "kaskadowym podejściem" do tego zagadnienia.
Wykorzystanie tej konstrukcji tak na dobrą sprawę ma sens albo gdy chcemy szybciej napisać kod ("? :" to zdecydowanie mniej znaków niż "if() else"), albo gdy do danej zmiennej zamierzamy przypisać jakąś wartość (np. parsowanie danych wprowadzonych przez użytkowników)
@element
Oczywiście poza isset() istnieje również metoda "empiryczna"... a dzięki operatorowi @ możemy ignorować generowane przez PHP błędy (Notice: Undefined index) związane z nieistnieniem elementu, do którego się odwołujemy.
Pliki
W przypadku plików również mamy kilka możliwości sprawdzenia czy istnieją.. Jednak tutaj opisze tylko trzy: include, file_exists() oraz is_file().
file_exists()
Funkcja ta generalnie służy do sprawdzenia czy dany plik istnieje.
@include
Tym razem znów skorzystamy ze znanego nam już operatora blokującego informacje o błędach.
is_file()
Ostatnią zaprezentowaną tutaj metodą jest użycie funkcji is_file(), która to zwraca TRUE jeśli wskazana przez nas ścieżka jest zwykłym plikiem lub FALSE w każdym innym przypadku (czyli jeśli np. wskazuje na folder lub nie wskazuje na nic).
Słowo na koniec
Tak więc jeśli chcemy sprawdzić czy w tablicy znajduje się dany element - to używamy isset(). Jeśli zaś chodzi o pliki, to w zależności od tego czy głównym scenariuszem użycia danego bloku kodu będzie wykorzystanie informacji o istnieniu lub nieistnieniu pliku powinniśmy użyć odpowiedniej funkcji - jeśli chcemy odczytać dany plik to używajmy is_file(), jeśli zaś chcemy stworzyć nowy plik o podanej nazwie - użyjmy file_exists().
A na koniec jak zwykle zapraszam do pobrania pliku z kodem użytym do testów: (link)
Elementy tablicy
Na pierwszy ogień pójdzie sprawdzanie istnienia elementów tablicy. By jednak nie było tak całkiem prosto i by było o czym pisać to założymy, że tablica jest wielowymiarowa, czyli składa się z tablic, które składają się z innych tablic:
$arr = array("Nested" => array("Nested" => array("Nested" => "Here")));
Najpopularniejszym sposobem sprawdzania (i generalnie wpajanym wszystkim od maleńkości) czy dany klucz istnieje, jest wykorzystanie funkcji isset(). Tylko, że możemy ją wykorzystać na wiele sposobów...if(isset())
Dla każdego przykładu użycia dodałem zarówno wywołanie dla elementu w tablicy się znajdującego (Nested), jak i tego, którego w niej nie ma (Indo).
if(isset($arr['Indo']['Indo']['Indo'])) $str = $arr['Indo']['Indo']['Indo']; if(isset($arr['Nested']['Nested']['Nested'])) $str = $arr['Nested']['Nested']['Nested'];
if & isset (not exist): 0.016935110092163 if & isset (exist): 0.029613971710205Jak widać PHP szybciej odkryje, że czegoś nie ma... niż, że coś jest :)
Jeden if, wiele isset()
Wydawać by się mogło, że sprawdzenie całej ścieżki w pojedynczym isset() jest o wiele lepszym rozwiązaniem niż wielokrotne wywołanie funkcji...
if(isset($arr['Indo']) && isset($arr['Indo']['Indo']) && isset($arr['Indo']['Indo']['Indo']))
{} else {}
if & isset (multi - line LR) (not exist): 0.019056081771851 if & isset (multi - line RL) (not exist): 0.021497964859009 if & isset (multi - line LR) (exist): 0.056113004684448... i niewątpliwie tak jest.. a na pewno jeśli wszystkie wywołania znajdują się w jednym "if". Dlaczego jednak zamieściłem tu ten przykład? Ano dlatego, że można z niego wynieść ważne informacje:
- PHP sprawdza warunki od lewej do prawej (Left to Right) i kończy obsługę warunku gdy pierwszy z nich == FALSE
Zatem taki zapis jest bardziej efektywny (po lewej warunki najważniejsze).if(isset($arr['Indo']) && isset($arr['Indo']['Indo']) && isset($arr['Indo']['Indo']['Indo'])) {} else {}niż zapis taki (najważniejsze warunki po stronie prawej)if(isset($arr['Indo']['Indo']['Indo']) && isset($arr['Indo']['Indo']) && isset($arr['Indo'])) {} else {} - Sprawdzenie pojedynczego poziomu tablicy jest szybsze niż sprawdzanie kilu poziomów
if(isset($arr['Indo']['Indo']['Indo'])) {} else {} if(isset($arr['Indo'])) {} else {}if & isset([][][])(not exist): 0.022554874420166 if & isset([]) (not exist): 0.016841888427734 if & isset([][][]) (not exist): 0.032048225402832 if & isset([]) (not exist): 0.017351150512695
if i isset() dla każdego poziomu
Taki zapis jest jakby typowym "kaskadowym podejściem" do tego zagadnienia.
if(isset($arr['Indo']))
if(isset($arr['Indo']['Indo']))
if(isset($arr['Indo']['Indo']['Indo']))
{}
Generalnie zaletą tego podejścia jest to, że możemy wcześniej wykryć nieistniejące elementy i nie musimy przeprowadzać analizy całej tablicy. Jeśli jednak nie zależy nam na wykluczeniu istnienia, a jego udowodnieniu, to sens użycia takiego sposobu jest nikły. Do tego dochodzi konieczność obsługi na każdym poziomie kaskady sytuacji nieistnienia elementu.
if & isset (multi - cascade) (not exist): 0.018480777740479 if & isset (multi - cascade) (exist): 0.068065166473389isset() ? operacja : operacja
Wykorzystanie tej konstrukcji tak na dobrą sprawę ma sens albo gdy chcemy szybciej napisać kod ("? :" to zdecydowanie mniej znaków niż "if() else"), albo gdy do danej zmiennej zamierzamy przypisać jakąś wartość (np. parsowanie danych wprowadzonych przez użytkowników)
isset($arr['Indo']['Indo']['Indo']) ? null : null;
isset & ? (not exist): 0.018883943557739 isset & ? (exist): 0.031083106994629Bo jak widać pod względem wydajności metoda ta jest nieznacznie gorsza od starego poczciwego if'a.
@element
Oczywiście poza isset() istnieje również metoda "empiryczna"... a dzięki operatorowi @ możemy ignorować generowane przez PHP błędy (Notice: Undefined index) związane z nieistnieniem elementu, do którego się odwołujemy.
$str = @$arr['Indo']['Indo']['Indo'];
@ (not exist): 0.16418194770813 @ (exist): 0.09358811378479 strict (exist): 0.030779838562012Tylko, że jak widać czas związany z obsługą błędu jest o wiele większy niż czas potrzebny na przeszukanie tablicy przy pomocy isset().
Pliki
W przypadku plików również mamy kilka możliwości sprawdzenia czy istnieją.. Jednak tutaj opisze tylko trzy: include, file_exists() oraz is_file().
file_exists()
Funkcja ta generalnie służy do sprawdzenia czy dany plik istnieje.
if(file_exists("empty.php")) {} else {}
file_exists (exist): 0.030549049377441 file_exists (not exist): 0.048150777816772 file_exists include (exist): 0.10239315032959 file_exists ? include (exist): 0.10641098022461 file_exists include (not exist): 0.048465013504028
@include
Tym razem znów skorzystamy ze znanego nam już operatora blokującego informacje o błędach.
$var = @include "empty.php";
@include (exist): 0.20435905456543 @include (not exist): 0.073977947235107Dlaczego przypisujemy to co zwraca include do zmiennej? Ano dlatego, że include zwracać może dowolne wartości, ale domyślnie (jeśli w includowanym pliku nie dodano returna) zwraca TRUE (jeśli plik załadowano) lub FALSE (jeśli pliku nie udało się załadować).
is_file()
Ostatnią zaprezentowaną tutaj metodą jest użycie funkcji is_file(), która to zwraca TRUE jeśli wskazana przez nas ścieżka jest zwykłym plikiem lub FALSE w każdym innym przypadku (czyli jeśli np. wskazuje na folder lub nie wskazuje na nic).
if(is_file("empty.php")) {} else {}
is_file (exist): 0.00079703330993652 is_file (not exist): 0.064265966415405To co zaskakuje to szybkość z jaką is_file() działa - ok. 40 razy szybciej wykrywa istniejące pliki. Tak więc jeśli szukamy szybkiego sposobu na sprawdzanie czy pliki istnieją - is_file() jest idealnym wyborem. Niestety jego wykrywanie nie istniejących plików jest wolniejsze niż file_exists() - tak więc w zależności od głównego celu naszego bloku kodu powinniśmy wybrać odpowiednią funkcję.
Słowo na koniec
Tak więc jeśli chcemy sprawdzić czy w tablicy znajduje się dany element - to używamy isset(). Jeśli zaś chodzi o pliki, to w zależności od tego czy głównym scenariuszem użycia danego bloku kodu będzie wykorzystanie informacji o istnieniu lub nieistnieniu pliku powinniśmy użyć odpowiedniej funkcji - jeśli chcemy odczytać dany plik to używajmy is_file(), jeśli zaś chcemy stworzyć nowy plik o podanej nazwie - użyjmy file_exists().
A na koniec jak zwykle zapraszam do pobrania pliku z kodem użytym do testów: (link)
Subskrybuj:
Posty (Atom)





