Android

Feb 07, 2011 51 Replies

To zabezpieczenie nie ma sensu, gdy len == 0 pętla się po prostu nie wykona. A jaki wyjątek rzuca?

A może problem wynika z tego, że jak nic nie wpiszesz to dostajesz null, na rzecz którego próbujesz wywołać jakieś metody? Już buf.length może być problematyczne. Wtedy potrzebny byłby test na null i tyle.

W dniu 09.02.2011 19:59, Lelek@ pisze:

Chyba trochę namieszałeś: > byte buf[] = new byte[256]; Tworzysz nową tablicę typu byte. Powinna być czytelna w odróżnieniu od tablicy Byte w której trzeba dodatkowo utworzyć każdy element.

//A mo¿e problem wynika z tego, ¿e jak nic nie wpiszesz to dostajesz //null, na rzecz którego próbujesz wywo³aæ jakie¶ metody? Ju¿ buf.length //mo¿e byæ problematyczne. Wtedy potrzebny by³by test na null i tyle.

wywalenie buf.length z kodu zakomentowanie go nic nie daje

// To zabezpieczenie nie ma sensu, gdy len == 0 pêtla siê po prostu nie // wykona. A jaki wyj±tek rzuca?

Nie wiem jak to sprawdziæ, bo dopiero od tygodnia to robiê :-) Nie wiem gdzie tam sa debugery, ktore co¶ pokazuj± :-) Podpowiedz mi :-)

Co do petli for(;;;) to mo¿e jej nie byæ. Chodzi o to, ¿e jak d³ugo¶æ jest 0 len=0 to nie wolno mi czytaæ buf[] bo aplikacja siê zamyka bez powodu :-) Jestem zdumiony tym zachowaniem. W ogóle jestem zdumiony, ¿e nie ma UNSIGNED w ca³ej tej javie i wszystko co sie chce robiæ trzeba robiæ na wiekszych, szczególnie boli uINT ¿e trzeba go obrabiaæ w LONG i stale maskowaæ & 0xFFFFFFFFL

Ja to wiem i ty to wiesz ale czemu oddaje pamiêæ przed koñcem funkcji? tfu metody i to jeszcze "likely" :-)

Kto¶ na pl.comp.programming zapoda³ ¿eby zadeklarowaæ ten buf[] jako final hmmm. Czy¿by w javie mo¿na tym zakazaæ wtr±caæ siê w tê tablicê ? To i ma w pewnym stopniu sens. Zaraz sprawdzê :-)

Przed koncem ? Raczej powinna przed poczatkiem - jak rozumiem to getBytes alokuje nowy bufor na odpowiedz.

Przy odrobinie optymalizacji moze nawet nie alokuje wtedy gdy wyraznie piszesz new ..

J.

byte buf[] = {0,0,0,0,0,0,0,0,0,0...............} Tak 256 razy. Nie wiem co to zmieni, bo samego byte buf[256] sie nie da w javie. Nie rozumiem ró¿nicy.

W dniu 2011-02-09 19:59 Lelek@ napisał(a):

[...]

Hmmm, coś chyba ściemniasz. Skopiowałem twój przykładowy kod i odpaliłem w emulatorze 2.2. Na głównej aktywności mam kontrolkę edycyjną o nazwie "editText1". Tak wygląda cała metoda (podpiąłem jej wywołanie pod naciśnięcie dodatkowego przycisku):

public void test() { EditText editText = (EditText) findViewById(R.id.editText1); String fromEditText = editText.getText().toString();

byte buf[] = new byte[256]; int bfx[] = new int[256]; int i, len;

try { buf = fromEditText.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); return; }

len = buf.length;

for (i = 0; i < len; i++) { bfx[i] = ((int)buf[i] & 0xFF); Log.d("TEST", "BYTE: " + bfx[i]); } }

Znajduje się tu wszystko, co przytoczyłeś plus dodatkowy kod na początku do odczytania ciągu znaków z kontrolki edycyjnej. Początkowe zaalokowanie bufora buf nie ma znaczenia bo metoda getBytes() i tak zwraca tablicę bajtów i zmienna buf zostanie nadpisana. Prościej jest nie deklarować tej zmiennej na początku tylko dopiero gdy jest potrzebna, np: byte buf[] = fromEditText.getBytes("UTF-8");

W każdym razie uruchomienie daje spodziewane rezultaty. Gdy kontrolka jest pusta to nic się nie wywala, metoda getBytes() zwraca pustą tablicę a nie null, w zmiennej len mamy wartość 0 i nic się nie wypisuje.

Natomiast gdy do kontrolki edycyjnej wpiszę jakiś tekst to także powyższy kod działa zgodnie z oczekiwaniami. Na debugu (to ten magiczny LogCat, w Eclipse możesz go pokazać wybierając z menu: Window/Show view/Other/Android/LogCat albo prościej naciskając Ctrl+3 i wpisując "logcat") jest to pokazywane:

02-09 22:04:03.585: DEBUG/TEST(336): BYTE: 97 02-09 22:04:03.585: DEBUG/TEST(336): BYTE: 100 02-09 22:04:03.585: DEBUG/TEST(336): BYTE: 97 02-09 22:04:03.585: DEBUG/TEST(336): BYTE: 109

Chyba nie unikniesz pokazania większego kawałka kodu aby ustalić co się wywala właściwie. Możesz spakować cały projekt i wrzucić gdzieś na sieć?

Mam dok³adnie tak jak ty masz. Moja metoda nazywa sie

public void Button1Click(View view) {

} I w niej to samo.co ty

W XML-u layoutu jest android:onClick="Button1Click" I to wszystko. Z tym sprawdzeniem zera dzia³a jak tego obaj oczekujemy. Wszystko gra. Sorki ale ca³o¶ci ciê¿ko by by³o pokazaæ :-) Wiesz jak jest :-)

No to chyba się wyjasniło

Tutaj buf jest referencją do twojej tablicy...

Ale tutaj już buf jest referencją do obiektu zwróconego przez FromEditText.getBytes(). Wskazanie do tablicy, która zaalokowałeś zostało stracone i przydzieloną pamięcią zajmie się przy najbliższej okazji garbage collector. Powyższy kod jest równoważny takiej linijce:

byte buf[] = FromEditText.getBytes("UTF-8");

Ja bym twój kod przepisał do takiej postaci:

byte buf[] = FromEditText.getBytes("UTF-8"); int bfx[] = nil; if(buf.length>0) { bfx[] = new int[buf.length]; for (i = 0; i < buf.length; i++) { //elementy buf mają po 8 bitów, więc maskowanie 0xff //jest trochę bez sensu bfx[i] = ((int)buf[i] & 0xFF); } }

if(bfx!=nil) { //robimy cos z bfx }

Bardzo ważne jest alokowanie pamięci na bfx po odczytaniu zawartości buf. Przy alokowaniu bfx o stałej długości, dopóki FromEditText.getBytes zwróci tablicę mniej niż 256 bajtów, program będzie działał poprawnie. Ale jeśli buf będzie dłuższe niż długość bfx, program wywali się z błędem dostępu do pamięci przy próbie zapisu pierwszego elementu, który się nie mieści w bfx.

BTW. próbowałeś przechwytywać wyjątki?

pzdr. j.

if(buf.length>0) <----------- on tego nie rozumie

dla niego ten buf nie istnieje. Trzeba go zadeklarowaæ globalnie w funkcji

To nie jest a¿ tak bez sensu, bo casting signed byte to sign integer kopiuje

8-my bit do 31-go a w³a¶ciwie rozszerza np (int)0x80 -> FFFFFF80 bo signed a nie 0x80 :-)

Zadeklaruj buf tak, żeby był widoczny wszędzie gdzie występują odwołania do niego. Z kodu, który zacytowałeś wynikało że buf jest deklarowany na tym samym poziomie zagłębienia co odwołanie do FromEditText.getBytes(). A ifie brakuje jeszcze jednego warunku: if((buf != nil ) && (buf.length>0))

A fakt. Zasugerowałem się typem buf i przyjąłem że bfx też jest typu byte :)

pzdr. j.

Ta Java to jeden wielki s*it :-) Jak siê operuje na strumieniach danych binarnych to w kó³ko trzeba konwerowaæ to co zwracaj± funkcje w byte signed do signed int ale wymaskowywaæ je. Idiotyzm.

Nie wiem, na razie dzia³a z tym testem czy len jest 0 czy nie, twoich rad nie umiem zastosowaæ. Nie rozumiem jak mam deklarowaæ ten sam bufor wiele razy :-) Przegl±dam od 10 dni ju¿ to co ludzie pisz±cy w javie wyprawiaj±. Dok³adnie robia to jakby zaczynali progframowaæ w bascomie i nie rozumiej± co czyni± :-) Z tego co siê dowiedzia³em to Java powsta³a bo ludzie nie rozumieli wska¼ników i zapominali o zwalnianiu zaalokowanych zasobów :-)

S*it bo nie umiesz się nią posłużyć. Napisałem w javie dobrych kilkadziesiąt tysięcy linii i uważam że jest to całkiem przyjemny język. Inne języki też znam, więc mam porównanie.

Nie bardzo wiem o co chodzi, ale mam wrażenie że usiłujesz zrobić coś na około.

Jak powiesz czego nie rozumiesz, to może będę mógł Ci pomóc. Na razie widzę że walczysz z samą ideą obiektów. Bufora nie deklarujesz kilka razy. Samą zmienna buf deklarujesz raz, w takim miejscu żeby była widoczna ze wszystkich miejsc w których musisz się do niej odwoływać (ale bez przesady. Najprawdopodobniej wystarczy ze zadeklarujesz ją lokalnie w funkcji). Buf w twoim przypadku przechowuje nie sam obiekt, a referencję do niego (referencja działa troszkę podobnie jak wskaźniki w C, choć to nie do końca jest to samo). Funkcja FromEditText.getBytes() sama alokuje pamięć na tablicę zawierającą wynik i zwraca Ci wskazanie na nią. Ta referencja jest wpisywane do zmiennej buf. Jeśli przed wywołaniem funkcji było w niej coś innego, poprzednia wartość jest tracona, a w jej miejsce jest wpisywana wartość zwracana przez przez getBytes. Nie następuje tam żadne przepisywanie tablic (dlatego nie trzeba wcześniej alokować pamięci).

Wszelkie operacje jakie wykonasz na zmiennej buf po wpisaniu do niej wartości zwróconej przez getBytes będą wykonywane nie na twojej tablicy, a na tablicy zaalokowanej wewnątrz funkcji. Sprawdzanie warunku buf.length jest potrzebne po to, żeby nie tworzyć tablicy o zerowej długości (przypisanej do bfx).

Może to ci, którzy przesiadają się na jave z bascoma :) Ja też widziałem dużo śmieci, ale też bardzo dużo kodu bardzo dobrej jakości.

Nie tyle zapominali, co woleli się skupić na rozwiązaniu problemu zamiast babrać się z gospodarką pamięcią. Operując na wskaźnikach bardzo łatwo z prostego programu stworzyć koszmarek - java stara się do tego nie dopuścić (a przynajmniej nie przez jeżdżenie po pamięci). Mając do dyspozycji dużo wolnego ramu, nie trzeba się martwić żeby jak najszybciej zwolnić przydzielony a nieużywany obszar. Ręczna gospodarka przydzielaną pamięcią w bardziej skomplikowanych projektach może przypominać chodzenie po polu minowym. Nic dziwnego że nawet najlepszym i najbardziej uważnym programistom zdarza się popełnić głupie błędy, typu nie zwalnianie czegoś czy wielokrotne zwalnianie. Mechanizm odzyskiwania nieużywaniej pamięci jest implementowany w wielu językach wysokiego poziomu. Java jest tylko jednym z nich.

pzdr. j.

Sam siê ¶miejesz ¿e Java to takie C ale nie rozumiesz, ¿e robisz w tej Javie co¶ w stylu:

char data[100]="abcedefghijklmnoprstuwz"; char * buf = (char*)malloc(100);

a potem robisz co¶ na kszta³t:

buf = data;

zamiast

strcpy(buf, data);

I dziwisz siê, ¿e nie masz tam tego, co zwróci³o malloc(). Pomy¶l chwilkê...

Dnia 07-02-2011 o 12:39:30 Lelek@ snipped-for-privacy@nndn.pl napisał(a):

Wszystko jest totalną porażką jeśli się nie ma odpowiedniej wiedzy :) Jedyne do czego można się przyczepić to, że kompilator Cie nie ostrzegł przed użyciem niezainicjowanej zmiennej. No chyba, że ostrzegł, tylko należysz do tych co instrukcje obsługi czytają dopiero jak wszystkie inne sposoby zawiodą :)

Alez byla zainicjowana i to nawet dwa razy.

Co najwyzej Javie brakuje definicji funkcji ktora moze zwrocic NULL zamiast referencji i ostrzegania jesli programista nie sprawdza tego warunku przed odwolaniem :-)

J.

Dnia 11-02-2011 o 14:06:52 J.F. <jfox snipped-for-privacy@poczta.onet.pl> napisał(a):

hmm.. jeszcze raz przejrzałem posty Lelka i nie widzę, żeby gdzieś ją inicjował.

Zwykła Java z tego co kojarzę inicjuje takie pola jedynie w wypadku gdy są to prywatne pola klasy. Pól deklarowanych w metodach Java nie inicjuje - w sensie "zeruje obszaru pamięci zajmowanej przez to pole". Tak jest w "zwykłej" javie.. nie wiem natomiast jakie cuda z tym kodem źródłowym czynią narzędzia dla AVR. Możemy się wymądrzać a okaże się, że całe to zamieszanie jest efektem niezamierzonym :)

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required