Trochę o widżetach

Pora wrócić do tematyki Androidowej – dziś parę słów o widżetach. Widżety to miniaturowe widoki aplikacji, które mogą być wbudowane w inne aplikacje (widget hosty; najczęściej jest to Home Screen).

Rejestracja widżetów w pliku AndroidManifest.xml

Ponieważ widżety są uruchamiane w ramach procesów swojego hosta, trzeba je zarejestrować w pliku AndroidManifest.xml. W tym miejscu definiujemy filtry intencji, które mogą aktualizować widżet  oraz umieszczamy informacje o pliku xml, który definiuje obiekt AppWidgetProviderInfo.

<receiver android:name=".WikiWidget">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>

    <meta-data
        android:name="android.appwidget.provider"
        android:resource="@xml/wiki_widget_info" />
</receiver>

AppWidgetProviderInfo

Obiekty z klasy  AppWidgetProviderInfo zawierają metadane widżetu takie jak układ widoku, czy częśtość z jaką widżet jest aktualizowany.

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialKeyguardLayout="@layout/wiki_widget"
    android:initialLayout="@layout/wiki_widget"
    android:minHeight="40dp"
    android:minWidth="100dp"
    android:previewImage="@drawable/example_appwidget_preview"
    android:resizeMode="horizontal|vertical"
    android:updatePeriodMillis="86400000"
    android:widgetCategory="home_screen"></appwidget-provider>

AppWidgetProvider

Klasa AppWidgetProvider jest rozszerzeniem klasy BroadcastReceiver, która umożliwia komunikację wewnątrz systemu. Obiekty z tej klasy odbierają informacje tylko o zdarzeniach, które dotyczą widżetu. W odpowiedzi na te informacje może być wywołana jedna z następujących metod:

onUpdate()

onAppWidgetOptionsChanged()

onDeleted(Context, int[])

onEnabled(Context)

onDisabled(Context)

onReceive(Context, Intent)

Układ widoku

Ponieważ widżety są uruchamiane w procesach innych aplikacji, do tworzenia układów widoków wykorzystywana jest klasa RemoteViews. Klasa ta ma ograniczonę liczbę układów (FrameLayout, LinearLayout, RelativeLayout, GridLayout)  oraz innych elementów interfejsu:

Klasy dziedziczące po wymienionych klasach, nie są wspierane przez RemoteViews.

A to zrzut widżeta wyświetlającego dzisiejszą datę w formacie zgodnym z artykułami z Wikipedii:

SC20160427-200049.png

Reklamy

Losowy fakt z 24 kwietnia

W tym tygodniu udało mi się napisać aplikację, która wyświetla losowy fakt z Wikipedii z 24 kwietnia.

index

Żądanie wysłane na poniższy url Mediawiki API:

https://en.wikipedia.org/w/api.php?action=query&prop=extracts&exchars=10000&explaintext&titles=april_24&format=json

nie zwraca najprzyjemniejszej dla oka odpowiedzi:

Screenshot from 2016-04-24 21-49-18.png

Na szczęście biblioteka Volley posiada również klasę JsonObjectRequest, która umożliwia pobranie obiektu JSONObject z danego url-a.

Napisałam klasę JsonParse, w której przeszłam przez kolejne poziomy zagnieżdzenia obiektów w powyższym JSONie i dalej na piechotę przy pomocy metod: indexOf(), substring() wycięłam tekst z samymi wydarzeniami w metodzie parseJson().

Mam takie poczucie, że estetyczniej byłoby gdyby ta metoda zwracała listę wydarzeń, ale tę listę robię dopiero w klasie RandomFact() (w meteodzie randomEvent() brutalnie przez split(„\\n”)). Metoda randomEvent() przy pomocy klasy Random zwraca losowy fakt.

Tak sobię o tym piszę, a to wszystko przecież na:

https://github.com/akrajewska/one-app-a-week/  🙂

 

Lepiej późno niż później – github

Tak naprawdę, powinnam była zacząć z gitem cały projekt, ale dopiero dziś zrobiłam pierwszego push requesta. Jak korzystać z githuba w Android Studio? Jak już mamy konto na githubie i utworzone tam repozytorium, otwieramy projekt naszej aplikacji w Android Studio i:

Krok 1. Tworzymy lokalne repozytorium. W Menu na górze wybieramy VCS > Import into Version Control > Create Git Repository. W okienku dialogowym wybieramy katalog, w którym chcemy to repozytorium stworzyć (czyli zostawiamy defaultowe ustawienia).

Krok 2. Tworzymy zdalne repozytorium. W terminalu wchodzimy do głównego katalogu naszej aplikacji i wywołujemy:

git remote add origin https://github.com/[login z githuba]/[nazwa repozytorium]

Krok 3. Dodajemy projekt do lokalnego repozytorium. Klikając prawym przyciskiem na główny katalog naszej aplikacji i wybierając Git > Add.

Krok 4. Zatwierdzamy zmiany lokalnie  Git > Commit Directory. Z tym krokiem miałam problem. Pojawiało się okienko, w którym widziałam jak proces się zaczynał i nagle kończył. Jeszcze 😉 nie rozumiem dlaczego, więc tradycyjnie posłuchałam Stack Overflow i odznaczyłam opcję Perform code analysis

Screenshot from 2016-04-23 18-59-04

 

Krok 5.  Robimy push requesta do repozytorium zdalnego. Klikamy prawym przyciskiem na katalog główny i wybieramy Git > Repository > Push po pojawieniu się okienka dialogowego logujemy się do githuba.

Zapraszam do zaglądania na https://github.com/akrajewska/one-app-a-week 🙂

Hello Volley,

czyli o tym, jak wysłać żądanie GET w Androidzie.

Volley to bibliteka sieciowa napisana przez Google, która służy do komunikacji przez protokół HTTP. Korzystając z niej tworzymy kolejkę żądań (RequestQueue), do której przekazujemy obiekty żądań (Request). W aplikacji pobierającej cokolwiek ze strony Wikpedii żądanie jest tylko jedno – HTTP GET, więc na razie nie poznałam jeszcze mocy Volley’a.

Aby zrobić cokolwiek z tą biblioteką, musimy w pliku AndroidManifest.xml nadać naszej aplikacji uprawnienia dostępu do sieci.

Poniżej zastosowanie biblioteki Volley w metodzie onCreate() głównej aktywności aplikacji pobierającej dane z Wikpedii*:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final TextView mTextView = (TextView) findViewById(R.id.text);
    RequestQueue queue = Volley.newRequestQueue(this);
    String url ="https://en.wikipedia.org/w/api.php?action=query&titles=Main%20Page&prop=revisions&rvprop=content&format=json";

    StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    mTextView.setText(response.substring(0,500));
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            mTextView.setText(error.toString());
        }
    });

    queue.add(stringRequest);
}

*zamieniłam xml na json. No nic, coś z tym jsonem trzeba będzie zrobić.

Mediawiki revisited

Po ostatnich problemach z aplikacją pobierającą dane ze strony Wikipedii, postanowiłam zrobić krok wstecz (a może po prostu zatrzymać się na chwilkę) i odpowiedzieć sobie na dwa sami-wiecie-jak ważne pytania:

  1. Co ja w zasadzie chcę teraz zrobić?
  2. Jak mogę to zrobić w Androidzie?

Ad. 1. Niby pisałam w ostatnim poście: chcę pobrać na razie cokolwiek ze strony Wikipedii, ale robiąc aplikację trochę zachłannie rzuciłam się na napisaną w Javie bibliotekę jwbf do korzystania z Mediawiki API. Pojawiły się jakieś problemy z importem, a rozwiązanie:

  1. zgoogluj komunikat błędu z nazwą biblioteki i nazwą Android Studio,
  2. wejdź na odpowiednią stronę Stack Overflow
  3. porób ctrl-c, ctrl-v rozwiązań z odpowiedziami o znaczeniu zbliżonym do thanks, it’s worked for me

u mnie nie zadziałało. A przecież chcę pobrać na razie cokolwiek ze strony Wikipedii.  To może chwilka, jak działa Mediawiki API?

Mediawiki action API to usługa internetowa,  która daje nam dostęp do Wikipedii poprzez adres URL na stronie api.php. Klient żąda konkretnej akcji, wyznaczonej  przez parametr action. Prosty przykład na stronie mówi, że wysyłając request HTTP GET na poniższy adres:

https://en.wikipedia.org/w/api.php?action=query&titles=Main%20Page&prop=revisions&rvprop=content&format=xml

dostaniemy plik xml z zawartością strony głównej Wikipedii.

  1. https://en.wikipedia.org/w/api.php – to jest endpoint (główna strona web service’u)
  2. ustawienie action=query umożliwia pobranie informacji na temat wiki oraz danych tam przechowywanych, np wikitextu.
  3. titles=Main%20Page, prop=revisions, rvprop=content - to są parametry wykorzystowane przez akcję query
  4. format=xml -to, no sami wiecie, co to:)

Et voila, poniżej screenshot z aplikacji, która wyświetla xml-a z zawartością pierwszej strony Wikipedii (a konkretnie pierwsze 500 znaków odpowiadającego mu stringa).

wikipedia_ss

Odpowiedź na drugie pytanie, czyli wysyłanie żądań HTTP w Androidzie, w następnym poście.

 

 

 

Bywa różnie

Screenshot from 2016-04-10 20-19-58.png

No niestety, w tym tygodniu mogę jedynie zaśpiewać w duecie z Krzysztofem Cugowskim Sen o dolinie. To hiperbola, ale uczę się na razie pobierać dane ze strony Wikipedii przy pomocy API Mediawiki. Dokładniej to próbuje skorzystać z biblioteki jbwf, ale niestety napotykam na bład java.lang.NoClassDefFoundError: net.sourceforge.jwbf.JWBF$1

Poniżej zawartość mojego pliku build.gradle. Ale to nie są jeszcze moje ostatnie słowa. Następnym razem to ja będe Sprite, a Mediawiki pragnienie.

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.example.antonina.mywiki"
        minSdkVersion 14
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        multiDexEnabled true

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    packagingOptions {
        exclude 'META-INF/DEPENDENCIES.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/DEPENDENCIES'
    }
}
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.android.support:design:23.2.1'
    compile 'net.sourceforge:jwbf:3.1.0'
}
configurations {
    compile.exclude group: "org.apache.httpcomponents", module: "httpclient"

Interfejs użytkownika

Dziś krótko o interfejsie użytkownika. Krótko, bo jak widzicie po screenshotach moich aplikacji, nie zjadłam jeszcze zębów na UI w Androidzie. Dlatego napiszę o tym, co do tej pory było mi potrzebne.

Interfejs użytkownika aplikacji jest zdefiniowany poprzez hierarchię obiektów z klas ViewGroup i View. Klasa ViewGroup to podklasa klasy View.  Obiekty z tej klasy, to takie „pudełka”, w których znajdują się inne obiekty z klasy View, takie jak przyciski i pola tekstowe. Szczególnym przykładem obiektów z klasy ViewGroup są layouty (różnego rodzaju układy) definiujące architekturę komponentów aplikacji (aktywności, widgetów). Hierarchie obiektów z klasy View mogą mieć różny stopień skomplikowania. Poniżej przykład hierarchii ze strony http://developer.android.com/guide/topics/ui/overview.html zestawiony z raczej nieskomplikowaną hierarchią Mojej Pierwszej Aplikacji:

Obiekty określające UI mogą być zdefiniowane w plikach XML lub mogą być inicjowane w kodzie, w trakcie działania aplikacji. W Mojej Pierwszej Aplikacji aktywności my activity odpowiadał  plik content_my_activity.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:showIn="@layout/activity_my_activity">
    <EditText
        android:id="@+id/edit_message"
        android:layout_weight="1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:hint="@string/edit_message" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button_send"
        android:onClick="sendMessage"/>
</LinearLayout>

Każdy z obiektów klasy View ma ustalone atrybuty, jak na przykład layout_weight, layout_width, text. W szczególności każdy obiekt z tej klasy posiada atrybut id, który umożliwia odwołanie się do będącego liczbą całkowitą identyfikatora obiektu.  Dzięki niemu do każdego obiektu możemy odwołać się w kodzie aplikacji. I tak na przykład poniższa metoda wyślij wiadomość za pomocą metody findViewById() wydobywa tekst wpisany w polu EditText:

 

Czytaj dalej