0

I have implemented countdown timer in listview.But problem is that when i close my app and reopen it timer gets reset from beginning.I want timer to run even if app is closed.For eg-If time is 10min and i close app and open after 6 min timer must show remaining time as 4 min.

MainActivity.java

public class MainActivity extends Activity {

    private ListView lvItems;
    private List<Product> lstProducts;

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

        lvItems = (ListView) findViewById(R.id.lvItems);
        lstProducts = new ArrayList<>();
        lstProducts.add(new Product("A", System.currentTimeMillis() + 10000));
        lstProducts.add(new Product("B", System.currentTimeMillis() + 250000));
        lstProducts.add(new Product("C", System.currentTimeMillis() + 200000));
        lstProducts.add(new Product("D", System.currentTimeMillis() + 300000));


        lvItems.setAdapter(new CountdownAdapter(MainActivity.this, lstProducts));
    }

}

Product.java

public class Product {
    String name;
    long expirationTime;

    public Product(String name, long expirationTime) {
        this.name = name;
        this.expirationTime = expirationTime;
    }
}

CountdownAdapter.java

public class CountdownAdapter extends ArrayAdapter<Product> {

    private LayoutInflater lf;
    private List<ViewHolder> lstHolders;
    private Handler mHandler = new Handler();
    private Runnable updateRemainingTimeRunnable = new Runnable() {
        @Override
        public void run() {
            synchronized (lstHolders) {
                long currentTime = System.currentTimeMillis();
                for (ViewHolder holder : lstHolders) {
                    holder.updateTimeRemaining(currentTime);
                }
            }
        }
    };

    public CountdownAdapter(Context context, List<Product> objects) {
        super(context, 0, objects);
        lf = LayoutInflater.from(context);
        lstHolders = new ArrayList<>();
        startUpdateTimer();
    }

    private void startUpdateTimer() {
        Timer tmr = new Timer();
        tmr.schedule(new TimerTask() {
            @Override
            public void run() {
                mHandler.post(updateRemainingTimeRunnable);
            }
        }, 1000, 1000);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = lf.inflate(R.layout.list_item, parent, false);
            holder.tvProduct = (TextView) convertView.findViewById(R.id.tvProduct);
            holder.tvTimeRemaining = (TextView) convertView.findViewById(R.id.tvTimeRemaining);
            convertView.setTag(holder);
            synchronized (lstHolders) {
                lstHolders.add(holder);
            }
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.setData(getItem(position));

        return convertView;
    }


    class ViewHolder {
        TextView tvProduct;
        TextView tvTimeRemaining;
        Product mProduct;

        public void setData(Product item) {
            mProduct = item;
            tvProduct.setText(item.name);
            updateTimeRemaining(System.currentTimeMillis());
        }

        public void updateTimeRemaining(long currentTime) {
            long timeDiff = mProduct.expirationTime - currentTime;
            if (timeDiff > 0) {
                int seconds = (int) (timeDiff / 1000) % 60;
                int minutes = (int) ((timeDiff / (1000 * 60)) % 60);
                int hours = (int) ((timeDiff / (1000 * 60 * 60)) % 24);
                tvTimeRemaining.setText(hours + " hrs " + minutes + " mins " + seconds + " sec");
            } else {
                tvTimeRemaining.setText("Expired!!");
            }
        }
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.ram.asynctimer.MainActivity">

    <ListView
        android:id="@+id/lvItems"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />



</RelativeLayout>

list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/tvProduct"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Product Name"
        android:textSize="16dp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/tvTimeRemaining"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:text="Time Remaining : " />


</LinearLayout>

MyService.java

public class MyService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        //throw new UnsupportedOperationException("Not yet implemented");
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // do your jobs here
        return super.onStartCommand(intent, flags, startId);
    }
}
Sachin
  • 1
  • 1

2 Answers2

0

Reason "timer gets reset" is that you are not saving each item timer on closing and when you start the app, you are again setting new timers .

Simply store each item timer in your onStop method and again load those ones in your onCreate and set if

if(item1_timer - System.currentTimeMillis()>0){
   {
      //set timer to item1 and so on
   }else{
           item1.timer = "Expired"
      }
Ali Ahsan
  • 405
  • 3
  • 13
0

If you modified Product.java to hold both expiration time and the remaining time then you might be able to save and restore that information using a bundle.

Product.java

public class Product {
String name;
long expirationTime;
long remainingTime

    public Product(String name, long expirationTime, long remainingTime) {
        this.name = name;
        this.expirationTime = expirationTime;
        if(remainingTime <= 0)
            this.remainingTime = this.expirationTime;
        else 
            this.remainingTime = remainingTime;
    }
}

From here you could make use of Shared Preferences to save the state of all of your products.

MainActivity.java

public class MainActivity extends Activity {
    public static final String PREFS_NAME = "TimerValsFile";
    private ListView lvItems;
    private List<Product> lstProducts;

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

        lvItems = (ListView) findViewById(R.id.lvItems);
        lstProducts = new ArrayList<>();

        // Access the shared preferences
        SharedPreferences timerVals = getSharedPreferences(PREFS_NAME, 0);

        // Restore remaining time from shared preferences
        long remA = timerVals.getLong("A", -1);
        long remB = timerVals.getLong("A", -1);
        long remC = timerVals.getLong("A", -1);
        long remD = timerVals.getLong("A", -1);

        lstProducts.add(new Product("A", System.currentTimeMillis() + 10000), remA);
        lstProducts.add(new Product("B", System.currentTimeMillis() + 250000), remB);
        lstProducts.add(new Product("C", System.currentTimeMillis() + 200000), remC);
        lstProducts.add(new Product("D", System.currentTimeMillis() + 300000), remD);


        lvItems.setAdapter(new CountdownAdapter(MainActivity.this, lstProducts));
    }

    @Override
    protected void onStop(){
        super.onStop();

        // We need an Editor object to make preference changes.
        // All objects are from android.context.Context
        SharedPreferences timerVals = getSharedPreferences(PREFS_NAME, 0);
        SharedPreferences.Editor editor = timerVals.edit();
        editor.putLong("A", lstProducts.get(0).remainingTime);
        editor.putLong("B", lstProducts.get(1).remainingTime);
        editor.putLong("C", lstProducts.get(2).remainingTime);
        editor.putLong("D", lstProducts.get(3).remainingTime);

        // Commit the edits!
        editor.apply();
    }

}

Now that you're loading from instance state you need to modify the ViewHolder class

class ViewHolder {
    TextView tvProduct;
    TextView tvTimeRemaining;
    Product mProduct;

    public void setData(Product item) {
        mProduct = item;
        tvProduct.setText(item.name);
        updateTimeRemaining(System.currentTimeMillis());
    }

    public void updateTimeRemaining(long currentTime) {
        mProduct.remainingTime -= currentTime;
        if (mProduct.remainingTime > 0) {
            int seconds = (int) (mProduct.remainingTime / 1000) % 60;
            int minutes = (int) ((mProduct.remainingTime / (1000 * 60)) % 60);
            int hours = (int) ((mProduct.remainingTime / (1000 * 60 * 60)) % 24);
            tvTimeRemaining.setText(hours + " hrs " + minutes + " mins " + seconds + " sec");
        } else {
            tvTimeRemaining.setText("Expired!!");
        }
    }
}

I haven't actually tested this but will get around to it soon but I hope this gives you the general idea. This is basically an alternative to using a service.

Sources:

SO: Android Shared preferences example

Android developer Guide: https://developer.android.com/guide/topics/data/data-storage.html#pref

https://developer.android.com/reference/android/content/SharedPreferences.Editor.html

Community
  • 1
  • 1
Aflah Bhari
  • 108
  • 2
  • 6
  • *Fingers crossed* – Aflah Bhari May 12 '17 at 07:27
  • Can you post the exact error you're getting? Or is it that the state isn't being persisted? – Aflah Bhari May 12 '17 at 07:53
  • Timer isnt getting stored its value is reset again when i open app again. – Sachin May 15 '17 at 03:27
  • Sounds like you may need to use shared preferences. I'll be updating my answer a little later today. In the mean time I suggest reading the link I've posted at the bottom of my answer. – Aflah Bhari May 15 '17 at 04:38
  • Yes will be waiting for ur answer.Till then i will read the link and try to get solution. – Sachin May 15 '17 at 05:38
  • Give it a go now. The only real change I made was modifying **MainActivity.java** to use shared prefs instead of bundles. Which allows the data to be persisted even when the application is destroyed. – Aflah Bhari May 15 '17 at 08:21