O artigo anterior mostrou brevemente as vantagens da programação declarativa de aplicativos cliente-servidor para android em comparação com o imperativo.Agora, escreveremos um projeto pequeno, mas suficiente, para avaliar a eficácia da biblioteca DePro. Faz parte de um dos exemplos educacionais da biblioteca . O design de todas as telas que descrevemos é mostrado nas seguintes figuras:

Tela DRAWER Tela CATALOG Tela PRODUCT_LIST

CATALOG_ DESCRIPT CHARACTERISTIC

FITNESS FITNESS_
Nessas telas, sua funcionalidade é geralmente entendida. O menu lateral contém dois itens: "Catálogo" e "Fitness". Quando você seleciona um item, a tela correspondente é exibida. A tela CATALOG contém uma lista horizontal "Notícias". Quando você clica em qualquer "novo produto", uma tela com uma descrição desse produto é exibida. Descrição consiste em duas guias: "Descrição" e "Características". Também na tela CATÁLOGO, há uma lista suspensa "Catálogo". Quando você clica na seta para baixo, o diretório é aberto (fecha). Quando você clica na linha inteira, a tela PRODUCT_LIST é exibida com uma lista de produtos para o item selecionado no catálogo.Quando você clica no item "Fitness", a tela FITNESS com uma lista de serviços é exibida. A lista depende do clube selecionado no botão giratório. Quando você tenta sair do aplicativo, uma caixa de diálogo de aviso é exibida.O servidor transfere dados no formato json para o aplicativo. A estrutura de dados para cada tela é descrita abaixo. Nos aplicativos gravados no DePro a partir da API, apenas a URL é usada, a estrutura de dados é necessária apenas para definir corretamente a exibição de nome (id), porque a ligação é realizada por nome. Vale a pena notar que os dados são uma fatia incompleta de dados reais. Portanto, pode não haver conexões em nomes, imagens. Em particular, as imagens do produto totalizam 20 peças. Portanto, a mesma imagem pode estar em muitos produtos.API por exemplo telasCATALOG () URL depro/cron/news, GET. . .
{
"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":","
},
. . .
]
Agora considere nossas etapas para escrever um aplicativo.1. No estúdio, criaremos um novo projeto. O nome pode ser definido a seu critério.2. Implantação de recursos. Conforme mencionado no primeiro artigo, os arquivos de recurso (XML) são usados convencionalmente. Portanto, para não perder tempo com coisas conhecidas, basta baixar todos os recursos necessários .Descompacte o arquivo res_example.zip resultante. No estúdio, exclua todo o conteúdo da pasta res.Transfira o conteúdo da pasta res descompactada para a pasta res do projeto. Depois disso, levando em conta os recursos do Android Studio, talvez seja necessário limpar o projeto e / ou executar o comando Caches / Reiniciar Inválidos.3. Conexão da bibliotecaNa seção dependências do arquivo build.gradle do módulo, você precisa especificar: implementation 'github.com/deprosystem/depro:compon:3.0.1'
Na seção android do arquivo build.gradle do módulo, você precisa especificar: packagingOptions {
exclude 'META-INF/DEPENDENCIES'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
Ao escolher o atributo minSdkVersion, é necessário considerar que a biblioteca suporta minSdkVersion = 17. Após alterar o build.gradle, você precisa sincronizar o projeto.4. Criação de classes necessárias (arquivos). Ao trabalhar com a biblioteca, apenas 4 classes são usadas: MyDeclareScreens - todas as telas são descritas; MyParams - defina os parâmetros necessários para a aplicação; MyApp - a biblioteca DePro é iniciada; MainActivity - atividade inicial. Você pode usar seus próprios nomes de classe.Crie a classe MyDeclareScreens.java. Seu conteúdo é o seguinte: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);
}
Mais adiante, descreveremos todas as construções de DePro usadas. Para conectar a importação, use as teclas alt + enter. O vermelho também será destacado na classe Api na qual os endereços para todas as solicitações estão definidos. Seu conteúdo será dado posteriormente.Crie a classe MyParams.java. Na maioria dos casos, as configurações padrão são suficientes. No nosso caso, definiremos apenas o URL base.public class MyParams extends AppParams {
@Override
public void setParams() {
baseUrl = "https://deprosystem.com/";
}
}
Altere o conteúdo criado pelo estúdio da classe MainActivity para o seguinte:public class MainActivity extends BaseActivity {
@Override
public String getNameScreen() {
return MyDeclareScreens.MAIN;
}
}
No manifesto de MainActivity, você pode especificar a orientação de retrato. Em princípio, a biblioteca suporta a rotação da tela, mas nesta versão para telas do tipo activity (), além do início, a orientação de retrato também é prescrita.Crie a classe 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());
}
}
Este é um singleton regular no método onCreate no qual MyParams e MyDeclareScreens estão definidos.Lembre-se de descrever o MyApp no manifesto.Para finalizar, crie a classe 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. Agora você pode executar o aplicativo para execução.Se tudo for inserido corretamente, quando o aplicativo iniciar, todas as telas especificadas serão exibidas (e funcionarão).Como vemos, temos apenas cinco classes simples para todo o aplicativo. E quatro deles são auxiliares. Seu conteúdo é independente do número de telas. A descrição, geralmente não trivial, das telas também ocupa um pouco de espaço (menos de 80 linhas). Agora mostramos que a descrição não é apenas não grande, mas também não é complicada. Para fazer isso, descrevemos a operação dos componentes de biblioteca usados.Conforme indicado no primeiro artigo, as telas da biblioteca podem ser atividade ou fragmento, o que define o nome da tela (linha) e o layout. Links para telas são criados por seus nomes. A escolha de qual tipo de tela usar é realizada da maneira usual.Tela PRINCIPALAssim, a partir do design, pode-se ver que a tela inicial possui um menu lateral e um contêiner para fragmentos. Na marcação de R.layout.activity_main, um DrawerLayout padrão é definido. Portanto, na descrição da tela PRINCIPAL, especificamos o componente da gaveta, para o qual passamos o ID do próprio DrawerLayout e seus contêineres para a barra lateral e os fragmentos. Também indicamos o nome da tela (DRAWER), que será exibida na barra lateral. O navegador finishDialog indica que, antes de sair do aplicativo, é necessário emitir um diálogo de confirmação.Tela DRAWERContém apenas um componente de menu para o qual um modelo do tipo Menu é especificado no modelo e na visualização id de um elemento de marcação do tipo RecyclerView, que exibirá o menu. O próprio menu indica que o item de menu “CATALOG” será exibido no contêiner de fragmentos quando o menu for iniciado.Tela CATALOGContém uma nova lista horizontal. Ao receber dados do servidor, seu modelo usa paginação e exibe o progresso em R.id.progr. Se sua Internet for rápida, você poderá não notar a aparência de um painel com progresso. Se você quiser assistir, poderá mudar para uma Internet mais lenta ou alterar a cor de fundo de R.id.progr. Nesse caso, você verá pelo menos piscando. Para paginação, os parâmetros especificados no AppParams por padrão são usados. A visualização recebe R.id.recycler_news com um RecyclerView e layout para itens. Quando você clica em qualquer item da lista, a tela PRODUCT_DESCRIPT é iniciada.A lista de diretórios é uma lista suspensa. O nível de divulgação é definido no campo "extendedLevel". Se não for transmitido com os dados de origem, a própria biblioteca lidará com isso. O mesmo parâmetro define qual layout da lista usar em cada nível de divulgação. O fato de a lista estar suspensa serve à funcionalidade expandida (...) O modelo será definido no cator para receber dados do servidor para os próximos níveis. O modelo especifica o endereço da solicitação Api.CATALOG_EX e o nome do parâmetro de solicitação "catalog_id". Em expandido, R.id.expand também é indicado - um elemento de marcação nos itens clicando no qual a lista será expandida e o ID do elemento que será rotativamente animado em 180 graus ao expandir - fechando a lista. E, finalmente, o navegador indicaquando você clicar no item da lista, a tela do PRODUCT_LIST será chamada.O navegador, que se refere à tela inteira, indica que quando você clica no elemento R.id.back, um painel lateral é aberto.Tela PRODUCT_LISTAo especificar uma tela, é indicado que o valor atual do parâmetro catalog_name será mostrado no cabeçalho e a animação de saída será da direita para a esquerda (AS.RL). A descrição da lista já é familiar para nós. A única coisa para a apresentação é o visibleManager, que controla a visibilidade dos elementos de marcação, dependendo dos valores dos dados correspondentes. O navegador relacionado à tela inteira indica que, quando você clica no elemento R.id.back, você volta à tela anterior.Tela PRODUCT_DESCRIPTNovo para nós é um componente do tipo PAGER_F. Está associado a um ViewPager comum. Ele mostra uma lista de telas (fragmentos) a serem exibidas e o TabLayout (setTab) está conectado.A tela PRODUCT_DESCRIPT aparece na guia DESCRIPTION.Um componente do tipo PANEL exibe dados obtidos pelo modelo. A lista "Analógicos" exibe uma lista de produtos similares, se houver, ou usando a funcionalidade noDataView (), a mensagem "Faltam analógicos".Tela CARACTERÍSTICAExibe uma lista de recursos do produto.Tela FITNESSUm componente do tipo SPINNER exibe uma lista de clubes com a opção de selecionar um. A lista de clubes é definida no modelo como uma string json.A lista de categorias de classes é normal. A funcionalidade eventFrom (...) indica que, ao alterar o componente associado ao R.id.spinner (no nosso caso, o spiner), é necessário atualizar os dados.O código do aplicativo discutido no artigo pode ser visualizado no Github .O artigo é apenas para orientação. Mais detalhadamente com os recursos da biblioteca DePro está disponível na documentação .