środa, lutego 27, 2019

Powiadomieniami w walce z uzależnienie od WhatsApp i Telegrama ;-)

Z zasady mam wyłączone praktycznie wszystkie powiadomienia na swoich urządzeniach.
Jedynie SMSy i nieodebrane połączenia przechodzące są wyświetlane.

To się jednak chyba zmieni ;-) i pozwolę na wyświetlanie powiadomień z WhatsApp i Telegrama.

Bo trzeba przyznać, mam lekki problem z WhatsApp i Telegramem.

Mam tendencję do uruchamiana ich żeby sprawdzić czy ktoś coś napisał, albo czy przeczytał moją wiadomość.

To jest strasznie uzależniające, bo dość często, ale nie zawsze jest ten mały pik dopaminy, że ktoś coś napisał, albo że przeczytał.

Już wywaliłem obie aplikacje z ekranu startowego, wyłączyłem sugerowane aplikacje... ale nadal umiem otworzyć każdą z nich w ciągu 2 sekund.

Stąd stwierdziłem, że spróbuję inaczej ;-)

Skoro zaglądam do tych aplikacji żeby sprawdzić czy ktoś do mnie coś napisał, to żeby to wyeliminować włączyłem powiadomienia ;-)

Nie dostaję setek wiadomości dziennie, więc nie powinno mi to jakoś szczególnie przeszkadzać, a z drugiej strony będę widział w razie ktoś napisze.

Nadal bez dźwięków i innych takich, ale już są powiadomienia.
Muszę jeszcze tylko sprawić by nie pokazywały mi się na zegarku.

Kto by pomyślał, że z jednej strony wszyscy próbują nas shackować i trzeba się samemu hackować żeby jakoś przetrwać? ;-)

Podobne postybeta
"Odstawianie" telefonu ;-)
Telegram
Pomodoro z positive reinforcement? ;-)
Przydatne narzędzia ;-)
23 kg to "okrągła" liczba ;-)

sobota, lutego 23, 2019

Serializacja w Java'ie - revisited ;-)

Blisko 9 lat temu napisałem chyba najpopularniejszy wpis na moim blogu, o serializacji i relfeksji.

Dziś postanowiłem wrócić do tematu ;-)

Zacznę od tego, że Serializable był rzeczą, która mnie zachwyciła w Java'ie.

Do teraz mnie zachwyca, chociaż już nie tak bardzo ;-)

Czym jest serializacja?
To zamiana obiektu w strumień danych, dzięki czemu można obiekty zapisywać "na później" albo przesyłać.
Po drugiej stronie procesu jest deserializacja, czyli "zbudowanie" obiektu na podstawie tego co wcześniej zapisaliśmy.

Jakie obiekty są serializowalne?
Żeby obiekt był serializowalny w Java'ie MUSI implementować Serializable.
Sam interfejs Serializable jest interfejsem znacznikowym, nie wprowadza wymogu implementacji żadnych metod, a sygnalizuje tylko JVM, że dany obiekt obiecuje, że da się zserializować.

To jest tylko obietnica.
Kompilator w compile time nie jest w stanie stwierdzić czy to jest prawda.
JVM dopiero w runtime próbując dokonać serializacji, czy też deserializacji sprawdza czy jest to możliwe.

Jest to istotne o tyle, że fakt posiadania wśród przodków klasy, które implementuje Serializable i jest serializowalna nie oznacza wcale, że nasza klasa ładnie się zserializuje.

Samo implementowanie Serializable też nie znaczy, że jesteśmy z automatu serializowalni.
By to była prawda musimy zapewnić tą serializowalność.

Pola w nasze klasie, jak i superklasach muszą być serializowalne, oznaczone jako transient albo musimy dostarczyć mechanizmu serializacji.

Wszystkie pola niestatyczne i nie oznaczone jako transient są serializowane, niezależnie od ich widoczności.

Do tego to, że obiekt dało się zserializować nie oznacza od razu, że uda się go zdeserializować.

Czy konstruktory są używane w trakcie deserializacji?
I nie i tak ;-)
Ogólnie nie, jeśli klasa implementuje Serializable to jej konstruktor nie będzie wołany.
Ale, jeśli któryś z przodków po drodze nie implementuje Serializable i nie ma konstruktora domyślnego to mamy problem ;-)
Tutaj warto pamiętać, że jeśli nie napiszemy żadnego konstruktora dla naszej klasy, to Java sama doda bezparametrowy konstruktor domyślny.
Do tego gdy piszemy nasz konstruktor i nie zawołamy w naszym konstruktorze konstruktora klasy bazowej to Java dopisze nam super() jako pierwszą linię naszego konstruktora, czyli wywoła konstruktor domyślny superklasy.
Jeśli nie ma takiego konstruktora to kod nam się nie skompiluje, no chyba że sami zrobimy super z parametrami do jednego z istniejących konstruktorów.

W trakcie deserializacji JVM używa więc konstruktorów dla tych klas które są w hierarchii przed pierwszą klasą oznaczoną jako taka, która implementuje Serializable.

Jeśli ta klasa nie ma konstruktora domyślnego, a nasza klasa ma wywołanie któregoś z niedomyślnych (czyli kod się kompiluje) to choć mamy kompilowalny kod to deserializacja będzie niemożliwa.

Stąd rule of thumb jest, jeśli już musisz używać serializacji/deserializacji to upewnij się, że klasa bazowa na której budujesz swój obiekt implementujący Serializable ma konstruktor domyślny ;-)

Jak zserializować obiekt?
To jest akurat proste, trzeba skorzystać z ObjetOutputStream, tutaj przykład jak to wygląda gdy chcemy nasz obiekt zapisać do pliku:

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("toster.dat")); 
oos.writeObject(obj);
oos.close();

To zapisze nam obiekt do pliku "toster.dat" (oczywiście trzeba jeszcze obsłużyć wyjątki, które mogą stąd polecieć).
To wszystko przy założeniu, że obj, które próbujemy zapisać jest serializowalne.

OK, czyli jak sprawić by obiekt był serializowalny?
Jak już było wyżej, by obiekt był serializowalny wymagania są takie:

  • musi implementować Serializable (lub jedna z jego superklas musi),
  • wszystkie pola muszą być albo:
    • serializowalne (czyli implementować Serializable),
    • byś typami prostymi,
    • być oznaczone jako transient
      • by je zapisać trzeba dostarczyć własny mechanizm serializacji, lub pole takie będzie zignorowane.
Pola, które są typów prostych, lub takich które implementują Serializable zostaną zserializowane przez wbudowane w JVM mechanizmy, pola transient zostaną przez te mechanizmy zignorowane.

Jak zserializować dane z pól oznaczonych jako transient?
Da się ;-)
W takim przypadku trzeba dostarczyć własny mechanizm, który to mechanizm opiera się o 3 metody:

private void writeObject(java.io.ObjectOutputStream out) throws IOException; private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; 
private void readObjectNoData() throws ObjectStreamException;

W trakcie serializacji ważna jest pierwsza metoda, dwie pozostałe są istotne w trakcie deserializacji.

Najpierw wołamy defaultWriteObject(), która to metoda zapisze za nas wszystkie pola niestatyczne i nietransient.
Oczywiście nie ma obowiązku wołania tej metody ;-)
Dalej dajemy kod, który zapisuje wartości które będziemy umieli później wykorzystać do zbudowania obiektu czy obiektów oznaczonych jako transient.

Jak zdeserializować obiekt?

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("toster.dat")); OurType object = (OurType)ois.readObject();
ois.close();


Warto zwrócić uwagę na to rzutowanie w 2 linii, które jest ważne o tyle, że readObject() zwraca Object, który musimy zrzutować na to co wczytujemy.
Oczywiście wypadałoby wcześniej sprawdzić czy to co wczytujemy jest instancją naszego typu i dopiero wtedy rzutować.

Mamy też dla pól oznaczonych jako transient metodę readObject(), która najpierw przy pomocy defaultReadObject(), wczytuje standardowo zapisane pola i po tym implementujemy mechanizm wczytujący pola transient.

W przypadku methody readObjectNoData() napiszę to co napisałem 9 lat temu ;-)
Ostatnią metodą jest readObjectNoData(), której przyznam się nigdy nie musiałem używać :-) więc mogę się w jej opisie oprzeć tylko na opisie z JavaDoc'a. W skrócie metoda ta jest wołana wtedy gdy "podnoszonej" klasy nie ma w strumieniu, który próbujemy odczytać...... ale przyznam, że nie udało mi się tego teraz oprogramować :-(

Oczywiście mechanizm z writeObject/readObject można wykorzystać także do napisania własnego mechanizmu serializacji/deserializacji, nie ma przymusu używania tych wbudowanych w Java'ę.

Serializacja w Java'ie pozwala jeszcze na użycie metod writeReplace() i readResolve(), które służą temu by zapisać alternatywne obiekty.
Powiedzmy, że nasz obiekt jest serializowalny, ale nie chcemy go zapisywać całego, potrafimy zapisać go w "lepszy" sposób, wtedy implementujemy writeReplace() które zwróci inny obiekt, który zostanie zapisany przez domyślny mechanizm serializacji.
readResolve() zostanie użyte w trakcie deserializacji.

Przyznam, że nigdy nie musiałem używać tych 2 metod.

A co z wersjonowaniem?
No właśnie...
Nie jest dobrze z wersjonowaniem.
Obiekt implementujący Serializable powinien mieć statyczne finalne pole typu long o nazwie serialVersionUID, które mówi o wersji obiektu.
W trakcie serializacji wartość tego pola jest zapisywana, a w trakcie deserializacji wartość tego pola jest porównywalna z tą w klasie deserializowanego obiektu i jeśli się nie zgadzają JVM zgłasza wyjątek.
Jeśli nie stworzymy sami tego pola to kompilator zrobi to za nas. Ale jeśli zmienimy cokolwiek w naszej klasie, dodamy pole, usuniemy, albo nawet po prostu zrobimy dowolną edycję w pliku to kolejna skompilowana klasa z naszego pliku będzie miała inną wartość serialVersionUID....
Czyli chociaż mechanizm deserializacji powinien być w stanie odczytać nasz plik to nie będzie umiał.
Nawet nasza własna implementacja readObject nas tu nie uratuje....

Czy powinno się używać serializacji w Java'ie?
Nie do końca ;-)
Po pierwsze problem z wersjonowaniem jest poważny i mocno ogranicza możliwość pracy z Serializable.

Po drugie i chyba ważniejsze ;-) Oracle planuje wyłączenie serializacji w kolejnych wersjach Java'y.

To przez to, że serializacja i deserializacja są źródłem największej ilości błędów bezpieczeństwa w Java'ie.

Wszystko dzięki temu, że cały proces deserializacji to nic innego jak interpreter, a interpretery w samej swej naturze są niebezpieczne.

Stąd jeśli zdecydujesz się na używanie serializacji to z jednej strony ryzykujesz, że któraś z przyszłych wersji Java'y wyłączy ten mechanizm, ryzykujesz też otwarcie powierzchni do ataku swojej aplikacji.

Istnieją też mechanizmy alternatywne, które lepiej nadają się do serializacji i deserializacji obiektów.
Ale to już temat na kolejny wpis ;-)


Podobne postybeta
Refleksje i serializacja w Java'ie - podstawy i obalanie mitów ;-)
Wymiana obiektów między PC a Androidem... - użyj serializacji Luke ;-)
Lenistwo w działaniu, "piklujemy" Androida ;-)
Czemu trzeba pomagać Jacksonowi? ;-)
Konstruktory

piątek, lutego 22, 2019

Kiedy polecimy na Marsa?

Szczerze zawsze mi się wydawało, że Elon Musk i SpaceX są zbyt optymistyczni, bo Elon Musk ma taki sposób estymacji, że bierze najbardziej optymistyczną estymatę i skraca ją o 30-50% zakładając, że ludzie będą pracowali po 100 godzin tygodniowo.

Ale... po obejrzeniu Fist Man o Neilu Amstrongu pooglądałem ile trwał cały program Apollo.
Zaczęli w 1963 roku, a w 1969 wylądowali na Księżycu.
Pierwszy lot człowieka był w 1961 roku.

W 8 lat przeszli od wysłania człowieka w kosmos do lądowania na Księżycu.

Fakt, po stronie USA (które od początku to robiły bardziej planowo i profesjonalnie, Rosjanie robili to tak bardziej amatorsko i na "taśmę klejącą") w porywach wydawano chyba 4.5% rocznego budżetu USA na NASA, ale jednak potrzebowali tylko głupich 8 lat.

Stąd, skoro SpaceX ma jeszcze do 2030 roku 11 lat, to może z tym BFR (teraz zwanym SuperHeavy + Starship chyba) im wyjdzie? Może nawet do 2030 roku wylądujemy na Księżycu znowu?


Podobne postybeta
Coś chyba robimy nie tak w programowaniu ;-)
Dysonans poznawczy roku 2017 ;-)
Ponowne oglądanie Buffy
Świat disco polo...
Książkowa faza - stare hard SF :-)

niedziela, lutego 17, 2019

Gdzie popełniliśmy błąd?

Współczesne tworzenie aplikacji to ciągła walka z narzędziami i bibliotekami.

Dziś postanowiłem usunąć z mojej aplikacji do blogowania, czyli z Bloggeroida możliwość uploadowania obrazków.
Czemu to muszę zrobić?
Bo kiedyś zdecydowałem się używać 3rd party usługi, czyli Picasy od Google do przechowywania obrazków (używam też Bloggera, ale Bloggeroid to klient Bloggera ;-)).
A Google po wielu latach wspierania Picasy uznało, że już jej nie będzie wspierać, że Google Photos są lepsze.
To zabijają Picasę, proponując przejście do Google Photos. Które to Google Photos nie mają możliwości publikacji obrazków tak by były możliwe do osadzenia na innych stronach.

To usunąłem z Bloggeroida odpowiednie fragmenty kodu, a szczerze to nawet nie kod, a jego użycia.

Zrobiłem wersję z podpisem.... próbowałem wrzucić do Google Play Console, które mnie opluło, że nie, bo wersja targetApi jest 25, a powinna być najmniej 26....

To zmieniłem to, ale to wymagało zmienienia wersji narzędzi buildujących....
To znów zmianę wersji bibliotek.

Jak już niby wszystko było OK, to znów Gradle zaczął płakać, że Jack (kompilator który pozwalał używać ficzerów w Java 8) jest deprecated.
Gdy wyłączyłem Jacka to zaczęło płakać, że bez niego nie mogę używać ficzerów z Java 8.

Żeby móc ich używać zainstalowałem wtyczkę Androida do Gradle w wersji 3.0.0 lub wyższej.

To zaczęło płakać, że nie umie pobrać Kotlina z repozytorium od Google...

Zmieniłem wersję Android Studio (bo z IntelliJ i tak nie chciało działać).

Okazało się, że muszę zmienić wersję Gradle'a.

Zmieniłem wersję Gradle'a to okazało się, że moje pliki buildowe są niekompatybilne bo używam compile i testCompile, a powiniennem implementation i testImplementation....

To nie pomogło bo znów coś leci....

Jak rozumiem teraz dlatego, że gdzieś któryś kawałek kodu, którego nie używam, ale używa jakaś biblioteka jest niekompatybilny z najnowszym Gradle....

Gdzie popełniliśmy błąd?

Programiści mieli podobno rozwiązywać problemy przy pomocy kodu, a teraz głównie spędzają czas walcząc z narzędziami.

Wprowadzono narzędzia i biblioteki, które miały ułatwić nam pracę, miały sprawić, że nie będziemy marnować czasu na niepotrzebne zadania.
A w rezultacie dostaliśmy kolejne.

Gdy potrzebujesz zrobić coś bardzo typowego, powiedzmy stworzenie nowego projektu, to coś co zajęłoby Ci może 15 minut zajmie Ci 30 sekund, plus jakieś 30 minut polowania po internecie na instrukcję skąd co pobrać.
Gdy narzędzia przestaną działać spędzisz wiele, naprawdę wiele godzin walcząc z nimi.

Podobne postybeta
Rant po toolach w stylu Mavane, Gradle, Bowera i całej tej hałastry
Tak Maven'ie, zbłądziłem ;-)
Kilka Androidów w domu... jak to jest?
Taki tam rant po Gradle i Dockerze ;-)
Jak zmusić Gradle'a do używania ramdysku (na OS X)

sobota, lutego 16, 2019

Skalowanie miernika jakości powietrza ;-)

Jakiś czas temu kupiłem sobie miernik jakości powietrza.
Ale, jak wykazało porównywanie jego odczytów z tym co mówiły bardziej oficjalne wyniki nie do końca to co pokazywał zgadzało się z rzeczywistością.
Zwykle drań mocno przesadza.

Więc w końcu zrobiłem to co każdy absolwent dowolnego kierunku technicznego czy ścisłego, postanowiłem sprawdzić jak wygląda funkcja opisująca zależność tego co pokazuje mój miernik z tym co pokazują "bardziej oficjalne" mierniki.
Jako bardziej oficjalnego użyłem Airly ;-)

To wrzuciłem wyniki do tabelki:


miernik [PM2.5]Airly [PM2.5]
4019
5323
8127
14241

Później narysowałem wykres w Google Sheets:

Jak widać Google Sheets pokazały mi już nawet równanie ;-) [trzeba się pobawić w Series].
Głębsze oglądanie pokazało mi też, że R2=0.993.

Czyli teraz już wiem, że chcąc poznać rzeczywiste zanieczyszczenie PM2.5 gdy mój miernik coś pokazuje to powinienem wrzucić to do wzoru:

Prawdziwe_PM2.5=0.21*wynik_PM2.5_z_miernika+10.9

Albo po prostu podzielić wynik przez 5 i dodać 11 ;-)

Tutaj taka uwaga, mój miernik mierzy przy pomocy diody, pewnie nie używa rozproszenia Rayleigha, a patrzy pewnie tylko na ilość odbitego, albo przepuszczonego światła...
Więc możliwe, że np. PM10 też mocno wpływa na wzór, tego jeszcze nie wiem ;-)

Ale wszystko wskazuje, że jak mój miernik już panikuje i pokazuje:


Z podpisem Moderate, to tak naprawdę PM2.5 wynosi jakieś 18.5 µg/m3, a nie 35.9 µg/m3 ;-)



Podobne postybeta
Airly + Python + Oczyszczacz Powietrza = lepsze oddychanie ;-)
Algorytm - czemu w szkole nie uczą jak obliczyć pierwiastek? ;-)
Spektroskop z płyty CD :-)
Chyba wiem czemu widzę Gdynie z Juraty ;-)
3 Home w jednym domu ;-)