Como executar código em um encadeamento em segundo plano no Android?

131

Eu quero que algum código seja executado em segundo plano continuamente. Eu não quero fazer isso em um serviço. Existe alguma outra maneira possível?

Eu tentei chamar a Threadclasse na minha, Activitymas meus Activityrestos permanecem em segundo plano por algum tempo e depois para. A Threadturma também para de trabalhar.

class testThread implements Runnable {
        @Override
        public void run() {
            File file = new File( Environment.getExternalStorageDirectory(), "/BPCLTracker/gpsdata.txt" );
            int i = 0;

            RandomAccessFile in = null;

            try {
                in = new RandomAccessFile( file, "rw" );
            } catch (FileNotFoundException e) {
// TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
// TODO Auto-generated catch block
                e.printStackTrace();
            }
//String line =null;
            while ( true ) {
                HttpEntity entity = null;
                try {
                    if ( isInternetOn() ) {
                        while ( ( line = in.readLine() ) != null ) {

                            HttpClient client = new DefaultHttpClient();
                            String url = "some url";
                            HttpPost request = new HttpPost( url );
                            StringEntity se = new StringEntity( line );
                            se.setContentEncoding( "UTF-8" );
                            se.setContentEncoding( new BasicHeader( HTTP.CONTENT_TYPE, "application/json" ) );
                            entity = se;
                            request.setEntity( entity );
                            HttpResponse response = client.execute( request );
                            entity = response.getEntity();
                            i++;
                        }
                        if ( ( line = in.readLine() ) == null && entity != null ) {
                            file.delete();
                            testThread t = new testThread();
                            Thread t1 = new Thread( t );
                            t1.start();
                        }


                    } else {
                        Thread.sleep( 60000 );
                    } // end of else

                } catch (NullPointerException e1) {
                    e1.printStackTrace();
                } catch (InterruptedException e2) {
                    e2.printStackTrace();
                } catch (IOException e1) {
// TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }// end of while
        }// end of run

    }
user2082987
fonte
1
Oi. Você pode postar algum código como um exemplo do que você tentou? Existem diferentes maneiras de executar o código em um thread em segundo plano, mas você deve se lembrar de que, se estiver acessando algum componente da interface do usuário, deve acessá-lo no thread da interface do usuário usando o runOnUiThread()método
Alex Wiese
3
Existe algum motivo específico para não usar o Serviço
DeltaCap019 18/13/13
isso não é tão recomendado. A operação contínua esgotará a bateria do dispositivo.
HelmiB
Eu enviei o código.
user2082987
Eu tentei usá-lo em serviço, mas está enviando o mesmo registro várias vezes.
user2082987

Respostas:

379

Se você precisar:

  1. executar código em um plano de fundo

  2. executar código que NÃO toque / atualize a interface do usuário

  3. executar código (curto) que levará no máximo alguns segundos para concluir

ENTÃO, use o seguinte padrão limpo e eficiente que usa o AsyncTask:

AsyncTask.execute(new Runnable() {
   @Override
   public void run() {
      //TODO your background code
   }
});
Brandon Rude
fonte
10
Nota: Requer API nível 11
friederbluemle 25/11
9
Por que você não usaria o seguinte, que é mais leve: new Thread (new Runnable () {@Override public void run () {// código de plano de fundo}}). Start ();
awardak
3
Existe a possibilidade de isso causar vazamento de memória?
Hilfritz 22/06/19
5
Uma coisa a notar é que as AsyncTasks são processadas. Se você usar isso para várias chamadas de API do servidor, elas não serão executadas em paralelo.
21818 Chase Roberts
45

Lembre-se de executar o plano de fundo, executar continuamente são duas tarefas diferentes.

Para processos em segundo plano a longo prazo, os Threads não são ideais no Android. No entanto, aqui está o código e faça-o por sua conta e risco ...

Lembre-se de que o Serviço ou o Thread será executado em segundo plano, mas nossa tarefa precisa acionar (chamar várias vezes) para obter atualizações, ou seja, uma vez concluída a tarefa, precisamos recuperar a função para a próxima atualização.

Temporizador (gatilho periódico), Alarme (gatilho da base de tempo), Transmissão (gatilho da base de eventos), a recursão ativará nossas funções.

public static boolean isRecursionEnable = true;

void runInBackground() {
    if (!isRecursionEnable)
        // Handle not to start multiple parallel threads
        return;

    // isRecursionEnable = false; when u want to stop
    // on exception on thread make it true again  
    new Thread(new Runnable() {
        @Override
        public void run() {
            // DO your work here
            // get the data
            if (activity_is_not_in_background) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        // update UI
                        runInBackground();
                    }
                });
            } else {
                runInBackground();
            }
        }
    }).start();
}

Usando o serviço: se você iniciar um serviço, ele iniciará, executará a tarefa e será encerrado automaticamente. após a execução da tarefa. rescindido também pode ser causado por exceção, ou o usuário o eliminou manualmente das configurações. START_STICKY (Serviço fixo) é a opção fornecida pelo Android, que o serviço será reiniciado automaticamente se o serviço for encerrado.

Lembre-se da diferença de perguntas entre multiprocessamento e multithreading? O serviço é um processo em segundo plano (assim como a atividade sem interface do usuário). Da mesma maneira que você inicia o encadeamento na atividade para evitar a carga no encadeamento principal (encadeamento de atividades), da mesma maneira que você precisa iniciar encadeamentos (ou tarefas assíncronas) no serviço para evitar carga no serviço.

Em uma única instrução, se você deseja executar uma tarefa em segundo plano continua, é necessário iniciar um StickyService e executar o encadeamento no serviço na base de eventos

Sandeep P
fonte
Você recomendaria esse método para executar um SignalStrengthListener personalizado em segundo plano por uma média de 20 minutos, enquanto captura valores do ouvinte uma vez por segundo para atualizar o thread da interface do usuário? Aqui está mais contexto: stackoverflow.com/questions/36167719/…
JParks
Como o processo é executado novamente se você definir 'isRecursionEnable = true'? Você chama dentro do método 'run' para 'runInBackground ()', como ele não inseria a instrução if no início da função?
26418 Mickey
23

Eu quero que algum código seja executado em segundo plano continuamente. Eu não quero fazer isso em um serviço. Existe alguma outra maneira possível?

O mecanismo mais provável que você está procurando é AsyncTask. É designado diretamente para executar o processo em segundo plano no Thread em segundo plano. Além disso, seu principal benefício é o fato de oferecer alguns métodos que são executados no Thread Principal (UI) e possibilitam a atualização da interface do usuário, se você deseja avisar o usuário sobre algum progresso na tarefa ou atualizar a UI com os dados recuperados do processo em segundo plano.

Se você não sabe como começar aqui, é um bom tutorial:

Nota: Também existe a possibilidade de usar IntentServicecom ResultReceiverisso também funciona.

Simon Dorociak
fonte
@ user2082987 então você tentou?
Simon Dorociak
esses parâmetros do asyncTask são confusos
user2082987:
AsyncTask é apenas um invólucro em torno do fio de qualquer maneira, por isso não resolve o problema do Android matar o aplicativo enquanto ele estiver no fundo
Lassi Kinnunen
Oi @LassiKinnunen Eu escrevi essa resposta há 5 anos. Agora tudo mudou e, no momento, não estou usando o AsyncTask porque sua memória vaza não é segura.
Simon Dorociak
Sim, eu sei disso, mas as pessoas ainda encontrarão isso no google e eu tenho visto muitos comentários de pessoas recomendando o uso dos invólucros do Google, mesmo quando isso serve pouco ou nenhum objetivo, desculpe. Quanto à pergunta original, se alguém estiver procurando por respostas em 2018, crie um serviço, inicie-o e marque-o como estando em primeiro plano com uma notificação, se desejar maximizar as chances de não ser morto. O processo real de execução longa pode ser tratado com manipuladores ou um thread separado. Ainda não perceberam que eles conseguiram impedir que o vazamento de memória fosse seguro?
Lassi Kinnunen
16

3-Liner simples

Uma maneira simples de fazer isso que encontrei como comentário de @awardak na resposta de Brandon Rude :

new Thread( new Runnable() { @Override public void run() { 
  // Run whatever background code you want here.
} } ).start();

Não tenho certeza se, ou como, isso é melhor do que usar, AsyncTask.executemas parece funcionar para nós. Quaisquer comentários sobre a diferença serão apreciados.

Obrigado, @awardak !

Joshua Pinter
fonte
usamos o método handler.post () para publicá-lo novamente no thread principal dentro do método run do Thread.
androidXP 26/02
2

Uma alternativa ao AsyncTask é o robospice. https://github.com/octo-online/robospice .

Algumas das características do robospice.

1. executa solicitações de rede de forma assíncrona (em segundo plano, AndroidService) (por exemplo: solicitações REST usando o Spring Android). Notifica seu aplicativo, no segmento da interface do usuário, quando o resultado estiver pronto.

2.é fortemente digitado! Você faz seus pedidos usando POJOs e obtém POJOs como resultados da solicitação.

3. não force restrições nos POJOs usados ​​para solicitações nem nas classes de atividade que você usa em seus projetos.

4.Caches results (no Json com Jackson e Gson, ou Xml, ou arquivos de texto simples ou binários, mesmo usando o ORM Lite).

5. notifica suas atividades (ou qualquer outro contexto) do resultado da solicitação de rede se e somente se ainda estiverem ativas

6. nenhum vazamento de memória, como o Android Loaders, ao contrário do Android AsyncTasks notifica suas atividades no thread da interface do usuário.

7. usa um modelo de tratamento de exceções simples, mas robusto.

Amostras para começar. https://github.com/octo-online/RoboSpice-samples .

Uma amostra do robospice em https://play.google.com/store/apps/details?id=com.octo.android.robospice.motivations&feature=search_result .

Raghunandan
fonte
Como armazenar uma matriz obtida da rede no SQLite? Basicamente, eu gostaria de: obter dados da rede E salvá-los no meu SQLite - ambos no thread de segundo plano e, em seguida, notificar minha interface do usuário para atualizar o ListView. Eu costumo fazer isso com o IntentService, mas o RoboSpice é menos digitado.
Yar
@ yar, você pode usar um serviço de intenção se for uma operação de longa duração. Além disso, você pode usar o asynctask, mas apenas se for por um curto período. Você pode criar um thread e fazer todas as suas coisas lá. Não uso robospice há muito tempo. Há outras bibliotecas de rede, como vôlei ...
Raghunandan
OK obrigado. Pensei em usar o Robospice, mas parece que não é muito bom (flexível) para minhas necessidades. Eu uso o IntentService por um longo tempo com sucesso.
Yar
2
class Background implements Runnable {
    private CountDownLatch latch = new CountDownLatch(1);
    private  Handler handler;

    Background() {
        Thread thread = new Thread(this);
        thread.start();
        try {
            latch.await();
        } catch (InterruptedException e) {
           /// e.printStackTrace();
        }
    }

    @Override
    public void run() {
        Looper.prepare();
        handler = new Handler();
        latch.countDown();
        Looper.loop();
    }

    public Handler getHandler() {
        return handler;
    }
}
Geno Papashvili
fonte
5
Bem-vindo ao StackOverflow. As respostas com apenas código nelas tendem a ser sinalizadas para exclusão por serem de "baixa qualidade". Leia a seção de ajuda para responder a perguntas e considere adicionar alguns comentários à sua resposta.
Graham
0

Se você precisar executar um encadeamento com códigos diferentes, aqui está um exemplo:

Ouvinte:

public interface ESLThreadListener {

    public List onBackground();

    public void onPostExecute(List list);

}

Classe de Thread

public class ESLThread extends AsyncTask<Void, Void, List> {


    private ESLThreadListener mListener;

    public ESLThread() {

        if(mListener != null){

            mListener.onBackground();
        }
    }

    @Override
    protected List doInBackground(Void... params) {

        if(mListener != null){

            List list = mListener.onBackground();

            return list;
        }

        return null;
    }

    @Override
    protected void onPostExecute(List t) {
        if(mListener != null){

            if ( t != null) {
                mListener.onPostExecute(t);
            }
        }

    }


    public void setListener(ESLThreadListener mListener){

        this.mListener = mListener;
    }
}

Execute códigos diferentes:

  ESLThread thread = new ESLThread();
                        thread.setListener(new ESLThreadListener() {
                            @Override
                            public List onBackground() {
                                List<EntityShoppingListItems>  data = RoomDB.getDatabase(context).sliDAO().getSL(fId);

                                return data;

                            }

                            @Override
                            public void onPostExecute(List t) {

                                List<EntityShoppingListItems> data = (List<EntityShoppingListItems>)t;
                                adapter.setList(data);
                            }
                        });

                        thread.execute();
Ucdemir
fonte