Construindo a Tela e a Lógica de Último Vídeo - YouTuber Android App - Parte 7

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes! Você receberá um email de confirmação. Somente depois de confirma-lo é que eu poderei lhe enviar os conteúdos semanais exclusivos. Os artigos em PDF são entregues somente para os inscritos na lista.

Email inválido.
Blog /Android /Construindo a Tela e a Lógica de Último Vídeo - YouTuber Android App - Parte 7

Construindo a Tela e a Lógica de Último Vídeo - YouTuber Android App - Parte 7

Vinícius Thiengo
(2354)
Go-ahead
"O método consciente de tentativa e erro é mais bem-sucedido que o planejamento de um gênio isolado."
Peter Skillman
Prototipagem Android
Capa do curso Prototipagem Profissional de Aplicativos
TítuloAndroid: Prototipagem Profissional de Aplicativos
CategoriasAndroid, Design, Protótipo
AutorVinícius Thiengo
Vídeo aulas186
Tempo15 horas
ExercíciosSim
CertificadoSim
Acessar Curso
Quer aprender a programar para Android? Acesse abaixo o curso gratuito no Blog.
Lendo
TítuloDomain-driven Design Destilado
CategoriaEngenharia de Software
Autor(es)Vaughn Vernon
EditoraAlta Books
Edição
Ano2024
Páginas160
Conteúdo Exclusivo
Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba gratuitamente conteúdos Android sem precedentes!
Email inválido

Tudo bem?

Neste artigo vamos continuar com o nosso projeto de aplicativo Android para YouTubers.

Nesta parte sete do projeto nós vamos construir passo a passo toda a configuração da principal tela do aplicativo, a tela de "Último vídeo" liberado em canal:

Animação de abertura de vídeo YouTube a partir do app Android para YouTubers

Antes de prosseguir, saiba que:

A versão e-book (PDF 📙) do projeto completo está disponível somente para os inscritos da lista de e-mails 📧 do Blog.

Se você se inscrever ainda hoje é possível que o link do e-book esteja disponível na página de confirmação de sua inscrição na lista de e-mails do Blog.

A seguir os tópicos que estaremos abordando neste sétimo conteúdo do projeto de aplicativo Android para YouTubers:

O que já temos até aqui

Se você chegou no projeto somente agora, saiba que este não é o primeiro e nem mesmo o último artigo já publicado sobre essa proposta de aplicativo Android.

Todo o roteiro de construção do projeto está na listagem a seguir:

Para tirar o máximo proveito do projeto de aplicativo que estaremos desenvolvendo... para isso é inteligente seguir cada um dos conteúdos na ordem apresentada na lista anterior.

Repositório

Para ter acesso a todos os códigos fontes do projeto já finalizado, entre no repositório GitHub dele em:

➙ GitHub do projeto de aplicativo Android para YouTuber.

Fragmento de Último vídeo

Assim podemos partir para o principal fragmento do projeto de app para YouTubers.

Fragmento responsável por apresentar o último vídeo disponibilizado em canal e assim incentivar o clique no player:

Abrindo o vídeo no YouTube a partir do app Android

A proposta do player é justamente essa:

Incentivar o clique e assim levar o usuário a assistir ao vídeo. Consequentemente aumentando o engajamento dos seguidores no canal.

O vídeo será aberto ou no app oficial do YouTube ou no site oficial via navegador Web mobile.

Na pior das hipóteses, algo utópico, não haverá nenhum aplicativo capaz de abrir o vídeo e assim uma mensagem Toast será apresentada ao usuário para que ele instale algum app compatível com a necessidade "assistir ao vídeo".

Então é isso, vamos aos códigos.

Estáticos de interface

Vamos iniciar com a parte estática, XML. Que por sinal são os trechos desta tela de último vídeo que mais têm códigos.

Rótulos

No arquivo de Strings, mais precisamente o arquivo /res/values/strings.xml, adicione as seguintes novas definições:

...
<!-- LastVideoFragment -->
<string name="last_video_content_title">
Último vídeo liberado
</string>
<string name="last_video_play_content_desc">
Ícone de play do vídeo.
</string>
<string name="volume_icon_content_desc">
Ícone de controle volume.
</string>
<string name="head_phones_icon_content_desc">
Ícone de fones de ouvido.
</string>
<string name="video_resolution_icon_content_desc">
Ícone de controle de resolução (HD).
</string>
<string name="like_icon_content_desc">
Ícone de like, gostei do conteúdo.
</string>
<string name="touch_to_watch">
Toque para assistir
</string>
<string name="leave_a_comment">
Deixe seu comentário
</string>
<string name="last_video_toast_alert">
É preciso ou o aplicativo do YouTube ou um
navegador Web para que o vídeo \"%s\" comece.
</string>
...

Cores

No arquivo de cores, /res/values/colors.xml, adicione as seguintes novas definições de cores:

...
<!-- Video player -->
<color name="colorVideoPlayerBackground">#000000</color>
<color name="colorVideoPlayerForeground">#BB000000</color>
<color name="colorVideoPlayerIcon">#FFFFFF</color>

<!-- YouTube block -->
<color name="colorVideoPlayerYBBackground">#DDDDDD</color>
<color name="colorVideoPlayerYBText">#666666</color>

<!-- Comment block -->
<color name="colorVideoPlayerCBBackground">#B7E1C2</color>
<color name="colorVideoPlayerCBText">#666666</color>
...

 

Um detalhe importante, na verdade uma "lembrança":

O arquivo de definição de cores certamente será o que mais passará por atualizações quando você for reutilizar esse "projeto framework" para atender a algum outro canal cliente ou o seu próprio canal YouTube.

Por isso nós vamos dar uma atenção especial a este XML, colocando comentários para melhor identificar o que será atualizado em layout se houverem mudanças de cores.

Ícones vetoriais

Vamos agora adicionar todos os ícones vetoriais que precisaremos nesta tela de projeto. Serão poucos.

No arquivo /res/drawable, de sua versão de projeto, adicione os ícones a seguir (faça o download deles):

Ícone de play do vídeo, ic_play_button.xml:

Ícone de play do vídeo

Ícone de volume do vídeo, ic_volume.xml:

Ícone de volume do vídeo

Ícone de head phone, ic_head_phone.xml:

Ícone de head phone

Ícone de resolução do vídeo, ic_hd_video.xml:

Ícone de resolução do vídeo

Ícone de compartilhamento, like do vídeo, ic_like.xml:

Ícone de compartilhamento

Ícone da logo colorida do YouTube, ic_youtube_mini_color.xml:

Ícone da logo colorida do YouTube

Ícone colorido de caixa de comentários, ic_comment_color.xml:

Ícone colorido de caixa de comentários

Lembrando que esses ícones estão presentes em tela, pois fazem parte da estratégia de: incentivar o toque do usuário e assim conseguir com que ele realmente entre no vídeo pelo YouTube.

Novos estilos

Além do estilo de título de conteúdo (AppTheme.Title) já definido em projeto e que também estaremos utilizando nesta tela de "último vídeo"...

... além disso nesta tela teremos ainda mais estilos para que o código de layout XML fique consideravelmente menor e fácil de aplicar manutenção.

Em /res/values/styles.xml adicione os novos estilos a seguir:

...
<style name="AppTheme.VideoPlayerIcons">
<item name="android:layout_width">20dp</item>
<item name="android:layout_height">20dp</item>
<item name="android:tint">@color/colorVideoPlayerIcon</item>
</style>

<style name="AppTheme.VideoPlayerBand">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
<item name="android:drawablePadding">10dp</item>
<item name="android:ellipsize">end</item>
<item name="android:gravity">center_vertical</item>
<item name="android:maxLines">1</item>
<item name="android:paddingStart">10dp</item>
<item name="android:paddingTop">5dp</item>
<item name="android:paddingEnd">10dp</item>
<item name="android:paddingBottom">5dp</item>
<item name="android:textColor">@color/colorVideoPlayerYBText</item>
<item name="android:textSize">12sp</item>
<item name="android:textStyle">bold</item>
<item name="android:background">@drawable/bg_video_player_band</item>
</style>

<style name="AppTheme.VideoPlayerTextsBelow">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginStart">@dimen/standard_screen_side_margin</item>
<item name="android:layout_marginEnd">@dimen/standard_screen_side_margin</item>
<item name="android:layout_marginTop">10dp</item>
<item name="android:textColor">@color/colorContentText</item>
<item name="android:ellipsize">end</item>
<item name="android:maxLines">2</item>
</style>
...

 

Somente tente imaginar se o estilo AppTheme.VideoPlayerBand não tivesse sido isolado em styles.xml...

... a quantidade de código (15 linhas) que teríamos repetido em layout!

E sim, ainda é preciso criar o arquivo bg_video_player_band.xml no folder /res/drawable.

É este arquivo de recursos desenháveis que nos permite ter também as bordas arredondadas nas pequenas caixas informativas abaixo do vídeo player:

Caixas com informações extras de vídeo

Então, em /res/drawable, adicione o XML bg_video_player_band.xml com o código a seguir:

<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<solid android:color="@color/colorVideoPlayerYBBackground" />
<corners android:radius="4dp" />
</shape>

 

Note que a cor padrão em bg_video_player_band.xml é a cor da primeira caixa informativa:

Informação: Toque para assistir ao vídeo

Porém a caixa de comentários também utiliza o mesmo background... com o atributo android:backgroundTint definido em estrutura para mudar apenas a cor definida no arquivo de background:

...
<TextView
...
style="@style/AppTheme.VideoPlayerBand"
...
android:backgroundTint="@color/colorVideoPlayerCBBackground"
... />
...

 

Informação: Deixe seu comentário no vídeo

Prática comum para evitar a definição desnecessária de dois arquivos de background com praticamente a mesma configuração, mudando somente a cor.

Layout

Assim o layout do fragmento de vídeo. Primeiro o diagrama dele:

Diagrama do layout fragment_last_video.xml

Agora, em /res/layout, crie o arquivo XML fragment_last_video.xml com o seguinte código estático:

<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.fragment.LastVideoFragment">

<TextView
style="@style/AppTheme.Title"
android:text="@string/last_video_content_title" />

<LinearLayout
android:id="@+id/ll_last_video_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:orientation="vertical">

<androidx.cardview.widget.CardView
android:id="@+id/cv_last_video"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginStart="@dimen/standard_screen_side_margin"
android:layout_marginEnd="@dimen/standard_screen_side_margin"
android:layout_weight="1"
app:cardCornerRadius="8dp"
app:cardElevation="10dp">

<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<!--
ImageView responsável por conter o
banner do vídeo como background do
player em tela.
-->
<ImageView
android:id="@+id/iv_last_video_thumb"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorVideoPlayerBackground"
android:scaleType="centerCrop" />

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorVideoPlayerForeground"
android:padding="20dp">

<ImageView
android:id="@+id/iv_last_video_play"
android:layout_width="34dp"
android:layout_height="34dp"
android:layout_centerInParent="true"
android:contentDescription="@string/last_video_play_content_desc"
android:scaleType="fitCenter"
android:src="@drawable/ic_play_button"
app:tint="@color/colorVideoPlayerIcon" />

<ImageView
android:id="@+id/iv_volume"
style="@style/AppTheme.VideoPlayerIcons"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:contentDescription="@string/volume_icon_content_desc"
android:src="@drawable/ic_volume" />

<ImageView
style="@style/AppTheme.VideoPlayerIcons"
android:layout_alignParentBottom="true"
android:layout_marginStart="10dp"
android:layout_toEndOf="@+id/iv_volume"
android:contentDescription="@string/head_phones_icon_content_desc"
android:src="@drawable/ic_head_phone" />

<ImageView
style="@style/AppTheme.VideoPlayerIcons"
android:layout_alignParentEnd="true"
android:layout_alignParentBottom="true"
android:contentDescription="@string/video_resolution_icon_content_desc"
android:src="@drawable/ic_hd_video" />

<ImageView
style="@style/AppTheme.VideoPlayerIcons"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:contentDescription="@string/like_icon_content_desc"
android:src="@drawable/ic_like" />
</RelativeLayout>
</FrameLayout>
</androidx.cardview.widget.CardView>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/standard_screen_side_margin"
android:layout_marginTop="15dp"
android:layout_marginEnd="@dimen/standard_screen_side_margin"
android:orientation="horizontal">

<TextView
android:id="@+id/tv_touch_to_watch"
style="@style/AppTheme.VideoPlayerBand"
android:drawableStart="@drawable/ic_youtube_mini_color"
android:text="@string/touch_to_watch" />

<TextView
android:id="@+id/tv_comment"
style="@style/AppTheme.VideoPlayerBand"
android:layout_marginStart="5dp"
android:backgroundTint="@color/colorVideoPlayerCBBackground"
android:drawableStart="@drawable/ic_comment_color"
android:text="@string/leave_a_comment"
android:textColor="@color/colorVideoPlayerCBText" />
</LinearLayout>

<TextView
android:id="@+id/tv_last_video_title"
style="@style/AppTheme.VideoPlayerTextsBelow"
android:textSize="18sp"
android:textStyle="bold" />

<TextView
android:id="@+id/tv_last_video_desc"
style="@style/AppTheme.VideoPlayerTextsBelow"
android:layout_marginTop="5dp" />
</LinearLayout>
</LinearLayout>

 

Sim, este é um dos pontos de projeto que podem ser melhorados em futuros releases.

Mas confesso que não é nem de perto um ponto crítico, pois o layout é carregado apenas um vez, nós não o estamos utilizando dentro de algum framework de lista.

Sendo assim, ao menos para mim, perder muito tempo nesta parte do projeto é perder tempo com "vaidade". Isso ao menos nos primeiros releases.

Carregamento remoto de banner

Com a definição do layout anterior, mais precisamente na parte:

...
<!--
ImageView responsável por conter o
banner do vídeo como background do
player em tela.
-->
<ImageView
android:id="@+id/iv_last_video_thumb"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorVideoPlayerBackground"
android:scaleType="centerCrop" />
...

 

Com está definição já temos que esta próximo o momento de utilizarmos a URI referenciada na propriedade thumbUrl (da classe LastVideo) para carregarmos em projeto uma imagem remota.

Sendo assim vamos configurar a API que considero a mais eficiente para este tipo de tarefa: "carregamento remoto de imagem". A Picasso API.

No Gradle Nível de Aplicativo, ou build.gradle (Module: app), adicione em dependencies a seguinte definição:

...
dependencies {
...

/*
* Picasso API para carregamento de imagens remotas
* de maneira eficiente.
* */
implementation 'com.squareup.picasso:picasso:2.71828'
}
...

 

Se na época em que você estiver implementando o projeto houver uma versão mais atual da Picasso API, então utilize a versão mais atual, pois o projeto deverá continuar funcionando sem problemas.

Ao final sincronize o projeto.

Agora no AndroidManifest.xml vamos adicionar a permissão de Internet e uma definição de "confiança na origem" da requisição remota:

...
<uses-permission android:name="android.permission.INTERNET" />

<application
...
android:usesCleartextTraffic="true">
...

 

No Android Oreo, API 27, e anteriores o valor de usesCleartextTraffic é true por padrão.

Este atributo, em resumo (bem resumido), quando com o valor true informa que:

A requisição remota partindo do aplicativo pode acontecer sem receios, pois a fonte requisitada é segura.

Como estaremos sempre requisitando dados dos servidores do Google (YouTube), até mesmo as imagens. Então tranquilamente podemos ter essa definição em nosso aplicativo.

E já lhe adianto que se android:usesCleartextTraffic="true" não for definido em projeto como fizemos anteriormente...

... neste caso, em algumas ocasiões, as imagens não serão carregadas mesmo com o uso da Picasso API.

LastVideoFragment

Por fim a nossa configuração de fragmento da tela de último vídeo.

Configuração um pouco maior do que as realizadas nos fragmentos já apresentados até este ponto de nosso aplicativo Android.

Vamos iniciar com o básico e assim ir acrescentando o que for necessário.

Em /ui/fragment crie o fragmento LastVideoFragment com o seguinte código fonte:

package thiengo.com.br.canalvinciusthiengo.ui.fragment

import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.fragment_last_video.*
import thiengo.com.br.canalvinciusthiengo.R
import thiengo.com.br.canalvinciusthiengo.data.dynamic.UtilDatabase
import thiengo.com.br.canalvinciusthiengo.data.fixed.LastVideoData
import thiengo.com.br.canalvinciusthiengo.model.LastVideo

/**
* Contém toda a UI de último vídeo disponível
* no canal YouTube do app.
*
* @constructor cria um objeto completo do tipo
* [LastVideoFragment].
*/
class LastVideoFragment : Fragment() {

companion object {
/**
* Constante com o identificador único do
* fragmento [LastVideoFragment] para que
* ele seja encontrado na pilha de fragmentos
* e assim não seja necessária a construção
* de mais de um objeto deste fragmento em
* memória enquanto o aplicativo estiver em
* execução.
*/
const val KEY = "LastVideoFragment_key"
}

/**
* [lastVideo] sempre inicia com algum dado válido
* de "último vídeo" liberado, mesmo que nenhum
* vídeo tenha sido ainda enviado ao app.
*/
private var lastVideo: LastVideo = LastVideoData.getInitialVideo()

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle? ): View? {

return inflater.inflate(
R.layout.fragment_last_video,
container,
false
)
}
}

 

Apesar de lastVideo já ter algum dado inicial, ele ainda não está sendo configurado em tela, em layout.

Definição de UI em tela

Sendo assim, em LastVideoFragment, adicione os métodos setUiModel() e descriptionStatus() como a seguir:

...
/**
* Responsável pela configuração dos dados de
* "último vídeo disponível" em tela.
*
* Como é possível que a invocação deste método
* ocorra fora da Thread Principal, então é
* importante sempre ter o código de atualização
* de vídeo dentro de runOnUiThread().
*
* Outro ponto importante é garantir que não
* haverá NullPointerException caso os dados
* cheguem em método quando a UI não mais está no
* foreground (primeiro plano). Assim o operador
* not null (?.) é utilizado com frequência.
*
* @param lVideo último vídeo liberado em canal.
*/
private fun setUiModel( lVideo: LastVideo? ){

if( lVideo != null ){
activity?.runOnUiThread{
lastVideo = lVideo

try{
Picasso
.get()
.load( lVideo.thumbUrl )
.into( iv_last_video_thumb )

iv_last_video_thumb?.contentDescription = lVideo.title
}
catch( e: Exception ){}

tv_last_video_title?.text = lVideo.title
descriptionStatus( description = lVideo.description )
}
}
}

/**
* Garante que o componente visual de apresentação
* de descrição do vídeo somente estará em tela
* caso exista descrição (alguns vídeos não têm).
*
* @param description descrição do vídeo.
*/
private fun descriptionStatus( description: String ){

if( description.isNotEmpty() ){
tv_last_video_desc?.text = description
tv_last_video_desc?.visibility = View.VISIBLE
}
else{
tv_last_video_desc?.visibility = View.GONE
}
}
...

 

O dado de descrição esta isolado para configuração no método descriptionStatus(), pois como informado no trecho de definição dele na classe LastVideo: esse dado é opcional.

Note que em setUiModel() nós já estamos com o código de atualização de componentes visuais garantido em Thread Principal:

...
activity?.runOnUiThread{
...
}
...

 

Isso, pois este método também será invocado a partir de algoritmos de execução em banco de dados local, Room.

Ou seja, algoritmos que estão fora da Thread Principal e com dados de atualização de UI.

Note também que para todos os componentes visuais nós estamos utilizando o operador "not null", (?.).

Isso para garantir que não teremos um NullPointerException quando os dados de carregamento assíncrono (os que vêm do banco de dados local) forem entregues somente quando o fragmento LastVideoFragment não mais está em foreground.

Isso pode ocorrer se o usuário, por exemplo, logo na abertura do app trocar de tela, utilizando o menu principal para isto.

Com a utilização do operador not null nós conseguimos de maneira simples driblar esse possível problema.

Com frequência também estaremos utilizando o operador "force NullPointerException" (!!) junto a propriedade activity.

Isso, pois a definição dela em código nativo Java deixa claro que ela pode ser null.

Porém nós conhecemos o fluxo do código e assim sabemos que ela nunca será utilizada em algum método do ciclo de vida do fragmento onde ela seria null.

Mas tome cuidado com esse comportamento.

Estamos fazendo aqui, pois o código total do app é pequeno e sim: nós conhecemos todo o fluxo do código.

Voltando aos fontes...

... agora precisamos definir o primeiro ponto onde setUiModel() é invocado.

Adicione-o no método de ciclo de vida onActivityCreated() do fragmento de último vídeo, como a seguir:

...
override fun onActivityCreated( savedInstanceState: Bundle? ) {
super.onActivityCreated( savedInstanceState )
setUiModel( lVideo = lastVideo )
}
...

 

Thiengo, e o listener de clique?

Ouvidor de clique e abertura de vídeo

Se você voltar ao layout do fragmento LastVideoFragment você vai perceber que não há ao menos um listener de clique definido em nenhuma parte do layout.

E isso, a definição de listener de clique, é necessária para que seja possível abrir o vídeo em aplicativo do YouTube.

Sendo assim, ainda no mesmo fragmento, adicione os métodos openVideoOnYouTube() e setListeners() como a seguir:

...
/**
* Configura os listeners de alguns componentes
* visuais em tela.
*/
private fun setListeners(){

ll_last_video_container?.setOnClickListener{
openVideoOnYouTube()
}
}

/**
* Invoca o aplicativo do YouTube para que o usuário
* tenha acesso ao último vídeo liberado no canal.
*
* Caso o dado de URI presente no objeto [lastVideo] seja
* inválido para a abertura do app nativo do YouTube
* ou abertura da versão dele em app de navegador Web,
* então uma mensagem de falha é apresentada.
*/
private fun openVideoOnYouTube(){

val intent = Intent(
Intent.ACTION_VIEW,
lastVideo.webUri()
)

/*
* É utópico, mas pode ocorrer de não haver instalado
* no aparelho do usuário o aplicativo do YouTube e
* nem mesmo um navegador Web.
*
* Sendo assim, ao invés de gerar uma exceção, nós
* avisamos ao usuário a necessidade de instalar o
* aplicativo adequado.
* */
if( intent.resolveActivity( activity!!.packageManager ) == null ){
Toast
.makeText(
activity,
String.format(
getString( R.string.last_video_toast_alert ),
lastVideo.title
),
Toast.LENGTH_LONG
)
.show()

return
}

activity!!.startActivity( intent )
}
...

 

LinearLayout de id ll_last_video_container é justamente o LinearLayout container de todo o conteúdo de vídeo:

Estrutura toda dentro do LinearLayout container

Criamos um método setListeners(), pois nele também haverá outra definição de listener (spoiler). Definição que será colocada nos próximos conteúdos deste projeto.

Agora é definir o setListeners() no local correto.

Aqui, no método onActivityCreated():

...
override fun onActivityCreated( savedInstanceState: Bundle? ) {
super.onActivityCreated( savedInstanceState )
setListeners()
setUiModel( lVideo = lastVideo )
}
...

 

Ainda falta o acesso aos dados direto do banco de dados.

Dados da base de dados local

Apesar da propriedade lastVideo já iniciar com dados:

...
private var lastVideo = LastVideoData.getInitialVideo()
...

 

A ideia principal é que esses dados sejam carregados da base local, pois na configuração de banco de dados local de nosso projeto a persistência Room (SQLite) já é iniciada com alguns dados.

Mas ai vem um segredo (problema):

No primeiro carregamento do banco de dados local, quando ele é criado, a entrega dos dados inseridos em inicialização é lenta e não podemos apostar que ela ocorrerá com certeza em um período curto de tempo.

Sendo assim, a estratégia que adotamos aqui para superar esse problema de primeiro carregamento foi:

Vamos iniciar a propriedade principal de preenchimento de UI já com dados estáticos em projeto e ao mesmo tempo vamos também solicitar dados da base local.

O que vamos fazer nesta seção é adicionar a parte que falta "(...) solicitar dados da base local".

No fragmento LastVideoFragment adicione o método de ciclo de vida onCreate() como a seguir:

...
override fun onCreate( savedInstanceState: Bundle? ) {
super.onCreate( savedInstanceState )

/**
* Para garantir que o banco de dados local
* será acessado apenas na primeira vez que
* o fragmento é carregado.
*
* Sendo assim o usuário poderá mudar de tabs
* (itens de menu) que não haverá novos
* carregamentos somente devido à mudança de
* tab. Isso se o objeto de fragmento for
* retido em memória.
*/
UtilDatabase
.getInstance( context = activity!!.applicationContext )
.getLastVideo{
setUiModel( lVideo = it )
}
}
...

 

Primeiro:

setUiModel(), quando invocado em getLastVideo(), está sendo invocado fora da Thread Principal.

Agora é evidente a necessidade de uso de activity?.runOnUiThread() em setUiModel().

Segundo:

Estamos realizando o acesso ao banco de dados local no método onCreate(), pois na lógica de negócio que construiremos na atividade principal para acesso aos fragmentos de opções de menu...

... nessa lógica de negócio nós vamos reter os fragmentos em memória.

Retenção que vai permitir a não criação desnecessária de fragmentos já criados.

Ou seja, para cada fragmento em projeto o método onCreate() será invocado somente uma vez enquanto o aplicativo se mantém em execução.

No caso dos dados locais de LastVideo, precisamos do acesso a eles somente uma única vez.

Tendo em mente que não estamos utilizando os componentes de arquitetura do Android, é importante invocar o acesso ao banco de dados local no método correto do ciclo de vida do fragmento.

Aqui o método onCreate().

Importante:

Como fundamento Android, domine os métodos de ciclo de vida das APIs Activity e Fragment.

Até este ponto do projeto temos a seguinte configuração física (pacotes das entidades de código dinâmico que foram adicionadas) em IDE:

Configuração física do projeto Android

Próximo conteúdo

Finalizamos a configuração inicial do principal fragmento do projeto, LastVideoFragment.

No próximo conteúdo vamos a construção do fragmento de PlayLists do canal. Um dos fragmentos opcionais, mas que pode ajudar no engajamento do usuário ao canal.

Segue o link para acesso ao próximo conteúdo:

➙ Desenvolvendo a Tela e a Lógica de PlayLists - Parte 8.

Então é isso.

Descanse. Tome um café ☕ 🍰 ♟. E...

... te vejo na Parte 8 do projeto.

Se houverem dúvidas ou dicas deste sétimo conteúdo do aplicativo, então deixe nos comentários que logo eu lhe respondo.

Não esqueça de conhecer também o meu canal no YouTube (caso você ainda não conheça) e...

... não deixe de se inscrever na 📩 lista de e-mails para também garantir a versão em PDF não somente deste projeto de aplicativo Android, mas também de cada novo "conteúdo mini-curso".

Abraço.

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes!
Email inválido

Relacionado

Colocando Telas de Introdução em Seu Aplicativo AndroidColocando Telas de Introdução em Seu Aplicativo AndroidAndroid
PhotoView Android Para a Completa Implementação de ZoomPhotoView Android Para a Completa Implementação de ZoomAndroid
Como Impulsionar o App Android - Compartilhamento NativoComo Impulsionar o App Android - Compartilhamento NativoAndroid
Porque e Como Utilizar Vetores no AndroidPorque e Como Utilizar Vetores no AndroidAndroid

Compartilhar

Comentários Facebook

Comentários Blog

Para código / script, coloque entre [code] e [/code] para receber marcação especifica.
Forneça seu nome válido.
Forneça seu email válido.
Forneça o comentário.
Enviando, aguarde...