Pokazywanie postów oznaczonych etykietą 15'dev. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą 15'dev. Pokaż wszystkie posty

czwartek, 20 sierpnia 2020

Android Basics - User Interface

Tego kursu wcześniej nie słuchałam i jak teraz usłyszałam, że to dla kogoś, kto nigdy nie napisał ani jednej linijki kodu, to zaczęłam wątpić...

Ale dobrze, pomyślałam, przekonaj się, że to umiesz, a przy okazji może usłyszysz jakąś informację, o której nie wiesz. I tak dowiedziałam się o:

  • atrybucie android:textAppearance="?android:textAppearanceSmallInverse"  , którego mogę użyć, gdy nie będę wiedzieć jaki rozmiar czcionki wybrać
  • atrybucie layout_weight, który może wystąpić w LinearLayout przy layout_width="0dp", a jego wartość określa jaką częścią całości jest dany element (sumuje się wartości tego atrybutu u wszystkich dzieci rodzica i proporcjonalnie rozdysponowuje się miejsce)
  • RelativeLayout - gdy robiłam kurs mniej podstawowy, ten layout był pominięty, zastąpiony ConstraintLayout, okazuje się, że są bardzo podobne a atrybutem typu android:layout_toLeftOf lub  android:layout_below można ustawiać elementy obok siebie

Tak więc:
  • da się sensownie podzielić ekran bez wartości procentowych Guideline w ConstraintLayout
  • to, co ma być wyświetlane na ekranie nie musi być od razu w całoścu widoczne - mogę użyć ScrollView i wewnątrz niego zaprojektować ciekawy układ elementów

Liczyłam na to, że dowiem się coś ciekawego o projektowaniu ekranów. Początkowo byłam sceptyczna, bo nie jestem aż tak początkująca, ale ogólnie warto było obejrzeć, ponieważ pojawiło się wiele przykładów i często omawiane było, dlaczego warto zastosować takie a nie inne podejście.

Kurs, o którym piszę znajduje się tutaj.

środa, 19 sierpnia 2020

Jak dopasować style tekstu - wnioski z Material Design

Jak się okazuje, AndroidStudio ma zaimplementowane style wg Material Design, tylko nigdy nie dałam sobie czasu na to, żeby się w tym zorientować. To teraz już wiem :)
Planowałam te style przenieść do mojego projektu wpisując wszystkie dane, zgodnie z informacjami, a już nie muszę, bo tam wszystko jest. Tylko kroje czcionek zmieniłam.

I teraz wskazówki z tamtej strony (są tam też ciekawe, dobrze ilustrujące zagadnienia przykłady):

  • Nagłówki 
    • to krótkie, ważne teksty,
    • wyraźne, ciekawe kroje czcionek,
    • mniejsze nagłówki będą lepiej wyglądać w spokojniejszym kroju czcionki.
  • Podtytuły
    • mniejsze od nagłówków,
    • krókie teksty,
    • wyraźne kroje czcionek.
  • Treść
    • długa forma,
    • wyraźne kroje czcionek.
  • Podpisy
    • mogą być pod lub nad,
    • dotyczą tekstu, tytułu lub obrazu,
    • najmniejszy rozmiar czcionki,
    • proste, wyraźne kroje czcionek.
  • Przycisk
    • często allCaps,
    • często sans serif,
    • powinien być wyraźny, widoczny, dawać jasno do zrozumienia co robi.
  • Wyrównanie tekstu
    • Najczęściej do lewej
    • Cytaty wyśrodkowane, nie bardzo długie

O typografii z Material Design jest tutaj.

czwartek, 13 sierpnia 2020

Zmiana myślenia

Choć pozornie nie ma to nic wspólnego z programowaniem, od 4 tygodni realizuję program Droga Artysty. Bardzo polecam, to chyba najlepszy program rozwojowy, w jakim brałam udział. A możę pierwszy, za który wzięłam się na poważnie?

Tak czy inaczej - on oraz mój zespół Mastermind pomogli mi odkryć moją największą blokadę.

Ja NIE MOGĘ być programistą

Taka myśl, za każdym razem w mojej głowie. I nie chodzi o to, że nie będę dobrym programistą, czy idealnym, że nie w jakomś języku. Wcale. Nie mogę i już. Nie moja ścieżka, nie moje miejsce. NIE. Wstęp wzbroniony, możesz sobie siedzieć  IT, zajmować się czymkolwiek, ale tego nie wolno dotknąć. Jak Drzewo Poznania Dobra i Zła. A ja się słuchałam, nie moje, to nie. Czy kusiło? Nie wiem. Lubiłam inne rzeczy, lubiłam to, co robiłam.

Aż do środy, 3 tygodnie temu, kiedy uświadomiłam sobie, skąd to się wzięło i dlaczego to jest takie złe.

A zatem się z tego uwalniam, wróciłam do kursu, zaplanowałam kolejne. Wymyśliłam jak wykorzystam wiedzę w praktyce. 

Jest lepiej, serio. Jeśli Cię coś blokuje i nie masz z kim pogadać - napisz do mnie, zrozumiem Cię :)


Zapiszę sobie jeszcze co sobie przypomniałam powtarzając pierwszy moduł kursu (już to umiałam, tylko zapomniałam):

  • Używaj najprostrzego layoutu w kolejności:
    • Frame
    • Linear
    • Constrain
  • Ustawianie tekstu w TextView:
    • setText - wpisuje nową wartość
    • append - dodaje wartość do tego co już było

czwartek, 6 lutego 2020

Dobre praktyki - Lekcja 2

1. Commituj gdy kończysz pracę w danym momencie (nawet w wyniku przerwania).
2. Weryfikuj wywołania funkcji - czy na pewno tylko raz (rozsądne logi).
3. Porównuj Stringi przez .equals() a nie przez "=="

wtorek, 7 sierpnia 2018

Exception - org.json.JSON.typeMismatch

Dlaczego wystąpił?

Myślałam, że parsowany string to JSONObject a to był JSONArray.
Plik .json (a właściwie String) zrobiłam sama, więc wystarczyło usunąć [ ] z początku i końca.

sobota, 28 lipca 2018

Android - testy wydania

Kilka dni temu wysłałam kolejną wersję aplikacji, jeszcze ciągle w wersji próbnej, testowej, w trakcie pracy. Ogólnie wydawałoby się - nic poważnego. Ale jednak wysłałam ją komuś - to jest poważne, powinnam być za to odpowiedzialna. Zrozumiałam, że nie zrobiłam jej wcześniej absolutnie podstawowych testów wydania. Nawet nie mam przygotowanych... Pora to zmienić.

Testy wydania aplikacji - android (ogólne)

  1. Aplikacja aktualizuje się z poprzedniej wersji do nowej (update)
  2. Aplikacja w aktualnej wersji może być zainstalowana na "czystym" urządzeniu (na takim, na którym nie jest zainstalowana) (instal)
  3. Aplikacja po wybraniu ikony włącza się i pokazuje ekran startowy (start)
  4. Aplikacja po wybraniu przycisku cofinij wyłącza się (end)
  5. Aplikacja wykonuje podstawową funkcję (work)
  6. Aplikacja aktualizuje się do poprzedniej wersji (downgrade)

Testy wydania aplikacji - android (dodatkowe)

  1. Aplikacja działa bez internetu (internet permission)
    1. brak wyjątków
    2. informacja o braku połączenia
    3. niezakłócone działanie
  2. Aplikacja działa przy obracaniu ekranu (orientation)
    1. dźwięk
    2. obraz
    3. funkcje
  3. ...

poniedziałek, 23 lipca 2018

Jak dodać odtwarzacz audio?

  1. Dodaj do pliku build.gradle -> dependencies
    compile 'com.google.android.exoplayer:exoplayer:r2.2.0'
  2. Dodaj do swojej aktywności
    implements View.OnClickListener, ExoPlayer.EventListener
  3. Dodaj do swojej aktywności obsługującej audio zmienne ExoPlayer
    private SimpleExoPlayer mExoPlayer;
    private SimpleExoPlayerView mPlayerView;
    private static MediaSessionCompat mMediaSession;
    private PlaybackStateCompat.Builder mStateBuilder;
    private NotificationManager mNotificationManager;
  4. Zainicjalizuj wstępnie zmienne
    mPlayerView = (SimpleExoPlayerView) findViewById(R.id.playerView);
    mPlayerView.setPlayer(mExoPlayer);
    initializeMediaSession();
    initializePlayer(Uri.parse(audioPath));

  5. Zaimplementuj inicjalizację MediaSession
     mMediaSession = new MediaSessionCompat(this, this.getClass().getSimpleName());
    mMediaSession.setFlags(
            MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
                    MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
    mMediaSession.setMediaButtonReceiver(null);
    mStateBuilder = new PlaybackStateCompat.Builder()
            .setActions(
                    PlaybackStateCompat.ACTION_PLAY |
                    PlaybackStateCompat.ACTION_PAUSE |
                    PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS |
                    PlaybackStateCompat.ACTION_PLAY_PAUSE);
    mMediaSession.setPlaybackState(mStateBuilder.build());
    mMediaSession.setCallback(new MySessionCallback());
    mMediaSession.setActive(true);
  6. Zaimplementuj podklasę MySessionCallback
            @Override
            public void onPlay() {
                mExoPlayer.setPlayWhenReady(true);
            }

            @Override
            public void onPause() {
                mExoPlayer.setPlayWhenReady(false);
            }

            @Override
            public void onSkipToPrevious() {
                mExoPlayer.seekTo(0);
            }
  7. Zaimplementuj inicjalizację playera
    if (mExoPlayer == null) {
        // Create an instance of the ExoPlayer.
        TrackSelector trackSelector = new DefaultTrackSelector();
        LoadControl loadControl = new DefaultLoadControl();
        mExoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
        mPlayerView.setPlayer(mExoPlayer);

        // Set the ExoPlayer.EventListener to this activity.
        mExoPlayer.addListener(this);
       
        // Prepare the MediaSource.
        String userAgent = Util.getUserAgent(this, "ClassicalMusicQuiz");
        MediaSource mediaSource = new ExtractorMediaSource(mediaUri, new DefaultDataSourceFactory(
                this, userAgent), new DefaultExtractorsFactory(), null, null);
        mExoPlayer.prepare(mediaSource);
        mExoPlayer.setPlayWhenReady(true);
    }
  8. Zaimplementuj funkcję zamykania playera
    mNotificationManager.cancelAll();
    mExoPlayer.stop();
    mExoPlayer.release();
    mExoPlayer = null;
  9. Dodaj funkcję zamykania playera do odDestroy()
        super.onDestroy();
        releasePlayer();
        mMediaSession.setActive(false);
  10. Zaimplementuj funkcję onPlayerStateChanged()
    if((playbackState == ExoPlayer.STATE_READY) && playWhenReady){
        mStateBuilder.setState(PlaybackStateCompat.STATE_PLAYING,
                mExoPlayer.getCurrentPosition(), 1f);
    } else if((playbackState == ExoPlayer.STATE_READY)){
        mStateBuilder.setState(PlaybackStateCompat.STATE_PAUSED,
                mExoPlayer.getCurrentPosition(), 1f);
    }
    mMediaSession.setPlaybackState(mStateBuilder.build());
    showNotification(mStateBuilder.build());
  11. Zaimplementuj MediaReceiver
    public static class MediaReceiver extends BroadcastReceiver {
        public MediaReceiver() {
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            MediaButtonReceiver.handleIntent(mMediaSession, intent);
        }
    }
  12. Dodaj do manifestu aktywność obsługującą odtwarzacz
    <activity android:name=".QuizActivity"
        android:launchMode="singleTop"/>
    <receiver android:name=".QuizActivity$MediaReceiver">
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_BUTTON" />
        </intent-filter>
    </receiver>
  13. Przygotuj layout uwzględniający SimpleExoPlayerView
     <com.google.android.exoplayer2.ui.SimpleExoPlayerView
            android:id="@+id/playerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="0dp"
            android:layout_marginRight="0dp"
            android:layout_marginBottom="0dp"
            android:layout_marginLeft="0dp"/>

niedziela, 22 lipca 2018

Jak przechowywać dane - json

Jedną z możliwości przechowywania danych jest plik w formacie .json (JavaScript Object Notation).

Cechy w porównaniu z XML i JAML
  • dostęp do danych w formacie JSON jest bardziej naturalny z poziomu języka JavaScript niż dostęp do tych samych danych w formacie XML
  • nie jest już jednak tak naturalny dla Javy i wymaga stosowania specjalnych bibliotek
  • w nowszych wersjach standardów dopuszczana jest wymiana danych za pomocą JSON-a (np. w REST)
  • w praktyce zajmuje znacząco mniej miejsca niż analogiczny obiekt przesyłany za pomocą formatu XLM.
  • JSON jest łatwiejszy do analizowania składni niż jego nadzbiór YAML
Przykład (kurs android - udacity)

[

{

"name": "Toccata and Fugue in D minor",

"id": 0,

"uri": "asset:///toccata_fugue.mp3",

"composer": "Johann Sebastian Bach",

"albumArtID": "bach"

},

{

"name": "Fur Elise",

"id": 1,

"uri": "asset:///fur_elise.mp3",

"composer": "Ludwig van Beethoven",

"albumArtID": "beethoven"

}
]














Jak zastosować?

Stworzyć obiekt .java, który będzie odczytywał dane, np.:

private Sample(int sampleID, String composer, String title, String uri, String albumArtID) {
        mSampleID = sampleID;
        mComposer = composer;
        mTitle = title;
        mUri = uri;
        mAlbumArtID = albumArtID;
    }


środa, 11 lipca 2018

wtorek, 10 lipca 2018

Jak dodać menu do aplikacji?

  1. Nadaj nazwy swoim opcjom - np. wprowadź je jako wartości w strings.xml
  2. Utwórz katalog zasobów dla menu:
    1. Kliknij prawy przyciskiem na katalog res
    2. Wybierz New Resource Directory
    3. Zmień Recource Type z value na menu
  3.  Dodaj w katalogu plik menu.xml:
    1. Kliknij prawy przyciskiem na katalog menu
    2. Wybierz New -> Menu Resource File
  4. Wprowadź ustawienia opcji menu, np.:
    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android" 
     xmlns:app="http://schemas.android.com/apk/res-auto"> 
          <item android:id="@+id/menu_day1" 
                android:orderInCategory="1"         
                app:showAsAction="never" 
                android:title="@string/menu_d1" />
    </menu> 
  5. Zaimplementuj w aktywności, która udostępnia menu funkcje onCreateOptionsMenu i onOptionsItemSelected, np.:
    @Overridepublic boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);    return true;}
    
    @Overridepublic boolean onOptionsItemSelected(MenuItem item) {
        return selectItem(item);}
    
    public boolean selectItem(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_day1:
                return true;        case R.id.menu_day2:
                return true;        case R.id.menu_day3:
                return true;        case R.id.menu_day4:
                return true;        case R.id.menu_day5:
                return true;        default:
                return super.onOptionsItemSelected(item);    }
    }

piątek, 22 czerwca 2018

Jak działa AppWidgetProvider czyli jakie widget otrzymuje sygnały i co się wtedy dzieje

AppWidgetProvider (zadeklarowany w Manifeście jako <receiver>) umożliwia odbieranie sygnałów przeznaczonych tylko dla widgetów z następujących metod:
  • onUpdate()
    • wywoływana automatycznie zgodnie z parametrem updatePeriodMillis
    • wywoływana automatycznie przy dodawaniu widgetu, żeby np. domyślnie skofigurować widget, jeśli trzeba uruchomić serwis
    • wywoływana z aktywności przy dodawaniu widgetu tylko wtedy, jeśli zostało tak zaprogramowane - programista musi zapewnić, że widget będzie w zupełności skonfigurowany, jeśli decyduje się sosać aktywność umożliwiającą konfigurację
  • onAppWidgetOptionsChanged()
    • wywoływana przy dodawaniu widgetu
    • wywoływana przy zmianie rozmiaru widgetu
    • umożliwia pokazanie lub schowanie elementów widgetu w zależności od jego rozmiaru
    • wprowadzona w Android 4.1 (API 16)
  • onDeleted(Context, int[])
    •  wywoływana gdy App Widget host zamyka widget - konkretną instancję, tylko jedną
  • onEnabled(Context)
    • wywoływana gdy dodawany jest pierwszy obiekt danego widgetu
    • jeśli widget może mieć więcej niż jedną instancję, przy dodawaniu drugiej metoda nie jest wywoływana
    • metoda odpowiednia do implementacji wszystkich funkcji, które mają się wykonać tylko raz, np. stworzenie bazy danych, szczególna konfiguracja
  • onDisabled(Context)
    • wywoływana gdy z App Widget host usuwana jest ostatnia instancja widgetu
    • metoda odpowiednia do implementacji funkcji, które "posprzątają" po widgecie, np. usuną czasowe bazy danych
  • onReceive(Context, Intent)
    • wywoływana przy każdym odebraniu sygnału
    • wywoływana przed każdą ze wspomnianych powyżej metod
    • nie musi być implementowana - AppWidgetProvider ma domyślną implementację, która w odpowiedni sposób radzi sobie z odbieranymi sygnałami i wywołuje odpowiednie funkcje

Wygląd widgetu - zmiana rozmiaru

Widget nie musi mieć stałego, wybranego przez nas rozmiaru - może być konfigurowany przez użytkownika.
Nie musi też mieć stałych elementów - można je dopasować do wybranego rozmiaru.
Podczas zmiany rozmiaru widgetu wywoływana jest metoda onAppWidgetOptionsChanged(). To w jej treści możemy określić które elementy będą widoczne a które nie. Żeby zorientować się jaki jest aktualny (ustawiony przez użytkownika) rozmiar trzeba wywołać metodę getAppWidgetOptions(), która zwróci w odpowiedzi obiekt typu Bundle, który zawiera:

  • OPTION_APPWIDGET_MIN_WIDTH - dolna granica szerokości w jednostkach dp
  • OPTION_APPWIDGET_MAX_WIDTH - górna granica szerokości w jednostkach dp
  • OPTION_APPWIDGET_MIN_HEIGHT - dolna granica długości w jednostkach dp
  • OPTION_APPWIDGET_MAX_HEIGHT - górna granica długości w jednostkach dp

Wygląd widgetu - podstawowy projekt

Układ widgetu bazuje na klasie RemoteViews

Tworząc układ widgetu trzeba pamiętać o:
  • sprawdzeniu, czy wybrany układ (layout) i elementy są wspierane przez RemoteViews
  • marginesach całego widgetu - widget nie powinien stykać się z krawędziami ekranu i z innymi aplikacjami (od wersji Android 4.0 (targetSdkVersion >= 14) te marginesy są ustawiane domyślnie, nie trzeba ich dodatkowo wprowadzać)
  • marginesach elementów widgetu - powinny być od siebie trochę odsunięte, żeby dało się ich używać
Ciekawym elementem układu jest stub - niewidoczny obiakt, który można w trakcie wykonywania programu zmienić na inny, powiązany.

czwartek, 21 czerwca 2018

Konfiguracja widgetu czyli metadane

Metadane określają podstawowe parametry widgetu:
  • minWidth, minHeight - minimalna, domyślna przestrzeń zajmowana przez widget
    •  widgety zajmują na ekranie pewne zdefiniowane komórki (tak samo ustawiając ikonki aplikacji na ekranie też nie możemy ich mieć gdziekolwiek), jeśli podana wartość nie będzie odpowiadała wielkości pełnych komórek, zostanie zaokrąglona w górę, tak aby zająć pełną liczbę zdefiniowanych komórek
    • minimalna wartość nie może być większa niż 4x4 komórki (żeby zachować przenoszalność widgetu na różne urządzenia)
  •  minResizeWidth, minResizeHeight - wielkość, poniżej której widget nie będzie nadawał się do użycia
    • ustawienie tych parametrów oznacza, że użytkownik będzie mógł zmienić wielkość widgetu na mniejszy niż domyślny (ale nie mniejszy niż podany w tym parametrze)
  •  updatePeriodMillis - częstotliwość z jaką widget będzie wysyłał żądanie aktualizacji (onUpdate(), AppWidgetProvider )
    • podana wartość jest tylko szacunkowa, system wykona aktualizację mniej więcej w tym czasie, jeśli będzie mógł
    • trzeba ostrożnie dobrać ten parametr, żeby nie zużywać za dużo baterii 
    • sysem wybudzi urządzenie z uśpienia gdy nadejdzie czas aktualizacji ustawiony w tym parametrze
    • żeby uniknąć budzenia urządzenia, można ustawić aktualizację opartą na alarmie "niebudzącym" urządzenia
      • korzystając z AlarmManager ustaw alarm przez Intent otrzymywany przez AppWidgetProvider
      • ustaw alarmowi typ ELAPSED_REALTIME lub RTC
      • ustaw updatePeriodMillis = 0
  • initialLayout - ścieżka do pliku określającego wygląd (layout) widgetu
  • configure - aktywność, która zostanie uruchomiona po dodaniu widgetu w celu umożliwienia użytkownikowi skonfigurowania go
  • previewImage - podgląd przykładowo skonfigurowanego widgetu dla użytkownika, dostępny dla niego gdy wybiera widgety
    • jeśli nie ma ustwionego tego parametru, jako podgląd wyświetlana będzie ikona aplikacji
  • autoAdvanceViewId - id widoku "rozszerzonego"
    • dla widgetów, które mogą być rozbudowywane (advanceable)
    • informuje host co powinno być rozbudowywane
    • host będzie wykonywał akcję advance() gdy będzie to sensowne, czyli np. tylko gdy widget będzie widoczny
  • resizeMode - określa zasady zmiany rozmiaru widgetu - horizontal, vertical, none
  • widgetCategory - określa gdzie może być wyświetlany widget - home_screen, keyguard (tylko do Android 5.0), both

środa, 20 czerwca 2018

AndroidManifest - dodajemy widget

W manifeście informujemy aplikację o składowych częściach widgetu.

(deklarujemy obiekt, który będzie mógł odbierać informacje od aplikacji i/lub systemu)
<receiver android:name="nazwa AppWidgetProvider" > 
(tu powyżej -"name"- mówimy aplikacji jak nazywa się klasa, która ma informacje jak będzie zachowywał się ten obiekt - widget)
    <intent-filter> 
(tu deklarujemy, na co widget będzie reagował, co będzie odbierał)
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> 
(jeśli widget ma być aktualizowany należy to koniecznie zadeklarować)
    </intent-filter> (tu mówimy gdzie są dane konfiguracyjne widgetu)
    <meta-data android:name="android.appwidget.provider"
               android:resource="@xml/example_appwidget_info" />
</receiver>
więcej o atrybucie <receiver>

wtorek, 19 czerwca 2018

Z czego składa się widget?

  • AppWidgetProviderInfo - plik XML zawierający metadane naszego widgetu
    • metadane -  dane o danych – ustrukturalizowane informacje stosowane do opisu zasobów informacji lub obiektów informacji, dostarczające szczegółowych danych, dotyczących atrybutów zasobów lub obiektów informacji, w celu ułatwienia ich znalezienia, identyfikacji, a także zarządzania tymi zasobami
  • AppWidgetProvider (implementacja) - zdefiniownie tego jak widget będzie się zachowywał pod wpływem różnych działań
  • View layout - plik XML opisujący wygląd widgetu
  • App Widget configuration Activity (opcjonalnie) - sktywność, która otworzy się w momencie dodawania widgetu i umożliwi ustawienie konfiguracji
  • zmiana w AndroidManifest.xml - deklaracja atrybutu <receiver> o takiej nazwie jaką ma dodany wcześniej AppWidgetProviderInfo

poniedziałek, 18 czerwca 2018

Co to jest widget?

To taka miniaturka aplikacji - np. większość telefonów ma na Home Screen ustawiony zegar.
Widget:
  • może być osadzony w innych aplikacjach (taka aplikacja to App Widget Host i jest nią np. home screen),
  • cyklicznie się aktualizuje,
  • jest wyświetlany dzięki App Widget Provider.

piątek, 18 maja 2018

Dlaczego moja aplikacja nie ma tej ładnej ikonki?

Znowu się na to złapałam.
Wygrywam apkę na wirtualkę a tam androidek zamiast mojej ikonki.
Sprawdzam manifest - OK.
Sprawdzam grafikę - OK.
Co się dzieje?
Jest nie w tym katalogu - znowy bezmyślnie dodałam ją do katalogu anydpi. A z tego katalogu poprawnie obsługiwane są grafiki wektorowe a nie rastowe...
Po przełożeniu mojego .png do innego katalogu wszystko zadziałało.

czwartek, 17 maja 2018

Dlaczego "R" jest czerwone?

Coś jest nie tak z moimi zasobami.
Po raz kolejny mam nadzieję, że to kompilator ma jakiś problem - przecież dopiero go włączyłam, pewnie coś się źle załadowało. W dodatku znowu chce zrobić jakiś update. Pewnie to to.

NIE!

Zrobiłam "niewielką" modyfikację w zasobach, dodałam tylko jedną linijkę w stylach, kompilator jej nie podkreślił, uznałam, że wszystko jest OK. A jednak nie było.

Od dziś:
Jeśli zasoby nie budują się poprawnie, upewnij się, że wprowadzone zmiany są poprawne.