Я создаю приложение обратного отсчета, которое показывает время, оставшееся до указанной даты, и я решил внедрить службу переднего плана, чтобы показать время, оставшееся на панели уведомлений. Тем не менее, я столкнулся с проблемой при «тестировании ошибок» приложения.
В настоящее время у меня есть кнопка запуска службы и кнопка остановки службы, которая, кажется, работает нормально. Однако это работает только тогда, когда я остаюсь в том же экземпляре запуска приложения.
Пример оставшегося в том же экземпляре запуска:
1) Запуск службы (обратный отсчет при запуске уведомлений)> Останов службы (обратный отсчет) в уведомлении исчезает)
2) Запустить службу (начинается обратный отсчет в уведомлении)> Нажмите кнопку «Домой»> снова запустить приложение> Остановить службу (отсчет в уведомлении исчезает)
Когда я пытаюсь запустить службу и остановить службу в В другом экземпляре запуска приложения возникает проблема.
Пример другого экземпляра запуска:
Запуск службы (начинается обратный отсчет в уведомлении)> Нажмите кнопку «Домой»> «Убить приложение в ящике приложения»> «Запустить приложение снова»> «Стоп» служба (обратный отсчет в уведомлении должен исчезнуть, но не исчезает)
Обратный отсчет остается, когда я нажимаю кнопку «Остановить службу», когда убиваю и перезапускаю приложение (единственный способ убить его - очистить хранилище / удалить приложение). Я полагал, что это может быть 2 службы, конфликтующие из-за изменения 1 переменной и т. Д. c ... но даже после нескольких часов попыток найти ошибку и исследовать форумы, я все еще не могу найти причину, по которой это происходит.
Любая помощь или руководство будет высоко ценится. Очень жаль за ужасное форматирование.
MainActivity. java
public class MainActivity extends AppCompatActivity implements DatePickerDialog.OnDateSetListener {
private Handler mHandler = new Handler();
private TextView dateText;
private CountDownTimer countDownTimer;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// if first start
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
boolean firstStart = prefs.getBoolean("firstStart", true);
if(firstStart)
{
showStartDialog();
}
// set dateText to date_text
dateText = findViewById(R.id.date_text);
// show date picker when click on show_dialog button
findViewById(R.id.show_dialog).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDatePickerDialog();
}
});
startTimer();
}
private void showStartDialog()
{
new AlertDialog.Builder(this)
.setTitle("One Time Dialog")
.setMessage("This should only be shown once")
.setPositiveButton("ok", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
showDatePickerDialog();
}
})
.create().show();
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("firstStart", false);
editor.apply();
}
private void showDatePickerDialog()
{
DatePickerDialog datePickerDialog = new DatePickerDialog(
this,
this,
Calendar.getInstance().get(Calendar.YEAR),
Calendar.getInstance().get(Calendar.MONTH),
Calendar.getInstance().get(Calendar.DAY_OF_MONTH)
);
datePickerDialog.show();
}
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth)
{
Date endDate = new Date((year-1900),month,dayOfMonth);
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putLong("endDate", endDate.getTime());
editor.apply();
startTimer();
}
private void startTimer()
{
long difference = getRemainDays();
if(countDownTimer !=null)
{
countDownTimer.cancel();
countDownTimer = null;
}
countDownTimer = new CountDownTimer(difference,1000) // 1 second
{
@Override
public void onTick(long millisUntilFinished)
{
int days = (int)(millisUntilFinished/(1000*60*60*24));
int hours = (int)((millisUntilFinished/(1000*60*60))%24);
int mins = (int)((millisUntilFinished/(1000*60))%60);
int sec = (int)((millisUntilFinished/(1000))%60);
dateText.setText(String.format("%02d Days %d Hours %d Mins %d Sec",days,hours,mins,sec));
}
@Override
public void onFinish()
{
// Done
dateText.setText("Done");
}
}.start();
}
private long getRemainDays()
{
Date currentDate = new Date();
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
long endDate = prefs.getLong("endDate", currentDate.getTime());
return endDate - currentDate.getTime();
}
public void startService(View v){
String input = dateText.getText().toString();
Intent serviceIntent = new Intent(this, ExampleService.class);
serviceIntent.putExtra("inputExtra", input);
ContextCompat.startForegroundService(this,serviceIntent);
mNotificationRunnable.run();
}
public void stopService(View v){
Intent serviceIntent = new Intent(this,ExampleService.class);
stopService(serviceIntent);
mHandler.removeCallbacks(mNotificationRunnable);
}
private void updateNotification() {
String input = dateText.getText().toString();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Example Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_android)
.setContentIntent(pendingIntent)
.build();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, notification);
}
private Runnable mNotificationRunnable = new Runnable()
{
@Override
public void run() {
updateNotification();
mHandler.postDelayed(this,1000);
}
};
}
ExampleService. java
public class ExampleService extends Service {
@Override
public void onCreate()
{
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("inputExtra");
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Example Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_android)
.setContentIntent(pendingIntent)
.build();
startForeground(1,notification);
return START_NOT_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Новый MainActivity. java
private TextView dateText;
private CountDownTimer countDownTimer;
private NotificationSingleton notificationSingleton;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// if first start
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
boolean firstStart = prefs.getBoolean("firstStart", true);
if(firstStart)
{
showStartDialog();
}
// set dateText to date_text
dateText = findViewById(R.id.date_text);
// show date picker when click on show_dialog button
findViewById(R.id.show_dialog).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDatePickerDialog();
}
});
notificationSingleton = NotificationSingleton.getInstance();
startTimer();
}
private void showStartDialog()
{
new AlertDialog.Builder(this)
.setTitle("One Time Dialog")
.setMessage("This should only be shown once")
.setPositiveButton("ok", new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
showDatePickerDialog();
}
})
.create().show();
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("firstStart", false);
editor.apply();
}
private void showDatePickerDialog()
{
DatePickerDialog datePickerDialog = new DatePickerDialog(
this,
this,
Calendar.getInstance().get(Calendar.YEAR),
Calendar.getInstance().get(Calendar.MONTH),
Calendar.getInstance().get(Calendar.DAY_OF_MONTH)
);
datePickerDialog.show();
}
@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth)
{
Date endDate = new Date((year-1900),month,dayOfMonth);
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putLong("endDate", endDate.getTime());
editor.apply();
startTimer();
}
private void startTimer()
{
long difference = getRemainDays();
if(countDownTimer !=null)
{
countDownTimer.cancel();
countDownTimer = null;
}
countDownTimer = new CountDownTimer(difference,1000) // 1 second
{
@Override
public void onTick(long millisUntilFinished)
{
int days = (int)(millisUntilFinished/(1000*60*60*24));
int hours = (int)((millisUntilFinished/(1000*60*60))%24);
int mins = (int)((millisUntilFinished/(1000*60))%60);
int sec = (int)((millisUntilFinished/(1000))%60);
dateText.setText(String.format("%02d Days %d Hours %d Mins %d Sec",days,hours,mins,sec));
}
@Override
public void onFinish()
{
// Done
dateText.setText("Done");
}
}.start();
}
private long getRemainDays()
{
Date currentDate = new Date();
SharedPreferences prefs = getSharedPreferences("prefs", MODE_PRIVATE);
long endDate = prefs.getLong("endDate", currentDate.getTime());
return endDate - currentDate.getTime();
}
public void startService(View v){
String input = dateText.getText().toString();
Intent serviceIntent = new Intent(this, ExampleService.class);
serviceIntent.putExtra("inputExtra", input);
ContextCompat.startForegroundService(this,serviceIntent);
notificationSingleton.mNotificationRunnable.run();
}
public void stopService(View v){
Intent serviceIntent = new Intent(this,ExampleService.class);
stopService(serviceIntent);
notificationSingleton.stopService();
}
public TextView getDateText()
{
return dateText;
}
УведомлениеSingleton. java
public Handler mHandler = new Handler();
private static NotificationSingleton instance;
private NotificationSingleton()
{
//private to prevent any else from instantiating
}
public static synchronized NotificationSingleton getInstance()
{
if (instance == null){
instance = new NotificationSingleton();
}
return instance;
}
public void stopService()
{
mHandler.removeCallbacks(mNotificationRunnable);
}
public Runnable mNotificationRunnable = new Runnable()
{
@Override
public void run() {
updateNotification();
mHandler.postDelayed(this,1000);
}
};
private void updateNotification() {
MainActivity mainActivity = new MainActivity();
String input = mainActivity.getDateText().getText().toString();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Example Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_android)
.setContentIntent(pendingIntent)
.build();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mNotificationManager.notify(1, notification);
}