O princípio de funcionamento do Binder e os quatro componentes principais: Service, BroadCastReceiver, ContentProvider

Princípio de funcionamento do serviço

O serviço possui dois conjuntos de processos, um é o processo de inicialização e o outro é o processo de vinculação. Todos os nossos alunos que desenvolvem aplicativos devem saber

Insira a descrição da imagem aqui

1) Inicie o serviço em um novo processo

Vejamos primeiro o processo de inicialização do Serviço, supondo que o Serviço a ser iniciado esteja em um novo processo, que é dividido em 5 etapas:

  1. App envia uma mensagem ao AMS para iniciar o Serviço.
  2. O AMS verifica se o processo que iniciou o Serviço existe. Caso não exista, primeiro salva as informações do Serviço e depois cria um novo processo.
  3. Após o início do novo processo, o AMS é notificado de que posso fazê-lo.
  4. AMS envia as informações de serviço recém salvas para o novo processo
  5. Novo processo inicia serviço
Estágio 1

Insira a descrição da imagem aqui
Muito semelhante à Atividade, as informações do Serviço a ser iniciado ainda são enviadas ao AMS através do AMM/AMP.

Estágio 2
  1. O AMS verifica se o Serviço está declarado no Manifesto. Caso contrário, um erro será reportado diretamente.

  2. O AMS verifica se o processo que iniciou o Serviço existe. Caso não exista, primeiro salva as informações do Serviço e depois cria um novo processo.

  3. No AMS, cada serviço é salvo usando um objeto ServiceRecord.

Etapa 3

O processo de início do novo processo onde o Serviço está localizado é semelhante ao processo de início do Aplicativo apresentado anteriormente.

Depois que o novo processo for iniciado, um novo ActivityThread também será criado e, em seguida, o objeto ActivityThread será passado ao AMS por meio do AMP, informando ao AMS que o novo processo foi iniciado com sucesso.

Estágio 4

O AMS transforma o objeto ActivityThread passado em ApplicationThreadProxy, que é ATP. Através do ATP, ele envia as informações do Serviço a ser iniciado para o novo processo.

Estágio 5

Insira a descrição da imagem aqui
O novo processo recebe as informações do AMS por meio de ApplicationThread, que é igual à última etapa de início da Activity apresentada anteriormente.Com a ajuda de ActivityThread e H, o método onCreate de Service é executado. Durante este período, o objeto Contexto é criado para o Serviço e associado ao Serviço.

O que precisa ser focado é o método handleCreateService de ActivityThread.
Insira a descrição da imagem aqui

Você descobrirá que este código é semelhante ao handleLaunchActivity apresentado anteriormente. Ele retira as informações do pacote packageInfo do PMS. Este é um objeto LoadedApk, então obtém seu carregador de classe e reflete um objeto de classe. O que é refletido aqui é Service. .

A lógica dos quatro componentes principais é a mesma, então precisamos torná-lo um plug-in. Podemos fazer barulho aqui e alterá-lo para o carregador de classe do plug-in para carregar os quatro componentes principais do plug-in.

Neste ponto, iniciamos um Serviço em um novo processo.

2) Inicie o Serviço do mesmo processo

Se o Serviço for iniciado no processo atual, as etapas acima serão simplificadas para:

  1. App envia uma mensagem ao AMS para iniciar o Serviço.

  2. O AMS realiza verificações de rotina, como se o Serviço está declarado, e registra o Serviço no AMS. AMS descobre que o Serviço a ser iniciado é o Serviço onde o Aplicativo está localizado e notifica o Aplicativo para iniciar este Serviço.

  3. O aplicativo inicia o serviço.

3) Vincule o serviço no mesmo processo

Se o Serviço estiver vinculado ao mesmo processo, o processo será:

  1. App envia uma mensagem vinculada ao Serviço para AMS.

  2. O AMS realiza verificações de rotina, como se o Serviço está declarado, e registra o Serviço no AMS. O AMS descobre que o Serviço a ser iniciado é o Serviço do processo no qual o Aplicativo está localizado e, em seguida, notifica o Aplicativo para iniciar o Serviço e, em seguida, notifica o Aplicativo para vincular o Serviço.

  3. O aplicativo recebe a primeira mensagem do AMS e inicia o serviço.

  4. O aplicativo recebe a segunda mensagem do AMS, vincula o serviço e passa um objeto Binder para o AMS.

  5. AMS envia o objeto Binder recebido para o aplicativo

  6. O App recebe o objeto Binder e pode utilizá-lo.

Você pode perguntar, se eles estão todos no mesmo processo, não seria melhor usar o objeto Binder diretamente dentro do App? Na verdade, temos que considerar o cenário de não estarmos no mesmo processo, e não podemos escrever dois cópias do código e dois conjuntos de lógica, então juntamos todos., mesmo no mesmo processo, você tem que contornar o AMS.

Fase 1: O aplicativo envia uma mensagem vinculando o serviço ao AMS.
Insira a descrição da imagem aqui
Estágio 4: Processando a segunda mensagem
Insira a descrição da imagem aqui
Estágio 5 e Estágio 6:
Esta etapa precisa ser explicada com cuidado, porque o AMS passa o objeto Binder para o App. ATP e APT não são usados ​​aqui, mas AIDL é usado para implementar isso. O nome de AIDL é IServiceConnection.
Insira a descrição da imagem aqui
O método connect do ServiceDispatcher eventualmente chamará o método onServiceConnected do ServiceConnectiont. Estamos muito familiarizados com esse método. Os desenvolvedores de aplicativos obtêm a conexão desse método e podem fazer suas próprias coisas.

Como funciona o receptor BroadCast

O receptor é dividido em dois tipos: transmissão estática e transmissão dinâmica.

O Receptor declarado no Manifesto é um broadcast estático:
Insira a descrição da imagem aqui
o código de registro escrito manualmente no programa é um broadcast dinâmico:
Insira a descrição da imagem aqui
ambos possuem a mesma função, mas são escritos de maneiras diferentes. Nesse caso, podemos alterar todas as transmissões estáticas para dinâmicas, o que evita a necessidade de declará-las no arquivo de manifesto e evita verificações do AMS. O que vem à sua mente a seguir? Sim, a solução de plug-in do Receiver é baseada nesta ideia.

A seguir, vamos ver como o Receiver lida com o AMS, ele é dividido em duas partes, uma é o registro e a outra é o envio da transmissão.

Somente se você se registrar para esta transmissão você poderá ser notificado e o método onReceive executado quando esta transmissão for enviada.

Tomemos como exemplo o reprodutor de música, cadastre o Receptor na Atividade e envie a transmissão no Serviço. Quando o Serviço reproduzir a próxima música, ele notificará a Atividade para modificar o nome da música atualmente sendo reproduzida.

O processo de registro é o seguinte:

  1. Na Atividade, cadastre o Destinatário e notifique a AMS.
    Insira a descrição da imagem aqui

Aqui, Activity usa o método RegisterReceiver fornecido pelo Context e, em seguida, passa um receptor para AMS por meio de AMN/AMP.

Ao criar este objeto Receiver, você precisa especificar um IntentFilter para o receptor. Este filtro é o cartão de identificação do receptor e é usado para descrever o receptor.

No método RegisterReceiver de Context, ele utiliza PMS para obter as informações do pacote, que é o objeto LoadedApk.

É este objeto LoadedApk e seu método getReceiverDispatcher encapsula o Receiver em um objeto Binder que implementa a interface IIntentReceiver.

Apenas passamos esse objeto Binder e filtramos para o AMS.

Não basta apenas passar o Receptor para o AMS. Ao enviar uma transmissão, o AMS não sabe para quem enviar? Portanto, o processo onde a Atividade está localizada também precisa enviar um objeto próprio para o AMS.

  1. Após o AMS receber a mensagem, ele armazenará as informações acima em uma lista, que armazena todos os Receptores.

Atenção, estou ocupado aqui há muito tempo registrando receptores dinâmicos.
Quando o receptor estático foi registrado na AMS? É quando o App é instalado. O PMS analisará as quatro principais informações dos componentes do Manifesto e armazenará o receptor entre eles.
O receptor dinâmico e o receptor estático são armazenados em diferentes variáveis ​​​​do AMS, respectivamente. Ao enviar uma transmissão, os dois receptores serão mesclados e então enviados. Entre eles, os dinâmicos são classificados antes dos estáticos, de modo que os receptores dinâmicos sempre recebem mensagens antes dos receptores estáticos.

Além disso, sempre que o sistema Android for iniciado, ele também registrará receptores de transmissão estáticos no AMS. Porque toda vez que o sistema Android for iniciado, todos os apks serão reinstalados.

O processo de envio de uma transmissão é o seguinte:
  1. Em Serviço, a transmissão é enviada para AMS através de AMM/AMP, e a transmissão transporta Filtro.

  2. Após o AMS receber esta transmissão, ele encontra o receptor correspondente de acordo com o filtro na lista de receptores, que pode ser múltipla, e coloca todos eles em uma fila de transmissão. Por fim, envie uma mensagem para a fila de mensagens do AMS.

    Quando a mensagem na fila de mensagens é processada, o AMS encontra o receptor apropriado na fila de transmissão e envia a transmissão para o processo onde o receptor de transmissão está localizado.

  3. Quando o processo onde o receptor está localizado recebe a transmissão, ele não a envia diretamente ao receptor. Em vez disso, ele encapsula a transmissão em uma mensagem e a envia para a fila de mensagens do thread principal. Quando a mensagem é processada, a transmissão na mensagem é Enviar ao destinatário.

Vamos dar uma olhada mais de perto nessas três etapas por meio do diagrama abaixo:

Etapa 1, o serviço envia uma transmissão para o AMS

Insira a descrição da imagem aqui
A transmissão é enviada através do parâmetro Intent, que carrega o Filtro, informando assim ao AMS que tipo de receptor pode aceitar a transmissão.

Etapa 2, o AMS recebe a transmissão e a envia.

O recebimento e o envio de transmissões não são sincronizados. Cada vez que o AMS recebe uma transmissão, ele a lança na fila de envio de transmissão.Se o envio foi bem-sucedido, ele não se importa.

Como os receptores são divididos em receptores não ordenados e receptores ordenados, a fila de envio de transmissão também é dividida em duas, e essas duas transmissões são enviadas separadamente.

O AMS envia um broadcast para o cliente, que é outra comunicação entre processos, ou envia a mensagem para o APT através do ATP. Como o objeto Receiver precisa ser passado, ele também é um objeto Binder e pode ser passado. Como dissemos antes, ao registrar o Receiver no AMS, o Receiver será encapsulado em um objeto Binder da interface IIntentReceiver. Em seguida, o AMS retornará o objeto da interface IIntentReceiver.

Etapa 3, o aplicativo lida com a transmissão
Insira a descrição da imagem aqui

Este processo é descrito a seguir:

  1. A mensagem é transmitida do AMS para o cliente, e o objeto de interface IIntentReceiver no AMS é convertido em um objeto InnerReceiver. Este é o receptor. Esta é uma comunicação de processo cruzado AIDL.

  2. Em seguida, encapsule um objeto Args em ReceiverDispatcher (este é um objeto Runnable, para implementar o método run), incluindo todas as informações necessárias ao receptor de transmissão, e entregue-o ao ActivtyThread para envio

  3. A próxima etapa é aquela com a qual estamos familiarizados: ActivtyThread lança a mensagem Args no H Hanlder e envia a mensagem para a fila de mensagens do thread principal. Quando a mensagem Args é executada, o método run de Args é executado naturalmente.

  4. No método run de Args, instancie um objeto Receiver e chame seu método onReceiver.

  5. Finalmente, no método run de Args, quando a chamada do método onReceiver do Receiver termina, uma mensagem será enviada ao AMS através do AMN/AMP, informando ao AMS que a transmissão foi enviada com sucesso. Após o AMS ser notificado, ele envia uma transmissão para o próximo receptor.

Nota: InnerReceiver é o stub de IIntentReceiver e é a extremidade receptora do objeto Binder.

Tipo de transmissão

As transmissões do Android são classificadas em três tipos de acordo com o método de envio: transmissão não ordenada, transmissão ordenada (OrderedBroadcast) e transmissão fixa (StickyBroadcast).

  1. A transmissão fora de ordem é o tipo mais comum de transmissão.

  2. A transmissão ordenada difere da transmissão não ordenada porque pode especificar a prioridade.

Esses dois receptores existem em diferentes variáveis ​​do AMS e podem ser considerados como dois conjuntos de receptores que enviam diferentes tipos de transmissões.

  1. A transmissão fixa é um tipo de transmissão fora de ordem.

Não vemos muitas transmissões fixas, mas você entenderá quando eu falar sobre um cenário: energia da bateria. Quando o nível da bateria for inferior a 20%, o usuário será avisado.
A obtenção de informações sobre a energia da bateria é realizada por meio de transmissão.
Mas na transmissão geral, acaba quando é enviado. Precisamos ter uma transmissão que possa continuar a existir após ser enviada, e os futuros registrantes também possam receber essa transmissão.Esse tipo de transmissão é uma transmissão fixa.

Como um receptor dinâmico só pode ser registrado e receber transmissões quando o método onCreate() da Activity é chamado, ele não pode receber transmissões quando o programa não está em execução; mas o registro estático não depende se o programa está em execução.

Como funciona o ContentProvider

1.Como usar o CP

Vamos revisar rapidamente como usar o CP no aplicativo.
Insira a descrição da imagem aqui

  1. App1 que define CP
    define uma subclasse CP MyContentProvider em App1 e a declara no Manifesto. Para tanto, quatro métodos de adição, exclusão, modificação e verificação de CP devem ser implementados em MyContentProvider:

Insira a descrição da imagem aqui

Insira a descrição da imagem aqui

  1. App2 usando CP:
    App2 acessa o CP definido em App1. Para isso, é utilizado ContentResolver, que também fornece quatro métodos de adição, exclusão, modificação e verificação de acesso ao CP definido em App1:
    Insira a descrição da imagem aqui

Primeiro, vamos dar uma olhada na implementação subjacente dos quatro métodos de adição, exclusão, modificação e verificação do ContentResolver. Na verdade, todos eles se comunicam com o AMS e, finalmente, chamam os quatro métodos de adição, exclusão, modificação e verificação de CP do App1. Falaremos sobre esse processo mais tarde.

Em segundo lugar, URI é o cartão de identificação e identificador único do CP.

Declaramos o URI para CP no App1, ou seja, o valor das autoridades é baobao. Se quisermos utilizá-lo no App2, especificamos o URI nos quatro métodos Add, Delete, Modify e Check no ContentResolver. O formato é :

uri = Uri.parse("content://baobao/");

Em seguida, coloque ambos os aplicativos no modo de depuração e você poderá depurar do App2 para o App1, por exemplo, operação de consulta.

2.A essência do CP

Várias fontes de dados vêm em vários formatos, como mensagens de texto e catálogos de endereços. São tabelas de dados diferentes no SQLite. No entanto, para usuários externos, elas precisam ser encapsuladas em um método de acesso unificado, como para coletas de dados. Em outras palavras , quatro métodos de adição, exclusão, modificação e consulta devem ser fornecidos, então encapsulamos uma camada sobre o SQLite, que é CP.

3. Memória Compartilhada Anônima (ASM)

CP lê dados usando memória compartilhada anônima, abreviada como ASM em inglês, então você pode ver que CP e AMS estão muito ocupados se comunicando acima, mas na verdade, há um cenário diferente abaixo.

Quanto ao conceito de ASM, na verdade é uma comunicação do Binder, vou fazer um desenho e vocês vão entender:

Insira a descrição da imagem aqui
O CursorWindow aqui é uma memória compartilhada anônima.

O processo, simplesmente, é este:

1) Existe um objeto CursorWindow dentro do Cliente. Ao enviar uma requisição este objeto do tipo CursorWindow é ignorado, este objeto fica temporariamente vazio.

2) O servidor recebe a solicitação, coleta os dados e os preenche no objeto CursorWindow.

3) O cliente lê o objeto CursorWindow interno e obtém os dados.

Pode-se observar que este objeto CursorWindow é uma memória compartilhada anônima, que é a mesma memória anônima.

Para dar um exemplo de vida, você pede leite e coloca uma caixa na sua porta. O leiteiro coloca um saco de leite na caixa toda manhã. Quando você acorda, você vai buscar o leite na caixa. Esta caixa de leite é uma memória compartilhada anônima.

4.Processo de comunicação entre CP e AMS

Vejamos o exemplo do App2 querendo acessar o CP definido no App1. Vejamos o método de inserção do CP.
Insira a descrição da imagem aqui
As 5 linhas de código acima incluem duas partes: iniciar o CP e executar o método CP. O divisor de águas é o método insert. A implementação do método insert. A primeira metade ainda está iniciando o CP. Quando o CP é iniciado, o objeto proxy do CP é obtido.A segunda metade é Através do objeto proxy, chame o método insert.

O processo geral é mostrado na figura abaixo:

Insira a descrição da imagem aqui
1) App2 envia mensagem para AMS e deseja acessar o CP no App1.

2) A verificação do AMS constatou que o CP no App1 não foi iniciado, portanto, um novo processo foi aberto para iniciar o App1, e então o CP iniciado pelo App1 foi obtido e o objeto proxy do CP foi retornado ao App2.

3) App2 obtém o objeto proxy do CP, que é IContentProvider, e chama seus quatro métodos de adição, exclusão, modificação e verificação. A próxima etapa é usar ASM para transmitir ou modificar dados, que é a classe CursorWindow mencionada acima . Obter dados ou resultados de operação é suficiente. Como desenvolvedor de aplicativos, você não precisa saber muitos detalhes subjacentes e isso não é útil.

Acho que você gosta

Origin blog.csdn.net/jxq1994/article/details/130410469
Recomendado
Clasificación