2017-02-12 33 views
0

請隨意跳到了一個問題,這樣的背景下理解可能沒有必要爲您服務。使用FragmentStatePagerAdapter時無法刪除頁面 - 使用整數主鍵時,行ID的常見行爲是什麼?

我是新來的android和sqlite,我正在設計一個應用程序,它有一個內容提供者訪問一個sqlite數據庫與多個表。有幾種活動使用不同的適配器來顯示從數據庫到UI的信息(即遊標適配器,分段狀態頁面適配器和陣列適配器)。我一直在使用不使用遊標適配器的所有活動中的刪除功能問題。當我嘗試從表中更新或刪除一行時,它會刪除錯誤的行,或者根本不刪除任何內容。我相信這是適配器的問題,我試圖找出將哪個行發送給內容提供商的正確信息。

相同的Java代碼工作完全用光標適配器和行正常刪除和其他CRUD操作工作。插入和查詢函數對所有表都正常工作。提供程序代碼爲每個表使用switch語句,但對於每個Uri情況,它基本相同。所有表都有_id作爲未設置爲自動增量的整數主鍵。由於我不完全理解行號是如何工作的,所以我的java代碼沒有反映出來,而且我一直都有這些問題。儘管我已經閱讀了許多關於內容提供者,適配器,sqlite數據庫等的文檔,但某些關鍵細節並不清楚。

我的問題是當數據庫設置爲_id列作爲主鍵時,行ID如何獲取數據庫中的分配號碼,以及數據庫更改時會發生什麼?

例如,說我有一個空數據庫。最初插入第一行後,Uri將返回0行的路徑段,並且適配器位置將爲0 ...數據庫的行ID爲(0或1)是什麼?

然後爲每一行我插入,我知道,行號會被一個整數增加。說我插入4行 - 0,1,2,3。現在,當我準備刪除 - 應該對URI的最後一個路徑段是一個整數比的行數(即我送一個URI爲2的最後路徑段刪除第3行)少了?最後,在刪除之後,行ID會自動重新分配,以便第4行現在變成第3行?是否有一些代碼需要編寫才能在數據庫中實現?主鍵未設置爲自動增量。

我有不同的適配器和活動的地方一旦數據被顯示在UI我無法訪問實際的數據庫行ID,所以我使用的適配器位置作爲替代。這就是爲什麼我在更新和刪除時遇到問題。 非常感謝您閱讀完整個問題並花時間回答問題,這對我非常有幫助。

我有一個選項卡式的活動,並使用由數據庫填充的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();** 

這是微調活動來選擇行/片段進行編輯或刪除。

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。例如,我有一個選項卡式活動,它使用片段狀態尋呼機適配器根據從數據庫拉出的光標循環添加片段。我使用微調來指示選擇哪個片段基於選項卡名稱(我還沒有想過如何直接從onTabSelected獲得標籤中的id)。但是,當選擇該項目並從微調器中檢索標識時,它不會導致刪除數據庫中的正確行。 – GreenTea

+0

當該列是「INTEGER PRIMARY KEY」時,它總是自動增量。而且你不能使用列表中的位置,這對於過濾/排序列表不起作用。 –

回答

0

感謝@pskink,@CL和@albeee--這是我從你們和我自己的研究中學到的。

爲了從填充FragmentStatePagerAdapter或ArrayAdapter的數據庫中刪除行,您必須能夠將正確的行與適配器中顯示的內容鏈接起來。否則,行將不會刪除,或者會不一致或不正確。 CursorAdapter將自動處理觀察變更併爲您選擇ID。如果您可以使用CursorAdapter或直接onItemClickListener,並使用getSelectedId()直接從AdapterView獲取id或僅獲取長ID,那麼獲取行ID是一種好方法。但是,如果您通過其他方式間接獲取ID,則必須處理關聯...

1. 您不應使用適配器位置,微調器位置或甚至微調器ID來選擇該行。這些僅用於確定您想要的項目/片段。只有項目本身上的OnClickListener的ID將始終如一地給出正確的行。

2. 數據庫行的行爲如此 - 即使未選擇AUTOINCREMENT,整數主鍵也會自動遞增,但行ID一旦分配後就是穩定的。這意味着每個新行的ID都會比最後一個ID更高,但是如果刪除其中的行,它將不會更改剩餘行的ID。所以當編輯和刪除時,行會跳過並且不連續。出於這個原因,你必須有一種方法將項目永久鏈接到ID。可能有更好的方法來做到這一點,但是,我將編輯上面的代碼,以顯示我能夠爲FragmentStatePagerAdapter執行此操作的一種方式,以便用戶可以動態添加和刪除片段。

0

建議的話 - 儘量寫出你的問題儘可能簡單的代碼。你不應該在這裏分享太多的代碼。人們會忽略。

  1. 您正在使用CursorLoader,但沒有正確使用它。使用LoadFinished方法的遊標數據。

  2. 然後你可以直接將光標傳遞給你的FragmentPageAdapter並直接在那裏使用它。

希望這會有所幫助。

+0

非常感謝。我會更多地縮短我的代碼。 :')我閱讀了OnLoad Finished的文檔,但我不明白它如何幫助我刪除該行。我現在更瞭解行id如何行爲,我相信這會幫助我解決問題。 – GreenTea

相關問題