Pular para o conteúdo principal

Tutorial e exemplos do Android Service

Um serviço é um componente de aplicação andróide que representa:

  1. Uma aplicação que deseja realizar operações de longa duração sem interagir com o usuário.
  2. Um componente para fornecer funcionalidade a outras aplicações.

Quando devo utilizar um Serviço?​

Utilize um serviço se você tiver uma operação de longa duração ou uma tarefa que tenha um ciclo de vida longo. É um bom projeto que operações de longa duração sejam executadas em segundo plano.

Um exemplo é uma tarefa de sincronização de dados em segundo plano.

Nesse tipo de tarefa você pode criar um `serviço' que roda periodicamente ou conforme necessário. Você pode fazer uso de um alarme de sistema.

Então, seu "serviço" pode terminar quando a tarefa terminar.

Ao fazer o trabalho em segundo plano, o principal "tópico" fica livre de ter que fazer essas tarefas, impedindo assim que a interface do usuário seja congelada sempre que uma tarefa intensiva estiver sendo executada.

Mesmo que possamos apenas rodar um novo "tópico" mesmo dentro de uma "atividade", uma maneira muito melhor e mais limpa é delegar as operações em segundo plano a um "serviço".

Onde funciona o "Serviço"?​

Todos os componentes andróides, incluindo o "serviço", são executados no principal "tópico" do processo de aplicação.

O ciclo de vida do 'Serviço' é diferente do 'Ciclo de vida da atividade'. O primeiro está melhor adaptado para lidar com operações de longa duração do que o segundo.

Uma vez que passamos nossas operações de longa duração a um "fio" de fundo, podemos iniciar e lidar com esse "fio" dentro do "serviço".

Operações de longa duração que não requerem a interação do usuário são o melhor candidato para delegação a um "serviço".

Vantagens de um serviço.​

  1. O 'Serviço' nos proporciona um mecanismo mais eficiente para desacoplarmos operações de longa duração da interface do usuário.

Exemplo de utilização de um `Serviço'.​

(a). Serviços' sem a entrada do usuário​
  1. Aplicativos que utilizam a rede freqüentemente para fazer pesquisas de atualização.
  2. Aplicativos que tocam música.
  3. Aplicativo de mensagens.
(b). Serviços com entrada do usuário.​
  1. Aplicação para compartilhamento de fotos.

Rápido Serviço Snippets e How-to's​

1. Como iniciar um `Serviço'.​

No primeiro exemplo, nos foi dado o nome da classe:

    public static void startService(String className) {
try {
startService(Class.forName(className));
} catch (Exception e) {
e.printStackTrace();
}
}

No segundo exemplo, temos dado a própria Classe e o contexto:

   public static void startService(Class<?> cls, Context context) {
Intent intent = new Intent(context, cls);
context.startService(intent);
}

2. Como parar um `Serviço'.​

Digamos que você queira parar um serviço e lhe foi fornecido o nome da classe:

    public static boolean stopService(String className) {
try {
return stopService(Class.forName(className));
} catch (Exception e) {
e.printStackTrace();
return false;
}
}

E se a classe em si tiver sido providenciada?

    public static boolean stopService(Class<?> cls, Context context) {
Intent intent = new Intent(context, cls);
return context.stopService(intent);
}
3. Como ligar um `Serviço'.​

Temos dois exemplos. Aqui está o primeiro:

    public static void bindService(String className, ServiceConnection conn, int flags) {
try {
bindService(Class.forName(className), conn, flags);
} catch (Exception e) {
e.printStackTrace();
}
}

então o segundo exemplo:

    public static void bindService(Class<?> cls, ServiceConnection conn, int flags,Context context) {
Intent intent = new Intent(context, cls);
context.bindService(intent, conn, flags);
}
4. como desvincular um `Serviço'.​
    public static void unbindService(ServiceConnection conn,Context context) {
context.unbindService(conn);
}

5. Como colocar Todos em funcionamento `Serviços'.​

Você quer obter todos os "serviços" em funcionamento no sistema e retornar seus nomes como um "Conjunto".

    public static Set getAllRunningService(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningServiceInfo> info = activityManager.getRunningServices(0x7FFFFFFF);
Set<String> names = new HashSet<>();
if (info == null || info.size() == 0) return null;
for (RunningServiceInfo aInfo : info) {
names.add(aInfo.service.getClassName());
}
return names;
}

Rápido Serviço Exemplos​

1. Como carregar canções em uma "ArrayList" em um "Serviço".​

Temos que fazer isso em um "tópico" de fundo, pois não desejamos congelar nossa interface de usuário.

Registraremos estas músicas, mas é claro que você pode renderizá-las em reciclerview ou listview e implementar uma classe para tocá-las.

Primeiro vamos começar definindo um objeto Song. Esta é a nossa classe Song bean:

public final class Song {

private String name;

private String artist;

private String coverUri;

private long time;

private String location;

public String getName() {
return name;
}

public Song setName(String name) {
this.name = name;
return this;
}

public String getArtist() {
return artist;
}

public Song setArtist(String artist) {
this.artist = artist;
return this;
}

public String getCoverUri() {
return coverUri;
}

public Song setCoverUri(String coverUri) {
this.coverUri = coverUri;
return this;
}

public long getTime() {
return time;
}

public Song setTime(long time) {
this.time = time;
return this;
}

public String getLocation() {
return location;
}

public Song setLocation(String location) {
this.location = location;
return this;
}

@Override
public String toString() {
return String.format("name = %s, artist = %s, location = %s",
name,
artist,
location);
}
}

Em seguida, procedemos à criação de nosso "Serviço".

Você começa criando uma classe que implementa o `Serviço``:

public class ScanMusicService extends Service {...}

Normalmente, quando um "serviço" é criado, o método "onCreate()`service' é invocado pelo sistema.

É aqui que iniciaremos um "tópico" que escaneará nossas músicas e as carregará em um "tópico" de fundo:

    @Override
public void onCreate() {
super.onCreate();

new Thread(new Runnable() {
@Override
public void run() {
ArrayList<Song> songs = scanSongs(ScanMusicService.this);
LogUtils.d(songs);
ToastUtils.showLongToast(songs.toString());
}
}).start();

}

O método scanSongs() será responsável por escanear e preencher nosso arrailista com canções.

Aqui está a classe completa:

import android.app.Service;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.IBinder;
import android.provider.MediaStore;
import android.support.annotation.Nullable;

import com.jiangkang.tools.bean.Song;
import com.jiangkang.tools.utils.LogUtils;
import com.jiangkang.tools.utils.ToastUtils;

import java.util.ArrayList;

public class ScanMusicService extends Service {

@Override
public void onCreate() {
super.onCreate();

new Thread(new Runnable() {
@Override
public void run() {
ArrayList<Song> songs = scanSongs(ScanMusicService.this);
LogUtils.d(songs);
ToastUtils.showLongToast(songs.toString());
}
}).start();

}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
super.onDestroy();
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}

private ArrayList<Song> scanSongs(Context context) {
ArrayList<Song> result = new ArrayList<>();
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
null,
null,
null,
null);
if (cursor != null && !cursor.isClosed() && cursor.moveToFirst()) {
while (cursor.moveToNext()) {
String songName = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
String artist = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
String location = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));

Song song = new Song();
song.setName(songName)
.setArtist(artist)
.setLocation(location);
LogUtils.d(song.toString());
result.add(song);
}
}
return result;
}
}

E essa é a classe para nos ajudar no carregamento de músicas.

2. Como utilizar o System Download Manager e o `Service' para baixar​

Queremos ver como criar um serviço que possa baixar dados utilizando o System DownloadManager.

Vamos direto ao assunto. Primeiro começamos criando um 'serviço' andróide:

public class DownloadService extends Service {

Em seguida, procedemos à criação de vários campos de classe e instância nessa classe:

    private BroadcastReceiver receiver;
private DownloadManager dm;
private long enqueue;
private String downloadUrl = "http://192.168.3.186/StaffAssistant.apk";
private static String apkname = "StaffAssistant.apk";

São eles:

  1. BroadcastReceiver - nossa instância receptora de radiodifusão.
  2. DownloadManager - nosso gerenciador de download do sistema.
  3. Enqueue'(longo) - A identificação única de tarefa de download atribuída pelo gerenciador de download do sistema, que pode ser utilizada para consultar ou processar a tarefa de download através desta identificação.
    1. Download URL - url onde baixar o apk.
  4. ApK name - nome da aplicação

Lembre-se de que estendemos o "serviço" e ainda não implementamos nenhum dos métodos que precisamos anular. Aqui está um:


@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

Voltamos "nulos" lá e nos mudamos para nosso onStartCommand().

    @Override
public int onStartCommand(Intent intent, int flags, int startId) {
....

Lá, antes de mais nada, receberemos nosso fio de url para download via 'Intent'.

Em seguida, instanciaremos nossa classe BroadcastReceiver e substituiremos o método onReceive().

        receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
install(context);
}
};

Dentro do método onReceive() você pode ver que estamos invocando o método install(). Esse método é um método personalizado, que criaremos para instalar nossa aplicação.

Fora de nosso método onReceive(), registraremos nosso BroadcastReceiver, já que é um componente andróide.

registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));

É claro que você pode ver que o registramos programmaticamente, já que o criamos como uma classe anônima.

Então, invocamos o método 'startDownload()`, outro método personalizado que criaremos mais tarde.

startDownload ( downloadUrl );

Note que isto requer um cartão SD com permissões de escrita. Se você estiver usando umSDKVersion alvo maior ou igual a 23, então você pode usar a permissão dinâmica.

Vamos agora ver como instalar o aplicativo de forma programática depois de baixá-lo.

Primeiro criamos o método install(). Ele receberá um objeto Context que nos permitirá invocar o método startActivity().

    public static void install(Context context) {

Então, instanciamos um java.io.file. Passamos o caminho onde estamos criando o arquivo e o nome do arquivo:

        File file = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
, apkname);

Em seguida, criamos um objeto Intent:

        Intent intent = new Intent(Intent.ACTION_VIEW);

Como a atividade não é iniciada no ambiente Atividade, defina o seguinte rótulo:

        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

Se a versão está acima da 7.0.

        if (Build.VERSION.SDK_INT >= 24) {

Invocamos então o método 'getUriForFile()`getUriForFile' da classe 'FileProvider'. Estes incluem:

  1. Contexto.
  2. Endereço do provedor anfitrião.
  3. O arquivo a ser instalado.
            Uri apkUri =
FileProvider.getUriForFile(context, "com.hzecool.slhStaff.fileprovider", file);
//Adding this sentence means temporarily authorizing the file represented by the Uri to the target application.
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.fromFile(file),
"application/vnd.android.package-archive");
}
context.startActivity(intent);
}

Em seguida, nós viemos e anulamos o método onDestroy() da classe `Service'. Aqui estamos desregistando nosso BroadcastReceiver.

    @Override
public void onDestroy() {
unregisterReceiver(receiver);
super.onDestroy();
}

Vamos agora ver como fazer o download.
Primeiro vamos criar o método startDownload():

    private void startDownload(String downUrl) {

Primeiro, vamos buscar o sistema DownloadManager:

        dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);

Começamos por instantâneo com a classe "DownloadManager.Request". Enquanto instanciamos, analisamos nossa url de download utilizando o método parse() da classe Uri, e a passamos para nossa classe Request:

        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downUrl));

Então definimos nosso tipo de mímica ou tipo de arquivo como APK utilizando o método setMimeType():

        request.setMimeType("application/vnd.android.package-archive");

Em seguida, definimos o destino para nosso download utilizando o setDestinationInExternalPublicDir(). Neste caso, utilizamos o diretório de downloads.

        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkname);

Invocamos a setNotificationVisibility() para indicar se uma notificação será exibida quando o download estiver completo.

        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);

Então definimos o título

        request.setTitle("Download new version");

Por último, mas não menos importante, realizamos o download e devolvemos a identificação única da tarefa

        enqueue = dm.enqueue(request);
}
}

Aqui está o código completo do serviço:

import android.app.DownloadManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.content.FileProvider;
import android.text.TextUtils;

import java.io.File;

public class DownloadService extends Service {
private BroadcastReceiver receiver;
private DownloadManager dm;
private long enqueue;
private String downloadUrl = "http://192.168.3.186/StaffAssistant.apk";
private static String apkname = "StaffAssistant.apk";

@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
downloadUrl = intent.getStringExtra("downloadUrl");
if (TextUtils.isEmpty(downloadUrl)) {
apkname = downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1, downloadUrl.length());
}
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
install(context);

}
};
registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
startDownload(downloadUrl);
return Service.START_STICKY;
}

public static void install(Context context) {
File file = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
, apkname);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 24) {
Uri apkUri =
FileProvider.getUriForFile(context, "com.hzecool.slhStaff.fileprovider", file);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.fromFile(file),
"application/vnd.android.package-archive");
}
context.startActivity(intent);
}

@Override
public void onDestroy() {
unregisterReceiver(receiver);
super.onDestroy();
}

private void startDownload(String downUrl) {
dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downUrl));
request.setMimeType("application/vnd.android.package-archive");
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkname);
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setTitle("Download new version");
enqueue = dm.enqueue(request);
}
}

Exemplos completos de "Serviço​

Vejamos exemplos totalmente autônomos que você pode baixar e executar.

1. Exemplo de `Serviço' Simples​

**MainActivity.java***

Esta é a principal atividade. Esta classe é derivada da AppCompatActivity e é responsável por nossa interface de usuário.

Aqui estão algumas definições de API que você pode não conhecer:

**(a). SeviceConnection***.

Esta é uma interface que reside no pacote 'android.content' e é destinada ao monitoramento do estado de um aplicativo 'serviço'.

**(b). IBinder***.

O 'IBinder' é a interface base para objetos removíveis, a parte central de um mecanismo leve de chamada de procedimento remoto projetado para alto desempenho ao realizar chamadas em processo e chamadas entre processos.

package com.example.ankitkumar.boundservice;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
BoundService myService;
boolean isBound = false;

TextView currenttime, time, date;
Button btn_start_service;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//Set the activity content from a layout resource
setContentView(R.layout.activity_main);
time = (TextView) findViewById(R.id.tv_time);
date = (TextView) findViewById(R.id.tv_date);
currenttime = (TextView) findViewById(R.id.textView_current_time);
btn_start_service = (Button) findViewById(R.id.button_start_service);
Intent intent = new Intent(MainActivity.this, BoundService.class);

/*
Connect to an application service
Automatically create the service as long as the binding exists
*/
bindService(intent, myConnection, Context.BIND_AUTO_CREATE);
}

public void getcurrenttime(View view) {
currenttime.setText(myService.getCurrentTime());
time.setVisibility(View.VISIBLE);
date.setVisibility(View.VISIBLE);
}

//Setting Up BoundService
private ServiceConnection myConnection = new ServiceConnection() {

//Service Connected
public void onServiceConnected(ComponentName className,
IBinder service) {
BoundService.MyLocalBinder binder = (BoundService.MyLocalBinder) service;
myService = binder.getService();
isBound = true;
}

//Service is Disconnected
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}

};

}

**BoundService.java***

Esta é nossa subclasse "serviço".

package com.example.ankitkumar.boundservice;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class BoundService extends Service {

//Base interface for a remotable object, the core part of a lightweight remote procedure call mechanism
private final IBinder myBinder = new MyLocalBinder();

//Binding Service
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return myBinder;
}

//Formatting and parsing dates in a locale-sensitive manner
public String getCurrentTime() {
SimpleDateFormat dateformat = new SimpleDateFormat("HH:mm:ss dd/MMM/yyyy", Locale.US);
return (dateformat.format(new Date()));
}

class MyLocalBinder extends Binder {
BoundService getService() {
return BoundService.this;
}
}
}

**activity_main.xml***

O layout principal da `atividade'.

<?xml version="1.0" encoding="UTF-8"?>

<RelativeLayout
tools_context="com.example.ankitkumar.boundservice.MainActivity" android_background="#efedef" android_layout_height="match_parent" android_layout_width="match_parent" android_id="@+id/activity_main" >

<TextView
android_layout_height="wrap_content" android_layout_width="100sp" android_id="@+id/tv_time" android_visibility="gone" android_textStyle="bold" android_textSize="18sp" android_textColor="@android:color/background_dark" android_text="@string/time" android_gravity="end" android_fontFamily="sans-serif-condensed" android_layout_marginTop="40sp"/>

<TextView
android_layout_height="wrap_content"
android_layout_width="140sp" android_id="@+id/tv_date" android_visibility="gone" android_textStyle="bold" android_textSize="18sp" android_textColor="@android:color/background_dark" android_text="@string/date" android_gravity="bottom" android_fontFamily="sans-serif-condensed" android_layout_marginTop="40sp" android_layout_alignParentRight="true" android_layout_alignParentEnd="true"/>

<TextView
android_layout_height="wrap_content" android_layout_width="match_parent" android_id="@+id/textView_current_time" android_textSize="36sp" android_textColor="#ee6f64" android_gravity="center" android_fontFamily="sans-serif-condensed" android_layout_marginTop="70dp" android_hint="@string/time_label" android_layout_centerHorizontal="true"/>

<Button
android_background="#e54048" android_layout_height="60sp" android_layout_width="200sp" android_id="@+id/button_start_service" android_textStyle="bold" android_textSize="18sp" android_textColor="#ffff" android_text="@string/show_time" android_fontFamily="sans-serif-condensed" android_onClick="getcurrenttime" android_layout_centerInParent="true"/>

</RelativeLayout>

Faça o download do código abaixo.

---

Android IntentService​

public abstract class IntentService
extends Service
java.lang.Object
↳ android.content.Context
↳ android.content.ContextWrapper
↳ android.app.Service
↳ android.app.IntentService

A "IntentService" é uma classe base para "Serviços" que lidam com solicitações assíncronas (expressas como "Intenções") sob demanda. Os clientes enviam solicitações através de chamadas startService(Intent); o service é iniciado conforme necessário, trata cada Intent por sua vez utilizando um thread de trabalhador, e pára a si mesmo quando ele fica sem trabalho.

Este padrão de "processador de fila de trabalho" é comumente utilizado para descarregar tarefas a partir do "thread" principal de uma aplicação. A classe "IntentService" existe para simplificar este padrão e cuidar da mecânica. Para utilizá-lo, amplie o IntentService e implemente o onHandleIntent(Intent). O "IntentService" receberá o "Intents", lançará um "thread" para o trabalhador e interromperá o "serviço" conforme apropriado.

Todas as solicitações são tratadas em um único "tópico" - elas podem levar o tempo necessário (e não bloquearão o loop principal da aplicação), mas apenas uma solicitação será processada de cada vez.