How to run CountDownTimer in a Service in Android?
Asked Answered
D

2

23

I want a service which runs a CountDownTimer and in every tick I want to show the countdown in a Activity and after some interval play a sound.

All the process are going fine in a single Activity but during incoming call the countdown not working that's why I want to do this using a Service.

Can anybody help me?

thanks in advance.

Update...

mCountDownTimer = new CountDownTimer(mTimerDuration, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                if (mTimerDuration > 0) {
                    mDurationCount += 1000;
                    showCountDown(
                            ActivityA.this,
                            (mSimpleDateFormat.format(mTimerDuration
                                    - mDurationCount)));
                    if (mDurationCount == mTimerDuration) {
                        if (mRepeatTime > 1) {
                            startRepeatTimer();
                        }
                        finishTimer();
                    }
                }
            }

            @Override
            public void onFinish() {
            }
        }.start();
Dreamland answered 19/3, 2014 at 5:16 Comment(7)
try thisVendetta
Will this be running during incoming call?Dreamland
Timer stops during app switching.Dreamland
try this may be help to youVendetta
I have done that,but I want the timer to be run in a service and the countdown will show in a activity.Dreamland
please post your code....Vendetta
I have posted the code.kindly take a look.Dreamland
D
56

The easiest way is probably to create a broadcast receiver in your activity and have the service send broadcasts to the receiver. Here's a full listing for a service class with a simplified CountDownTimer.

package com.example.cdt;

import android.app.Service;
import android.content.Intent;
import android.os.CountDownTimer;
import android.os.IBinder;
import android.util.Log;

public class BroadcastService extends Service {

    private final static String TAG = "BroadcastService";

    public static final String COUNTDOWN_BR = "your_package_name.countdown_br";
    Intent bi = new Intent(COUNTDOWN_BR);

    CountDownTimer cdt = null;

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

            Log.i(TAG, "Starting timer...");

            cdt = new CountDownTimer(30000, 1000) {
                @Override
                public void onTick(long millisUntilFinished) {

                    Log.i(TAG, "Countdown seconds remaining: " + millisUntilFinished / 1000);
                    bi.putExtra("countdown", millisUntilFinished);
                    sendBroadcast(bi);
                }

                @Override
                public void onFinish() {
                    Log.i(TAG, "Timer finished");
                }
            };

            cdt.start();
        }

        @Override
        public void onDestroy() {

            cdt.cancel();
            Log.i(TAG, "Timer cancelled");
            super.onDestroy();
        }

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

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

And here are the relevant lines from a main activity:

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

    startService(new Intent(this, BroadcastService.class));
    Log.i(TAG, "Started service");
}

private BroadcastReceiver br = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {            
        updateGUI(intent); // or whatever method used to update your GUI fields
    }
};

@Override  
public void onResume() {
    super.onResume();        
    registerReceiver(br, new IntentFilter(BroadcastService.COUNTDOWN_BR));
    Log.i(TAG, "Registered broacast receiver");
    }

@Override
public void onPause() {
    super.onPause();
    unregisterReceiver(br);
    Log.i(TAG, "Unregistered broacast receiver");
}

@Override
public void onStop() {
    try {
        unregisterReceiver(br);
    } catch (Exception e) {
        // Receiver was probably already stopped in onPause()
    }
    super.onStop();
}
@Override
public void onDestroy() {        
    stopService(new Intent(this, BroadcastService.class));
    Log.i(TAG, "Stopped service");
    super.onDestroy();
}

private void updateGUI(Intent intent) {
    if (intent.getExtras() != null) {
        long millisUntilFinished = intent.getLongExtra("countdown", 0);
        Log.i(TAG, "Countdown seconds remaining: " +  millisUntilFinished / 1000);            
    }
}

You'll also need to define the service between the start/end application tags in your manifest file.

<service android:name=".BroadcastService" />
Durrett answered 19/3, 2014 at 6:45 Comment(9)
If I stop the service in onPause() then during incoming call the timer will stop.Dreamland
You're not stopping the service; you're stopping the broadcast receiver in your activity. In other words, you're just telling Android that your activity doesn't need to listen for the broadcasts while it's asleep. The service will keep sending them during that time, but they'll be ignored.Durrett
Which type of service should I use? Can u post some code?Dreamland
I've modified my answer to show a more complete example. In order to be more generally helpful, it doesn't include your specific timer operations.= and just passes back a long value. You'll need to tweak the code to fit your needs.Durrett
It's working fine but how do I get the intent send from caller activity in onCreate().I can get it from onStartCommand() but onCreate() calling before onStartCommand().Dreamland
I'm not sure what you're asking. There are 2 intents: an anonymous one in the activities onCreate() to start the service and bi, the one used by the service to send the broadcast.Durrett
Great example, only thing I would do different is I would put cdt.start(); in onStartCommand()Boxhaul
But did u face any exception while using CountDownTimer in service class ? Since Handler is using inside CountDownTimer and the handler is not calling Looper.prepare() . "java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() " exception might come.Seldun
When my answer was written 6.5 years ago, it didn't throw any exceptions. I haven't used CountDownTimer since then, so I don't know if there have been any breaking changes. With the increasing restrictions that Google keeps adding to services, using a service is probably not a good way to do this anymore. (It likely never was, but the OP specifically asked how to do this via a service.)Durrett
H
1

Download source code Android Countdown Timer Run In Background

activity_main.xml

<RelativeLayout android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">


    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/et_hours"
        android:hint="Hours"
        android:inputType="time"
        android:layout_marginRight="5dp"
        />

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/btn_timer"
    android:layout_above="@+id/btn_cancel"
    android:text="Start Timer"/>

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:id="@+id/btn_cancel"
    android:text="cancel timer"/>

<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/tv_timer"
    android:layout_centerInParent="true"
    android:textSize="25dp"
    android:textColor="#000000"
    android:text="00:00:00"/>

</RelativeLayout>

Timer_Service.java

package com.countdowntimerservice;

import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.util.Log;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

public class Timer_Service extends Service {

public static String str_receiver = "com.countdowntimerservice.receiver";

private Handler mHandler = new Handler();
Calendar calendar;
SimpleDateFormat simpleDateFormat;
String strDate;
Date date_current, date_diff;
SharedPreferences mpref;
SharedPreferences.Editor mEditor;

private Timer mTimer = null;
public static final long NOTIFY_INTERVAL = 1000;
Intent intent;

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

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

    mpref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    mEditor = mpref.edit();
    calendar = Calendar.getInstance();
    simpleDateFormat = new SimpleDateFormat("HH:mm:ss");

    mTimer = new Timer();
    mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 5, NOTIFY_INTERVAL);
    intent = new Intent(str_receiver);
}


class TimeDisplayTimerTask extends TimerTask {

    @Override
    public void run() {
        mHandler.post(new Runnable() {

            @Override
            public void run() {

                calendar = Calendar.getInstance();
                simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
                strDate = simpleDateFormat.format(calendar.getTime());
                Log.e("strDate", strDate);
                twoDatesBetweenTime();

            }

        });
    }

}

public String twoDatesBetweenTime() {


    try {
        date_current = simpleDateFormat.parse(strDate);
    } catch (Exception e) {

    }

    try {
        date_diff = simpleDateFormat.parse(mpref.getString("data", ""));
    } catch (Exception e) {

    }

    try {


        long diff = date_current.getTime() - date_diff.getTime();
        int int_hours = Integer.valueOf(mpref.getString("hours", ""));

        long int_timer = TimeUnit.HOURS.toMillis(int_hours);
        long long_hours = int_timer - diff;
        long diffSeconds2 = long_hours / 1000 % 60;
        long diffMinutes2 = long_hours / (60 * 1000) % 60;
        long diffHours2 = long_hours / (60 * 60 * 1000) % 24;


        if (long_hours > 0) {
            String str_testing = diffHours2 + ":" + diffMinutes2 + ":" + diffSeconds2;

            Log.e("TIME", str_testing);

            fn_update(str_testing);
        } else {
            mEditor.putBoolean("finish", true).commit();
            mTimer.cancel();
        }
    }catch (Exception e){
        mTimer.cancel();
        mTimer.purge();


    }

    return "";

}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.e("Service finish","Finish");
}

private void fn_update(String str_time){

    intent.putExtra("time",str_time);
    sendBroadcast(intent);
}
}

MainActivity.java

package com.countdowntimerservice;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.text.SimpleDateFormat;
import java.util.Calendar;


public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Button btn_start, btn_cancel;
private TextView tv_timer;
String date_time;
Calendar calendar;
SimpleDateFormat simpleDateFormat;
EditText et_hours;

SharedPreferences mpref;
SharedPreferences.Editor mEditor;

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


}

private void init() {
    btn_start = (Button) findViewById(R.id.btn_timer);
    tv_timer = (TextView) findViewById(R.id.tv_timer);
    et_hours = (EditText) findViewById(R.id.et_hours);
    btn_cancel = (Button) findViewById(R.id.btn_cancel);



    mpref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
    mEditor = mpref.edit();

    try {
        String str_value = mpref.getString("data", "");
        if (str_value.matches("")) {
            et_hours.setEnabled(true);
            btn_start.setEnabled(true);
            tv_timer.setText("");

        } else {

            if (mpref.getBoolean("finish", false)) {
                et_hours.setEnabled(true);
                btn_start.setEnabled(true);
                tv_timer.setText("");
            } else {

                et_hours.setEnabled(false);
                btn_start.setEnabled(false);
                tv_timer.setText(str_value);
            }
        }
    } catch (Exception e) {

    }



}

private void listener() {
    btn_start.setOnClickListener(this);
    btn_cancel.setOnClickListener(this);

}

@Override
public void onClick(View v) {

    switch (v.getId()) {
        case R.id.btn_timer:


            if (et_hours.getText().toString().length() > 0) {

                int int_hours = Integer.valueOf(et_hours.getText().toString());

                if (int_hours<=24) {


                    et_hours.setEnabled(false);
                    btn_start.setEnabled(false);


                    calendar = Calendar.getInstance();
                    simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
                    date_time = simpleDateFormat.format(calendar.getTime());

                    mEditor.putString("data", date_time).commit();
                    mEditor.putString("hours", et_hours.getText().toString()).commit();


                    Intent intent_service = new Intent(getApplicationContext(), Timer_Service.class);
                    startService(intent_service);
                }else {
                    Toast.makeText(getApplicationContext(),"Please select the value below 24 hours",Toast.LENGTH_SHORT).show();
                }
/*
                mTimer = new Timer();
                mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 5, NOTIFY_INTERVAL);*/
            } else {
                Toast.makeText(getApplicationContext(), "Please select value", Toast.LENGTH_SHORT).show();
            }
            break;


        case R.id.btn_cancel:


         Intent intent = new Intent(getApplicationContext(),Timer_Service.class);
         stopService(intent);

            mEditor.clear().commit();

            et_hours.setEnabled(true);
            btn_start.setEnabled(true);
            tv_timer.setText("");


            break;

    }

}

private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String str_time = intent.getStringExtra("time");
        tv_timer.setText(str_time);

    }
};

@Override
protected void onResume() {
    super.onResume();
    registerReceiver(broadcastReceiver,new IntentFilter(Timer_Service.str_receiver));

}

@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(broadcastReceiver);
}
}
Hasa answered 7/11, 2016 at 7:55 Comment(1)
Code working but when I clear the app from recent opened apps and launch it again the timer is running..How to cancel when user remove from it from backgroundRoadway

© 2022 - 2024 — McMap. All rights reserved.