Android: 5 - 5 - Threads, AsyncTasks & Handlers - Part 1

Como todos os dispositivos de computação de hoje, cada vez mais conter vários núcleos de computação. E uma coisa que isto significa é que vários programas, ou threads de execução, pode ser executado no seu dispositivo, tudo ao mesmo tempo. E isso é uma coisa poderosa, porque permite fazer mais trabalho em um curto período de tempo. Mas também pode fazer seus programas muito mais complexo, levando a erros e problemas de desempenho se você não tiver cuidado.  

Assim, nesta lição, vamos falar sobre a escrita de programas multi-threaded para o Android. E nós também vamos discutir algumas das classes que o Android oferece para suportar isto. Em particular, nesta lição eu vou começar com uma breve discussão de "Thread itself". Em seguida, eu vou falar sobre a interface do usuário do Android, A Main Thread em que aplicativos do Android executam a maioria de seu trabalho.


E eu também vou discutir como isso impacta o design do seu software de aplicação. Depois disso, eu vou falar sobre a classe AsyncTask, o que ajuda a simplificar a segmentação no Android. E, finalmente, eu vou encerrar com uma discussão sobre o Handle , um outro mecanismo de thread do Android. Então, eu continuo usando thread, mas o que é uma thread? Bem, essencialmente, um thread é um dos possivelmente muitos cálculos em execução ao mesmo tempo dentro de um processo do sistema operacional.  

Em termos de implementação, cada thread tem seu próprio contador de programa e executar pilha tempo, mas compartilha a pilha e áreas de memória estática com outras threads em execução dentro de um processo do sistema operacional. Agora, este gráfico mostra esses conceitos, e aqui estou mostrando um dispositivo de computação hipotética. Agora, este dispositivo tem dois processadores. CPU 1. E CPU dois. Cada um desses CPUs podem executar as instruções que compõem os aplicativos em execução no dispositivo.  


Agora, em CPU dois, eu estou mostrando dois processos em execução, P3 e P4. Agora, uma maneira de pensar sobre os processos é que eles são ambientes de execução auto-contido. Eles têm recursos como memória, arquivos abertos, conexões de rede e outras coisas que eles gerenciam e manter separado de outros processos em seu dispositivo.


E dentro de um desses processos, P4, estou mostrando duas threads em execução, T7 e T8.
Agora cada um desses tópicos é uma seqüência de instruções de execução de fluxo com a sua própria pilha de chamadas. Mas uma vez que está dentro do mesmo processo, eles podem cada acesso compartilhado de recursos de processo, incluindo memória heap e variáveis ​​estáticas.

No Java, threads são representados por um objeto do tipo thread no Java.
Pacote Lang. Encadeamentos Java implementar a interface executável, o que significa que eles devem ter um método público, chamado de run, que não tem argumentos, e que não tem nenhum valor de retorno.

Agora, para este curso, eu estou supondo que você já aprendeu sobre tópicos de Java, e que você sabe como usá-los. No entanto, se você precisar de uma reciclagem por favor dê uma olhada no tutorial de concorrência no seguinte URL.  Agora alguns dos métodos de thread que veremos nesta lição incluem o método start para iniciar um thread, e o método de sleep para suspender temporariamente uma thread.

Alguns métodos de objetos que você pode precisar quando você está usando, quando você está usando threads incluem o método de espera, o que permite que o thread atual para desistir de um bloqueio que detém e esperar até que outra thread chama um método correspondente, como notificar ou notificar todos.
E quando isso acontece, o segmento de espera pode readquirir o bloqueio que ela desistiu quando ele chamado de espera, e pode continuar a execução.


O método notificar acorda um único segmento que está esperando este objeto.
Agora, para usar um fio, você normalmente faz as seguintes coisas. Primeiro, crie o segmento. Por exemplo, usando o novo comando de rosca. Agora, os fios não comece automaticamente quando você cria-los. Para iniciar a discussão, é preciso chamar o método start do segmento. Fazendo isso, eventualmente, leva a método de execução do segmento que está sendo chamado, e a linha continua a execução até que o método run termina.

Este gráfico ajuda a mostrar esse comportamento.
Em primeiro lugar, um aplicativo em execução emite um novo comando para criar um novo objeto de segmento. Quando esta chamada termina, o aplicativo continua. E algum tempo depois, invoca o método start do segmento. E essa chamada retorna novamente para a aplicação, mas também faz com que o código em método de execução do thread para executar bem.

E como o programa continua, agora existem duas threads em execução. E, claro, você pode fazer isso várias vezes, criar e executar o maior número de tópicos que você deseja. Então, vamos olhar para uma aplicação em que rosqueamento seria útil. A primeira aplicação que vamos discutir nesta lição é chamado de Threading Não Threading. E, como você verá em um segundo, o aplicativo exibe uma interface de usuário simples com dois botões. O primeiro botão é rotulado LoadIcon. Quando o usuário clica neste botão, o aplicativo abre e lê um arquivo contendo um bitmap. E uma vez que isso é feito, ele mostra o bitmap carregado apenas no visor.

A idéia aqui é que esta operação tem uma quantidade considerável de tempo. Agora, o código que usei em toda esta lição, eu estou indo realmente para exagerar quanto tempo isso leva, ok? Mas não deixe que distraí-lo, o ponto ainda é o mesmo.

Algumas operações levar um tempo relativamente longo período de tempo. E você, como um desenvolvedor, tem que entender e lidar com isso. O segundo botão é rotulado OtherButton, quando o usuário clica neste botão uma mensagem brinde aparece exibindo algum texto. E a idéia aqui é que se você ver o texto, então você sabe que o trabalho do botão. Agora, se você não pode clicar no botão, ou se não aparecer o texto, então algo está errado. Em particular, o usuário deve ser capaz de clicar em um dos botões, a qualquer momento, e que o sistema deve funcionar. Então, vamos executar uma versão desta aplicação que não utiliza qualquer threading.

Agora o que você acha que vai acontecer?
Será que vou ser capaz de pressionar os dois botões sempre que eu quero? Vamos ver. Aqui, eu vou iniciar a aplicação ThreadingNoThreading. Como você pode ver, há, há dois botões que falamos. Eu vou primeiro pressionar o outro botão, e como você pode ver, eu posso clicar nele e a mensagem prometeu aparecer no visor. Agora eu vou fazer duas coisas. Primeiro vou pressionar o botão Carregar Ícone, que irá iniciar a demorada operação de leitura no bitmap de um arquivo e, em seguida, exibi-lo. E logo depois que eu pressionar o botão Carregar Ícone, vou apertar o outro botão novamente. Aqui vamos nós Agora, eu vou pressionar o botão Carregar Ícone, e agora eu vou pressionar o outro botão.

Okay. Então, por isso, o que está acontecendo aqui?
O outro botão parece estar preso. Por que isso? Bem, a resposta é que, quando eu estava tentando pressionar o outro botão, o Android ainda estava a carregar o ícone de volta quando eu apertei o botão do ícone de carga. E essa primeira operação foi prevenir a segunda operação ocorra.

Ok, então uma solução aparentemente óbvia, mas em última análise incorreta para este problema, seria ir para o ouvinte que está anexado ao botão de carga Ícone e simplesmente criar um novo segmento que carrega o bitmap e, em seguida, exibe.
Então, eu tenho implementado essa abordagem em um aplicativo chamado Threadingsimple. Vamos dar uma olhada no que a aplicação e falar sobre por que ele realmente não funciona.  

  Então, aqui está o código para o aplicativo Threadingsimple. Aqui está o ouvinte botão para o botão Load Ícone. Ele chama o método LoadIcon, que está listado logo abaixo. Este código cria um novo segmento, o que leva algum tempo a carregar o bitmap e, em seguida, tenta definir o bitmap em uma visão de imagem que faz parte do layout. Então, vamos executar este código. Agora, vou começar-se a aplicação. E agora eu vou pressionar o botão do ícone de carga. E agora, eu vou pressionar o outro botão.

Bem em primeiro lugar, eu pressionei o outro botão e viu que ele respondeu.
Então carregar o ícone não aparecer para bloquear pressionando o outro botão. Então, isso é bom, nós fizemos algum progresso. No entanto, você pode ver que nós temos um problema maior agora. Já caiu a aplicação. Se investigarmos a saída logcat, vemos que há uma mensagem dizendo "only the original thread that created a view hierarchy can touch its views". Assim, o Android simplesmente não vai permitir que segmentos para começar a andar com as vistas que foram criados por outros segmentos.

Então isso significa que enquanto o novo segmento que criamos para carregar o bitmap pode fazer esse trabalho, não pode realmente dar o último passo e adicionar o bitmap resultante para o display.
Então, qual o segmento realmente criado hierarquia vista desta aplicação? Bem, todos os aplicativos do Android tem uma main thread, que também é chamado o segmento.

Componentes de aplicativos que são executados no mesmo processo, que tudo o que fazem por padrão, use o mesmo segmento.
Em todos esses métodos de ciclo de vida que estamos falando, OnCreate, OnStart, etc, todos eles são manipulados no segmento. E, além disso, o próprio kit de ferramentas UI não é thread-safe. E o que tudo isto significa é que se você bloquear o thread de interface do usuário com uma operação de longa duração, em seguida, você vai evitar que seu aplicativo de responder a outras coisas que o usuário está fazendo.

Na verdade, vimos que, na aplicação ThreadingNoThreading. Assim, as operações de longa execução precisam ser colocadas em threads em segundo plano. Ao mesmo tempo, no entanto, não podemos acessar o kit de ferramentas UI de um segmento não-UI. E isso é o que nos meteu em problemas com a aplicação ThreadingSimple.

Então, nós precisamos fazer o trabalho em uma discussão de fundo, mas quando esse trabalho é feito o que precisamos fazer as atualizações de interface do usuário, de volta ao segmento. E Android, de fato, nos dá um monte de maneiras de fazer exatamente isso. Em particular, o Android fornece vários métodos que são garantidos para ser executado no segmento.

Dois desses métodos são método post da classe ponto de vista, e runOnUiThread da classe de atividade.
Ambos os métodos tomar um parâmetro executável. Este executável seria, por exemplo, contêm o código que atualiza a exibição em nossos exemplos recentes. Então, se estamos usando esses métodos, que iria carregar o bitmap em uma thread em segundo plano e quando essa operação for concluída, poderíamos usar um desses métodos para executar um executável que, em seguida, define o bitmap na tela.

Vamos ver isso em ação. Então, aqui está o meu dispositivo. E eu vou iniciar a aplicação de segmentação viewpost. E há os dois botões. E mais uma vez, eu vou fazer duas coisas agora. Vou pressionar o botão do ícone de carga. E então, logo depois disso, eu vou pressionar o outro botão. E eu espero ver que o Outro de operação do botão não está bloqueado pela operação de carga ícone. E, eu espero ver que o ícone realmente carrega sem bater a aplicação. Então, aqui vai. Agora, eu vou pressionar o botão Carregar Ícone, e agora eu vou pressionar o outro botão.

Há o texto de o outro botão e, finalmente, há o bitmap.
Vamos dar uma olhada no código fonte também. Então aqui está o meu pedido, aberto no IDE. Eu vou abrir a atividade principal para esta aplicação, e eu vou direto para o método LoadIcon, que é chamado quando o usuário pressiona o botão do ícone de carga. Como antes, este código cria uma nova linha e, em seguida, carrega o bitmap. Mas depois as cargas de bitmap, você vê que nós temos agora uma chamada para view.post, passando em um executável, cujo código realmente chama o método setImageBitmap para definir o bitmap carregado apenas no que vê imagem.

Comentários

Postagens mais visitadas deste blog

Rails CanCan

Meus insights mais valiosos sobre criptomoedas para 2018 e além

Como pegar a senha do Whatsapp de um Android ou Iphone