2017-02-12 35 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

相关问题