Programação para a Plataforma Android Aula 8 Comunicação entre A0vidades Como invocar uma a0vidade a par0r de outra? Como descrever um serviço em Android? Como duas a0vidades se comunicam? Como abrir uma página web no disposi0vo móvel? Como usar expressões regulares para extrair informação de texto? Como exibir listas de dados na tela do aparelho celular?
O Modelo Android O modelo de execução é composto por várias a0vidades. Essas podem ser usadas como aplicações independentes. Mas também ficam à disposição de outras aplicações. Bem diferente de um sistema operacional tradicional, em que cada processo não tem qualquer vínculo com os outros.
Comunicação entre processos Quais aplica0vos um programa como o MicrosoO Word pode chamar enquanto executa? O MSWord pode chamar o Mozilla Firefox? Em Android um aplica0vo pode chamar qualquer outro aplica0vo. Por que é possível essa integração em Android? Quais os benevcios dessa integração?
Abrindo um Navegador Escreva uma atividade que possua uma caixa de texto e um botão, e que, tendo sido o botão pressionado, invoque um navegador para abrir a URL que estiver escrita na caixa de texto.
Layout da A0vidade Por agora, escrever esse layout deve ser facinho, facinho:
Layout da A0vidade caller.xml E como podemos invocar o navegador a partir de uma atividade? <LinearLayout xmlns:android="h^p://schemas.android.com/apk/res/android" android:id="@+id/root" android:orienta0on="ver0cal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/text1" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" /> <Bu^on android:id="@+id/bu^on1" android:text="@string/okbu^onlabel" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" /> </LinearLayout>
CallerAc0vity.java Invocando o Navegador public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.caller); ((Bu^on) findviewbyid(r.id.bu^on1)).setonclicklistener(new Bu^on.OnClickListener() { public void onclick(view arg0) { EditText t = (EditText) findviewbyid(r.id.text1); String urlname = t.gettext().tostring(); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlName)); startac@vity(intent); } }); Para que servem essas linhas de código?
Permissões Por questões de segurança, alguns recursos do aparelho são privilegiados. U0lizar esses recursos requer permissão. O canal de comunicação é um desses recursos. Permissões são asseguradas no manifesto
Manifesto <?xml version="1.0" encoding="ur 8"?> <manifest xmlns:android="h^p://schemas.android.com/apk/res/android" package="com.aula8" android:versioncode="1" android:versionname="1.0"> <applica0on android:icon="@drawable/icon" android:label="@string/app_name">... </applica0on> <uses permission android:name="android.permission.internet"> </uses permission> </manifest>
Escolhendo uma A0vidade public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.caller); ((Bu^on) findviewbyid(r.id.bu^on1)) Existem várias.setonclicklistener(new Bu^on.OnClickListener() { atividades capazes public void onclick(view arg0) { de lidar com URLs. EditText t = (EditText) findviewbyid(r.id.text1); Android nos String urlname = t.gettext().tostring(); mostra todas elas. Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlName)); startac0vity(intent); } });
Escolhendo uma A0vidade public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.caller); ((Bu^on) findviewbyid(r.id.bu^on1)).setonclicklistener(new Bu^on.OnClickListener() { public void onclick(view arg0) { EditText t = (EditText) findviewbyid(r.id.text1); String urlname = t.gettext().tostring(); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlName)); startac0vity(intent); } });
A0vidades, Contextos, Intenções Activity é um processo que executa em sua aplicação Android. Funciona como uma máquina de estados. Intent s são os objetos usados para que diferentes a0vidades possam comunicar se. Context é a classe pai de Ac0vity, e possui métodos para passar Intents entre as a0vidades.
Alguns métodos de Activity Intent getintent() Esse método retorna a intenção com a qual a a0vidade foi chamada. Uma a0vidade não mantém vínculos diretos com a a0vidade que a iniciou. Essa comunicação, em geral é feita via Intents. setintent(intent) Usado para definir a intenção com a qual uma a0vidade é chamada.
View Fonte Escreva uma atividade que mostre na tela do dispositivo o texto de uma página web. Como será o layout dessa aplicação?
sourceview.xml ScrollView <ScrollView xmlns:android="h#p://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dip"> <TextView android:id="@+id/textview" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </ScrollView> E como será a atividade?
Visualizador de Fontes de HTML TextViewAc0vity.java import android.app.ac0vity; import android.content.intent; import android.os.bundle; import android.widget.textview; public class TextViewAc0vity extends Ac0vity { private TextView text; @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.sourceview); text = (TextView) findviewbyid(r.id.textview); Intent intent = getintent(); URL url = Useful.openPage(intent); text.settext(useful.htmltostring(url)); } }
Visualizador de Fontes de HTML TextViewAc0vity.java @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.sourceview); text = (TextView) findviewbyid(r.id.textview); Intent intent = getintent(); URL url = Useful.openPage(intent); text.settext(useful.htmltostring(url)); } O que esse comando faz? Estamos criando uma mini biblioteca E esse comando, como funciona?
Useful.java Abrindo uma página web public sta0c URL openpage(intent intent) { Uri data = intent.getdata(); URL url = null; try { url = new URL(data.getScheme(), data.gethost(), data.getpath()); } catch (MalformedURLExcep0on e) { e.printstacktrace(); } return url; } O que é o esquema de uma URI? E o host de uma URI, o que é? Recursos em Android são codificados como URIs. E por último, o que é esse path?
Useful.java Entendendo uma URI public sta0c URL openpage(intent intent) { Uri data = intent.getdata(); URL url = null; try { Log.v("Useful scheme", data.getscheme()); Log.v("Useful host", data.gethost()); Log.v("Useful path", data.getpath()); url = new URL(data.getScheme(), data.gethost(), data.getpath()); } catch (MalformedURLExcep0on e) { e.printstacktrace(); } return url; } O que será impresso para a URI acima?
Useful.java Entendendo uma URI public sta0c URL openpage(intent intent) { Uri data = intent.getdata(); URL url = null; try { Log.v("Useful scheme", data.getscheme()); Log.v("Useful host", data.gethost()); Log.v("Useful path", data.getpath()); url = new URL(data.getScheme(), data.gethost(), data.getpath()); } catch (MalformedURLExcep0on e) { e.printstacktrace(); } return url; } 10 30 10:49:05.633: VERBOSE/ Useful scheme: h^p 10 30 10:49:05.663: VERBOSE/ Useful host www.dcc.ufmg.br 10 30 10:49:05.673: VERBOSE/ Useful path /~fpereira/links Ainda falta implementar htmltostring
Useful.java htmltostring public sta0c String htmltostring(url url) { String text = ""; BufferedReader rd = null; try { rd = new BufferedReader (new InputStreamReader(url.openStream())); String line = null; while ((line = rd.readline())!= null) { text += line; } } catch (IOExcep@on e) { e.printstacktrace(); } return text; } Como explicar para o ambiente de execução que essa atividade entende de endereços web? O método anterior também possuia tratamento de exceções. O que é isso? Será que o programa compila sem esse código de tratamento de exceções?
Useful.java Bibliotecas public sta0c String htmltostring(url url) { String text = ""; BufferedReader rd = null; try { rd = new BufferedReader (new InputStreamReader(url.openStream())); String line = null; while ((line = rd.readline())!= null) { text += line; } } catch (IOExcep0on e) { e.printstacktrace(); } return text; } A classe Useful é uma biblioteca. O que é isso? Qual a diferença de bibliotecas para arcabouços? Que outras bibliotecas nós conhecemos?
manifest.xml Manifesto <ac0vity android:name=".textviewac0vity" android:label="@string/textviewappname" > <intent filter> <ac0on android:name="android.intent.ac@on.view" /> <category android:name="android.intent.category.default" /> <data android:scheme="h^p" /> </intent filter> </ac0vity> E qual a diferença entre ação e categoria? Que outras ações nós já vimos? E que outras categorias já vimos?
Ainda o Manifesto <?xml version="1.0" encoding="ur 8"?> <manifest xmlns:android="h^p://schemas.android.com/apk/res/android" package="com.aula7" android:versioncode="1" android:versionname="1.0"> <applica0on android:icon="@drawable/icon" android:label="@string/app_name"> <ac@vity android:name=".callerac@vity" android:label="@string/app_name"> <intent filter> <ac@on android:name="android.intent.ac@on.main" /> <category android:name="android.intent.category.launcher" /> </intent filter> </ac@vity> <ac@vity android:name=".textviewac@vity" android:label="@string/textviewappname"> <intent filter> <ac@on android:name="android.intent.ac@on.view" /> O que acontece quando existem várias atividades capazes de tratar um recurso? <category android:name="android.intent.category.default" /> <data android:scheme="h]p" /> </intent filter> </ac@vity> </applica0on> <uses permission android:name="android.permission.internet"></uses permission> </manifest>
Várias a0vidades <?xml version="1.0" encoding="ur 8"?> <manifest xmlns:android="h^p://schemas.android.com/apk/res/android" package="com.aula7" android:versioncode="1" android:versionname="1.0"> <applica0on android:icon="@drawable/icon" android:label="@string/app_name"> <ac@vity android:name=".callerac@vity" android:label="@string/app_name"> <intent filter> O que determina o nome de cada ícone? <ac@on android:name="android.intent.ac@on.main" /> <category android:name="android.intent.category.launcher" /> </intent filter> </ac@vity> <ac@vity android:name=".textviewac@vity" android:label="@string/textviewappname"> <intent filter> <ac@on android:name="android.intent.ac@on.view" /> <category android:name="android.intent.category.default" /> <data android:scheme="h]p" /> </intent filter> </ac@vity> </applica0on> <uses permission android:name="android.permission.internet"></uses permission> </manifest>
Buscas em Texto Altere o exemplo anterior para não somente mostrar o texto da página web, mas também permitir a busca de palavras nesse texto. Seu layout deverá possuir uma caixa de texto para receber o dado de pesquisa, um botão para iniciar a pesquisa, e uma caixa de texto contendo o texto fonte. Sua aplicação deverá exibir, em um Toast, o número de ocorrências do padrão procurado. Comecemos pelo layout. Como seria?
search.xml <LinearLayout android:id="@+id/linearlayout01" android:orienta0on="verdcal" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="h#p://schemas.android.com/apk/res/android"> <LinearLayout android:id="@+id/linearlayout02" android:layout_width="wrap_content" android:layout_height="wrap_content"> <EditText android:id="@+id/edittext01" android:width="240sp" android:layout_width="wrap_content" android:layout_height="wrap_content"> </EditText> <Bu^on android:text="@string/searchbu#onlabel" android:id="@+id/bu#on01" android:layout_width="wrap_content" android:layout_height="wrap_content"> </Bu^on> </LinearLayout> <ScrollView xmlns:android="h#p://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dip"> <TextView android:id="@+id/textview" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </ScrollView> </LinearLayout> Layout de nosso buscador Parte da atividade nós já vimos, não já?
Carregando o texto da página TextSearchAc0vity.java @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.search); text = (TextView) findviewbyid(r.id.textview); Intent intent = getintent(); URL url = Useful.openPage(intent); text.settext(useful.htmltostring(url)); final EditText tb1 = (EditText) findviewbyid(r.id.edittext01); Bu^on bt = (Bu^on) findviewbyid(r.id.bu^on01); bt.setonclicklistener(...); } O que o evento do botão deve fazer? Como implementar esse evento?
Expressões Regulares TextSearchAc0vity.java bt.setonclicklistener(new Bu^on.OnClickListener() { public void onclick(view arg0) { int counter = 0; String pa^ernstr = tb1.gettext().tostring(); String htmltext = text.gettext().tostring(); Pa]ern pa^ern = Pa^ern.compile(pa^ernStr); Matcher pagematcher = pa^ern.matcher(htmltext); while (pagematcher.find()) { counter++; } Toast.makeText(TextSearchAc@vity.this, "" + counter, Toast.LENGTH_SHORT).show(); } }); O que são expressões regulares? E esse código, ele faz o quê?
Expressões Regulares bt.setonclicklistener(new Bu^on.OnClickListener() { public void onclick(view arg0) { int counter = 0; String pa^ernstr = tb1.gettext().tostring(); String htmltext = text.gettext().tostring(); Pa^ern pa^ern = Pa^ern.compile(pa^ernStr); Matcher pagematcher = pa^ern.matcher(htmltext); while (pagematcher.find()) { counter++; } Toast.makeText(TextSearchAc0vity.this, "" + counter, Toast.LENGTH_SHORT).show(); } }); Ainda temos de adicionar a atividade ao manifesto Esse nome, Toast, designa um objeto?
Mais Manifesto manifest.xml <ac0vity android:name=".textsearchac0vity" android:label="@string/textsearchappname"> <intent filter> <ac0on android:name="android.intent.ac0on.view" /> <category android:name="android.intent.category.default" /> <data android:scheme="h^p" /> </intent filter> </ac0vity>
Crie agora uma nova atividade, que também trata URLs. Dessa vez, a sua atividade deverá abrir uma página web, e extrair todos os links daquela página e exibílos em uma lista. Caso o usuário clique em algum desses links, então sua atividade deverá abrir uma página web mostrando o conteúdo daquele endereço. Buscas de links Comecemos pelo layout. Como seria?
Layout Pré Montados de Listas public class LinkViewAc0vity extends ListAc0vity implements AdapterView.OnItemLongClickListener, AdapterView.OnItemClickListener { @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); Intent intent = getintent(); URL url = Useful.openPage(intent); String htmltext = Useful.htmlToString(url); List<String> links = extractlinks(htmltext); setlistadapter(new ArrayAdapter<String>(this, android.r.layout.simple_list_item_1, links)); getlistview().settextfilterenabled(true); getlistview().setonitemclicklistener(this); getlistview().setonitemlongclicklistener(this); } } LinkViewAc0vity.java Onde essa classe foi declarada? Temos de implementar esse método. Adaptadores são outro padrão de projetos.
Adaptadores Adapter é um padrão de projetos que procura adaptar uma interface às necessidades de algum cliente. Trata se tão somente de uma camada em torno de um objeto, que converte a interface desse objeto para a interface esperada pelo cliente. O que estava sendo adaptado no exemplo anterior? Mas, enfim ainda temos de implementar extractlinks
Extraindo Links LinkViewAc0vity.java private List<String> extractlinks(string htmltext) { Pa^ern linkpa^ern = Pa^ern.compile( "(h]ps? bp file)://[ a za Z0 9+&@#/%?=~_!:,.;]*[ a za Z0 9+&@#/%=~_ ]", Pa]ern.CASE_INSENSITIVE Pa]ern.DOTALL); Matcher pagematcher = linkpa^ern.matcher(htmltext); List<String> links = new ArrayList<String>(); while (pagematcher.find()) { links.add(pagematcher.group()); } return links; } E essas constantes, o que querem dizer? O que quer dizer essa expressão regular?
LinkViewAc0vity.java Eventos para Tratar @Override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); Intent intent = getintent(); URL url = Useful.openPage(intent); String htmltext = Useful.htmlToString(url); List<String> links = extractlinks(htmltext); setlistadapter(new ArrayAdapter<String>(this, android.r.layout.simple_list_item_1, links)); getlistview().settextfilterenabled(true); getlistview().setonitemclicklistener(this); getlistview().setonitemlongclicklistener(this); } Qual a diferença entre esse tipo de evento e esse? Então vamos começar implementando esse tipo de evento.
LinkViewAc0vity.java Abrindo mais páginas web public void onitemclick(adapterview<?> av, View v, int pos, long id) { String urlname = ((TextView) v).gettext().tostring(); Intent browserintent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlName)); startac0vity(browserintent); finish(); } E como abrir uma atividade específica? Qual atividade será aberta por esse tratador de eventos? O que quer dizer essa sintaxe?
Invocando uma a0vidade específica LinkViewAc0vity.java public boolean onitemlongclick (AdapterView<?> av, View v, int pos, long id) { String urlname = ((TextView) v).gettext().tostring(); Intent i = new Intent(this, WebViewAc@vity.class); i.putextra("url", urlname); startac0vity(i); return false; } Temos de implementar essa atividade!
WebView web.xml Android determina um layout para visões web: <?xml version="1.0" encoding="ur 8"?> <LinearLayout xmlns:android= "h^p://schemas.android.com/apk/res/android" android:orienta0on="ver0cal" android:layout_width="fill_parent" android:layout_height="fill_parent"> <WebView android:id="@+id/webview" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>
WebViewAc0vity.java WebView public class WebViewAc0vity extends Ac0vity { public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.web); WebView webview = (WebView) findviewbyid(r.id.webview); webview.getse Intent i = getintent(); String urlname = i.getstringextra("url"); webview.loadurl(urlname); } } ngs().setjavascriptenabled(true); Não esqueçam de adicionar a atividade ao manifesto! Como se dá a comunicação entre as atividades?
Manifesto AndroidManifest.xml <ac0vity android:name=".webviewac0vity" android:label="newwebview" > <intent filter> <ac0on android:name="android.intent.ac0on.view" /> <category android:name="android.intent.category.default" /> <data android:scheme="h^p" /> </intent filter> </ac0vity>
LinkViewAc0vity.java Comunicação entre A0vidades public boolean onitemlongclick (AdapterView<?> av, View v, int pos, long id) { String urlname = ((TextView) v).gettext().tostring(); Intent i = new Intent(this, WebViewAc0vity.class); i.putextra("url", urlname); startac0vity(i); return false; } WebViewAc0vity.java public class WebViewAc0vity extends Ac0vity { public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.web); WebView webview = (WebView) findviewbyid(r.id.webview); webview.getse ngs().setjavascriptenabled(true); Intent i = getintent(); String urlname = i.getstringextra("url"); webview.loadurl(urlname); } }
Intenções Implícitas e Explicitas Intenções explícitas abrem uma a0vidade específica. Essas intenções contêm o nome da a0vidade alvo. Em geral são usados para comunicação entre a0vidades da mesma aplicação. Intent i = new Intent(this, SomeAc'vity.class); i.putextra("key", value); startac'vity(i);
Intenções Implícitas e Explicitas Intenções implícitas fazem um chamado para qualquer a0vidade que saiba lidar com elas. Em geral são usados para comunicação entre a0vidades de aplicações diferentes. Usam filtros para indicar a a0vidade alvo. Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(urlName)); startac'vity(intent);