O que exatamente o método de postagem faz?


106

Eu encontrei um recurso muito estranho.

Quando tento executar uma animação no thread principal, ela não inicia. Quando executo essa animação usando

getView().post(new Runnable() {
            @Override
            public void run() {
                getView().startAnimation(a);
            }
        });

Ele começa.

Imprimi o CurrentThreadantes de iniciar a animação e ambos imprimem main.

Obviamente, estou faltando alguma coisa aqui, pois ambos devem iniciar a animação no thread principal ... Meu palpite é que conforme a postagem adiciona a tarefa à fila, ela começa em um "horário mais correto", mas eu adoraria saber o que acontece aqui com mais profundidade.

EDIT: Deixe-me esclarecer as coisas - minha pergunta é, por que iniciar a animação no post faz com que ela comece, ao passo que iniciar a animação no thread principal não.


Este comportamento é específico de uma versão do Android? Não consegui reproduzir no Android 4.1.2!
Akdeniz

Reproduzi esse comportamento no Android 2.3.3. Mas para AnimationDrawable! A Animationinstância comum começou a ser animada com sucesso em cada configuração. No AnimationDrawablecaso; quando você tenta iniciá-lo onCreate, ele não inicia por não estar conectado à visualização naquele momento. Portanto, não é um problema de segmentação AnimationDrawable. Talvez a mesma coisa se aplique Animation? developer.android.com/guide/topics/graphics/…
Akdeniz

Respostas:


161

post : post faz com que o Runnable seja adicionado à fila de mensagens,

Executável: representa um comando que pode ser executado. Frequentemente usado para executar código em um Thread diferente.

run () : inicia a execução da parte ativa do código da classe. Este método é chamado quando um thread é iniciado que foi criado com uma classe que implementa Runnable.

getView().post(new Runnable() {

         @Override
         public void run() {
             getView().startAnimation(a);
         }
     });

código :getView().startAnimation(a);

em seu código,

post faz com que o Runnable (o código será executado em um thread diferente) adicione a fila de mensagens.

Portanto, startAnimation será acionado em uma nova thread quando for buscado em messageQueue

[EDITAR 1]

Por que usamos um novo thread em vez de UI thread (thread principal)?

Tópico da interface do usuário:

  • Quando o aplicativo é iniciado, Ui Thread é criado automaticamente

  • é responsável por despachar os eventos para os widgets apropriados e isso inclui os eventos de desenho.

  • É também o tópico com o qual você interage com widgets Android

Por exemplo, se você tocar no botão a na tela, o encadeamento da IU despacha o evento de toque para o widget que, por sua vez, define seu estado pressionado e posta uma solicitação de invalidação na fila de eventos. O encadeamento da IU retira a solicitação e notifica o widget para se redesenhar.

O que acontece se um usuário pressionar um botão que fará longOperation?

((Button)findViewById(R.id.Button1)).setOnClickListener(           
             new OnClickListener() {        
        @Override
    public void onClick(View v) {
            final Bitmap b = loadImageFromNetwork();
            mImageView.setImageBitmap(b);
}
});

A IU congela. O programa pode até travar.

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
        final Bitmap b = loadImageFromNetwork();
        mImageView.setImageBitmap(b);
    }
  }).start();
}

Ele quebra a regra do Android de nunca atualizar a IU diretamente do thread de trabalho

O Android oferece várias maneiras de acessar o thread de IU de outros threads.

  • Activity.runOnUiThread (Executável)
  • View.post (executável)
  • View.postDelayed (executável, longo)
  • Handler

Como abaixo,

View.post (executável)

public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      final Bitmap b = loadImageFromNetwork();
      mImageView.post(new Runnable() {
        public void run() {
          mImageView.setImageBitmap(b);
        }
      });
    }
  }).start();
}

Handler

final Handler myHandler = new Handler(Looper.getMainLooper());

(new Thread(new Runnable() {

    @Override
    public void run() {
       final Bitmap b = loadImageFromNetwork();
      myHandler.post(new Runnable() {                           

        @Override
        public void run() {
           mImageView.setImageBitmap(b);
          }
        });
      }
    })).start();                
}

insira a descrição da imagem aqui

Para mais informações

http://android-developers.blogspot.com/2009/05/pellence-threading.html

http://www.aviyehuda.com/blog/2010/12/20/android-multithreading-in-a-ui-environment/


15
Então, por que iniciar a animação na postagem é diferente de executá-la no thread principal, quando ambos, eventualmente, são executados no mesmo thread?
Gal

Porque este modelo de thread único pode resultar em baixo desempenho em aplicativos Android.
Talha

1
O que o desempenho ruim tem a ver com não mostrar uma animação?
Gal

17
Não acho que isso responda à pergunta, é mais como uma resposta genérica para iniciantes que não sabem nada sobre ui-thread e multi-threading. Isso não explica por que lançar a animação à frente na fila faz com que ela funcione; uma animação deve ser algo a ser executado diretamente no ui-thread sem usar nenhum truque post () ou runOnUiThread ().
carrizo

3
Todo o trabalho da IU deve estar no thread principal (thread da IU). O truque que faz a animação funcionar usando post () em vez de chamar no thread principal imediatamente é o tempo: se você chamar imediatamente no thread principal, isso significa que você disse "comece a animação agora", mas neste momento pode ser que a visualização não esteja pronta para animação (medir, desenhar ...). Mas se você colocar isso em post (), ele aguardará startAnimation na fila para preparar a visualização pronta para anim.
NguyenDat

35

Isso está sendo feito em onCreate ou onCreateView? Nesse caso, o aplicativo pode não estar em um estado em que a Visualização esteja anexada à janela. Muitos algoritmos baseados nas métricas do View podem não funcionar, pois coisas como as medidas e a posição do View podem não ter sido calculadas. As animações do Android normalmente exigem que executem matemática da IU

View.post, na verdade, enfileira a animação no loop de mensagem da View, portanto, uma vez que a view é anexada à janela, ela executa a animação em vez de fazê-la manualmente.

Na verdade, você está executando coisas no thread da IU, mas em um momento diferente


A resposta aceita é enganosa onde o postador afirma "a postagem causa o Runnable (o código será executado em um tópico diferente)". Esta é a resposta correta "Você está realmente executando coisas no thread de IU, mas em um momento diferente" - mais 1
smitty1

18

Dê uma olhada aqui para uma boa resposta. view.post () é basicamente o mesmo que handler.post (). Ele vai para a fila de threads principal e é executado após a conclusão das outras tarefas pendentes. Se você chamar activity.runOnUiThread (), ele será chamado imediatamente no thread de interface do usuário.


31
Uma diferença enorme (e extremamente útil) que encontrei é o executável em view.post () será chamado quando o View for mostrado pela primeira vez. Ou seja, você pode configurá-lo para iniciar uma animação ao aumentar a visualização e, em algum ponto no futuro, finalmente adicioná-lo à hierarquia de visualização. Nesse ponto, a animação será executada e você não terá que se preocupar com isso.
DeeV

Na verdade, handler.post () nem sempre posta uma mensagem / executável no thread principal. Depende de como o manipulador é criado (pode ser associado a um Looper em uma thread diferente). Por outro lado, view.post () sempre será executado no thread principal
Yair Kukielka

4

O problema, eu acho, pode ser o método de ciclo de vida em que você está chamando o método post (). Você está fazendo isso em onCreate ()? em caso afirmativo, veja o que encontrei na documentação onResume () da atividade:

Resumindo()

Adicionado na API de nível 1 void onResume () Chamado após onRestoreInstanceState (Bundle), onRestart () ou onPause (), para que sua atividade comece a interagir com o usuário. Este é um bom lugar para começar animações , abrir dispositivos de acesso exclusivo (como a câmera), etc.

https://developer.android.com/reference/android/app/Activity.html#onResume ()

Portanto, como disse Joe Plante, talvez a visualização não esteja pronta para iniciar animações no momento em que você chama post (), então tente movê-la para onResume ().

PD: Na verdade, se você mover o código para onResume (), então acho que você pode remover a chamada post (), uma vez que você já está no ui-thread e a visualização deve estar pronta para iniciar as animações.


3
onResumepode ser chamado várias vezes (as telas hibernam, atividade empurrada para o backstack, etc ...) após ser inicialmente quando "a visualização está pronta". Se chamado de onResume, um sinalizador pode ser necessário para rastrear o tempo em que a animação já foi iniciada, para evitar (re) iniciar várias vezes.
samis
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.