and20140324qe
description
Transcript of and20140324qe
Threads em Android
Quando um componente de aplicação inicia e a aplicação não tem outros componentes rodando,
o sistema Android inicia outro processo Linux para a aplicação com uma single thread de
execução. Por padrão, todos os componentes da mesma aplicação rodam em um mesmo
processo e thread (chamada thread principal). Se um componente de aplicação inicia e existe um
processo para aquela aplicação (pois outro componente da aplicação já existe), então o
componente é iniciado dentro do processo e usa a mesma thread de execução. Contudo, você
pode fazer com que diferentes componentes em sua aplicação rodem em processos separados e
poderá também criar threads adicionais para quaisquer processos.
Quando uma aplicação é lançada o sistema cria uma thread de execução para aquela aplicação,
chamada de thread principal. Essa thread é muito importante pois ela é encarregada de fazer o
gerenciamento dos processos subsequentes. Ela também é chamada de UI Thread ou Thread de
Interface.
O sistema NÃO cria uma thread separada para cada instância de um componente. Todos os
componentes que rodam em um mesmo processo são instanciados na mesma UI Thread e as
chamadas a cada componente que o sistema faz são despachadas a partir dessa thread.
Consequentemente, métodos que respondem a chamadas callback do sistema (como
onKeyDown()) sempre rodam na UI Thread do processo.
Por conta disso, quando um usuário toca um botão na tela, a UI Thread de sua aplicação envia
um evento touch para o widget que então modifica seu estado para pressionado e posta uma
requisição dizendo que é inválido. A UI Thread retira da fila a requisição e notifica o widget que
ele tem de ser redesenhado (é quando vemos a imagem do botão como pressionado).
Quando sua aplicação realiza trabalho intensivo em resposta a uma interação do usuário, uma
thread simples pode começar a ter uma resposta pobre a não ser que você faça implementações
em sua aplicação. Especificamente, se tudo está rodando na UI Thread, realizar longas tarefas
como um acesso a rede ou banco de dados por bloquear toda a interface da sua aplicação
enquanto essa tarefa estiver rodando. Pior, a aplicação pode demorar tanto a responder que o
sistema Android poderá entender que ela está travada e mostrar a mensagem de "application not
responding". O usuário então terá de decidir se sair da aplicação ou se a desinstala.
Worker thread
Com o modelo de thread única mostrada acima, é vital que a responsividade de sua interface de
aplicação não bloqueie a UI Thread. Se as operações que são realizadas não são instantâneas
então você deve se certificar de criá-las em threads separadas (threads backgroud ou worker
threads).
Por exemplo, abaixo está um código de um listener click que faz o download de uma imagem em
uma thread separada e a mostra dentro de um ImageView:
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap b = loadImageFromNetwork("http://example.com/image.png");
mImageView.setImageBitmap(b);
}
}).start();
}
Inicialmente, parece ser um código perfeito, já que ele cria uma nova thread e manuseia a
operação de rede. No entanto, ele viola a segunda regra do modelo de thread única: não acessar
a toolkit de interface do Android de fora da UI Thread. Esse exemplo modifica um ImageView a
partir de um Worker Thread ao invés da UI Thread.
Para corrigir esse problema, o Android oferece diversas maneiras de acessar a UI Thread de
outras threads. Aqui a lista de alguns métodos que podem ajudá-lo nessa tarefa:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Por exemplo, você poderá corrigir o código acima usando o método View.post(Runnable):
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap bitmap =
loadImageFromNetwork("http://example.com/image.png");
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(bitmap);
}
});
}
}).start();
}
Agora sua implementação está em modo thread-safe: a operação de rede é realizada em uma
thread separada enquanto a ImageView é manipulada pela UI Thread.
Iremos construir um exemplo bem simples onde é realizado o download de uma imagem, o
sistema exibe uma mensagem para o usuário durante o download e a imagem é exibida ao
término do processo.
Criar projeto no ADT: prjDownloadImagem
Insira um ImageView no Activity, com o ID imgView
Deixar o com.prjdownloadimagem.view.MainActivity.java da seguinte forma:
private static final
String URL="http://i909.photobucket.com/albums/ac294/simonvinicius/ROCKNTECH1/android-
robot1.jpg";
private ProgressDialog dialog;
private Handler handler = new Handler();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_download);
//Exibe mensagem ao usuário
dialog = ProgressDialog.show(this, "Exemplo", "Buscando
imagem,aguarde!",false,true);
//Chama função downloadImage passando a URL como parametro
downloadImagem(URL);
}
private void downloadImagem(final String urlImg) {
//Cria uma nova Thread
newThread(){
@Override
public void run(){
try {
// Faz o download da imagem
URL url = new URL(urlImg);
InputStream imputStream = url.openStream();
final Bitmap btImagem = BitmapFactory.decodeStream(imputStream);
imputStream.close();
atualizaTela(btImagem);
}catch (MalformedURLException e) {
return;
}catch(IOException e){
Log.e("Erro ao fazer o download", e.getMessage(),e);
}
}
}.start();
}
//Utiliza um handler para atualizar a tela
private void atualizaTela(final Bitmap imagem) {
handler.post(new Runnable() {
@Override
public void run() {
// Fecha a janela de mensagem ao usuário
dialog.dismiss();
ImageView imgView = (ImageView) findViewById(R.id.imgView);
imgView.setImageBitmap(imagem);
}});
}
}