The task is to write a listView with chronometers and when turning to save the state of each timer. But when I start the timer / timers and turn the screen, no matter what timer I start from, the first list item starts the report. It is not formally launched, but the report begins. Here is the code snippet:

  public class MainActivity extends ActionBarActivity implements LoaderManager.LoaderCallbacks<Cursor>{ ListView listView; MyAdapter myAdapter; private final int LOADER_ID =1; SQLiteDatabase db; Bundle bundle; List<Long> lastPauseList; List<Integer> positionnList; List<Boolean> startList; List<Long> basesList; List<Long> tested; List<Long> elapsed; List<Tracker> trackerList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bundle = savedInstanceState; db = RemindMe.db; trackerList = Tracker.getListAll(db); String[] from = {Tracker.COL_NAME,Tracker.COL_ELAPSED_TIME}; int[]to={R.id.row_name,R.id.row_chronometer}; startList = new ArrayList<Boolean>(trackerList.size()); lastPauseList = new ArrayList<Long>(trackerList.size()); for (int i = 0; i <trackerList.size() ; i++) { startList.add(false); lastPauseList.add((long)0); } if(bundle!=null) { for (int i = 0; i < trackerList.size(); i++) { startList.set(i,savedInstanceState.getBoolean("start " + i)); lastPauseList.set(i,bundle.getLong("lastPause "+i)); Log.d("myTag", "OnCreate-----------------------------------------"); Log.d("myTag", "position " + i); Log.d("myTag", "elapsedTime "+ getTime(savedInstanceState.getLong("elapsedTime " + i))); Log.d("myTag", "base " + getTime(savedInstanceState.getLong("base " + i))); Log.d("myTag", "lastPause "+ getTime(savedInstanceState.getLong("lastPause "+i))); Log.d("myTag", "start "+ savedInstanceState.getBoolean("start " + i)); Log.d("myTag", "------------------------------------------end onCreate"); } } listView=(ListView)findViewById(R.id.listView); myAdapter = new MyAdapter(this,R.layout.list_item, Tracker.getAll(db),from,to,0); listView.setAdapter(myAdapter); getSupportLoaderManager().initLoader(LOADER_ID,null,this); } public void onCLick(View v){ Intent intent = new Intent(this,AddTrack.class); startActivity(intent); } @Override public Loader<Cursor> onCreateLoader(int i, Bundle bundle) { return new TrackLoader(this,db); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { myAdapter.swapCursor(cursor); } @Override public void onLoaderReset(Loader<Cursor> loader) { } static class TrackLoader extends CursorLoader { SQLiteDatabase db; public TrackLoader(Context context,SQLiteDatabase db){ super(context); this.db = db; } @Override public Cursor loadInBackground() { return Tracker.getAll(db); } } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); for (int i = 0; i <elapsed.size() ; i++) { if(basesList.get(i)>1000){ outState.putLong("elapsedTime " + i, elapsed.get(i)); } outState.putLong("base "+i,basesList.get(i)); outState.putLong("lastPause "+i,lastPauseList.get(i)); outState.putBoolean("start " + i, startList.get(i)); Log.d("myTag", "OnSavedInstanceState-----------------------------------------"); Log.d("myTag", "position " + i); Log.d("myTag", "elapsedTime " + getTime(outState.getLong("elapsedTime "+i))); Log.d("myTag", "base "+ getTime(outState.getLong("base "+i))); Log.d("myTag", "lastPause "+ getTime(outState.getLong("lastPause "+i))); Log.d("myTag", "start "+ outState.getBoolean("start " + i)); Log.d("myTag","------------------------------------------end onSavedInstanceState"); } } String getTime(long time){ int hours = (int)(time/3600000); int minutes = (int)(time -hours*3600000)/60000; int seconds = (int)(time-hours*3600000-minutes*60000)/1000; String hour = (hours<9?"0"+hours:hours).toString(); String min = (minutes<9?"0"+minutes:minutes).toString(); String sec = (seconds<9?"0"+seconds:seconds).toString(); return ""+hour+":"+min+":"+sec; } public class MyAdapter extends SimpleCursorAdapter{ Context context; int resorceID; @TargetApi(Build.VERSION_CODES.HONEYCOMB) public MyAdapter(Context context,int resourceID,Cursor c,String[] from,int[]to,int flags){ super(context,resourceID,c,from,to,flags); this.context=context; this.resorceID =resourceID; elapsed = new ArrayList<Long>(trackerList.size()); basesList = new ArrayList<Long>(trackerList.size()); for (int i = 0; i <trackerList.size() ; i++) { elapsed.add((long) 0); basesList.add((long)0); } } @Override public View getView(final int position, View convertView, final ViewGroup parent) { View row = convertView; TrackHolder holder=null; final Tracker tracker = trackerList.get(position); final long[] lastPause = new long[1]; long elapsedTime; final long base; boolean bundleIsItStart; if(row==null){ LayoutInflater inflater = ((Activity)context).getLayoutInflater(); row = inflater.inflate(resorceID,parent,false); holder = new TrackHolder(); holder.name = (TextView)row.findViewById(R.id.row_name); holder.chronometer = (Chronometer)row.findViewById(R.id.row_chronometer); holder.start = (Button)row.findViewById(R.id.btStart); holder.stop = (Button)row.findViewById(R.id.btStop); row.setTag(holder); }else{ holder = (TrackHolder)row.getTag(); } if(!trackerList.isEmpty()) { final TrackHolder finalHolder = holder; holder.start.setEnabled(true); holder.stop.setEnabled(false); if(bundle!=null){ holder.name.setText(tracker.getName()); elapsedTime = bundle.getLong("elapsedTime "+position);//получеаем значение прошедшего времени после поворота экрана base = bundle.getLong("base " + position);//получаем, сохраненную на пред экране. lastPause[0]=bundle.getLong("lastPause " + position);//получаем разницу во времени(паузу) с SavedInstanceState bundleIsItStart=bundle.getBoolean("start " + position);//получаем статус: запущен/остановлен basesList.set(position,base); if(elapsedTime>elapsed.get(position))//если время, полученое после поворота больше, которое насчитает в onTick, запишется в список, но такого никогда не будет elapsed.set(position, elapsedTime); if(startList.get(position)==bundleIsItStart)//по аналогии как выше, если если текущий элемент == статусу, пишем в список статус, иначе элемент остается в списке startList.set(position,bundleIsItStart); if(lastPauseList.get(position)>lastPause[0]) lastPauseList.set(position,lastPause[0]); if(bundleIsItStart){ holder.stop.setEnabled(true); holder.start.setEnabled(false); holder.chronometer.setBase(base); holder.chronometer.start(); } if(!bundleIsItStart && base>1000){ holder.chronometer.setBase(base+(SystemClock.elapsedRealtime()-base+lastPause[0])); holder.stop.setEnabled(false); holder.start.setEnabled(true); } }else{ holder.name.setText(tracker.getName()); holder.start.setEnabled(true); holder.stop.setEnabled(false); } holder.start.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finalHolder.chronometer.setBase(SystemClock.elapsedRealtime() + lastPause[0]); finalHolder.chronometer.start(); finalHolder.stop.setEnabled(true); finalHolder.start.setEnabled(false); basesList.set(position, finalHolder.chronometer.getBase()); startList.set(position,true); } }); holder.stop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { lastPause[0]=finalHolder.chronometer.getBase()-SystemClock.elapsedRealtime(); finalHolder.chronometer.stop(); finalHolder.start.setEnabled(true); finalHolder.stop.setEnabled(false); lastPauseList.set(position,lastPause[0]); startList.set(position,false); } }); holder.chronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() { @Override public void onChronometerTick(Chronometer chronometer) { elapsed.set(position, SystemClock.elapsedRealtime() - finalHolder.chronometer.getBase()); Log.d("myTag", "elapsedTime = " + getTime(elapsed.get(position)) + " position = " + position); } }); } return row; } String getTime(long time){ int hours = (int)(time/3600000); int minutes = (int)(time -hours*3600000)/60000; int seconds = (int)(time-hours*3600000-minutes*60000)/1000; String hour = (hours<9?"0"+hours:hours).toString(); String min = (minutes<9?"0"+minutes:minutes).toString(); String sec = (seconds<9?"0"+seconds:seconds).toString(); return ""+hour+":"+min+":"+sec; } class TrackHolder{ TextView name; Chronometer chronometer; Button start,stop; } } } 

Debug many times, after this line, let's say on element 2, we go into onTick and there, if you hover the cursor in debug-mode on position , it shows 0 element and writes elapsedTime . I removed the onTick method, but still the first element counts down the time.

 if(bundleIsItStart){ holder.stop.setEnabled(true); holder.start.setEnabled(false); holder.chronometer.setBase(base); --- после нее holder.chronometer.start(); } 
  • one
    This part of the code is not enough to understand the logic of work when turning, but apparently the position also needs to be saved in the bundle so that it survives the rotation, and is not initialized again when restarting the activation - pavlofff
  • it’s not at all clear how you handle state saving. - aratj
  • @pavlofff I added all the class code, it seems to me that there is no problem with saving the data, and I use lists, that is, I write the data into them on an equal position, then pull data from the correct list for the desired position - Dennis Zinkovsky
  • when you rotate the screen, the activation is destroyed and re-created. So, how do you recover timer data? - aratj
  • one
    For this task, it may be worthwhile to transfer the logic of the list to the fragment? Since here the work with the counters and the visual is not enough, setRetainInstance(true) is created just for such cases. - Silento

1 answer 1

Disable the re-creation of the activation in a coup. Perhaps the activation is recreated (if you have not disabled) and your code is called again.

 <activity android:name="Ваша активити" android:label="@string/app_name" android:configChanges="orientation|keyboardHidden|keyboard|screenSize" ... </activity> 
  • four
    Activity should be recreated, do not give bad advice - DeKaNszn
  • @DeKaNszn and why recreate the activity if we allow the application to work only in the landscape and uses only one size? This is not always bad advice. - Sergey
  • @ Sergey faced with devices like asus padfone? - DeKaNszn
  • There is no direct link, but in my Google console, these azuses are full and no one complained about the application with such a manifest. - Sergey