Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Communication between Android Services and Activities

see architecture

I want to develop an Android App with three activities and two services.

The first Service, named WebClientService, calls a REST API every 30 seconds, using an Handler, and has to notify the active Activity with the result. It also has to notify a second Service, named DatabaseService, in order to update a local DB.

The Database Service will be called just once onCreate of the activity (in case of app crash and restart) and just once at onRestart (in this way we have data to show in case there were connectivity issues). The activities will then keep themselves updated thanks to the WebClientService that notifies the "alive" activity every 30 seconds.

Questions are:

  • What's the best way to notify for an update both the active activity and the background DatabaseService? My idea is to use sendBroadcast() within WebClientService and a BroadcastReceiver in every activity and within the DatabaseService, is it the right approach?

  • Should I use the same approach for the communication between AllMeetingRoomActivity and DatabaseService or should I use a Bound Service?

Thanks

UPDATE: DatabaseService won't be a background service anymore but just a shared instance of the db layer between WebClientService and the activities.

So question now is: is it a good approach to just write my 30 seconds updates to the local db and allow the activities to update themselves every few seconds simply reading from the local db? Would that affect the performance too much?

Context:

Follows what I've implemented so far but using SettableFutures and thus needs to be re-implemented using Services and Broadcasts once I've clear how to make them communicate effectively:

public class MainActivity extends AppCompatActivity {               

    private TextView meetingsTextView;
    private EditText mEdit, editSubject;

    private final ConnectorInitializer clientInitializer = new ConnectorInitializer();
    private AppConnector genericClient; // can use OutlookClient or a test client to talk with a mock server

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // initializes client based on the settings in "config.json"
        genericClient = clientInitializer.create(this);

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        meetingsTextView = (TextView) findViewById(R.id.NowMeeting);
        mEdit   = (EditText)findViewById(R.id.editText);
        editSubject   = (EditText)findViewById(R.id.editSubject);

        Futures.addCallback(genericClient.logon(this, scopes), new FutureCallback<Boolean>() {
            @Override
            public void onSuccess(Boolean result) {
                Log.d("APP", "-- Logged in. --");

                databaseConnector.synchronouslyGetBackupFromLocalDatabase() // FUTURE
                // callback here
                // onSuccess, onFailure

            }

            @Override
            public void onFailure(@NonNull Throwable t) {
                Log.e("\n ~~~~>> logon \n", t.getMessage());
                meetingsTextView.setText(R.string.Login_Failed);
            }
        });

    }

    /** At the moment the UI is not updated automatically every 30 seconds
    *   but manually using a refresh button
    */
    public void getBookings(@SuppressWarnings("UnusedParameters") View view){

        Log.d("APP", "Retrieve button clicked: "+(DateTime.now())+". Calling async getCalendar.");
        meetingsTextView.setText(R.string.retrieving_events);

        try{
            Futures.addCallback( genericClient.getCalendarEvents(), new FutureCallback<String>(){
                @Override
                public void onSuccess(final String resultCalendars) {

                    Log.d("APP", "Success. Result: "+resultCalendars);

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {

                            Log.d("APP", "Calendars SUCCESSFULLY retrieved.");
                            String meetingsRetrieved = getString(R.string.calendar)+resultCalendars;
                            meetingsTextView.setText(meetingsRetrieved);

                            Toast.makeText(getApplicationContext(), "Success!", Toast.LENGTH_LONG).show();
                        }
                    });

                    databaseConnector.asyncUpdateLocalDbWithResults(); // FUTURE
                    // callback here
                    // onSuccess, onFailure

               }

                @Override
                public void onFailure(@NonNull Throwable t) {
                    Log.e( "APP", "Calendar error. Cause: "+t.getLocalizedMessage() );
                    String retrieveError = "Retrieve error. \n\n\n"+t.getLocalizedMessage();
                    meetingsTextView.setText(retrieveError);
                    Toast.makeText(getApplicationContext(), "Fail!", Toast.LENGTH_LONG).show();
                }
            });

        }catch(Exception ex){    
            Log.e("APP","Something went wrong in your code. Cause:"+ex);
        }
    }
like image 610
Gabe Avatar asked Apr 10 '16 03:04

Gabe


People also ask

How do you communicate between service and activity?

We already know that we can communicate with Service from activity just by using method startService() and passing Intent to the argument in the method, or either we can use bindService() to bind the service to the activity with argument Intent.

How can I communicate between two services in Android?

You have to use BroadcastReceiver to receive intents, and when you want to communicate simply make an Intent with appropriate values. This way you should be able to make a 2-way communication between any component.

How do you establish communication between a service and an activity explain with a program example?

This example demonstrates how do I communicate between Activity and Service in android. Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main. xml.

How does a user interact with an Android service?

Types of Android Services Users can interact with the service by the notifications provided about the ongoing task. Such as in downloading a file, the user can keep track of the progress in downloading and can also pause and resume the process.


2 Answers

Best option ever:

Use LocalBroadcastManager. More reference here.

MyService.java:

private LocalBroadcastManager localBroadcastManager;
private final String SERVICE_RESULT = "com.service.result";
private final String SERVICE_MESSAGE = "com.service.message";

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

   // Other stuff

   localBroadcastManager = LocalBroadcastManager.getInstance(this);
}

Add below method in service, whenever you want to update data from service to Activity, call method by passing Arguments.

private void sendResult(String message) {
    Intent intent = new Intent(SERVICE_RESULT);
    if(message != null)
        intent.putExtra(SERVICE_MESSAGE, message);
    localBroadcastManager.sendBroadcast(intent);
}

HomeActivity.java:

private BroadcastReceiver broadcastReceiver;

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    super.setContentView(R.layout.activity_home);
    broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String s = intent.getStringExtra(MyService.SERVICE_MESSAGE);
            // do something here.
        }
    };
}

@Override
protected void onStart() {
    super.onStart();
    LocalBroadcastManager.getInstance(this).registerReceiver((broadcastReceiver), 
        new IntentFilter(MyService.SERVICE_RESULT));
}

@Override
protected void onStop() {
    LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiver);
    super.onStop();
}

Hope this will help you.

like image 94
Hiren Patel Avatar answered Sep 21 '22 11:09

Hiren Patel


I think your approach is ok with BroadCastReceiver. However, BroadCastReceiver should be used for a global purpose (like communicating between 2 applications). If you intend to use BroadCastReceiver for your app only, I prefer using LocalBroadcastManager instead. Using LocalBroadcastManager is faster and more security when it can be caught only by your app.

There's another way to communicate between your activitys and your services is using EventBus. It will be much easier than using BroadCastReceiver (especially in passing data between them).

Update: About your update question:

  1. is it a good approach to just write my 30 seconds updates to the local db and allow the activities to update themselves every few seconds simply reading from the local db? --> Of course NO. You should let your activities update themselves when they need. When you update your local db, you should know that is there any changes or not. If there is any change, use LocalBroadcastmanager to notify your activity to update.
  2. Would that affect the performance too much? --> Yes, that do. The db connection will take time to execute and it will block your UI in some cases. in that case, you should use a thread with ExecutorService for each execute (insert, update...). One more thing to consider is updating that frequently will drain your phone battery very, very fast.
like image 35
Kingfisher Phuoc Avatar answered Sep 22 '22 11:09

Kingfisher Phuoc