How to keep a CountDownTimer running even if the app is closed?

前端 未结 2 1480
被撕碎了的回忆
被撕碎了的回忆 2020-11-28 14:19

I spent my summer learning how to code and building my first app (in android studio). Therefore I am not an expert coder. This week I encountered a problem. Basically, I am

相关标签:
2条回答
  • 2020-11-28 14:24

    Run it in a service as such: use create a broadcast receiver in your activity and have the service send broadcasts.

    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;
            }
    }
    

    From the 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);            
        }
    }
    

    Note I got this code from How to run CountDownTimer in a Service in Android?, which I modified for my own android countDownTimer.

    0 讨论(0)
  • 2020-11-28 14:49

    Download source code from here 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>
    

    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);
        }
    }
    

    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);
        }
    }
    

    Thanks!

    0 讨论(0)
提交回复
热议问题