2017-02-12 20 views
0

Пожалуйста, не стесняйтесь пропустить вопрос, так как это понимание фона может не понадобиться для вас.Невозможно удалить страницы при использовании FragmentStatePagerAdapter. Каково обычное поведение идентификаторов строк при использовании целочисленного первичного ключа?

Я новичок в android и sqlite, и я разрабатываю приложение, у которого есть поставщик контента для доступа к базе данных sqlite с несколькими таблицами. Существует несколько действий, которые используют разные адаптеры для отображения информации из базы данных в пользовательский интерфейс (например, адаптеры курсора, адаптер страницы состояния фрагмента и адаптеры массивов). У меня возникли проблемы с функцией удаления во всех моих действиях, которые не используют адаптер курсора. Когда я пытаюсь обновить или удалить строку из таблицы, она удалит неправильную строку или вообще ничего не удалит. Я считаю, что это проблема с адаптером, где я пытаюсь выяснить, какая строка предназначена для отправки правильной информации поставщику контента.

Идентичный код Java отлично работает с адаптером курсора, а строки удаляются нормально, а другие операции CRUD работают. Функции вставки и запроса работают нормально для всех таблиц. Код провайдера использует оператор switch для каждой таблицы, но он в основном идентичен для каждого случая Uri. Все таблицы имеют _id как целочисленный первичный ключ, который НЕ установлен для автоматического увеличения. Поскольку я не совсем понимаю, как работает идентификатор строки, мой код Java не отражает его, и у меня все эти проблемы. Хотя я прочитал много документов о контент-провайдерах, адаптерах, базах данных sqlite и т. Д., Некоторые ключевые данные мне не понятны.

Мой вопрос: Как идентификатор строки получает присвоенные номера в базе данных, когда в качестве первичного ключа установлен столбец _id, и что происходит с этими числами при изменении базы данных?

Например, у меня есть пустая база данных. Изначально после вставки первой строки Uri вернет сегмент пути для строки 0, а позиция адаптера будет равна 0 ..., каков будет идентификатор строки для базы данных (0 или 1)?

Затем для каждой строки, которую я вставляю, я знаю, что число строк увеличится на одно целое число. Скажем, я вставляю 4 строки - 0,1,2,3. Теперь, когда я готов удалить - должен ли последний сегмент пути на Uri быть одним целым числом меньше числа строк (например, я отправляю Uri с последним сегментом пути 2 для удаления строки 3)? Наконец, после удаления, идентификаторы строк затем автоматически будут переназначены так, что строка 4 теперь станет третьей строкой? Есть ли какой-то код, который мне нужно написать, чтобы это произошло в базе данных? Первичные ключи не настроены на автоматическое увеличение.

У меня есть разные адаптеры и действия, где я не могу получить доступ к фактическому идентификатору строки базы данных после отображения данных в пользовательском интерфейсе, поэтому я использую позицию адаптера в качестве суррогата. Вот почему у меня возникают проблемы с обновлением и удалением. Большое спасибо, если вы прочитали весь этот вопрос и нашли время ответить на него, это очень помогло бы мне.

У меня есть активность, которая имеет вкладку и использует FragmentStatePagerAdapter, который заполняется базой данных. Вот адаптер, который я настроил, чтобы следить за строками:

**EDITED:** 

    public class TankSectionsPagerAdapter extends FragmentStatePagerAdapter { 

private ArrayList<Fragment> tankFragments = new ArrayList<>(); 
private ArrayList<String> tankTitles = new ArrayList<>(); 

//I added this ArrayList below to store the tankIDs to match the Fragments// 

**public ArrayList<Integer> tankIDs = new ArrayList<>();** 



public TankSectionsPagerAdapter(FragmentManager fm) { 
    super(fm); 
} 


@Override 
public Fragment getItem(int position) { 

    return tankFragments.get(position); 
} 


@Override 
public int getCount() { 
    return tankFragments.size(); 
} 


@Override 
public String getPageTitle(int position) { 

    return tankTitles.get(position); 
} 


public void addPage(Fragment fragment, String tankName) { 

    tankFragments.add(fragment); 
    tankTitles.add(tankName); 

    // I added this below so the ID position would match each fragment position // 

    **tankIDs.add(tankId);** 

    notifyDataSetChanged(); 
} 
// Finally I added this method below to the adapter// 

    ** public ArrayList<Integer> getPageId(){ 
    return tankIDs; 
    }** 

Вот активность, где вызывается метод и где он вытаскивает данные из курсора для перехода к адаптеру. Существует цикл, где каждая строка создает (вкладка) страницы в ViewPager:

public class MyClass extends Tank implements TabLayout.OnTabSelectedListener, LoaderManager.LoaderCallbacks<Cursor> { 

public TankSectionsPagerAdapter tankSectionsPagerAdapter; 

TabLayout tabLayout; 

private ViewPager mViewPager; 
... 

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


    mViewPager = (ViewPager) findViewById(R.id.container); 

    addPages(mViewPager); 

    tabLayout = (TabLayout) findViewById(R.id.tabLayout); 
    tabLayout.setupWithViewPager(mViewPager); 
    tabLayout.addOnTabSelectedListener(this); 

} 


    public void addPages(ViewPager mViewPager) { 

           tankSectionsPagerAdapter = new TankSectionsPagerAdapter(getSupportFragmentManager()); 

    mViewPager.setAdapter(tankSectionsPagerAdapter) 

     try { 
    ... 
           Cursor cursor = getContentResolver().query(MyProvider.CONTENT_URI_TABLE_TANK_SETUP, MyDatabaseHelper.ALL_TABLE_TANK_SETUP_COLUMNS, tankDataFilter, null, null); 

          if (cursor.moveToFirst()) { 
           do { 

    tName =  cursor.getString(cursor.getColumnIndex(MyDatabaseHelper.TANK_NAME));    ... 

    // all the variables are stored in the bundle passed to the fragment/ 
                                      ...     

                   **tankSectionsPagerAdapter.addPage(MainTankFragment.newInstance(tankBundle),tName, int tankID);** 

    tankDataFilter = tankDataFilter + (-1); 
           } 
           while (cursor.moveToNext()); 
           cursor.close(); 
          } else { 
           Toast... 
          } 
     } catch (Exception e) { 

     Toast.. 
    } 
     } 

    ... 

    // Get Row ID from cursor(tankID), parameter in addPage() above// 



//Get ID's from Adapter // 

    ** ArrayList <Integer> pageID= tankSectionsPagerAdapter.getPageId();** 

Это активность с Spinner, чтобы выбрать строки/фрагменты для редактирования или удаления.

public class EditTank extends Tank implements LoaderManager.LoaderCallbacks<Cursor> 
    ... 


// Get the ArrayList// 

    ArrayList<Integer> IDtags =getIDIntent.getIntegerArrayListExtra("tank_edit_key"); 

    loadEditTankSpinnerData(); 


////***Here is the Spinner. Use row ID from the ArrayList****** 
      Note: Don't use the id of the spinner 


     editTankSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 
     @Override 
     public void onItemSelected(AdapterView<?> parent, View view int position, long id) { 


    *** tankID = IDtags.get(position); ***   

     } 




    private void loadEditTankSpinnerData() { 

    List<String> tankNames = new ArrayList<String>(); 

     Cursor cursor = getContentResolver().query(MyProvider.CONTENT_URI_TABLE_TANK_SETUP, MyDatabaseHelper.TANK_NAMES, null, null,null); 
    try{ 
     if (cursor.moveToFirst()) { 
      do { 
       tankNames.add(cursor.getString(1)); 
      } while (cursor.moveToNext()); 
      cursor.close(); 
     } else { 
      deleteTankBtn.setEnabled(false); 
      editTankBtn.setEnabled(false); 
      Toast... 
     } 

    } catch (Exception e) { 
     Toast... 
    } 


... 
} 

Приведенный выше код работает хорошо с CursorAdapter, но не с fragmentStatePagerAdapter (*** До правок он не работал, теперь он работает хорошо и удаляет правильно).

Я потратил дни (недели) на это, потому что я не понимал, почему строки не удаляются. Я надеюсь, что это помогает кому-то.

+0

Вы видели последний параметр метода OnItemClickListener # onItemClick? – pskink

+0

Да, я понимаю, что вы имеете в виду, последний параметр - id. Однако у меня есть некоторые действия, которые не используют onItemClick напрямую. Например, у меня есть активность с вкладками, которая использует адаптер пейджера состояния фрагмента для добавления фрагментов на основе цикла вытягивания курсора из базы данных. Я использую счетчик, чтобы указать, какой фрагмент выбирается на основе имени вкладки (я не понял, как получить идентификатор из вкладки непосредственно наTabSelected). Однако, когда элемент выбран и идентификатор извлекается из счетчика, он не приводит к удалению правильной строки в базе данных. – GreenTea

+0

Когда столбец «INTEGER PRIMARY KEY», он всегда автоинкремент. И вы не должны использовать позицию в списке, это не будет работать с фильтрованным/отсортированным списком. –

ответ

0

Благодаря @pskink, @CL и @albeee - это то, что я узнал от вас, ребята и мои собственные исследования.

Чтобы удалить строки из базы данных, которая заполняет FragmentStatePagerAdapter или ArrayAdapter, вы должны уметь связывать правильную строку с тем, что отображается в адаптере. В противном случае строки не будут удалены или будут непоследовательными или неправильными. CursorAdapter автоматически обработает просмотр изменений и выбор идентификатора для вас. Если вы можете использовать CursorAdapter или direct onItemClickListener и получить идентификатор непосредственно из AdapterView с помощью getSelectedId() или просто длинного идентификатора, то это хороший способ получить идентификатор строки. Однако, если вы получаете идентификатор косвенно другими способами, тогда вам нужно обращаться с ассоциациями ...

1. Вы не должны использовать положение адаптера, положение поворотного устройства или даже идентификатор прядильника, чтобы выбрать строку. Они полезны только для определения того, какой элемент/фрагмент вы хотите. Только идентификатор OnClickListener на самом элементе будет последовательно давать правильную строку.

2. Строки базы данных ведут себя как таковые - целочисленный первичный ключ будет автоматически увеличиваться, даже если AUTOINCREMENT не выбран, но идентификаторы строк стабильны после назначения. Это означает, что каждая новая строка будет иметь более высокий идентификатор, чем последний, но если вы удалите строки между ними, это не изменит идентификаторы оставшихся строк. Таким образом, строки будут пропускаться и не быть последовательными, когда есть изменения и удаления. По этой причине у вас должен быть метод привязки элемента к идентификатору навсегда. Там может быть лучший способ сделать это, однако я отредактирую код выше, чтобы показать один способ, которым я смог это сделать для FragmentStatePagerAdapter, чтобы пользователь мог добавлять и удалять фрагменты динамически.

0

Word of advise - попробуйте написать свой вопрос как можно проще и в коде. Здесь вы не должны делиться слишком большим количеством кода. Люди просто проигнорируют.

  1. Вы используете CursorLoader, но не используете его должным образом. Используйте данные курсора метода LoadFinished.

  2. Затем вы можете напрямую передать курсор на ваш FragmentPageAdapter и использовать его прямо там.

Надеюсь, это поможет.

+0

Большое спасибо. Я еще больше сокращу свой код. : ') Я прочитал документы для OnLoad Finished, но я не понимаю, как это может помочь мне в удалении строки. Теперь я лучше понимаю, как ведут себя строки, и я считаю, что это поможет мне решить проблемы. – GreenTea