Olá pessoal,
No próximo dia 02 de julho, na Unipê em João Pessoa - PB, participarei pelo segundo ano consecutivo do Androidos! Um dos melhores eventos do Nordeste voltados para desenvolvedores Android e abordará temas muito legais do desenvolvimento de aplicações Android tais como: arquitetura, programação reativa, serviços de cloud, e muito mais.
Este ano, o Androidos contará com a participação de três Google Developer Experts em Android do Brasil: Marcelo Quinta (de Goiás), Ubiratan Soares (de São Paulo) e eu ;) Isso sem falar na ilustre participação do Josias Paes (Unipê) e do Gustavo Soares (IFPB).
Farei duas participações durante o evento: a primeira com uma palestra sobre Data Binding e log em seguida participarei de um Fireside chat, onde o público poderá fazer perguntas e tirar suas próprias dúvidas sobre Android.
Se você é desenvolvedor Android, não poder perder essa oportunidade. Mais informações no site do evento. Nos vemos lá!
[EDITADO 08/07/2016]
Slides da minha palestra.
O código-fonte do projeto mostrado nos slides está no meu GitHub.
https://github.com/nglauber/playground/tree/master/android/LivrosFirebase
4br4ç05,
nglauber
segunda-feira, 20 de junho de 2016
sexta-feira, 17 de junho de 2016
Firebase com Android
Olá povo,
Estava com vontade de escrever uns posts sobre Firebase aqui para o blog, mas achei que eles ficariam muito grandes. Então resolvi gravar alguns vídeos, com praticamente nenhuma edição, exceto alguns cortes que eu fiz pela demora na compilação/execução da aplicação.
É uma série com quatro vídeos onde abordo três dos principais serviços do Firebase: autenticação (Auth), armazenamento de arquivos (Storage) e o banco de dados em tempo real (RealTime database).
A ideia aqui foi criar um cadastro de livros do zero, onde o usuário deve realizar o login utilizando sua conta do Google para acessar a aplicação. O cadastro permite digitar o título do livro, o autor, e fazer o upload da capara do livro, obtida tirando uma foto com a câmera do aparelho. Para persistir as informações utilizamos o banco de dados do firebase, e para armazenar as imagens das capas do livro usamos o serviço de storage. O resultado ficou como abaixo:
Como vocês podem/vão notar, não me preocupei muito com a UI. Mas isso é uma melhoria que posso fazer nos próximos vídeos. Se vocês gostarem, posso evoluir esse aplicativo e/ou mostrando mais recursos do Firebase (como o analytics, crash report, login com facebook, etc).
Então, deixem seus comentários e espero que gostem! ;)
[EDITADO 08/07/2016]
O código desse exemplo (melhorado) encontra-se no meu GitHub:
https://github.com/nglauber/playground/tree/master/android/LivrosFirebase
4br4ç05,
nglauber
Estava com vontade de escrever uns posts sobre Firebase aqui para o blog, mas achei que eles ficariam muito grandes. Então resolvi gravar alguns vídeos, com praticamente nenhuma edição, exceto alguns cortes que eu fiz pela demora na compilação/execução da aplicação.
É uma série com quatro vídeos onde abordo três dos principais serviços do Firebase: autenticação (Auth), armazenamento de arquivos (Storage) e o banco de dados em tempo real (RealTime database).
A ideia aqui foi criar um cadastro de livros do zero, onde o usuário deve realizar o login utilizando sua conta do Google para acessar a aplicação. O cadastro permite digitar o título do livro, o autor, e fazer o upload da capara do livro, obtida tirando uma foto com a câmera do aparelho. Para persistir as informações utilizamos o banco de dados do firebase, e para armazenar as imagens das capas do livro usamos o serviço de storage. O resultado ficou como abaixo:
Como vocês podem/vão notar, não me preocupei muito com a UI. Mas isso é uma melhoria que posso fazer nos próximos vídeos. Se vocês gostarem, posso evoluir esse aplicativo e/ou mostrando mais recursos do Firebase (como o analytics, crash report, login com facebook, etc).
Então, deixem seus comentários e espero que gostem! ;)
[EDITADO 08/07/2016]
O código desse exemplo (melhorado) encontra-se no meu GitHub:
https://github.com/nglauber/playground/tree/master/android/LivrosFirebase
4br4ç05,
nglauber
segunda-feira, 13 de junho de 2016
Chrome Custom Tabs para Android
Olá povo,
Mais um post rápido :) Quando precisamos abrir uma URL dentro de uma aplicação Android normalmente utilizamos uma Intent como a seguir:
Uma outra abordagem é utilizar o componente WebView.
Chrome Custom Tabs junta os pontos positivos de ambas as abordagens, pois permite o controle da experiência web dentro do seu aplicativo. Com essa API podemos: definir transições customizadas; personalizar título; adicionar ações personalizadas; fazer um pré-carregamento da página para agilizar o carregamento; entre outros.
Como pode-se imaginar, esse recurso só funcionará se o usuário possuir o Chrome instalado no aparelho. Caso contrário, será disparada a Intent que mostramos no início do post.
Para usar o Chrome Custom Tabs, a primeira coisa a fazer é adicionar a dependência no build.gradle.
Como podemos observar, é bastante simples criar as custom tabs do Chrome. Criamos uma instância da classe CustomTabsIntent.Builder e com ela criamos podemos customizar a aba da maneira que desejarmos. Primeiro definimos a cor do título usando o método setToolbarColor(int). Em seguida instancimamos um Bitmap e uma PendingIntent que podem ser utilizadas para adicionar uma ação ou uma opção de menu na barra de título. A ação é adicionada por meio do método setActionButton(Bitmap,String,PendingIntent,boolean) e o menu por meio do método addMenuItem(String,PendingIntent).
As animações foram definidas utilizando o método setStartAnimations e setExitAnimations. Essas animações foram definidas como a seguir:
Abaixo podemos ver a aplicação em execução.
Mais detalhes aqui:
https://developer.chrome.com/multidevice/android/customtabs
4br4ç05,
nglauber
Mais um post rápido :) Quando precisamos abrir uma URL dentro de uma aplicação Android normalmente utilizamos uma Intent como a seguir:
Intent it = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.nglauber.com.br")); startActivity(it);O problema de usar essa abordagem é que exige o carregamento de outro aplicativo (o que é pesado computacionalmente falando) e fará com que o usuário deixe seu aplicativo, o que não é bom. Outro ponto negativo é que uma vez que você não tem acesso ao outro aplicativo (o browser nesse caso), você não consegue fazer nenhuma customização.
Uma outra abordagem é utilizar o componente WebView.
WebView webView = (WebView)findViewById(R.id.webView); webView.loadUrl("http://www.nglauber.com.br"); webView.setWebViewClient(new WebViewClient() { public boolean shouldOverrideUrlLoading(WebView view, String url){ view.loadUrl(url); return false; } });Nesse caso você possui um controle maior, uma vez que tudo é feito dentro do seu aplicativo. Entretanto, você terá que fazer vários controles para a navegação (como eu fiz aqui tratando o redirecionamento de página). Um problema aqui é que o WebView não compartilha a sessão do browser.
Chrome Custom Tabs junta os pontos positivos de ambas as abordagens, pois permite o controle da experiência web dentro do seu aplicativo. Com essa API podemos: definir transições customizadas; personalizar título; adicionar ações personalizadas; fazer um pré-carregamento da página para agilizar o carregamento; entre outros.
Como pode-se imaginar, esse recurso só funcionará se o usuário possuir o Chrome instalado no aparelho. Caso contrário, será disparada a Intent que mostramos no início do post.
Para usar o Chrome Custom Tabs, a primeira coisa a fazer é adicionar a dependência no build.gradle.
dependencies { ... compile 'com.android.support:customtabs:23.3.0' }Então é só chamar a aba como a seguir:
String url = "http://www.nglauber.com.br"; CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(); // Definindo a cor da toolbar (opcional) builder.setToolbarColor(ActivityCompat.getColor(this, R.color.colorPrimary)); // Adicionando uma ação/menu (opcional) Bitmap icon = BitmapFactory.decodeResource( getResources(), android.R.drawable.ic_menu_agenda); PendingIntent pit = PendingIntent.getActivity( this, 0, new Intent(this, MainActivity.class), 0); // Ação builder.setActionButton(icon, "Ação", pit, true); // Menu builder.addMenuItem("Menu", pit); // Definindo animações (opcional) builder.setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left); builder.setExitAnimations(this, R.anim.slide_in_left, R.anim.slide_out_right); // Abrindo a "aba" CustomTabsIntent customTabsIntent = builder.build(); customTabsIntent.launchUrl(this, Uri.parse(url));
Como podemos observar, é bastante simples criar as custom tabs do Chrome. Criamos uma instância da classe CustomTabsIntent.Builder e com ela criamos podemos customizar a aba da maneira que desejarmos. Primeiro definimos a cor do título usando o método setToolbarColor(int). Em seguida instancimamos um Bitmap e uma PendingIntent que podem ser utilizadas para adicionar uma ação ou uma opção de menu na barra de título. A ação é adicionada por meio do método setActionButton(Bitmap,String,PendingIntent,boolean) e o menu por meio do método addMenuItem(String,PendingIntent).
As animações foram definidas utilizando o método setStartAnimations e setExitAnimations. Essas animações foram definidas como a seguir:
// res/anim/slide_in_left.xml <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromXDelta="-100%p" android:toXDelta="0" android:duration="@android:integer/config_mediumAnimTime"/> </set> // res/anim/slide_in_right.xml <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromXDelta="100%p" android:toXDelta="0" android:duration="@android:integer/config_mediumAnimTime"/> </set> // res/anim/slide_out_left.xml <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromXDelta="0" android:toXDelta="-100%p" android:duration="@android:integer/config_mediumAnimTime"/> </set> // res/anim/slide_out_right.xml <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromXDelta="0" android:toXDelta="100%p" android:duration="@android:integer/config_mediumAnimTime"/> </set>Por fim, criamos uma instância da classe CustomTabsIntent e com o método launchUrl(Activity, Uri) abrimos essa nova aba.
Abaixo podemos ver a aplicação em execução.
Mais detalhes aqui:
https://developer.chrome.com/multidevice/android/customtabs
4br4ç05,
nglauber
terça-feira, 7 de junho de 2016
Carregando imagens da galeria do Android
Olá povo,
Nesse post rápido vou mostrar como carregar imagens da galeria de mídia do Android. O único detalhe a observar nesse post é que estamos carregando imagens tanto locais quando as que estão em algum serviço da nuvem como DropBox e Google Photos. Por isso, para começar coloque as permissões necessárias no AndroidManifest.xml.
Em seguida, inicie uma nova activity utilizando a ação ACTION_GET_CONTENT.
Como falamos anteriormente, carregaremos as imagens do sistema de arquivos ou da web. Por isso, devemos realizar essa operação fora da UI thread, então definimos a classe LoadImageTask.
Outra coisa interessante é que estamos utilizando o método openInputStream() da classe ContentResolver para obter a imagem propriamente dita.
A imagem retornada terá o seu tamanho original, se você preferir, pode utilizar a técnica de redimensionamento de imagem que eu mostrei nesse post.
Por fim, no onPostExecute, invocamos o método showImage da Activity.
4br4ç05,
nglauber
Nesse post rápido vou mostrar como carregar imagens da galeria de mídia do Android. O único detalhe a observar nesse post é que estamos carregando imagens tanto locais quando as que estão em algum serviço da nuvem como DropBox e Google Photos. Por isso, para começar coloque as permissões necessárias no AndroidManifest.xml.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.INTERNET"/>Lembrando que para o Android 6 (API Level 23) você deve checar essas permissões em tempo de execução.
Em seguida, inicie uma nova activity utilizando a ação ACTION_GET_CONTENT.
private static final int IMAGE_GALLERY_REQUEST = 1; ... public void selectImageClick(View view) { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult( Intent.createChooser( intent, getString(R.string.select_picture_title)), IMAGE_GALLERY_REQUEST); } else { ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE }, IMAGE_GALLERY_REQUEST); } }Ao selecionarmos uma imagem, o método onActivityResult será chamado.
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == IMAGE_GALLERY_REQUEST && resultCode == RESULT_OK){ new LoadImageTask(this).execute(data.getData()); } }
Como falamos anteriormente, carregaremos as imagens do sistema de arquivos ou da web. Por isso, devemos realizar essa operação fora da UI thread, então definimos a classe LoadImageTask.
class LoadImageTask extends AsyncTask<Uri, Void, Bitmap> { WeakReference<PickImageActivity> mActivity; public LoadImageTask(PickImageActivity activity) { this.mActivity = new WeakReference<>(activity); } public PickImageActivity getActivity() { return mActivity.get(); } @Override protected Bitmap doInBackground(Uri... params) { if (getActivity() != null) { try { return BitmapFactory.decodeStream( getActivity().getContentResolver().openInputStream(params[0])); } catch (FileNotFoundException e) { e.printStackTrace(); } } return null; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); if (getActivity() != null){ getActivity().showImage(bitmap); } } }Temos algumas coisas interessantes aqui. A primeira é essa classe não deve ser uma inner class da Activity/Fragment, pois uma inner class sempre contém uma referência para sua outer class. Uma vez que ela não é uma inner class, devemos passar a referência da activity/fragment para essa classe. Estamos utilizando uma WeakReference para armazenar a instância da activity, o motivo disso é evitar o leak de memória, já que se o usuário sair da tela antes da imagem ser baixada aquela memória ficará alocada desnecessariamente durante algum tempo.
Outra coisa interessante é que estamos utilizando o método openInputStream() da classe ContentResolver para obter a imagem propriamente dita.
A imagem retornada terá o seu tamanho original, se você preferir, pode utilizar a técnica de redimensionamento de imagem que eu mostrei nesse post.
Por fim, no onPostExecute, invocamos o método showImage da Activity.
public void showImage(Bitmap bitmap) { ImageView imageView = (ImageView)findViewById(R.id.imageView); if (imageView != null){ imageView.setImageBitmap(bitmap); } }Qualquer dúvida, deixe seu comentário ;)
4br4ç05,
nglauber
Assinar:
Postagens (Atom)