Listview с таймерами, поворот экрана. Нереальная задача.

Интерфейс, диалоги, темы, стили, меню
Ответить
Dandewine
Сообщения: 2
Зарегистрирован: 22 апр 2015, 21:52

Listview с таймерами, поворот экрана. Нереальная задача.

Сообщение Dandewine » 22 апр 2015, 22:39

Здравствуйте, столкнулся с проблемой с которой думал справится за вечер и сижу уже пол месяца. Задача - написать listview c таймером в каждом item listview, есть две кнопки Старт и Стоп, основная цель это возможность запуска >2 таймеров и после n поворотов сохранять стабильность их работы. Я уже кучу раз все переписывал, использовал 2 способа.

1 - через chronometer, лепил его в каждый item listview данные сохранялись хорошо, в onSaved и onRestore не было проблем, но после поворота экрана запускался первый элемент, и chronometer начинал лже-отсчет и брал время равное таймеру который внизу, визуально циферки тикают, но его данные никуда не заносятся.

2 - через интерфейс Runnable в связке с Handler, проблема почти та же, только в этот раз я использовал congifChanges="oriantation|screen" и оно теперь последнему элементу присваивает лже-время, которое берет с другого активного таймера.

В обоих случаях я писал свой адаптер, и я уверен что ошибка в его логике, т.к. это единственное общее между этими двумя разными приложениями. Сейчас мне кажется, что это просто нереальная задача, и я зашел в тупик и прошу помочь знающих людей.
Привожу весь код класса его много, но адаптер маленький,он - внутренний класс. Я там добавил комментарии.

Результат выполнения программы.
Нажали старт
Изображение
Перевернули отсчитало и нажали Стоп.
Изображение

Код: Выделить всё

 public class MainActivity extends FragmentActivity implements android.support.v4.app.LoaderManager.LoaderCallbacks<Cursor>,View.OnClickListener{
    MyAdapter adapter;
    ListView listview;
    Handler handler;
    DBHelper dbHelper;
    SQLiteDatabase db;
    List<Tracker> trackerList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        handler = new Handler();
        dbHelper = new DBHelper(this);
        db=dbHelper.getWritableDatabase();
        trackerList = Tracker.getListAll(db);

        String[] from = {Tracker.COL_NAME,Tracker.COL_ELAPSED_TIME,Tracker.COL_ELAPSED_TIME,Tracker.COL_ELAPSED_TIME,Tracker.COL_ELAPSED_TIME};
        int[] to = {R.id.tvName,R.id.tvDays,R.id.tvHours,R.id.tvMinutes,R.id.tvSeconds};
        listview = (ListView)findViewById(R.id.listView);
        adapter = new MyAdapter(this,R.layout.row,Tracker.getAll(db),from,to,0);
        listview.setAdapter(adapter);
        getSupportLoaderManager().initLoader(1, null, this);
        Log.d("myLog","onCreate");
    }

    @Override
    public void onClick(View v) {

    }

    @Override
    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
        Log.d("myTag","onCreateLoader");
        return new MyLoader(this,db);

    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        Log.d("myTag","onFinishLoader");
        adapter.swapCursor(cursor);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {

    }
   static class MyLoader extends CursorLoader{

        SQLiteDatabase db;
        MyLoader(Context context,SQLiteDatabase db){
            super(context);
            this.db=db;
        }

        @Override
        public Cursor loadInBackground() {
            Log.d("myTag","loadInBackground");
            return Tracker.getAll(db);
        }
    }


    class MyAdapter extends SimpleCursorAdapter{
        Context context;
        MyAdapter(Context context,int resourceID,Cursor cursor,String[] from,int[] to,int flag){
            super(context, resourceID,cursor,from,to,flag);
            this.context=context;
        }
        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            View row = convertView;
           final Tracker tracker = trackerList.get(position);
            final ViewHolder holder;
            if(row == null){
                holder = new ViewHolder();
                LayoutInflater inflater = ((Activity)context).getLayoutInflater();
                row = inflater.inflate(R.layout.row,parent,false);
                holder.name = (TextView)row.findViewById(R.id.tvName);
                holder.days = (TextView)row.findViewById(R.id.tvDays);
                holder.hours = (TextView)row.findViewById(R.id.tvHours);
                holder.minutes = (TextView)row.findViewById(R.id.tvMinutes);
                holder.seconds = (TextView)row.findViewById(R.id.tvSeconds);
                holder.start = (Button)row.findViewById(R.id.btStart);
                holder.stop = (Button)row.findViewById(R.id.btStop);
                row.setTag(holder);
            }else{
                holder = (ViewHolder)row.getTag();
            }
            holder.start.setEnabled(true);
            holder.stop.setEnabled(false);
            holder.name.setText(tracker.getName());
            final Runnable updateTimeThread = new Runnable() {
                @Override
                public void run() {
                    if (tracker.getIsStart()) {
                        tracker.setUpdateTime((System.currentTimeMillis() - tracker.getStartTime()) + tracker.getLastPause());
                        tracker.setSeconds(tracker.getUpdateTime() / 1000);
                        tracker.setMinutes(tracker.getSeconds() / 60);
                        tracker.setHours(tracker.getMinutes() / 60);

                        tracker.setSeconds(tracker.getSeconds() % 60);
                        tracker.setMinutes(tracker.getMinutes() % 60);
                        tracker.setHours(tracker.getHours() % 24);

                        holder.days.setText(String.format("%04d", tracker.getDays()));
                        holder.hours.setText(String.format("%02d", tracker.getHours()));
                        holder.minutes.setText(String.format("%02d", tracker.getMinutes()));
                        holder.seconds.setText(String.format("%02d", tracker.getSeconds()));

                        handler.post(this);
                    }
                    else{
                        handler.removeCallbacks(this);
                    }
                }
            };
            if(tracker.getIsStart()){
                holder.start.setEnabled(false);
                holder.stop.setEnabled(true);
            }
            View.OnClickListener onClickListener = new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    switch (v.getId()) {
                        case R.id.btStart:
                            tracker.setStartTime(System.currentTimeMillis());
                            tracker.setIsStart(true);

                            handler.post(updateTimeThread);
                            holder.start.setEnabled(false);
                            holder.stop.setEnabled(true);

                            Log.d("myTag", "onClickStart");
                            break;
                        case R.id.btStop:
                            tracker.setLastPause(tracker.getUpdateTime());
                            handler.removeCallbacks(updateTimeThread);
                            holder.stop.setEnabled(false);
                            holder.start.setEnabled(true);
                            tracker.setIsStart(false);
                            break;
                    }
                }
            };
            holder.start.setOnClickListener(onClickListener);
            holder.stop.setOnClickListener(onClickListener);
            return row;
        }
        class ViewHolder{
            TextView  name,days,hours,minutes,seconds;
            Button start,stop;
        }
    }


}

UPDATE

Проблема не в адаптере, создал тот же адаптер только в без Loader'a все работает хорошо, только адаптер наследовался не от SimpleCursorAdapter а от BaseAdapter. Проблема стала заключаться в отсутствии отображения изменения данных в последнем элементе списка после поворота. То есть, если в портретном нажмем Старт и повернем экран, программно он будет считать но не отображать, если вернемся на портрет он будет показывать отсчет.

Ответить