Tutorial e exemplos de Androide Handler

Um "handler" é uma classe "threading" definida no pacote "android.os" através da qual podemos enviar e processar objetos "Mensagem" e "Executáveis" associados a uma "fila de mensagens" de um "thread".

Você começa criando uma instância de Handler. Em seguida, essa instância é associada a um único "thread", bem como à fila de mensagens desse "thread". O "handler" que você acabou de criar será então vinculado à "fila de mensagens" do "thread" que o está criando. Assim, ele pode então entregar mensagens e "runnables" a essa fila de mensagens e executá-las à medida que saem da fila de mensagens.

Usos do `Handler''.

O "Handler" tem duas utilizações principais

  1. Retirada de mensagens e `runnables' que precisam ser executadas no futuro.
  2. Ações de enfileiramento que precisam ser executadas em segundo plano "thread".

Handler e Looper.

O "handler" é uma classe fundamental para a forma como fazemos a "leitura" em andróide, em nível de infra-estrutura. Funciona de mãos dadas com o "Looper". Juntos, eles sustentam tudo o que o "thread" principal faz - inclusive a invocação dos métodos do ciclo de vida da "atividade".

O "Looper" se encarregará de despachar o trabalho em seu "fio" de mensagem. Por outro lado, o "Handler" servirá a dois papéis:

  1. Em primeiro lugar, fornecerá uma interface para enviar mensagens ao seu "Looper".
    fila.
    2.Em segundo lugar, implementará a chamada de retorno para o processamento dessas mensagens quando elas forem despachadas pelo Looper.

Cada "Operador" fica vinculado a um único "Operador" e, por extensão, a um único "fio" e sua "Fila de Mensagens de "Operador".

Dissemos que o "Handler" fornece uma interface para submeter o trabalho aos fios do "Looper". Além disso, o Handler também define o código que processa as mensagens enviadas.

Por exemplo, no código a seguir, a classe 'MyHandler' substituirá o método 'handleMessage()Handler' do Handler'.

É aqui que escrevemos então nosso código de tratamento de mensagens:

public class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        // your message handling code here
    }
}

Digamos que criamos um "tópico" chamado "Meu tópico". Podemos então criar nosso "handler" dentro de nosso "MyThread" sobre o "thread" padrão.
"construtor" Handler().

Assim, o myHandler se apegará ao atual link do link em vez do principal link do link do link:

public class MyThread extends Thread{
    private Handler myHandler;
    @Override
    public void run() {
        Looper.prepare();
        myHandler = new MyHandler();
        Looper.loop();
    }
    public Handler getHandler(){
        return myHandler;
    }
}

Então, uma vez iniciado, o "laço" vai esperar dentro do método "laço" da classe "laço" para que as mensagens sejam adicionadas a sua fila.

Então, outro thread pode adicionar uma mensagem a essa fila. Ele pode fazer isso utilizando o método submit().

Quando isso acontece, o "thread" de espera enviará a mensagem para nosso alvo "MyHandler", invocando o método "handleMessage()handleMessage()dohandler'.

O Handler instância/objeto nos permite enviar mensagens para a classe Handler de qualquer thread e, como conseqüência, é sempre despachada para o Looper thread e manuseada pelo Handler correto,

Exemplos rápidos de "Handler

Vejamos os exemplos rápidos, trechos e howTos do "Handler".

1. Como mostrar uma atividade de splash através do `Handler'.

Nosso objetivo é mostrar uma atividade de respingo através do "Handler".

Suponha que você tenha este layout como nosso atividade_splash. Ele tem imageview e várias visualizações de texto.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout

    android_id="@+id/activity_splash"
    android_layout_width="match_parent"
    android_layout_height="match_parent"
    tools_context="com.pchef.cc.personalchef.Splash">

    <ImageView
        android_layout_width="match_parent"
        android_layout_height="match_parent"
        android_id="@+id/s_img"
        android_alpha="0.7"
        android_src="@drawable/splash"
        android_scaleType="centerCrop"/>

    <LinearLayout
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_orientation="vertical"
        android_layout_centerInParent="true">

        <TextView
            android_layout_width="200dp"
            android_layout_height="wrap_content"
            android_text="Personal Chef"
            android_layout_gravity="center"
            android_gravity="center"
            android_textColor="#fff"
            android_fontFamily="cursive"
            android_textStyle="bold|italic"
            android_layout_marginBottom="50dp"
            android_textSize="60dp"/>

        <TextView
            android_layout_width="match_parent"
            android_layout_height="wrap_content"
            android_gravity="center"
            android_textColor="#fff"
            android_textSize="22dp"
            android_fontFamily="sans-serif-condensed"
            android_id="@+id/tv1"
            android_text="Dont know what to cook ?"
            />

        <TextView
            android_layout_width="match_parent"
            android_layout_height="wrap_content"
            android_id="@+id/tv2"
            android_gravity="center"
            android_layout_marginLeft="20dp"
            android_layout_marginRight="20dp"
            android_textSize="18dp"
            android_textColor="#fff"

            android_fontFamily="sans-serif-condensed"
            android_text="Our Personal Chef Can help you"
            android_layout_marginTop="14dp" />

    </LinearLayout>

</RelativeLayout>

Então podemos vir a criar nossa SpashActivity. Ela é derivada da AppCompatActivity. Estamos fazendo várias importações, incluindo o próprio "Handler", bem como o Glide, uma biblioteca de carregadores de imagens.

import android.content.Intent;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.Spinner;

import com.bumptech.glide.Glide;

import java.util.concurrent.TimeUnit;

public class Splash extends AppCompatActivity {...}

Teremos um ImageView como pano de fundo:

    ImageView background;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);
        background = (ImageView) findViewById(R.id.s_img);

Usaremos o planeio para carregar a imagem em uma visualização da imagem:

        Glide.with(this)
                .load(R.drawable.splash)
                .into(background);

Finalmente chegamos e instanciamos nosso "handler":

        final Handler handler = new Handler();

Em seguida, invoque o método postDelayed() passando em uma Runnable onde implementamos o método run().

É dentro do método 'run()run() onde fazemos nossas coisas de fundo. Observe que também estamos passando o atraso em milissegundos.

        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //Do something after delay
                finish();
                startActivity(new Intent(Splash.this, Home.class));
            }
        }, 3000);
    }

}
3. Como utilizar um Handler para atualizar o WebView

Nesta amostra rápida, queremos utilizar o método 'Handler's postDelayed() refresh a webview. Você pode atualizar uma visualização da web utilizando o método reload() da visualização da web. Nós passamos o tempo de atraso em milissegundos.

void refreshWebPage(){
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                LightningView webview = getCurrentWebView();
                if (webview != null) {
                    webview.reload();
        }
            }
        }, 200);
    }
4. como utilizar um "Handler" para carregar animação

O Android é uma estrutura rica em animação. A capacidade de usar animações foi facilitada dada a presença de um Hnadler. Vejamos um exemplo de trecho que pode nos mostrar como carregar uma animação utilizando um "Handler".
Vamos passar a visão para animar, a identificação do recurso de animação, o tempo de atraso e o objeto Contexto. Utilizaremos o método Handler's postDelayed. Aí passaremos nossa classe 'Runnable', assim como o tempo de atraso.

public static void animationIn(final View view, final int animation, int delayTime, final Context context) {
    Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        public void run() {
            Animation inAnimation = AnimationUtils.loadAnimation(
                    context.getApplicationContext(), animation);
            view.setAnimation(inAnimation);
            view.setVisibility(View.VISIBLE);
        }
    }, delayTime);
}

Isso foi animação para dentro, bem, nós também temos animação para fora:

 public static void animationOut(final View view, final int animation, int delayTime, final boolean isViewGone, final Context context) {
        view.setVisibility(View.VISIBLE);
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            public void run() {
                Animation outAnimation = AnimationUtils.loadAnimation(
                        context.getApplicationContext(), animation);
                view.setAnimation(outAnimation);
                if (isViewGone)
                    view.setVisibility(View.GONE);
                else
                    view.setVisibility(View.INVISIBLE);
            }
        }, delayTime);
    }

Handler post()

O "Handler" tem um método chamado post():

post(Runnable r)

Como você pode ver, esse método leva um objeto executável. O post() método **causa o Runnable r para ser adicionado à fila de mensagens***.

Vejamos vários exemplos do mundo real deste método:

1. Utilize o método Handler's post()` para abrir o teclado

Veja aqui como utilizar o método 'Handler' para abrir um Teclado.

public void openIME(final EditText v) {
    final boolean focus = v.requestFocus();
    if (v.hasFocus()) {
        final Handler handler = new Handler(Looper.getMainLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                InputMethodManager mgr = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
                boolean result = mgr.showSoftInput(v, InputMethodManager.SHOW_FORCED);
                log.debug("openIME " + focus + " " + result);
            }
        });
    }
}
2. Método 'Handler' post() com Executor

Um 'Executor' é um objeto que executa tarefas 'Executáveis' submetidas.

public DownloadStatusDeliveryImpl(final Handler handler) {
    this.mDownloadStatusPoster = new Executor() {
        public void execute(Runnable command) {
            handler.post(command);
        }
    };
}
3. Completa Handler Classe Utilitária Reutilizável

Aqui está um exemplo de uma classe de utilidade que explora ainda mais a utilização do "Handler":

import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;

public final class HandlerUtils {

    private HandlerUtils() {
    }

    public static void uiPost(Runnable action) {
        if (action == null) {
            return;
        }
        uiHandler().post(action);
    }

    public static void uiPostDelayed(Runnable action, long delayMillis) {
        if (action == null) {
            return;
        }
        uiHandler().postDelayed(action, delayMillis);
    }

    public static void uiRemoveCallbacks(Runnable action) {
        uiHandler().removeCallbacks(action);
    }

    public static void threadPost(Runnable action) {
        if (action == null) {
            return;
        }
        threadHandler().post(action);
    }

    public static void threadPostDelayed(Runnable action, long delayMillis) {
        if (action == null) {
            return;
        }
        threadHandler().postDelayed(action, delayMillis);
    }

    public static void threadRemoveCallbacks(Runnable action) {
        threadHandler().removeCallbacks(action);
    }

    private static Handler uiHandler() {
        return Holder.handler;
    }

    private interface Holder {
        Handler handler = new Handler(Looper.getMainLooper());
    }

    private static Handler sThreadHandler;

    private static synchronized Handler threadHandler() {
        if (sThreadHandler == null) {
            HandlerThread thread = new HandlerThread("HandlerUtils.sThreadHandler");
            thread.start();
            sThreadHandler = new Handler(thread.getLooper());
        }
        return sThreadHandler;
    }
}

4. Como executar uma "runnable" especificada no tópico principal

Aprovamos a ação a ser executada no "fio condutor" da IU.

public final class HandlerUtils {
    private static Handler handler = new Handler(Looper.getMainLooper());

    public static void runOnUiThread(Runnable action) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            action.run();
        }
        else {
            handler.post(action);
        }
    }
}

Vejamos alguns exemplos completos.

Exemplo 1: Vários Exemplos `Handler'.

Este exemplo explorará vários cenários práticos de uso em que você provavelmente se envolverá ao utilizar a classe android.os.Handler.

Passo 1: Criar projeto Java ou Kotlin

Criar um projeto java no estúdio andróide. Você também pode criar um kotlin e usar o conversor de código para converter de java para kotlin.

Passo 2: Dependências

Não são necessárias dependências para este projeto.

Passo 3: Permissões

Nenhuma permissão é necessária para este projeto.

Passo 4: Layout do projeto

Isto envolve adicionar um monte de visualizações de texto ao layout de sua atividade principal. Acrescente também um botão. Você pode organizá-las usando um layout linear vertical:

**activity_main.xml***

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.lomza.examples.handlers.MainActivity">

    <TextView
        android:id="@+id/tv_01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_02"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_03"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_04"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_05"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/tv_06"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/button_07"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Post with a view Handler"/>

    <TextView
        android:id="@+id/tv_07"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

Passo 5: Escrever Código

Em seguida, escrevemos nosso código. você começa ampliando a `Aplicactividade de Compacta' para criar nossa atividade principal.

A atividade principal com métodos para demonstrar o uso de Handlers, Runnables e Messages:


public class MainActivity extends AppCompatActivity {
    private TextView tv01;
    private TextView tv02;
    private TextView tv03;
    private TextView tv04;
    private TextView tv05;
    private TextView tv06;
    private TextView tv07;
    private Button button07;

    private final Handler mainThreadHandler = new Handler(Looper.getMainLooper());
    private Handler currentThreadHandler;
    private Handler decorViewHandler;
    private final ChangeTextHandler customHandler = new ChangeTextHandler(this);
    private final Handler notLeakyHandler = new Handler();
    private final Runnable notLeakyRunnable = new ChangeTextRunnable(this, "Hi from leak-safe Runnable!");

    private static final String TAG = "[Handlers]";
    private static final String BUNDLE_KEY = "greeting";

Primeiro você pode postar uma tarefa com "thread" comum utilizando o seguinte código:

    private void postTaskWithOrdinaryThread() {
        Runnable notForHandlerTask = new Runnable() {
            @Override
            public void run() {
                // as written here - https://developer.android.com/guide/components/processes-and-threads.html#Threads,
                // do NOT access the Android UI toolkit from outside the UI thread, as sth unexpected may happen
                // for instance, you might get android.view.ViewRootImpl$CalledFromWrongThreadException
                tv01.setText("Hi from Thread(runnable)!");
                // if you call thread.run(), this would be TRUE, as no new Thread would be created
                // read the explanation here - http://stackoverflow.com/a/35264580/655275
                Log.d(TAG, "[postTaskWithOrdinaryThread] Current looper is a main thread (UI) looper: "
                        + (Looper.myLooper() == Looper.getMainLooper()));
            }
        };
        Thread thread = new Thread(notForHandlerTask);
        thread.start();
    }

E aqui está como você pode postar uma tarefa com "handler" no "tópico" principal:

    @UiThread
    private void postTaskWithHandlerOnMainThread() {
        Runnable mainThreadTask = new Runnable() {
            @Override
            public void run() {
                // since we use Looper.getMainLooper(), we can safely update the UI from here
                tv02.setText("Hi from Handler(Looper.getMainLooper()) post!");
                Log.d(TAG, "[postTaskWithHandlerOnMainThread] Current looper is a main thread (UI) looper: "
                        + (Looper.myLooper() == Looper.getMainLooper()));
            }
        };
        mainThreadHandler.post(mainThreadTask);
    }

Veja aqui como você pode postar tarefas com "handler" em "thread" concorrente:

    private void postTaskWithHandlerOnCurrentThread() {
        currentThreadHandler = new Handler();
        Runnable currentThreadTask = new Runnable() {
            @Override
            public void run() {
                // since we use current thread (and from onCreate(), it's the UI thread), we can safely update the UI from here
                tv03.setText("Hi from Handler() post!");
                Log.d(TAG, "[postTaskWithHandlerOnCurrentThread] Current looper is a main thread (UI) looper: "
                        + (Looper.myLooper() == Looper.getMainLooper()));
            }
        };
        currentThreadHandler.post(currentThreadTask);

    }

E aqui está como você pode colocar a tarefa dentro do "tópico de fundo":

    private void postTaskInsideBackgroundTask() {
        Thread backgroundThread = new Thread(new Runnable() {
            @Override
            public void run() {
                // pretend to do something "background-y"
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                mainThreadHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        tv04.setText("Hi from a Handler inside of a background Thread!");
                    }
                });
            }
        });

        backgroundThread.start();
    }

Veja como utilizar a anotação code>@UiThread</code para postar tarefas com esta janela e visualização de texto:

    @UiThread
    private void postTaskWithThisWindowAndTextViewHandlers() {
        // this line will return null from onCreate() (and even if called from onResume()) and cause NPE when trying to post();
        // this is because the handler isn't attached to the view if it's not fully visible
        decorViewHandler = getWindow().getDecorView().getHandler();
        Runnable decorViewTask = new Runnable() {
            @Override
            public void run() {
                // View's post() uses UI handler internally
                tv07.post(new Runnable() {
                    @Override
                    public void run() {
                        tv07.setText("Hi from getWindow().getDecorView().getHandler() > TextView.post()!");
                        Log.d(TAG, "[postTaskWithThisWindowAndTextViewHandlers] Current looper is a main thread (UI) looper: "
                                + (Looper.myLooper() == Looper.getMainLooper()));
                    }
                });
            }
        };
        decorViewHandler.post(decorViewTask);
    }

E aqui está como você pode postar tarefa com "handler" em fundo "thread":

    private void postTaskWithHandlerOnBackgroundThread() {
        final Runnable pretendsToBeSomeOtherTask = new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "[postTaskWithHandlerOnBackgroundThread] Is there a looper? " + (Looper.myLooper() != null));
                // you'll get java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
                // this is because Handlers need to have a Looper associated with them; when the task was run on the main thread,
                // main thread looper was used, but if we call this from the background thread, there is NO looper to use
                // read more - https://developer.android.com/reference/android/os/Looper.html

                postTaskWithHandlerOnCurrentThread();
            }
        };
        final Thread thread = new Thread(pretendsToBeSomeOtherTask);
        thread.start();
    }

Veja como você pode postar tarefas com um "Handler" e um "Executável" não vazios:

    private void postTaskWithNotLeakyHandlerAndRunnable() {
        // in order to eliminate leaks, both Handler and Runnable should be static
        // static inner classes do not hold an implicit reference to the outer class
        // it seems like a lot of useless work, but it's the most accurate and bug-free way
        // read more - http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html
        notLeakyHandler.postDelayed(notLeakyRunnable, 500);
    }

Aqui está o código completo;

**MainActivity.java***

package com.lomza.examples.handlers;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.UiThread;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;

/**
 * Main activity with methods to demonstrates the usage of Handlers, Runnables, and Messages :)
 *
 * @author Antonina Tkachuk
 */
public class MainActivity extends AppCompatActivity {
    private TextView tv01;
    private TextView tv02;
    private TextView tv03;
    private TextView tv04;
    private TextView tv05;
    private TextView tv06;
    private TextView tv07;
    private Button button07;

    private final Handler mainThreadHandler = new Handler(Looper.getMainLooper());
    private Handler currentThreadHandler;
    private Handler decorViewHandler;
    private final ChangeTextHandler customHandler = new ChangeTextHandler(this);
    private final Handler notLeakyHandler = new Handler();
    private final Runnable notLeakyRunnable = new ChangeTextRunnable(this, "Hi from leak-safe Runnable!");

    private static final String TAG = "[Handlers]";
    private static final String BUNDLE_KEY = "greeting";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initView();
    }

    @Override
    protected void onStart() {
        super.onStart();

        postTaskWithOrdinaryThread();
        postTaskWithHandlerOnMainThread();
        postTaskWithHandlerOnCurrentThread();
        postTaskInsideBackgroundTask();
        //postTaskWithHandlerOnBackgroundThread();
        postTaskWithNotLeakyHandlerAndRunnable();
        sendMessageToChangeTextHandler();
    }

    @Override
    protected void onStop() {
        super.onStop();
        // when posting Runnables or Messages, always remember to call removeCallbacks() or removeMessages()
        // or removeCallbacksAndMessages() for both.
        // this ensures that all pending tasks don't execute in vain; for instance, the user has left our activity
        // and he doesn't really care if some job is finished or not, so it's our responsibility to cancel it

        // pass null to remove ALL callbacks and messages
        mainThreadHandler.removeCallbacks(null);
        currentThreadHandler.removeCallbacks(null);
        if (decorViewHandler != null)
            decorViewHandler.removeCallbacks(null);
        customHandler.removeCallbacksAndMessages(null);
        notLeakyHandler.removeCallbacks(notLeakyRunnable);
    }

    private void initView() {
        tv01 = (TextView) findViewById(R.id.tv_01);
        tv02 = (TextView) findViewById(R.id.tv_02);
        tv03 = (TextView) findViewById(R.id.tv_03);
        tv04 = (TextView) findViewById(R.id.tv_04);
        tv05 = (TextView) findViewById(R.id.tv_05);
        tv06 = (TextView) findViewById(R.id.tv_06);
        tv07 = (TextView) findViewById(R.id.tv_07);
        button07 = (Button) findViewById(R.id.button_07);
        button07.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                postTaskWithThisWindowAndTextViewHandlers();
            }
        });
    }

    private void postTaskWithOrdinaryThread() {
        Runnable notForHandlerTask = new Runnable() {
            @Override
            public void run() {
                // as written here - https://developer.android.com/guide/components/processes-and-threads.html#Threads,
                // do NOT access the Android UI toolkit from outside the UI thread, as sth unexpected may happen
                // for instance, you might get android.view.ViewRootImpl$CalledFromWrongThreadException
                tv01.setText("Hi from Thread(runnable)!");
                // if you call thread.run(), this would be TRUE, as no new Thread would be created
                // read the explanation here - http://stackoverflow.com/a/35264580/655275
                Log.d(TAG, "[postTaskWithOrdinaryThread] Current looper is a main thread (UI) looper: "
                        + (Looper.myLooper() == Looper.getMainLooper()));
            }
        };
        Thread thread = new Thread(notForHandlerTask);
        thread.start();
    }

    @UiThread
    private void postTaskWithHandlerOnMainThread() {
        Runnable mainThreadTask = new Runnable() {
            @Override
            public void run() {
                // since we use Looper.getMainLooper(), we can safely update the UI from here
                tv02.setText("Hi from Handler(Looper.getMainLooper()) post!");
                Log.d(TAG, "[postTaskWithHandlerOnMainThread] Current looper is a main thread (UI) looper: "
                        + (Looper.myLooper() == Looper.getMainLooper()));
            }
        };
        mainThreadHandler.post(mainThreadTask);
    }

    private void postTaskWithHandlerOnCurrentThread() {
        currentThreadHandler = new Handler();
        Runnable currentThreadTask = new Runnable() {
            @Override
            public void run() {
                // since we use current thread (and from onCreate(), it's the UI thread), we can safely update the UI from here
                tv03.setText("Hi from Handler() post!");
                Log.d(TAG, "[postTaskWithHandlerOnCurrentThread] Current looper is a main thread (UI) looper: "
                        + (Looper.myLooper() == Looper.getMainLooper()));
            }
        };
        currentThreadHandler.post(currentThreadTask);

    }

    private void postTaskInsideBackgroundTask() {
        Thread backgroundThread = new Thread(new Runnable() {
            @Override
            public void run() {
                // pretend to do something "background-y"
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                mainThreadHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        tv04.setText("Hi from a Handler inside of a background Thread!");
                    }
                });
            }
        });

        backgroundThread.start();
    }

    @UiThread
    private void postTaskWithThisWindowAndTextViewHandlers() {
        // this line will return null from onCreate() (and even if called from onResume()) and cause NPE when trying to post();
        // this is because the handler isn't attached to the view if it's not fully visible
        decorViewHandler = getWindow().getDecorView().getHandler();
        Runnable decorViewTask = new Runnable() {
            @Override
            public void run() {
                // View's post() uses UI handler internally
                tv07.post(new Runnable() {
                    @Override
                    public void run() {
                        tv07.setText("Hi from getWindow().getDecorView().getHandler() > TextView.post()!");
                        Log.d(TAG, "[postTaskWithThisWindowAndTextViewHandlers] Current looper is a main thread (UI) looper: "
                                + (Looper.myLooper() == Looper.getMainLooper()));
                    }
                });
            }
        };
        decorViewHandler.post(decorViewTask);
    }

    private void postTaskWithHandlerOnBackgroundThread() {
        final Runnable pretendsToBeSomeOtherTask = new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "[postTaskWithHandlerOnBackgroundThread] Is there a looper? " + (Looper.myLooper() != null));
                // you'll get java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
                // this is because Handlers need to have a Looper associated with them; when the task was run on the main thread,
                // main thread looper was used, but if we call this from the background thread, there is NO looper to use
                // read more - https://developer.android.com/reference/android/os/Looper.html

                postTaskWithHandlerOnCurrentThread();
            }
        };
        final Thread thread = new Thread(pretendsToBeSomeOtherTask);
        thread.start();
    }

    private void postTaskWithNotLeakyHandlerAndRunnable() {
        // in order to eliminate leaks, both Handler and Runnable should be static
        // static inner classes do not hold an implicit reference to the outer class
        // it seems like a lot of useless work, but it's the most accurate and bug-free way
        // read more - http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html
        notLeakyHandler.postDelayed(notLeakyRunnable, 500);
    }

    private static class ChangeTextRunnable implements Runnable {
        private final WeakReference<MainActivity> activity;
        private final String greetingMessage;

        public ChangeTextRunnable(MainActivity activity, String greetingMessage) {
            this.activity = new WeakReference<>(activity);
            this.greetingMessage = greetingMessage;
        }

        public void run() {
            if (greetingMessage == null) {
                Log.e(TAG, "The message is null ChangeTextRunnable.run()!");
                return;
            }

            MainActivity activity = this.activity.get();
            if (activity == null) {
                Log.e(TAG, "Activity is null ChangeTextRunnable.run()!");
                return;
            }

            activity.tv05.setText(greetingMessage);
        }
    }

    // === OBTAIN AND HANDLE A MESSAGE ===
    private void sendMessageToChangeTextHandler() {
        Message messageToSend = customHandler.obtainMessage();
        Bundle bundle = new Bundle();
        bundle.putString(BUNDLE_KEY, "Hi from custom inner Handler!");
        messageToSend.setData(bundle);
        messageToSend.what = 6;
        customHandler.sendMessage(messageToSend);
    }

    private static class ChangeTextHandler extends Handler {
        private final WeakReference<MainActivity> activity;

        public ChangeTextHandler(MainActivity activity) {
            this.activity = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            MainActivity activity = this.activity.get();
            if (activity == null) {
                Log.e(TAG, "Activity is null ChangeTextHandler.handleMessage()!");
                return;
            }

            final String text = (String) msg.getData().get(BUNDLE_KEY);
            if (!TextUtils.isEmpty(text)) {
                switch (msg.what) {
                    case 6:
                        activity.tv06.setText(text);
                        break;
                    default:
                        activity.tv01.setText(text);
                        break;
                }
            }
        }
    }
    // === END - OBTAIN AND HANDLE A MESSAGE ===
}

Correr

Finalmente, executar o projeto.

Referência

Abaixo estão os links de referência do código:

Número Link Link
1. Código de download Código de download
2. Siga o autor do código Siga o autor do código [Siga o autor do código

Exemplo 2: Handler com barra de progresso Exemplo

Neste tutorial, queremos ver como postar atualizações a partir de um thread de fundo para a interface do usuário thread utilizando um Handler.

Clicamos em um botão e simulamos fazer um trabalho pesado em segundo plano. Enquanto isso, somos capazes de atualizar nossa barra de progresso à medida que o trabalho continua.

(a). MainActivity.java

Esta é a principal atividade. Nós derivamos da AppCompatActivity'. Uma das importações que adicionamos é o Handler do pacote android.os`.

...
import android.os.Handler;
...

Manteremos três campos de instância:

  1. "Handler" - uma classe definida no pacote "android.os" através da qual podemos enviar e processar objetos "Mensagem" e "Executáveis" associados a uma "Fila de Mensagem" de um "thread".
  2. Barra de Progresso - um widget que nos permite mostrar o progresso.
    1. `Button' - um botão de ação.

Aqui está o código completo:

package info.camposha.mrhandler;

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;

public class MainActivity extends AppCompatActivity {

    private Handler mHandler;
    private ProgressBar mProgressBar;
    private Button mStartButton;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mHandler = new Handler();
        mProgressBar = findViewById(R.id.mProgressBar);
        mStartButton = findViewById(R.id.startBtn);
        mStartButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                performStuff();
            }
        });
    }
    private void performStuff() {
        //Simulate Heavy task in background thread
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i <= 30; i++) {
                    final int currentProgressCount = i;
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                //Post updates to the User Interface
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            mProgressBar.setProgress(currentProgressCount);
                        }
                    });
                }
            }
        }).start();
    }
}

(b). activity_main.xml

Este é o layout da atividade principal. Na raiz, temos um [LinearLayout] (https://camposha.info/android/linearlayout). Este elemento nos permite organizar as crianças de forma linear, tanto na horizontal quanto na vertical. Também temos o TextView para exibir o texto de cabeçalho de nosso aplicativo. Também temos uma barra de progressão para exibir o progresso. Temos também um botão que quando clicado iniciará o thread para realizar nosso trabalho em segundo plano.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android_layout_width="match_parent"
    android_layout_height="match_parent"

    android_gravity="center"
    android_orientation="vertical"
    tools_context=".MainActivity">

    <TextView
        android_id="@+id/headerLabel"
        android_layout_width="wrap_content"
        android_layout_height="wrap_content"
        android_layout_alignParentTop="true"
        android_layout_centerHorizontal="true"
        android_fontFamily="casual"
        android_text="Handler ProgressBar"
        android_textAllCaps="true"
        android_textSize="24sp"
        android_textStyle="bold" />

    <ProgressBar
        android_id="@+id/mProgressBar"
        style="?android:attr/progressBarStyleHorizontal"
        android_layout_width="match_parent"
        android_layout_height="wrap_content"
        android_layout_margin="10dp"
        android_indeterminate="false"
        android_max="10" />

    <Button
        android_id="@+id/startBtn"
        android_layout_width="wrap_content"
        android_layout_height="wrap_content"
        android_text="Start" />
</LinearLayout>

Exemplo 3: Exemplo simples Handler com Timer

Este exemplo explora como utilizar Handler com Timer.

Passo 1: Dependências

Não são necessárias depedências de terceiros para este exemplo.

Passo 2: Layouts

Não precisamos de nenhum layout para este exemplo.

Passo 3: Escrever Código

Aqui está o código completo:

**HandlerActivity.java***

package com.sdwfqin.sample.handler;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

import com.sdwfqin.sample.R;

import java.lang.ref.WeakReference;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @author zhangqin
 */
public class HandlerActivity extends AppCompatActivity {

    private static final String TAG = "HandlerActivity";
    private MyHandler mMyHandler;
    private Timer mTimer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);

        mMyHandler = new MyHandler(this);

        mMyHandler.sendEmptyMessage(1);

        mTimer = new Timer();
        mTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                mMyHandler.sendEmptyMessage(2);
            }
        }, 1000, 1000);
        mMyHandler.sendEmptyMessage(3);
    }

    static class MyHandler extends Handler {

        private WeakReference<HandlerActivity> mActivity;

        public MyHandler(HandlerActivity activity) {
            mActivity = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            HandlerActivity activity = mActivity.get();
            switch (msg.what) {
                case 1:
                    Log.e(TAG, "handlerA:case:1");
                    break;
                case 2:
                    Log.e(TAG, "handlerA:case:2");
                    break;
                case 3:
                    Log.e(TAG, "handlerA:case:3");
                    break;
                default:
                    break;
            }
        }
    }

    @Override
    protected void onDestroy() {
        mTimer.cancel();
        mMyHandler.removeCallbacksAndMessages(null);
        super.onDestroy();
    }
}

Referência

Faça o download do código abaixo:

Número Link Link
1. Código de download Código de download [Código de download
2. Siga o autor do código Siga o autor do código [Siga o autor do código

Cofre de memória Handler

A implementação original do "handler" sempre mantém uma referência dura ao "handler" na fila de execução. Qualquer objeto na mensagem ou Runnable postado em android.os.Handler será duramente referenciado por algum tempo. Se você criar uma "Executável" anônima e chamar para "postDelayed" com grande timeout, essa "Executável" será mantida na memória até que o timeout passe. Mesmo que sua "Executável" pareça pequena, ela referencia indiretamente a classe do proprietário, que normalmente é algo tão grande quanto "Atividade" ou "Fragmento".

Você pode ler mais aqui.

Solução - Utilize o 'Weak `Handler'.

O que é um "handler" fraco?

É uma implementação mais segura da memória do android.os.Handler.

WeakHandler" é mais complicado do que "android.os.Handler", ele manterá "WeakReferences" para "runnables" e mensagens, e a GC poderia coletá-las uma vez que a instância "WeakHandler" não seja mais referenciada.

WeakHandler

Como você a utiliza?

Passo 1: Instale-o

Registre Jitpack como um maven url em seu arquivo build.gradle de nível de projeto como segue:

repositories {
    maven { url 'https://jitpack.io' }
}

Em seguida, adicione a declaração de implementação sob o fechamento das dependências em seu arquivo build.gradle de nível de aplicação:


dependencies {
    implementation 'com.github.badoo:android-weak-handler:1.2'
}

Sincronizar para instalá-lo.

Passo 2: Escrever Código

Você pode simplesmente utilizar "WeakHandler" como um substituto do "android.os.Handler". Basta utilizá-lo da maneira que você utilizaria o "Handler". Abaixo está um exemplo:

**ExemploActivity.java***

import com.badoo.mobile.util.WeakHandler;

public class ExampleActivity extends Activity {

    private WeakHandler handler; // We still need at least one hard reference to WeakHandler

    protected void onCreate(Bundle savedInstanceState) {
        handler = new WeakHandler();
        ...
    }

    private void onClick(View view) {
        handler.postDelayed(new Runnable() {
            view.setVisibility(View.INVISIBLE);
        }, 5000);
    }
}

Referência

Encontre os links de referência abaixo:

Número Link Link
1. Leia mais Leia mais Leia mais [Leia mais

Categorized in: