Pemrograman deklaratif aplikasi client-server di android. Bagian 2

The artikel sebelumnya secara singkat menunjukkan keuntungan dari pemrograman deklaratif aplikasi client-server untuk android dibandingkan dengan keharusan.

Sekarang kita akan menulis proyek kecil, tetapi cukup, untuk mengevaluasi efektivitas perpustakaan DePro. Itu adalah bagian dari salah satu contoh pendidikan perpustakaan . Desain semua layar yang kami jelaskan ditunjukkan pada gambar berikut:

gambar gambar gambar
Layar DRAWER layar KATALOG layar PRODUCT_LIST

gambar gambar gambar
 CATALOG_           DESCRIPT          CHARACTERISTIC

gambar gambar gambar
 FITNESS           FITNESS_          


Dari layar ini, fungsinya umumnya dipahami. Menu samping berisi dua item "Katalog" dan "Kebugaran". Ketika Anda memilih item, layar yang sesuai ditampilkan. Layar CATALOG berisi daftar "Berita" horisontal. Ketika Anda mengklik "produk baru" apa pun, layar dengan deskripsi produk ini ditampilkan. Deskripsi terdiri dari dua tab: "Deskripsi" dan "Karakteristik". Juga di layar CATALOG ada daftar drop-down "Katalog". Ketika Anda mengklik panah ke bawah, direktori terbuka (tertutup). Ketika Anda mengklik pada seluruh baris, layar PRODUCT_LIST ditampilkan dengan daftar produk untuk item yang dipilih dalam katalog.

Ketika Anda mengklik item "Kebugaran", layar FITNESS dengan daftar layanan ditampilkan. Daftarnya tergantung pada klub yang dipilih dalam pemintal. Saat Anda mencoba keluar dari aplikasi, dialog peringatan ditampilkan.

Server mentransfer data dalam format json ke aplikasi. Struktur data untuk setiap layar dijelaskan di bawah ini. Dalam aplikasi yang ditulis dalam DePro dari API, hanya URL yang digunakan, struktur data hanya diperlukan untuk mengatur tampilan nama (id) dengan benar, karena pengikatan dilakukan berdasarkan nama. Perlu dicatat bahwa data adalah sepotong data nyata yang tidak lengkap. Karenanya, mungkin tidak ada koneksi pada nama, gambar. Secara khusus, gambar produk total 20 pcs. Oleh karena itu, gambar yang sama dapat terdapat di banyak produk.

API untuk layar contoh
Layar CATALOG untuk daftar horizontal (Baru) URL depro / cron / news, metode GET. Saat membaca data tentang produk baru, pagination digunakan. Parameter pagination dilewatkan di header.

Menjawab

    {
        "product_id":4610,
        "catalog_id":15984,
        "product_name":"  20  6  ( 1*20) APRO",
        "catalog_code":"ZRG-20kit",
        "picture":"depro/cronimg/picture_1.jpeg",
        "bar_code":"4824041010653",
        "oem":"",
        "price":175.98,
        "brand":"APRO",
        "product_code":"032578",
        "gift":0,
        "bonus":0,
        "new_product":1,
        "quantity":5
    },
    . . .

URL depro/cron/catalog.

URL depro/cron/catalog_ex catalog_id id , .

:

[
    {
        "catalog_id":15510,
        "parent_id":0,
        "catalog_name":""
    },
    {
        "catalog_id":15584,
        "parent_id":0,
        "catalog_name":""
    },
    . . .
]

PRODUCT_LIST URL depro/cron/product_list : expandedLevel catalog_id.
expandedLevel β€” (0, 1 2), catalog_id β€” id .

0 1 , , .

GET

()

URL depro/cron/product_barcode
barcode_scanner.

URL depro/cron/product_search product_name. LIKE. product_name .

.

DESCRIPT

: URL depro/cron/product_id product_id. GET.



{
    "product_id":2942,
    "catalog_id":15594,
    "product_name":"   2110, 2111, 2112,  Sens ''  ",
    "catalog_code":"23.3828"
    ,"picture":"depro/cronimg/picture_16.jpeg",
    "bar_code":"2000000148472",
    "oem":"2112-3851010",
    "price":103.02,
    "brand":", . , ",
    "product_code":"027729",
    "gift":1,
    "bonus":0,
    "new_product":0,
    "quantity":16
}

: URL depro/cron/product_analog product_id. GET.



[
    {
        "product_id":561,
        "catalog_id":15587,
        "product_name":"   2110, 2111, 2112 (  16 . ) AURORA",
        "catalog_code":"WP-LA2112",
        "picture":"depro/cronimg/picture_12.jpeg",
        "bar_code":"2900011680711",
        "oem":"2112-1307010",
        "price":188.16,
        "brand":"AURORA, Poland",
        "product_code":"016807",
        "gift":0,
        "bonus":1,
        "new_product":0,
        "quantity":15
    },
    . . .
]


CHARACTERISTIC URL depro/cron/product_charact product_id. GET.


[
    {
        "prop_id":2764,
        "product_id":2942,
        "name":"",
        "value":", . , "
    },
    {
        "prop_id":2765,
        "product_id":2942,
        "name":"   ",
        "value":","
    },
    . . .
]


Sekarang perhatikan langkah-langkah kami untuk menulis aplikasi.

1. Di studio kami akan membuat proyek baru. Nama dapat diatur atas kebijaksanaan Anda.

2. Penyebaran sumber daya. Seperti disebutkan dalam artikel pertama, file sumber daya (XML) digunakan konvensional. Karena itu, agar tidak membuang waktu untuk hal-hal yang diketahui, kami cukup mengunduh semua sumber daya yang diperlukan .

Buka zip file res_example.zip yang dihasilkan. Di studio, hapus seluruh isi folder res.

Transfer isi folder res yang tidak di-zip ke folder res proyek. Setelah itu, dengan mempertimbangkan fitur-fitur Android Studio, Anda mungkin perlu menghapus proyek dan / atau menjalankan perintah Cache / Restart yang tidak valid.

3. Koneksi perpustakaan

Di bagian dependensi dari file build.gradle modul, Anda perlu menentukan:

    implementation 'github.com/deprosystem/depro:compon:3.0.1'

Di bagian android file build.gradle modul, Anda perlu menentukan:

    packagingOptions {
        exclude 'META-INF/DEPENDENCIES'
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

Saat memilih atribut minSdkVersion, perlu diingat bahwa perpustakaan mendukung minSdkVersion = 17. Setelah mengubah build.gradle, Anda perlu menyinkronkan proyek.

4. Pembuatan kelas yang diperlukan (file). Saat bekerja dengan perpustakaan, hanya 4 kelas yang digunakan: MyDeclareScreens - semua layar dijelaskan; MyParams - mengatur parameter yang diperlukan untuk aplikasi; MyApp - perpustakaan DePro dimulai; MainActivity - memulai aktivitas. Anda dapat menggunakan nama kelas Anda sendiri.

Buat kelas MyDeclareScreens.java. Isinya sebagai berikut:

public class MyDeclareScreens extends DeclareScreens {

    public final static String
            MAIN = "main", DRAWER = "DRAWER", CATALOG = "CATALOG",
            DESCRIPT = "DESCRIPT", CHARACTERISTIC = "CHARACTERISTIC",
            PRODUCT_LIST = "PRODUCT_LIST", PRODUCT_DESCRIPT = "PRODUCT_DESCRIPT",
            FITNESS = "FITNESS";

    @Override
    public void declare() {
        activity(MAIN, R.layout.activity_main)
                .navigator(finishDialog(R.string.attention, R.string.finishOk))
                .drawer(R.id.drawer, R.id.content_frame, R.id.left_drawer, null, DRAWER);

        fragment(DRAWER, R.layout.fragment_drawer)
                .menu(model(menu), view(R.id.recycler));

        fragment(CATALOG, R.layout.fragment_catalog)
                .navigator(handler(R.id.back, VH.OPEN_DRAWER))
                .component(TC.RECYCLER_HORIZONTAL, model(Api.NEWS_PROD).pagination().progress(R.id.progr),
                        view(R.id.recycler_news, R.layout.item_news_prod),
                        navigator(start(PRODUCT_DESCRIPT)))
                .component(TC.RECYCLER, model(Api.CATALOG),
                        view(R.id.recycler, "expandedLevel", new int[]{R.layout.item_catalog_type_1,
                                R.layout.item_catalog_type_2, R.layout.item_catalog_type_3})
                                .expanded(R.id.expand, R.id.expand, model(Api.CATALOG_EX, "catalog_id")),
                        navigator(start(PRODUCT_LIST)));

        activity(PRODUCT_LIST, R.layout.activity_product_list, "%1$s", "catalog_name").animate(AS.RL)
                .navigator(back(R.id.back))
                .component(TC.RECYCLER, model(Api.PRODUCT_LIST, "expandedLevel,catalog_id"),
                        view(R.id.recycler, R.layout.item_product_list)
                                .visibilityManager(visibility(R.id.bonus_i, "bonus"),
                                        visibility(R.id.gift_i, "gift"),
                                        visibility(R.id.newT, "new_product")),
                        navigator(start(PRODUCT_DESCRIPT)));

        activity(PRODUCT_DESCRIPT, R.layout.activity_product_descript, "%1$s", "catalog_name").animate(AS.RL)
                .navigator(back(R.id.back))
                .setValue(item(R.id.product_name, TS.PARAM, "product_name"))
                .component(TC.PAGER_F, view(R.id.pager, DESCRIPT, CHARACTERISTIC)
                        .setTab(R.id.tabs, R.array.descript_tab_name));

        fragment(DESCRIPT, R.layout.fragment_descript)
                .component(TC.PANEL, model(Api.PRODUCT_ID, "product_id"),
                        view(R.id.panel).visibilityManager(visibility(R.id.bonus, "bonus")))
                .component(TC.RECYCLER, model(Api.ANALOG_ID_PRODUCT,"product_id"),
                        view(R.id.recycler, R.layout.item_product_list).noDataView(R.id.not_analog)
                                .visibilityManager(visibility(R.id.bonus_i, "bonus"),
                                        visibility(R.id.gift_i, "gift"),
                                        visibility(R.id.newT, "new_product")),
                        navigator(start(0, PRODUCT_DESCRIPT, PS.RECORD),
                                handler(0, VH.BACK))) ;

        fragment(CHARACTERISTIC, R.layout.fragment_characteristic)
                .component(TC.RECYCLER, model(Api.CHARACT_ID_PRODUCT, "product_id"),
                        view(R.id.recycler, "2", new int[] {R.layout.item_property, R.layout.item_property_1}));

        fragment(FITNESS, R.layout.fragment_fitness)
                .navigator(handler(R.id.back, VH.OPEN_DRAWER))
                .component(TC.SPINNER, model(JSON, getString(R.string.clubs)),
                        view(R.id.spinner, R.layout.item_spin_drop, R.layout.item_spin_hider))
                .component(TC.RECYCLER, model(Api.FITNESS, "clubId"),
                        view(R.id.recycler, R.layout.item_fitness), null).eventFrom(R.id.spinner);
    }

    Menu menu = new Menu()
            .item(R.drawable.list, R.string.m_catalog, CATALOG, true)
            .divider()
            .item(R.drawable.ic_aura, R.string.fitness, FITNESS);
}

Kami nantinya akan menjelaskan semua konstruksi DePro yang digunakan. Untuk menghubungkan impor, gunakan tombol alt + enter. Merah juga akan disorot kelas Api di mana alamat untuk semua permintaan ditetapkan. Isinya akan diberikan nanti.

Buat kelas MyParams.java. Dalam kebanyakan kasus, pengaturan default sudah cukup. Dalam kasus kami, kami hanya akan menetapkan URL dasar.

public class MyParams extends AppParams {
    @Override
    public void setParams() {
        baseUrl = "https://deprosystem.com/";
    }
}

Ubah konten yang dibuat oleh studio dari kelas MainActivity menjadi yang berikut:

public class MainActivity extends BaseActivity {
    @Override
    public String getNameScreen() {
        return MyDeclareScreens.MAIN;
    }
}

Dalam manifes untuk MainActivity, Anda dapat menentukan orientasi potret. Pada prinsipnya, perpustakaan mendukung rotasi layar, tetapi dalam versi ini untuk layar jenis aktivitas (), selain dari awal, orientasi potret juga ditentukan.

Buat kelas MyApp:

public class MyApp extends Application {
    private static MyApp instance;
    private Context context;

    public static MyApp getInstance() {
        if (instance == null) {
            instance = new MyApp();
        }
        return instance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
        context = getApplicationContext();

        DeclareParam.build(context)
                .setAppParams(new MyParams())
                .setDeclareScreens(new MyDeclareScreens());
    }
}

Ini adalah singleton reguler dalam metode onCreate yang ditetapkan MyParams dan MyDeclareScreens.
Ingatlah untuk menggambarkan MyApp dalam manifes.

Untuk menyelesaikan, buat kelas Api:

public class Api {
    public static final String CATALOG = "depro/cron/catalog",
            NEWS_PROD = "depro/cron/news_prod",
            PRODUCT_LIST = "depro/cron/product_list",
            PRODUCT_ID = "depro/cron/product_id",
            ANALOG_ID_PRODUCT = "depro/cron/product_analog",
            CHARACT_ID_PRODUCT = "depro/cron/product_charact",
            FITNESS = "depro/cron/fitness",
            CATALOG_EX = "depro/cron/catalog_ex";
}

5. Sekarang Anda dapat menjalankan aplikasi untuk dieksekusi.

Jika semuanya dimasukkan dengan benar, maka ketika aplikasi dimulai, semua layar yang ditentukan akan ditampilkan (dan berfungsi).

Seperti yang kita lihat, kita hanya memiliki lima kelas sederhana untuk seluruh aplikasi. Dan empat dari mereka adalah pembantu. Isinya tidak tergantung pada jumlah layar. Deskripsi, umumnya tidak sepele, dari layar juga membutuhkan sedikit ruang (kurang dari 80 baris). Sekarang kami menunjukkan bahwa deskripsi tidak hanya tidak besar, tetapi juga tidak rumit. Untuk melakukan ini, kami menggambarkan operasi komponen perpustakaan yang digunakan.

Seperti yang ditunjukkan dalam artikel pertama, layar di perpustakaan dapat berupa aktivitas atau fragmen, yang menetapkan nama layar (garis) dan tata letak. Tautan ke layar dibuat dengan nama mereka. Pilihan jenis layar yang akan digunakan dilakukan dengan cara biasa.

Layar MAIN

Jadi, dari desainnya dapat dilihat bahwa layar mulai memiliki menu samping dan wadah untuk fragmen. Di markup R.layout.activity_main, DrawerLayout standar diatur. Oleh karena itu, dalam deskripsi layar MAIN, kami menentukan komponen laci, yang kami lewati id dari DrawerLayout itu sendiri dan wadahnya untuk sidebar dan fragmen. Kami juga menunjukkan nama layar (DRAWER), yang akan ditampilkan di bilah sisi. Navigator finishDialog menunjukkan bahwa sebelum keluar dari aplikasi Anda perlu mengeluarkan dialog konfirmasi.

Layar DRAWER Hanya

berisi satu komponen menu yang modelnya ditentukan oleh Menu, dan pada tampilan id elemen markup dari jenis RecyclerView, yang akan menampilkan menu. Menu itu sendiri menunjukkan bahwa item menu "CATALOG" akan ditampilkan dalam wadah fragmen ketika menu dimulai.

Layar CATALOG

Berisi satu Daftar Baru horisontal. Saat menerima data dari server, modelnya menggunakan pagination, dan menampilkan progresnya di R.id.progr. Jika Internet Anda cepat, maka Anda mungkin tidak melihat tampilan panel dengan kemajuan. Jika Anda ingin menontonnya, Anda dapat beralih ke Internet yang lebih lambat, atau mengubah warna latar belakang R.id.progr. Dalam hal ini, Anda setidaknya akan melihatnya berkedip. Untuk pagination, parameter yang ditentukan dalam AppParams secara default digunakan. Tampilan diberikan kepada R.id.recycler_news dengan RecyclerView dan tata letak untuk item. Saat Anda mengeklik salah satu item dalam daftar, layar PRODUCT_DESCRIPT dimulai.

Daftar Direktori adalah drop down. Level pengungkapan didefinisikan dalam bidang "extendedLevel". Jika tidak ditransmisikan dengan sumber data, perpustakaan itu sendiri akan menangani ini. Parameter yang sama mengatur tata letak mana dari daftar untuk digunakan pada setiap tingkat pengungkapan. Fakta bahwa daftar ini adalah drop-down melayani fungsionalitas diperluas (...). Model akan ditetapkan dalam kator untuk menerima data dari server untuk tingkat berikutnya. Model menentukan alamat permintaan Api.CATALOG_EX dan nama parameter permintaan β€œcatalog_id”. Dalam diperluas, R.id.expand juga ditunjukkan - elemen markup dalam item dengan mengeklik daftar mana yang akan diperluas dan id elemen yang akan dirotasi secara animasi sebesar 180 derajat saat memperluas - menutup daftar. Dan akhirnya, navigator menunjukkanbahwa ketika Anda mengklik pada item daftar, layar PRODUCT_LIST akan dipanggil.

Navigator, yang merujuk ke seluruh layar, menunjukkan bahwa ketika Anda mengklik pada elemen R.id.back, panel samping akan terbuka.

Layar PRODUCT_LIST

Ketika menentukan layar, ditunjukkan bahwa nilai saat ini dari parameter catalog_name akan ditampilkan dalam judul dan animasi output akan dari kanan ke kiri (AS.RL). Deskripsi daftar sudah tidak asing lagi bagi kami. Satu-satunya hal untuk presentasi adalah manajer visibilitas, yang mengontrol visibilitas elemen markup tergantung pada nilai data yang sesuai. Navigator yang terkait dengan seluruh layar menunjukkan bahwa ketika Anda mengklik pada elemen R.id.back, Anda akan kembali ke layar sebelumnya.

Layar PRODUCT_DESCRIPT

Yang baru bagi kami adalah komponen tipe PAGER_F. Ini dikaitkan dengan ViewPager biasa. Ia ditampilkan daftar layar (fragmen) untuk ditampilkan, dan TabLayout (setTab) terhubung.

Layar PRODUCT_DESCRIPT muncul di tab DESCRIPTION.

Komponen tipe PANEL menampilkan data yang diperoleh model. Daftar "Analog" menampilkan daftar produk serupa, jika ada, atau menggunakan fungsionalitas noDataView (), pesan "Analog hilang".

Layar CHARACTERISTIC

Menampilkan daftar fitur produk.

Layar FITNESS

Komponen tipe SPINNER menampilkan daftar klub dengan opsi untuk memilih satu. Daftar klub diatur dalam model sebagai string json.

Daftar kategori kelas adalah normal. Fungsi eventFrom (...) menunjukkan bahwa ketika mengubah komponen yang terkait dengan R.id.spinner (dalam kasus kami, spiner), perlu memperbarui data.
Kode aplikasi yang dibahas dalam artikel dapat dilihat di Github .

Artikel ini hanya untuk panduan. Lebih lengkap dengan kemampuan perpustakaan DePro tersedia dalam dokumentasi .

All Articles