I am trying to run chronometer inside a Service. But I am not able to run it. I press a button in Activity and that event is passed to the Service. If the button in pressed then start the Chronometer but problem is setOnChronometerTickListener is called only once and it stops. Where am I making mistake? Here is my Service and Activity class:
Service class:
public class TimerService extends Service {
NotificationManager notificationManager;
NotificationCompat.Builder mBuilder;
Callbacks activity;
private final IBinder mBinder = new LocalBinder();
private Chronometer chronometer;
SharedPreferences sharedPreferences;
private int state = 0; //0 means stop state,1 means play, 2 means pause
private boolean running = false;
private long pauseOffSet = -1;
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
if (event.message) {
if (!running) {
if (pauseOffSet != -1) {
pauseOffSet = sharedPreferences.getLong("milli", -1);
}
chronometer.setBase(SystemClock.elapsedRealtime() - pauseOffSet);
chronometer.start();
state = 1;
pauseOffSet = 0;
running = true;
}
} else {
if (running) {
chronometer.stop();
pauseOffSet = SystemClock.elapsedRealtime() - chronometer.getBase();
state = 2;
running = false;
}
}
}
#Override
public void onCreate() {
super.onCreate();
EventBus.getDefault().register(this);
}
#Override
public void onDestroy() {
EventBus.getDefault().unregister(this);
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
sharedPreferences = getSharedPreferences("myprefs", MODE_PRIVATE);
chronometer = new Chronometer(this);
state = sharedPreferences.getInt("state", 0);
chronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
#Override
public void onChronometerTick(Chronometer chronometer) {
Log.e("TimerService","timer");
pauseOffSet = SystemClock.elapsedRealtime() - chronometer.getBase();
if (pauseOffSet >= 79200000) {
chronometer.setBase(SystemClock.elapsedRealtime());
chronometer.stop();
running = false;
// progressBar.setProgress(0);
} else {
chronometer.setText(setFormat(pauseOffSet));
// int convertTime = (int) pauseOffSet;
// progressBar.setProgress(convertTime);
}
if (activity != null) {
activity.updateClient(pauseOffSet);
}
}
});
if (state == 1) { // its in play mode
running = true;
chronometer.setBase(SystemClock.elapsedRealtime() - sharedPreferences.getLong("milli", 0));
chronometer.start();
} else if (state == 2) { //its in pause mode
running = false;
pauseOffSet = sharedPreferences.getLong("milli", -1);
long time = SystemClock.elapsedRealtime() - pauseOffSet;
chronometer.setBase(time);
int convertTime = (int) pauseOffSet;
// progressBar.setProgress(convertTime);
} else {
running = false;
}
//Do what you need in onStartCommand when service has been started
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//returns the instance of the service
public class LocalBinder extends Binder {
public TimerService getServiceInstance() {
return TimerService.this;
}
}
//Here Activity register to the service as Callbacks client
public void registerClient(Activity activity) {
this.activity = (Callbacks) activity;
}
//callbacks interface for communication with service clients!
public interface Callbacks {
public void updateClient(long data);
}
String setFormat(long time) {
int h = (int) (time / 3600000);
int m = (int) (time - h * 3600000) / 60000;
int s = (int) (time - h * 3600000 - m * 60000) / 1000;
String hh = h < 10 ? "0" + h : h + "";
String mm = m < 10 ? "0" + m : m + "";
String ss = s < 10 ? "0" + s : s + "";
return hh + ":" + mm + ":" + ss;
}
}
This is my Activity class:
public class MainActivity extends AppCompatActivity implements View.OnClickListener, TimerService.Callbacks {
private static final String TAG = MainActivity.class.getSimpleName();
Chronometer tvTextView;
Button btnStart, btnStop;
private int state = 0; //0 means stop state,1 means play, 2 means pause
SharedPreferences sharedPreferences;
private boolean running = false;
private long pauseOffSet = -1;
ProgressBar progressBar;
Intent serviceIntent;
TimerService myService;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tvTextView = findViewById(R.id.textview);
progressBar = findViewById(R.id.puzzleProgressBar);
btnStart = findViewById(R.id.button1);
btnStop = findViewById(R.id.button2);
btnStart.setOnClickListener(this);
btnStop.setOnClickListener(this);
serviceIntent = new Intent(this, TimerService.class);
sharedPreferences = getSharedPreferences("myprefs", MODE_PRIVATE);
state = sharedPreferences.getInt("state", 0);
tvTextView.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
#Override
public void onChronometerTick(Chronometer chronometer) {
long time = SystemClock.elapsedRealtime() - chronometer.getBase();
pauseOffSet = time;
Log.e(TAG, "pauseOffSet " + pauseOffSet);
if (time >= 79200000) {
tvTextView.setBase(SystemClock.elapsedRealtime());
tvTextView.stop();
running = false;
progressBar.setProgress(0);
} else {
chronometer.setText(setFormat(time));
int convertTime = (int) time;
progressBar.setProgress(convertTime);
}
}
});
startService(serviceIntent); //Starting the service
bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE); //Binding to the service!
}
private ServiceConnection serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
TimerService.LocalBinder binder = (TimerService.LocalBinder) service;
myService = binder.getServiceInstance();
myService.registerClient(MainActivity.this);
Log.e(TAG, "service connected");
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "service disconnected");
}
};
public void onClick(View v) {
if (btnStart == v) {
EventBus.getDefault().post(new MessageEvent(true));
} else if (btnStop == v) {
EventBus.getDefault().post(new MessageEvent(false));
}
}
#Override
protected void onStop() {
super.onStop();
sharedPreferences.edit().putLong("milli", pauseOffSet).commit();
sharedPreferences.edit().putInt("state", state).commit();
}
String setFormat(long time) {
int h = (int) (time / 3600000);
int m = (int) (time - h * 3600000) / 60000;
int s = (int) (time - h * 3600000 - m * 60000) / 1000;
String hh = h < 10 ? "0" + h : h + "";
String mm = m < 10 ? "0" + m : m + "";
String ss = s < 10 ? "0" + s : s + "";
return hh + ":" + mm + ":" + ss;
}
#Override
public void updateClient(long data) {
Log.d(TAG, "Data from service" + data);
}
}
The Chronometer is a View, that is, a UI element. You never add your Chronometer to any layout, I guess that's why it's never updating.
You could try using a CountDownTimer or a Handler / Runnable combination.
http://developer.android.com/reference/android/os/CountDownTimer.html http://developer.android.com/reference/android/os/Handler.html
Here's an example using Handler / Runnable, I've even thrown in a stopTimer() method for good measure:
private Handler timerHandler;
private Runnable timerRunnable;
// ...
#Override
public void onCreate() {
super.onCreate();
Log.d(LOG_TAG, "TimerService created");
timerHandler = new Handler();
timerRunnable = new Runnable() {
#Override
public void run() {
Log.d(LOG_TAG, "TICK");
timerHandler.postDelayed(timerRunnable, 1000);
}
};
}
public void startTimer() {
Log.d(LOG_TAG, "Timer started");
timerHandler.post(timerRunnable);
}
public void stopTimer() {
Log.d(LOG_TAG, "Timer stopped");
timerHandler.removeCallbacks(timerRunnable);
}
Here is a video which do not use Handler and directly implement the chronometer ,
Do check it out...
https://youtu.be/RLnb4vVkftc
Plus I had this problem I solved by removing
android:format="00:00"
from Chronometer in activity_main.xml
So my code looks like this :
<Chronometer
android:id="#+id/chronometer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:height="20sp"
android:foregroundGravity="fill_horizontal|top|bottom|center|fill_vertical|fill"
android:maxLines="2"
android:minLines="2"
android:textColor="#FFF"
android:textSize="40sp"
android:verticalScrollbarPosition="defaultPosition"
app:layout_constraintBottom_toBottomOf="#+id/progress_breathing"
app:layout_constraintEnd_toEndOf="#+id/progress_breathing"
app:layout_constraintStart_toStartOf="#+id/progress_breathing"
app:layout_constraintTop_toTopOf="#+id/progress_breathing"
app:layout_constraintVertical_bias="0.43" />
Related
Nowdays I tried to make a timer by using handler and sharedpreferences.
Today I had a problem with sharedprefereces.
The problem is that it is okay to push start button and go to background and then restart this app, the app is working correctly.
But it is not okay if i try twice the pattern(push start button -> background -> app -> background -> app) , the textview which display the time turns to zero....
I don't know what is problem....
Here is the code..
private Button mStartBtn, mStopBtn, mRecordBtn, mPauseBtn;
private TextView mTimeTextView, mRecordTextView;
private Thread timeThread = null;
private Boolean isRunning = false;
ArrayList<String> record = new ArrayList<>();
Boolean timeThreadd = false;
long i;
long mEndTime;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stop_watch);
if (Build.VERSION.SDK_INT >= 21) {
getWindow().setStatusBarColor(Color.parseColor("#4ea1d3"));
}
mStartBtn = (Button) findViewById(R.id.btn_start);
mStopBtn = (Button) findViewById(R.id.btn_stop);
mRecordBtn = (Button) findViewById(R.id.btn_record);
mPauseBtn = (Button) findViewById(R.id.btn_pause);
mTimeTextView = (TextView) findViewById(R.id.timeView);
mRecordTextView = (TextView) findViewById(R.id.recordView);
mStartBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.setVisibility(View.GONE);
mStopBtn.setVisibility(View.VISIBLE);
mRecordBtn.setVisibility(View.VISIBLE);
mPauseBtn.setVisibility(View.VISIBLE);
if (isRunning != true) {
isRunning = true;
}// start 가 true 일때만 실행된다.
timeThread = new Thread(new timeThread());
timeThread.start();
}
});
mStopBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.setVisibility(View.GONE);
mRecordBtn.setVisibility(View.GONE);
mStartBtn.setVisibility(View.VISIBLE);
mPauseBtn.setVisibility(View.GONE);
mRecordTextView.setText("");
mTimeTextView.setText("00:00:00:00");
timeThread.interrupt();
i = 0;
mEndTime = 0;
timeThreadd = false;
isRunning = false;
if (record.size() > 1) {
for (int i = 0; i < record.size(); i++) {
record.remove(i);
}
}
SharedPreferences sharedPreferences = getSharedPreferences("timer", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
editor.apply();
}
});
mRecordBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
record.add(mTimeTextView.getText().toString());
mRecordTextView.setText(mRecordTextView.getText() + mTimeTextView.getText().toString() + "\n");
}// 앞에 mRecordTextView.getText()은 n번이상 저장할때 첫번째 값을 n-1번째 라인에 놓고
}); // n번째 저장한것을 n번째 놓기 위해서 설정
mPauseBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
isRunning = !isRunning;
if (isRunning) {
mPauseBtn.setText("PAUSE");
} else {
mPauseBtn.setText("PAUSE");
}
}
});
}
#SuppressLint("HandlerLeak")
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
int mSec = msg.arg1 % 100;
int sec = (msg.arg1 / 100) % 60;
int min = (msg.arg1 / 100) / 60;
int hour = (msg.arg1 / 100) / 360;
//1000 = 1 sec, 1000*60 = 1 min, 1000*60*10 = 10min 1000*60*60 = 1 hour
#SuppressLint("DefaultLocale")
String result = String.format(Locale.getDefault(), "%02d:%02d:%02d:%02d", hour, min, sec, mSec);
mTimeTextView.setText(result);
}
};
public class timeThread implements Runnable {
#Override
public void run() {
mEndTime = System.currentTimeMillis() / 10 + i;
timeThreadd = true;
while (true) {
while (isRunning) { //일시정지를 누르면 멈춤
Message msg = new Message();
msg.arg1 = (int) i++;
handler.sendMessage(msg);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
#Override
public void run() {
mTimeTextView.setText("");
mTimeTextView.setText("00:00:00:00");
}
});
return;
}
}
}
}
}
#Override
protected void onStop() {
super.onStop();
SharedPreferences sharedpreferences = getSharedPreferences("timer", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putLong("time", i);
editor.putBoolean("switch", isRunning);
editor.putInt("recordsize", record.size());
editor.putLong("endTime", mEndTime);
Log.v("i", String.valueOf(i));
Log.v("iswitch", String.valueOf(isRunning));
Log.v("endTime", String.valueOf(mEndTime));
isRunning = false;
for (int i = 0; i < record.size(); i++) {
editor.putString("record" + i, record.get(i));
}
editor.apply();
if (timeThreadd != false) {
timeThread.interrupt();
}
if (record.size() > 0) {
for (int i = 0; i < record.size(); i++) {
record.remove(i);
}
}
}
#Override
protected void onStart() {
super.onStart();
SharedPreferences sharedpreferences = getSharedPreferences("timer", MODE_PRIVATE);
i = sharedpreferences.getLong("time", 0);
isRunning = sharedpreferences.getBoolean("switch", isRunning);
int b = sharedpreferences.getInt("recordsize", 0);
for (int i = 0; i < b; i++) {
String c = sharedpreferences.getString("record" + i, null);
record.add(c);
mRecordTextView.setText(mRecordTextView.getText() + c + "\n");
}
if (isRunning) {
mEndTime = sharedpreferences.getLong("endTime", 0);
Log.v(" set mEndTime",String.valueOf(mEndTime));
i = System.currentTimeMillis() / 10 - mEndTime;
Log.v(" set i",String.valueOf(i));
if (i < 0) {
isRunning = false;
i = 0;
mEndTime = 0;
timeThreadd = false;
mRecordBtn.setVisibility(View.GONE);
mStartBtn.setVisibility(View.VISIBLE);
mPauseBtn.setVisibility(View.GONE);
mRecordTextView.setText("");
mTimeTextView.setText("00:00:00:00");
} else if (i > 0) {
mStartBtn.setVisibility(View.GONE);
mStopBtn.setVisibility(View.VISIBLE);
mRecordBtn.setVisibility(View.VISIBLE);
mPauseBtn.setVisibility(View.VISIBLE);
timeThread = new Thread(new timeThread());
timeThread.start();
}
}
}
}
I solve the problem.
public void run() {
if(timeThreadd!= true){
mEndTime = System.currentTimeMillis() / 10 + i;
timeThreadd = true;
}
The problem was System.currentTimeMillis().
The System.currentTimeMillis() needs to store just one time when user push the start button.
I am trying to run a timer on the activity's onCreate() method but its not running that way. the timer runs on the click of the button. I tried to call the runButtonClick() method in the onCreate() but its not running. in am passing the value through intent from another activity.
Here is my code:
public class TimerActivity extends AppCompatActivity {
private static final String TAG = TimerActivity.class.getSimpleName();
private TimerService timerService;
private boolean serviceBound;
private Button timerButton;
String GetTime;
private TextView timerTextView;
String replaceString;
// Handler to update the UI every second when the timer is running
private final Handler mUpdateTimeHandler = new UIUpdateHandler(this);
// Message type for the handler
private final static int MSG_UPDATE_TIME = 0;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer);
Intent in = getIntent();
GetTime = in.getStringExtra("order_name");
replaceString = GetTime.replaceAll(" Minutes","");
timerButton = findViewById(R.id.delivered_to_driver);
timerTextView = findViewById(R.id.timer);
timerButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// runButtonClick();
}
});
}
#Override
protected void onStart() {
super.onStart();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Starting and binding service");
}
Intent i = new Intent(this, TimerService.class);
i.putExtra("order_time",replaceString);
startService(i);
bindService(i, mConnection, 0);
}
#Override
protected void onStop() {
super.onStop();
updateUIStopRun();
if (serviceBound) {
// If a timer is active, foreground the service, otherwise kill the service
if (timerService.isTimerRunning()) {
timerService.foreground();
}
else {
stopService(new Intent(this, TimerService.class));
}
// Unbind the service
unbindService(mConnection);
serviceBound = false;
}
}
public void runButtonClick() {
if (serviceBound && !timerService.isTimerRunning()) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Starting timer");
}
timerService.startTimer();
updateUIStartRun();
}
else if (serviceBound && timerService.isTimerRunning()) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Stopping timer");
}
timerService.stopTimer();
updateUIStopRun();
}
}
/**
* Updates the UI when a run starts
*/
private void updateUIStartRun() {
mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
//timerButton.setText(R.string.timer_stop_button);
}
/**
* Updates the UI when a run stops
*/
private void updateUIStopRun() {
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
//timerButton.setText(R.string.timer_start_button);
}
/**
* Updates the timer readout in the UI; the service must be bound
*/
private void updateUITimer() {
if (serviceBound) {
timerTextView.setText(timerService.elapsedTime());
}
}
/**
* Callback for service binding, passed to bindService()
*/
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Service bound");
}
TimerService.RunServiceBinder binder = (TimerService.RunServiceBinder) service;
timerService = binder.getService();
serviceBound = true;
// Ensure the service is not in the foreground when bound
timerService.background();
// Update the UI if the service is already running the timer
if (timerService.isTimerRunning()) {
updateUIStartRun();
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Service disconnect");
}
serviceBound = false;
}
};
/**
* When the timer is running, use this handler to update
* the UI every second to show timer progress
*/
static class UIUpdateHandler extends Handler {
private final static int UPDATE_RATE_MS = 1000;
private final WeakReference<TimerActivity> activity;
UIUpdateHandler(TimerActivity activity) {
this.activity = new WeakReference<>(activity);
}
#Override
public void handleMessage(Message message) {
if (MSG_UPDATE_TIME == message.what) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "updating time");
}
activity.get().updateUITimer();
sendEmptyMessageDelayed(MSG_UPDATE_TIME, UPDATE_RATE_MS);
}
}
}
/**
* Timer service tracks the start and end time of timer; service can be placed into the
* foreground to prevent it being killed when the activity goes away
*/
public static class TimerService extends Service {
private long totalTimeCountInMilliseconds;
private long timeBlinkInMilliseconds;
private CountDownTimer countDownTimer;
private boolean blink;
int time;
private static final String TAG = TimerService.class.getSimpleName();
String thisTime;
// Start and end times in milliseconds
private String startTime, endTime;
// Is the service tracking time?
private boolean isTimerRunning;
// Foreground notification id
private static final int NOTIFICATION_ID = 1;
// Service binder
private final IBinder serviceBinder = new RunServiceBinder();
public class RunServiceBinder extends Binder {
TimerService getService() {
return TimerService.this;
}
}
#Override
public void onCreate() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Creating service");
}
startTime = "0";
endTime = "0";
isTimerRunning = false;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Starting service");
}
thisTime = intent.getStringExtra("order_time");
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Binding service");
}
return serviceBinder;
}
#Override
public void onDestroy() {
super.onDestroy();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Destroying service");
}
}
/**
* Starts the timer
*/
public void startTimer() {
if (!isTimerRunning) {
if (thisTime != null) {
time = Integer.parseInt(thisTime);
} else
Toast.makeText(TimerService.this, "",
Toast.LENGTH_LONG).show();
totalTimeCountInMilliseconds = 60 * time * 1000;
timeBlinkInMilliseconds = 30 * 1000;
// startTime = System.currentTimeMillis();
isTimerRunning = true;
countDownTimer = new CountDownTimer(totalTimeCountInMilliseconds, 500) {
#Override
public void onTick(long leftTimeInMilliseconds) {
long seconds = leftTimeInMilliseconds / 1000;
if (leftTimeInMilliseconds < timeBlinkInMilliseconds) {
if (blink) {
// mTextField.setVisibility(View.VISIBLE);
// if blink is true, textview will be visible
} else {
// mTextField.setVisibility(View.INVISIBLE);
}
blink = !blink;
}
String a = String.format("%02d", seconds / 60) + ":" + String.format("%02d", seconds % 60);
startTime = a;
isTimerRunning = true;
}
#Override
public void onFinish() {
Toast.makeText(TimerService.this, "Finished", Toast.LENGTH_SHORT).show();
}
}.start();
}
else {
Log.e(TAG, "startTimer request for an already running timer");
}
}
/**
* Stops the timer
*/
public void stopTimer() {
if (isTimerRunning) {
endTime = String.valueOf(System.currentTimeMillis());
isTimerRunning = false;
}
else {
Log.e(TAG, "stopTimer request for a timer that isn't running");
}
}
/**
* #return whether the timer is running
*/
public boolean isTimerRunning() {
return isTimerRunning;
}
/**
* Returns the elapsed time
*
* #return the elapsed time in seconds
*/
public String elapsedTime() {
// If the timer is running, the end time will be zero
return startTime;
}
/*Integer.parseInt(endTime) > Integer.parseInt(startTime) ?
(Integer.parseInt(endTime) - Integer.parseInt(startTime)) / 1000 :
(System.currentTimeMillis() - Integer.parseInt(startTime)) / 1000;*//*
}
/**
* Place the service into the foreground
*/
public void foreground() {
startForeground(NOTIFICATION_ID, createNotification());
}
/**
* Return the service to the background
*/
public void background() {
stopForeground(true);
}
/**
* Creates a notification for placing the service into the foreground
*
* #return a notification for interacting with the service when in the foreground
*/
private Notification createNotification() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setContentTitle("Timer Active")
.setContentText("Tap to return to the timer")
.setSmallIcon(R.mipmap.ic_launcher);
Intent resultIntent = new Intent(this, TimerActivity.class);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(this, 0, resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultPendingIntent);
return builder.build();
}
}
}
I don't understand what the problem might me..your help will be appreciated.thank you in advance...
You startService() called in onStart() method and serviceBound will true after starting service. so that in oncreate() method if condition in runButtonClick will not execute.
once a timer start it couldn't be stop for 3 hours.if I click on backpress timer stoped.I am not sure how to pause and resume the timer as the textview.Please check my code.
TextView timer;
SharedPreferences mpref;
SharedPreferences.Editor ed;
String output;
MyCount counter;
long seconds;
long millisFinished;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start__test2);
mpref=getSharedPreferences("com.example.bright", Context.MODE_PRIVATE);
timer = (TextView) findViewById(R.id.timer);
//startService(new Intent(this, MyService.class));
counter = new MyCount(10800000, 1000);
counter.start();
}
countDownTimer method
public class MyCount extends CountDownTimer {
Context mContext;
public MyCount(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
Log.e("timeeeee", millisInFuture + "");
}
public void onTick(long millisUntilFinished) {
Log.e("time",millisUntilFinished+"");
millisFinished = millisUntilFinished;
timer.setText(formatTime(millisUntilFinished));
/* String timer_str = timer.getText().toString();
//SharedPreferences sp=
ed = mpref.edit();
ed.putString("time", timer_str);
ed.commit();*/
if (seconds == 0) {
}
}
public void onFinish() {
Toast.makeText(getApplicationContext(), "Time Up", Toast.LENGTH_LONG).show();
}
}
#Override
protected void onResume() {
super.onResume();
/*// Log.e("valueeeee",millisFinished+"");
// new MyCount(millisFinished,1000);
// Log.e("value",millisFinished+"");*/
//counter
}
#Override
public void onDestroy() {
super.onDestroy();
// counter.cancel();
}
//================================================================================Time format
public String formatTime(long millis) {
output = "";
seconds = millis / 1000;
long minutes = seconds / 60;
long hours = minutes / 60;
seconds = seconds % 60;
minutes = minutes % 60;
hours = hours % 60;
String secondsD = String.valueOf(seconds);
String minutesD = String.valueOf(minutes);
String hoursD = String.valueOf(hours);
if (seconds < 10)
secondsD = "0" + seconds;
if (minutes < 10)
minutesD = "0" + minutes;
if (hours < 10)
hoursD = "0" + hours;
output = hoursD + " : " + minutesD + " : " + secondsD;
return output;
}
Please check my code
U need to use a service so that the timer runs even if the app is closed/destroyed. Try as below
public class TimerService extends Service {
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private Context mContext;
public IBinder onBind(Intent intent)
{
return null;
}
public void onCreate()
{
super.onCreate();
mContext = this;
startService();
}
private void startService()
{
scheduler.scheduleAtFixedRate(runner, 0, 3, TimeUnit.HOURS);
}
final Runnable runner = new Runnable() {
public void run()
{
mHandler.sendEmptyMessage(0);
}
}
public void onDestroy()
{
super.onDestroy();
Toast.makeText(this, "Service Stopped ...", Toast.LENGTH_SHORT).show();
}
private final Handler mHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
//do what ever you want as 3hrs is completed
}
};
}
If you create objects in your activities scope they will be disposed once the activity is gone because of the activity lifecycle.
The solution for running long background tasks is us inn services by IntentService.
You can read more about it here :
https://developer.android.com/training/run-background-service/create-service.html
Good luck!
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am trying to invoke method of a service class i.e getDur() from an activity class method i.e startPlay() but I am getting Null Pointer Exception. Below is the code of the project. I have also added some Log statements but nothing gets printed on the logs too
Herre I am trying to bind service class with activity class, if there is any other way by which I can call method of service class from activity class then please tell me.
songPlay.java
Imports *
public class songPlay extends AppCompatActivity {
private static final int UPDATE_FREQUENCY = 500;
private static final int STEP_VALUE = 4000;
private TextView songName = null;
private TextView songDurationCurrent = null;
private TextView songDurationTotal = null;
private TextView songArtistFile = null;
private SeekBar seekbar = null;
private ImageButton playButton = null;
private ImageButton prevButton = null;
private ImageButton nextButton = null;
private Drawable clipArt = null;
private ImageView albumCover = null;
MusicService musicService;
boolean mBound = false;
private boolean isStarted = false;
private boolean isMoveingSeekBar = false;
String songId="", songTitle="", songArtist="", songPath="";
private final Handler handler = new Handler();
private final Runnable updatePositionRunnable = new Runnable() {
public void run() {
updatePosition();
}
};
#Override
protected void onStart() {
super.onStart();
Log.v("Check", "OnStart");
Intent intent = new Intent(this, MusicService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_song_play);
Intent intent = getIntent();
if (intent != null && intent.hasExtra("SONG_ID")) {
songId = intent.getStringExtra("SONG_ID");
songTitle = intent.getStringExtra("SONG_TITLE");
songArtist = intent.getStringExtra("SONG_ARTIST");
songPath = intent.getStringExtra("SONG_PATH");
songTitle = songTitle.replaceAll("\\s*\\([^\\)]*\\)\\s*", "");
songTitle = songTitle.replaceAll("\\[.*?\\]", "");
songArtist = songArtist.replaceAll("\\s*\\([^\\)]*\\)\\s*", "");
songName = (TextView) findViewById(R.id.selectedfile);
songName.setText(songTitle);
songArtistFile = (TextView) findViewById(R.id.selectedfile_artistname);
songArtistFile.setText(songArtist);
songDurationCurrent = (TextView) findViewById(R.id.duration_current);
songDurationTotal = (TextView) findViewById(R.id.duration_total);
seekbar = (SeekBar) findViewById(R.id.seekbar);
playButton = (ImageButton) findViewById(R.id.play);
prevButton = (ImageButton) findViewById(R.id.prev);
nextButton = (ImageButton) findViewById(R.id.next);
albumCover = (ImageView) findViewById(R.id.cover);
String selection = MediaStore.Audio.Media._ID + " = "+songId+"";
Cursor cursor = getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, new String[] {
MediaStore.Audio.Media._ID, MediaStore.Audio.Media.ALBUM_ID},
selection, null, null);
if (cursor.moveToFirst()) {
long albumId = cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID));
Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri albumArtUri = ContentUris.withAppendedId(sArtworkUri, albumId);
try {
albumCover.setImageURI(albumArtUri);
}
catch (Exception e) {
Log.e("Check", "Not Found");
}
}
cursor.close();
seekbar.setOnSeekBarChangeListener(seekBarChanged);
playButton.setOnClickListener(onButtonClick);
nextButton.setOnClickListener(onButtonClick);
prevButton.setOnClickListener(onButtonClick);
start();
}
}
#Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacks(updatePositionRunnable);
isStarted = false;
}
private void start() {
startService(new Intent(getApplicationContext(), MusicService.class).putExtra("songPath", songPath));
startPlay();
}
private void startPlay() {
isStarted = true;
seekbar.setProgress(0);
seekbar.setMax(musicService.getDur());
long millis = musicService.getDur();
long second = (millis / 1000) % 60;
long minute = (millis / (1000 * 60)) % 60;
long hour = (millis / (1000 * 60 * 60)) % 24;
String temp="",a="",b="",c="";
if(hour==0)
a = "00";
else if(hour<=9 && hour>0)
a = "0" + String.valueOf(hour);
else
a = String.valueOf(hour);
if(minute==0)
b = "00";
else if(minute<=9 && minute>0)
b = "0" + String.valueOf(minute);
else
b = String.valueOf(minute);
if(second==0)
c = "00";
else if(second<=9 && second>0)
c = "0" + String.valueOf(second);
else
c = String.valueOf(second);
temp = a + ":" + b + ":" + c;
songDurationTotal.setText(temp);
playButton.setImageResource(android.R.drawable.ic_media_pause);
isStarted = true;
updatePosition();
}
private void stopPlay() {
//musicService.stopPlay();
Intent intent = new Intent("songAction");
intent.putExtra("action", "stopPlay");
sendBroadcast(intent);
playButton.setImageResource(android.R.drawable.ic_media_play);
handler.removeCallbacks(updatePositionRunnable);
seekbar.setProgress(0);
isStarted = false;
}
private void updatePosition() {
handler.removeCallbacks(updatePositionRunnable);
seekbar.setProgress(musicService.getCPos());
long millis = musicService.getCPos();
long second = (millis / 1000) % 60;
long minute = (millis / (1000 * 60)) % 60;
long hour = (millis / (1000 * 60 * 60)) % 24;
String temp="",a="",b="",c="";
if(hour==0)
a = "00";
else if(hour<=9 && hour>0)
a = "0" + String.valueOf(hour);
else
a = String.valueOf(hour);
if(minute==0)
b = "00";
else if(minute<=9 && minute>0)
b = "0" + String.valueOf(minute);
else
b = String.valueOf(minute);
if(second==0)
c = "00";
else if(second<=9 && second>0)
c = "0" + String.valueOf(second);
else
c = String.valueOf(second);
temp = a + ":" + b + ":" + c;
songDurationCurrent.setText(temp);
handler.postDelayed(updatePositionRunnable, UPDATE_FREQUENCY);
}
private View.OnClickListener onButtonClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play: {
if (musicService.isPlay()) {
handler.removeCallbacks(updatePositionRunnable);
//musicService.pausePlay();
Intent intent = new Intent("songAction");
intent.putExtra("action", "pausePlay");
sendBroadcast(intent);
playButton.setImageResource(android.R.drawable.ic_media_play);
} else {
if (isStarted) {
//musicService.startAgain();
Intent intent = new Intent("songAction");
intent.putExtra("action", "startAgain");
sendBroadcast(intent);
playButton.setImageResource(android.R.drawable.ic_media_pause);
updatePosition();
} else {
start();
}
}
break;
}
case R.id.next: {
int seekto = musicService.getCPos() + STEP_VALUE;
if (seekto > musicService.getDur())
seekto = musicService.getDur();
//musicService.pausePlay();
Intent intent = new Intent("songAction");
intent.putExtra("action", "seekTo");
intent.putExtra("value", String.valueOf(seekto));
sendBroadcast(intent);
//musicService.startAgain();
break;
}
case R.id.prev: {
int seekto = musicService.getCPos() - STEP_VALUE;
if (seekto < 0)
seekto = 0;
//musicService.pausePlay();
/*
Intent intent = new Intent("songAction");
intent.putExtra("action", "pausePlay");
sendBroadcast(intent);
player.seekTo(seekto);
intent.putExtra("action", "startAgain");
sendBroadcast(intent);
//musicService.startAgain();
*/
Intent intent = new Intent("songAction");
intent.putExtra("action", "seekTo");
intent.putExtra("value", String.valueOf(seekto));
sendBroadcast(intent);
break;
}
}
}
};
private SeekBar.OnSeekBarChangeListener seekBarChanged = new SeekBar.OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
isMoveingSeekBar = false;
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
isMoveingSeekBar = true;
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (isMoveingSeekBar) {
// player.seekTo(progress);
Intent intent = new Intent("songAction");
intent.putExtra("action", "seekTo");
intent.putExtra("value", String.valueOf(progress));
sendBroadcast(intent);
}
}
};
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
Log.v("Check", "Service Connected");
MusicService.LocalBinder binder = (MusicService.LocalBinder) service;
musicService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
}
MusicService.java
Imports*
public class MusicService extends Service {
String songPath = "", action = "";
MediaPlayer player = null;
private final IBinder mBinder = new LocalBinder();
private BroadcastReceiver yourReceiver;
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class LocalBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
public void onCreate() {
super.onCreate();
player = new MediaPlayer();
}
#Override
public int onStartCommand(Intent intent, int flags, final int startId) {
Log.v("Check", "Service Started");
songPath = intent.getStringExtra("songPath");
final IntentFilter theFilter = new IntentFilter();
player.setOnCompletionListener(onCompletion);
player.setOnErrorListener(onError);
player.stop();
player.reset();
try {
player.setDataSource(songPath);
player.prepare();
player.start();
}
catch (Exception e) {
}
this.yourReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action.equals("songAction")){
String state = intent.getExtras().getString("action");
if(state.equals("stopPlay")) {
stopPlay();
}
else if(state.equals("pausePlaye")) {
pausePlay();
}
else if(state.equals("startAgain")) {
startAgain();
}
else if(state.equals("seekTo")) {
int value = Integer.parseInt(intent.getExtras().getString("value"));
player.seekTo(value);
}
}
}
};
this.registerReceiver(this.yourReceiver, theFilter);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
player.stop();
player.reset();
player.release();
player = null;
}
void stopPlay() {
player.stop();
player.reset();
}
void pausePlay() {
player.pause();
}
void startAgain() {
player.start();
}
private MediaPlayer.OnCompletionListener onCompletion = new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
stopPlay();
}
};
private MediaPlayer.OnErrorListener onError = new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
return false;
}
};
int getCPos() {
return player.getCurrentPosition();
}
int getDur() {
return player.getDuration();
}
boolean isPlay() {
return player.isPlaying();
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.coderahul.player"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="24" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name="com.android.tools.fd.runtime.BootstrapApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.coderahul.player.MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.example.coderahul.beats.songPlay" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:enabled="true" android:process=":remote" android:name=".MusicService"/>
</application>
</manifest>
You are calling start() method from onCreate which is before your service is connected. Call start() method after your service has been binded or started so that you have instance of the service class.
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
MusicService.LocalBinder binder = (MusicService.LocalBinder) service;
musicService = binder.getService();
mBound = true;
//here
start();
}
bindService is asynchronous
put start() in onServiceConnected:
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
Log.d("TAG", "Service Connected");
MusicService.LocalBinder binder = (MusicService.LocalBinder) service;
musicService = binder.getService();
mBound = true;
//here
start();
}
Log
output
I am working with an application where i am creating a service which do some work in background, this service gets stop when i clear my application from recent open applications. I want my service to be run in background even if I clear the application. I am testing my application with Xiaomi Mi4i device.
This is my service class
public class LocalNotificationService extends Service {
private int i = 1;
public static final String TAG = LocalNotificationService.class.getSimpleName();
private static long UPDATE_INTERVAL = 1 * 5 * 1000; //default
private static Timer timer = new Timer();
private static final String TIME_FORMAT_LOCAL_NOTIFICATION = "HH:mm";
private boolean isNotificationFired = false;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public void onCreate() {
super.onCreate();
_startService();
startForeground(1,new Notification());
Log.v(TAG, "service created....");
}
private void _startService() {
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
doServiceWork();
}
}, 1000, UPDATE_INTERVAL);
}
private void doServiceWork() {
Log.v(TAG, "service working....");
try {
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
String dateString = null;
try {
String format = "yyyy-MM-dd";
final SimpleDateFormat sdf = new SimpleDateFormat(format);
dateString = sdf.format(new Date()) + "T00:00:00";
Log.v(TAG, dateString);
} catch (Exception e) {
e.printStackTrace();
}
List<AppointmentModel> list = new RushSearch().whereEqual("Date", dateString).find(AppointmentModel.class);
if (list != null & list.size() > 0) {
for (AppointmentModel model : list) {
try {
if (model.Status.equalsIgnoreCase("Confirmed")) {
SimpleDateFormat sdf = new SimpleDateFormat(LocalNotificationService.TIME_FORMAT_LOCAL_NOTIFICATION);
Date currentTime = sdf.parse(sdf.format(Calendar.getInstance().getTime()));
String From = DateAndTimeUtil.getTimeLocale_HHmm(model.FromTime);
Date FromTime = sdf.parse(From);
long difference = currentTime.getTime() - FromTime.getTime();
int days = (int) (difference / (1000 * 60 * 60 * 24));
int hours = (int) ((difference - (1000 * 60 * 60 * 24 * days)) / (1000 * 60 * 60));
int min = (int) (difference - (1000 * 60 * 60 * 24 * days) - (1000 * 60 * 60 * hours)) / (1000 * 60);
hours = (hours < 0 ? -hours : hours);
Log.v("======= days", " :: " + days);
Log.v("======= hours", " :: " + hours);
Log.v("======= min", " :: " + min);
switch (min){
case -15: {
if(!isNotificationFired){
Bundle bundle = new Bundle();
bundle.putString(ArkaaNotificationHandler.NOTIFICATION_KEY_FROM, "Appointment Reminder");
bundle.putString(ArkaaNotificationHandler.NOTIFICATION_KEY_TITLE, "Appointment Reminder");
bundle.putString(ArkaaNotificationHandler.NOTIFICATION_KEY_MESSAGE, "You Have Appointment With " + model.Doctor.Name + "At " + DateAndTimeUtil.getTimeLocale_HHmmaa(From));
bundle.putString(ArkaaNotificationHandler.NOTIFICATION_KEY_COLLAPSE_KEY, "");
ArkaaNotificationHandler.getInstance(LocalNotificationService.this).createSimpleNotification(LocalNotificationService.this, bundle);
isNotificationFired = true;
}
break;
}
case -5: {
if(!isNotificationFired){
Bundle bundle = new Bundle();
bundle.putString(ArkaaNotificationHandler.NOTIFICATION_KEY_FROM, "");
bundle.putString(ArkaaNotificationHandler.NOTIFICATION_KEY_COLLAPSE_KEY, "");
bundle.putString(ArkaaNotificationHandler.NOTIFICATION_KEY_MESSAGE, "You Have Appointment With" + model.Doctor.Name + "At" + DateAndTimeUtil.getTimeLocale_HHmmaa(From));
if(NetworkUtils.getNetworkClass(ArkaaApplicationClass.getInstance().getBaseContext()).equalsIgnoreCase("2G")){
bundle.putString(ArkaaNotificationHandler.NOTIFICATION_KEY_TITLE, "For Better Call Experience Please Switch To High BandWidth Network ");
}else{
bundle.putString(ArkaaNotificationHandler.NOTIFICATION_KEY_TITLE, "Appointment Reminder");
}
ArkaaNotificationHandler.getInstance(LocalNotificationService.this).createSimpleNotification(LocalNotificationService.this, bundle);
isNotificationFired = true;
}
}
case -4:
case -14:
isNotificationFired = false;
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return null;
}
}.execute();
} catch (Exception e) {
Log.v(TAG, e.toString());
}
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
stopSelf();
}
private void _shutdownService() {
if (timer != null) timer.cancel();
Log.i(getClass().getSimpleName(), "Timer stopped...");
}
#Override
public void onDestroy() {
super.onDestroy();
_shutdownService();
Log.v(TAG, "service destroyed.....");
// if (MAIN_ACTIVITY != null) Log.d(getClass().getSimpleName(), "FileScannerService stopped");
}
}
In your Activity, do the following to start your service. For example in onCreate():
Intent intent = new Intent(this, MyService.class);
startService(intent);
In your Service, do the following in onCreate():
int NOTIFICATION_ID = 2707;
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
builder.setSmallIcon(android.R.drawable.ic_menu_info_details)
.setContentTitle("MyAppName")
.setContentText("the service is running!")
.setTicker("the service is running!")
.setOnlyAlertOnce(true)
.setOngoing(true)
.setSound(alarmSound);
Notification notification = builder.build();
startForeground(NOTIFICATION_ID, notification);
Just hide stopSelf(); and _shutdownService(); or try WakefulBroadcastReceiver method
https://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.html