I would like to do a simple calculation in a Service and return the value to the Activity that called it.
To get the value of the Activity variables I call the getDoubleExtra(double)
of intent , but to send the result I should do as?
I would like to do a simple calculation in a Service and return the value to the Activity that called it.
To get the value of the Activity variables I call the getDoubleExtra(double)
of intent , but to send the result I should do as?
Adapted from Android documentation
If your service is only used by your application and runs in the same process as Activity , do the following:
At your service deploy a Binder . This class will be received by your Activity , allowing access to your public methods or even to the service.
Implementation of Binder
public class SeuServico extends Service {
// Binder
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
SeuServico getService() {
// Returna a instancia do SeuService
return SeuServico.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//Métodos a sere usados na sua Activity/Cliente
//Isto é apenas um exemplo
public int metodoDoServico(int valor) {
return valor*2;
}
}
In your Activity , implement a ServiceConnection
and connect to the service in onStart
public class SuaActivity extends Activity {
SeuServico mService;
boolean mBound = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
@Override
protected void onStart() {
super.onStart();
// Conectar ao SeuServico
Intent intent = new Intent(this, SeuService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Desconetar do serviço
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
// Define os callbacks da ligação ao serviço
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
LocalBinder binder = (LocalBinder) service;
//Obtenha a instância do seu serviço
//Com ela pode aceder a qualquer dos seus métodos públicos
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
You can access any public method of the service as follows.
Example for method metodoDoServico(int valor)
if (mBound) {
valor = mService.metodoDoServico(10);
}
If you want to do the calculation asynchronously use an IntentService and use the ResultReceiver class (as suggested by @Rudda Beltrao) to receive the result.
Example of an IntentService to calculate the factorial.
After the calculation is used a ResultReceiver, passed in the Intent that launches the service, to return the result.
FactorialCalculatorService.java
public class FactorialCalculatorService extends IntentService {
public static final String RESULT_RECEIVER_EXTRA = "result_receiver_extra";
public static final String VALUE_EXTRA = "valor_extra";
public static final String RESULT_DATA_KEY = "result_data_key";
public static final int SUCCESS_RESULT = 0;
public static final int FAILURE_RESULT = 1;
public static final String FAILURE_MESSAGE_KEY = "failure_message_key";
private ResultReceiver resultReceiver;
public FactorialCalculatorService() {
super("FactorialCalculatorService");
}
//Método para facilitar o uso do Service
public static void calculate(int value, Context context, @NonNull ResultReceiver resultReceiver){
if (value < 0) {
throw new IllegalArgumentException ("Value must be non-negative");
}
Intent intent = new Intent(context, FactorialCalculatorService.class);
intent.putExtra(RESULT_RECEIVER_EXTRA, resultReceiver);
intent.putExtra(VALUE_EXTRA, value);
context.startService(intent);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
resultReceiver = intent.getParcelableExtra(RESULT_RECEIVER_EXTRA);
if(resultReceiver == null){
throw new IllegalArgumentException("No ResultReceiver");
}
int value = intent.getIntExtra(VALUE_EXTRA, -1);
if (value < 0) {
throw new IllegalArgumentException ("Value must be non-negative");
}
int factorial = calculateFactorial(value);
deliverResultToReceiver(SUCCESS_RESULT, factorial, "");
}
//Calcula o factorial
private int calculateFactorial(int n){
if (n == 0)
return 1;
else
return(n * calculateFactorial(n-1));
}
//Usa o ResultReceiver para enviar o resultado
private void deliverResultToReceiver(int resultCode, int factorial, String failureMessage){
Bundle bundle = new Bundle();
bundle.putString(FAILURE_MESSAGE_KEY, failureMessage);
bundle.putInt(RESULT_DATA_KEY, factorial);
resultReceiver.send(resultCode, bundle);
}
}
Activity that uses the service:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private EditText edValue;
private TextView tvResult;
private FactorialResultReceiver resultReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
edValue = (EditText) findViewById(R.id.edValue);
tvResult = (TextView)findViewById(R.id.tvResult);
resultReceiver = new FactorialResultReceiver(new Handler(), this);
}
//Chama o serviço para calcular o factorial do valor introduzido no EditText
public void onClickCalculate(View view) {
int value = Integer.parseInt(edValue.getText().toString());
FactorialCalculatorService.calculate(value, this, resultReceiver);
}
// Usa o valor calculado(recebido na classe FactorialResultReceiver)
// e mostra-o no TextView
public void handleResult(int result){
tvResult.setText(Integer.toString(result));
}
//ResultReceiver para receber o resultado
private static class FactorialResultReceiver extends ResultReceiver{
private WeakReference<MainActivity> activityWeakReference;
public FactorialResultReceiver(Handler handler, MainActivity activity) {
super(handler);
activityWeakReference = new WeakReference<>(activity);
}
//O onReceiveResult() é chamado com o resultado quando o serviço chama send()
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
MainActivity activity = activityWeakReference.get();
if(resultCode == FactorialCalculatorService.SUCCESS_RESULT){
int result = resultData.getInt(FactorialCalculatorService.RESULT_DATA_KEY);
if(activity != null) {
activity.handleResult(result);
}
}
}
}
}
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"
tools:context="pt.amaral.rogerio.intentservicewithresultreceiver.MainActivity"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/edValue" />
<Button
android:id="@+id/btCalculate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Factorial"
android:onClick="onClickCalculate"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Resultado: "/>
<TextView
android:id="@+id/tvResult"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
Alternatively, you can use a BroadcastReceiver as described in this response.