Showing posts with label android. Show all posts
Showing posts with label android. Show all posts

Wednesday, June 19, 2013

Android NDK / JNI (Java Native Interface)


NDK - Native Development Kit NDK je sada nástrojov, ktorá umožňuje implementovať natívny kód v iných jazykoch (C, C + +).  NDK využíva štandardný java framework k tomu určený – JNI.
JNI – Java Native Interface je framework umožňujúci volať natívne programy a knižnice napísané v iných jazykoch (C, C++, ..) priamo v kóde, bežiacom v Java Virtual Machine (JVM).
Uplatnenie:
  • využitie staršieho kódu napísaného v inom jazyku (nie Java) bez nutnosti ho prepisovať do javy
  • využitie API iných jazykov (nie Java)
  • komunikácia s HW

Obmedzenia (nevýhody):
  • strata platformovej nezávislosti javy (natívny kód je potrebne prepísať pre každú platformu)
  • vlastnosti javy ako typová bezpečnosť, garbage collector sa nevzťahujú na natívny kód

Implementácia:
  1.  triede v ktorej chceme volať metódu, implementovanú v natívnom jazyku, vytvoríme deklaráciu natívnej metódy. Natívna metóda musí obsahovať modifikátor „native“,

    public native int callJni(int i);
    


  2. Signatúru natívnej metódy môžeme vytvoriť pomocou nástroja „javah“ (javah -jni ClassName), alebo ju vytvoríme ručne, teda vytvoríme samostatný súbor pre požadovanú metódu (napr.: „jni_part.cpp“) v adresári „jni“ (napr.: project_folder/jni/jni_part.cpp),


    #include <jni.h>
    extern "C" {
        JNIEXPORT jint JNICALL Java_com_example_test04jni_MainActivity_callJni(JNIEnv*, jclass, jint);
        JNIEXPORT jint JNICALL Java_com_example_test04jni_MainActivity_callJni(JNIEnv* je, jclass jc, jint i)
        {
            return (i * i);
        }
    }
    


  3. V mieste umiestnenia natívnej funkcie vytvoríme „makefile“ s názvom „Android.mk“ pre android build,

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE    := jni_example  
    LOCAL_SRC_FILES := jni_part.cpp
    include $(BUILD_SHARED_LIBRARY)
    


  4. Zbuildujeme natívnu metódu pomocou „android-ndk“,

    LINUX shell:
    "project dir"$ ~/.android-ndk-r8c/ndk-build
    

  5. Nakoniec v android aplikácii v mieste volania natívnej metódy, najskôr načítame knižnicu, ktorá bude kompilovať natívnu metódu a zavoláme samotnú metódu.

    // Load native library
    System.loadLibrary("jni_example");
    ...
    // call native method: "callJni(i)"
    textView_result.setText(Integer.toString(callJni(i)));
    


    Zdroj android triedy, v ktorej bola volaná natívna metóda:


    package com.example.test04jni;
     
    import android.os.Bundle;
    import android.app.Activity;
    import android.view.Menu;
    import android.view.View;
    import android.widget.Button;
    import android.widget.TextView;
    public class MainActivity extends Activity {
     
        private TextView textView_result;
         
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
             
            // Load native library
            System.loadLibrary("jni_example");
             
            textView_result = (TextView) findViewById(R.id.textView_result);
             
            final Button btn_start = (Button) findViewById(R.id.button1);
            btn_start.setOnClickListener(new View.OnClickListener() {
                 public void onClick(View v) {
                    Integer i = 10;                   
                    // call native method: "callJni(i)"                       
                    textView_result.setText(Integer.toString(callJni(i)));           }            
            });
             
        }
     
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
     
        // Declaration of native methods.
        public native int callJni(int i);
    }
    

Zdroj príkladu: Android-NDK-JNI-example

Monday, February 25, 2013

REST-ovaný Android s Djangom.

Krátka prezentácia komunikácie Android aplikácie s webovým portálom. Komunikácia spočíva v zobrazovaní obsahu z webového portálu v Android aplikácii, pomocou REST rozhrania reprezentovaného JSON formátom.

Vzorová aplikácia reprezentuje webový portál fiktívneho IT bazáru a k nemu prislúchajúcu Android aplikáciu pre zobrazovanie obsahu web portálu.

Technológie:
  • Django (python web framework)
  • Android (OS pre mob.)
  • REST (súbor architektonických princípov, umožňujúce návrh webových služieb)
  • JSON (dátový formát, určený pre prenos dát)

Web portál – Django
V tejto prezentácii sa nerieši UI webového portálu a teda URL web portálu vracia len JSON bez „template“).

Poznámka na úvod:
Štandardný MVC model je v Django frameworku prezentovaný ako MTV model. (Model View Controller = Model Template View)

Riešenie:
Web portál pozostáva z jednoduchého modelu (models.py), view (views.py) a admin rozhrania (admin.py) pre naplnenie dát, ktoré sú JSON výstupom pre Android aplikáciu.

[views.py]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# coding: UTF-8

from django.http import HttpResponse
from django.utils import simplejson
from django.core import serializers

from json01App.models import Category, Product

def index(request):
    '''
    index.html 
    '''
    cat_type = 0
    if 'cat_type' in request.GET and request.GET['cat_type']:
        cat_type = request.GET['cat_type']

    category = Category.objects.all()
    json_category = serializers.serialize("json",category)

    products = Product.objects.filter(category_id = cat_type)
    json_products = serializers.serialize('json', products, ensure_ascii=False)
    json_products_encode = json_products.encode('ascii', 'ignore')
    json_string = "{\"product\":" + str(json_products_encode) + "}"

    return HttpResponse(json_string, content_type='application/javascript; charset=utf-8')

URL je volaná s parametrom „cat_type“, definujúcim kategóriu, ktorej obsah sa má vrátiť (hodnota parametra predstavuje primárny kľúč entity „Category“ v DB, viď. „models.py“).

Príklad URL: http://192.168.1.1:8000/?cat_type=1

Dôležité:
Ak je web portál spúšťaný na localhost-e, je potrebné ho spustiť pod IP adresou samotného PC, predstavujúceho web server a nie ako „localhost“, alebo „loopback“ (127.0.0.1), nakoľko za týmto istým účelom používa OS Android tieto adresy. To znamená že po nastavení URL v Android aplikácii (viď nasledovný odstavec) a jej následnom spustení by sa volal „localhost“ OS Androidu a nie požadovaný web portál.

[models.py]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
from django.db import models

class Category(models.Model):
    name = models.CharField(max_length=30)

    def __unicode__(self):
        return self.name

class Product(models.Model):
    '''
    product id = implicit primary key 
    '''
    category_id = models.ForeignKey(Category)
    product_type = models.CharField(max_length=30)
    product_mob = models.CharField(max_length=30)
    product_mail = models.CharField(max_length=30)
    product_desc = models.CharField(max_length=160)
    product_price = models.CharField(max_length=30)

    def __unicode__(self):
        return self.product_type

[admin.py]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# Coding: UTF-8

from json01App.models import Category, Product
#from heatmap.models import *
from django.contrib import admin

class CategoryAdmin(admin.ModelAdmin):
    list_display = ('id','name',)
    fields = ('name',)
    ordering = ('id',)

class ProductAdmin(admin.ModelAdmin):
    list_display = ('id','category_id','product_type','product_mob','product_mail','product_price','product_desc',)
    fields = ('category_id','product_type','product_mob','product_mail','product_price','product_desc',)
    ordering = ('id',)

admin.site.register(Category, CategoryAdmin)
admin.site.register(Product, ProductAdmin)

Admin UI - Category:

Admin UI - Product:



Návratová hodnota URL je JSON:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
    "product": [
        {
            "pk": 3,
            "model": "json01App.product",
            "fields": {
                "product_mail": "PC01@pc.sk",
                "product_mob": "0948 620 720",
                "product_type": "Dell OptiPlex 755",
                "product_desc": "Parametre: OptiPlex 755 DT: Intel Core 2 Duo E7200 (2.53GHz, 1066MHz, 3MB) Desktop Chassis Resource DVD: OptiPlex 755 Diagnostics & Drivers Vista/XP Documentati",
                "product_price": "130 ",
                "category_id": 1
            }
        }
    ]
}

Android aplikácia

Aplikácia obsahuje na úvodnej obrazovke tri tlačítka a každé z nich reprezentuje vstup do inzertného obsahu danej kategórie. Po stlačení tlačítka sa zobrazia položky (inzeráty) danej kategórie a po následnom kliknutí na konkrétny inzerát sa zobrazí jeho podrobný obsah.

Poznámka na úvod:
Minimálne požiadavky na verziu OS je Android 3.0.x HONEYCOMB (API 11) z dôvodu použitia dialógového okna „DialogFragment“, namiesto zavrhovaného „AlertDialog“.

Riešenie:
  1. MainActivity.java - po spustení aplikácie sa na pozadí volá URL pre každú kategóriu zvlášť (inštancia „inner“ triedy [ReadJSONFeedTask]). Vrátená hodnota sa uloží ako JSONObject a rozparsovaný výsledok sa ukladá do HashMap premennej (ArrayList), pripravenej pre zobrazenie JSON obsahu, prezentovaného v UI ako zoznam položiek (ListActivity). Ak je návratová hodnota JSON prázdna, prípadne je URL neplatné, vyvolá sa dialógové okno (DialogFragmet) s informáciou o probléme.
  2. DisplayMessageActivity.java – kliknutím na ľubovoľné tlačítko predstavujúce jednu z kategórii sa volá aktivita, ktorá zostaví a zobrazí spomenutý zoznam položiek.
  3. SingleMenuItemActivity.java - následným kliknutím na niektorú z položiek zoznamu sa jej obsah zobrazí opäť ako nový zoznam položiek.


Dôležité:
Pred spustením (kompiláciou) Android aplikácie je potrebné upraviť nasledovné konštanty v hlavnej triede "MainActivity":

  • JSON_URL = URL webového portálu, volaný pre získanie JSON dát,
  • CATEGORY_TYPE_PC (NB,MOB) = číselný parameter definujúci kategóriu (hodnota parametra predstavuje primárny kľúč entity „Category“ v DB, viď. „models.py“).


Screenshot:



Sources:
Bazar_example.zip


Záver:
Ukážková aplikácia slúži ako priblíženie a nie ako komplexné riešenie danej problematiky, preto je potrebné brať v úvahu absenciu štandardných funkcionalít pri podobných riešeniach v praxi, ako napríklad ukladanie získaných dát v mobile pre neskoršiu prezentáciu – offline a podobne.


Monday, January 14, 2013

Kivy, (že by) skutočný multiplatformový framework?


Kivy je open source knižnica nástrojov pre platformne nezávislé (MacOSX, Linux, Windows, Android, iOS), „multy-touch“, GUI aplikácie.

Programovací jazyk – python

GUI interface – OpenGL

zdroj: http://kivy.org/


Ukážka jednoduchej aplikácie (okno s jedným tlačítkom):

(main.py)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import kivy
kivy.require('1.0.6')
 
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.uix.button import Button
 
class Controller2(BoxLayout):
 
    def __init__(self, **kwargs):
        super(Controller2, self).__init__(**kwargs)
 
        self.padding = 20
 
        button = Button(text='button')
        self.add_widget(button)
 
class Controller2App(App):
    def build(self):
        return Controller2()
 
if __name__ == '__main__':
    Controller2App().run()


Ten istý príklad s použitím "kivy language". Konfiguračný súbor (*.kv), popisujúci užívateľské rozhranie a interakcie umožňuje oddeliť zdrojový kód od kódu určujúceho vzhľad UI.

(main.py)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import kivy
kivy.require('1.0.6')
 
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
 
class Controller(BoxLayout):
    pass
 
class ControllerApp(App):
    def build(self):
        return Controller()
 
if __name__ == '__main__':
    ControllerApp().run()

(controller.kv)
1
2
3
4
5
6
7
8
9
#:kivy 1.0
 
<Controller>:
 
    BoxLayout:
        padding: 20
 
        Button:
            text: 'button'


Print screen jednoduchej app. na rôznych platformách t.j. jeden zdrojový kód (viď. nižšie) interpretovaný pod troma platformami (OS X nebol k dispozícii :-)

Linux Debian - GNOME 3:

Windows 7:

 Android 4.0:

Jednotný zdrojový kód ukážkovej aplikácie interpretovaný vo všetkých platfomách:

(main.py)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import kivy
kivy.require('1.0.5')
from kivy.uix.gridlayout import GridLayout
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.uix.image import Image
class MyClass(GridLayout):
    def __init__(self):
        super(MyClass, self).__init__()
        def my_callback(self, obj):
            print 'My button <%s> state is <%s>' % (self, obj)
            textOutput.text = textInput.text
        self.cols = 2
        self.padding = 200
        self.spacing = 10
  
        self.row_force_default = True
        self.row_default_height = 40
        wimg = Image(
            source='Logo.png',
            size_hint_x=None,
            width=200
            )
        textOutput1 = Label(
            size_hint_x=None,
            width=100
            )      
        textInput = TextInput(
            multiline=False,
            size_hint_x=None,
            width=200
            )
        button = Button(
            text='Push',
            size_hint_x=None,
            width=100
            )
        textOutput = Label(
            size_hint_x=None,
            width=200
            )      
        button.bind(state = my_callback)
        self.add_widget(wimg)
        self.add_widget(textOutput1)
        self.add_widget(textInput)
        self.add_widget(button)
        self.add_widget(textOutput)
 
class MyClassApp(App):
    def build(self):
        return MyClass()
if __name__ == '__main__':
    MyClassApp().run()

Výhody:
  • open source
  • skutočne jednotný kód pre všetky podporované platformy
  • jednoduchá tvorba GUI rozhrania
  • jednotný vzhľad GUI na všetkých platformách (dá sa považovať aj za nevýhodu, tak ako u JAVA app.)
  • podpora periférií mob. zariadení (multy-touch, kamera, telefón,... )
  • dobra dokumentácia (400 stranové pdf) a aktívna komunita

Nevýhody:
  • vyžaduje OpenGL od verzie 2.0 napriek tomu že táto verzia je vonku už od 2004, mnohé PC s OS Win XP majú GPU, ktorých ovládače ešte stále nepodporujú OpenGL 2.0 a už s najväčšou pravdepodobnosťou ani nebudú podporovať
  • jednotný vzhľad GUI, ktorý je silne orientovaný na mob. aplikácie (čierno – čierny šat aplikácie)
  • minimálna veľkosť aplikácie po nainštalovaní na OS Android mala 20MB (predpokladám že veľkosť app. lineárne nenarastá so zložitosťou samotnej app., ale aj tak je to dosť).

Záver:
Zaujímavý nástroj pre rýchlu a jednoduchú tvorbu GUI multiplatformových aplikácii, ktorý ale asi potrebuje ešte trošku vyzrieť a to nie len po komunitnej stránke.