How to send calculation made in a Service to Activity?

2

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?

    
asked by anonymous 17.01.2015 / 13:52

2 answers

4

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);
}
    
17.01.2015 / 18:19
0

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.

    
19.06.2017 / 15:44