2

I have a following chronometer implementation. I'd like to use it inside Service then sent its output to my fragment. The problem is that Service has no findViewById() because obviously it has no View at all. Is there any way I can get the chronometer to work inside Service and if not what can I use instead?

code:

Chronometer chronometer = (Chronometer) findViewById(R.id.chronometer);
    chronometer.setBase(SystemClock.elapsedRealtime());

    chronometer.setOnChronometerTickListener(
            new Chronometer.OnChronometerTickListener() {

                @Override
                public void onChronometerTick(Chronometer chronometer) {
                    // TODO Auto-generated method stub
                    long myElapsedMillis = SystemClock.elapsedRealtime() - chronometer.getBase();
                    String strElapsedMillis = String.valueOf(myElapsedMillis);

                    //  Toast.makeText(AndroidChronometer.this, strElapsedMillis, Toast.LENGTH_SHORT).show();
                    TextView tw5 = (TextView) findViewById(R.id.textView2);
                    tw5.setText(strElapsedMillis.format("%d min : %d sec",
                            TimeUnit.MILLISECONDS.toMinutes(myElapsedMillis),
                            TimeUnit.MILLISECONDS.toSeconds(myElapsedMillis) -
                                    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(myElapsedMillis))));
                }
            }
    );


    chronometer.start();
XorOrNor
  • 8,868
  • 12
  • 48
  • 81
  • IMHO that code is more GUI oriented (no time-consuming ops, high frequency) and there's no point in moving it to a service. – Mister Smith Jan 13 '14 at 14:21
  • I simply need to measure the time since service has started and send it to the fragment (if fragment exists). – XorOrNor Jan 13 '14 at 14:50
  • 2
    Ok, then use intents to pass a long extra param containing the timestamp. But be aware a service might be stopped (or self-stop itself) when the job is done, and might be even killed by the system. – Mister Smith Jan 13 '14 at 15:09

1 Answers1

0

One option is just to use

postDelayed(Runnable r, long milliseconds)

to trigger your runnable update method for whatever you update period is, without using a service. And then update the UI in your update method.

Another option is to use AsyncTask instead of Service, if your intention is to do something in the background. AsyncTask has access to the UI on its onProgressUpdate() method and you can do your stuff there.

If you have to use a Service, then you have to broadcast from the service to the UI activity and let the UI Activity do the view update:

This in your main activity:

private StatusReceiver mReceiver;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ...

    mReceiver = new StatusReceiver();

    ...
}


@Override
protected void onStart() {
    // Register the broadcast receiver
    IntentFilter filter = new IntentFilter();
    filter.addAction(getString(R.string.ACTION_UPDATE_CHRONO));
    filter.addCategory(Intent.CATEGORY_DEFAULT);
    registerReceiver(mReceiver, filter);

    ...
}

@Override
protected void onStop() {
    ...
    unregisterReceiver(mReceiver);
    ...
}

public class StatusReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if( action.equals(getString(R.string.ACTION_UPDATE_CHRONO)) ) {
             // Do your UI stuff here
        } 
    }
}

In the service class:

private void broadcast(String status, Exception error) {
    Intent broadcastIntent = new Intent((Intent) getText(R.string.ACTION_UPDATE_CHRONO));
    broadcastIntent.putExtra("STATUS", status);
    broadcastIntent.putExtra("ERROR", error);
    sendBroadcast(broadcastIntent);
}

Call this method when you want to communicate some "status" to your main activity, like "Time for update" or "set chrono to " + x + "milli".

ilomambo
  • 8,290
  • 12
  • 57
  • 106
  • Will it be ok if I use `ScheduledThreadPoolExecutor.scheduleAtFixedRate()` instead of `postDelayed`?. I'd prefer to avoid rescheduling inside loop. – XorOrNor Jan 13 '14 at 14:43
  • I have no hands-on experience with `ScheduledThreadPoolExecutor`, but the documentation seems to fit using it. Although if your goal is to measure the net time your service has been running you should start counting since the moment you bind it until it is dismissed, taking care of pausing the time count each time the service is destroyed and resume timing when it is recreated. – ilomambo Jan 13 '14 at 20:20