and20140324qe

6
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

description

20140324qe

Transcript of and20140324qe

Page 1: 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

Page 2: and20140324qe

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() {

Page 3: and20140324qe

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

Page 4: and20140324qe
Page 5: and20140324qe

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) {

Page 6: and20140324qe

//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);

}});

}

}