在片段中显示适当的 SQLite 数据(相同的条目出现在不同的选择条目中)

Posted

技术标签:

【中文标题】在片段中显示适当的 SQLite 数据(相同的条目出现在不同的选择条目中)【英文标题】:Display appropriate SQLite data in fragment (same entry is appearing for different chosen entry) 【发布时间】:2018-07-25 17:27:30 【问题描述】:

好的,我正在尝试在我的应用程序中进行搜索查询,这将允许用户在找到正确的杂货项目结果后将其添加到另一个数据结构(最终成为食谱)。我还没有处理的添加组件...

现在我选择了 Button btnaddToRecipe 来启动 new 活动 AddGroceryItemActivity 被用户点击后(参见 CustomAdapter 活动了解该代码)。

这个新活动将打开它的片段,其中将完成一些计算,当我开始处理它时,将创建/修改一个新的数据结构以允许用户添加该杂货项目到具有所需数量的项目的数据结构。

需要将有关杂货商品名称的数据以及 Grams-Cups 和 Cups-Grams 转换率(存储在我的数据库中)传递给这个新片段以进行计算(取决于用户将选择输入)。

(您可以在我的搜索查询代码中看到数据库列)

问题:

当我去选择任何搜索结果时,点击 btnaddToRecipe 我会在一个新活动(AddGroceryItemActivity,它承载 AddGroceryItemFragment)中打开 same 搜索结果,其中包含我的一个数据库条目 -这与我选择的错误匹配。这与我选择的 EVERY 选项相同。

所以我认为这与我的光标在 AddGroceryItemFragment 中的选项之间循环的方式有关。

或者是因为我没有将有关用户选择的搜索结果的正确数据传递给新活动。

要显示的片段类:

public class AddGroceryItemFragment extends Fragment 
private static final String TAG = "AddGroceryItemFragment";

private OnSaveClicked mSaveListener;
private AppDatabase dbHelper;

interface OnSaveClicked 
    void onSaveClicked();



@Override
public void onAttach(Context context) 
    super.onAttach(context);
    Log.d(TAG, "onAttach: starts");

    dbHelper = AppDatabase.getInstance(context);

    Activity activity = getActivity();
    if (!(activity instanceof OnSaveClicked)) 
        throw new ClassCastException(activity.getClass().getSimpleName()
                + " must implement AddGrocerItemFragment.OnSaveClicked interface");
    

    mSaveListener = (OnSaveClicked) activity;



@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
    Log.d(TAG, "onCreateView: starts");
    View view = inflater.inflate(R.layout.fragment_addgroceryitem, container, false);
    final ViewHolder holder = new ViewHolder();
    holder.mCalculate = (Button) view.findViewById(R.id.calculate);
    holder.mAddToList = (Button) view.findViewById(R.id.addToList);
    holder.mCupsToGrams = (TextView) view.findViewById(R.id.CupsToG);
    holder.mGramsToCups = (TextView) view.findViewById(R.id.gToCups);
    holder.name = (TextView) view.findViewById(R.id.name);
    holder.mQuantity = (EditText) view.findViewById(R.id.entry);

    SQLiteDatabase db = dbHelper.getReadableDatabase();
    String selectQuery = "SELECT rowid as " +
            GroceriesContract.Columns._ID + ", " +
            GroceriesContract.Columns.GROCERIES_NAME + ", " +
            GroceriesContract.Columns.GROCERIES_DESCRIPTION + ", " +
            GroceriesContract.Columns.GROCERIES_GRAMSTOCUPS + ", " +
            GroceriesContract.Columns.GROCERIES_CUPSTOGRAMS +
            " FROM " + GroceriesContract.TABLE_NAME;
    Cursor cursor = db.rawQuery(selectQuery, null);


    if (cursor.moveToFirst()) 
        do 
            holder.name.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns.GROCERIES_NAME)));
            holder.mGramsToCups.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns.GROCERIES_GRAMSTOCUPS)));
            holder.mCupsToGrams.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns.GROCERIES_GRAMSTOCUPS)));
         while (cursor.moveToNext());
    
        cursor.close();

 return view;



static class ViewHolder 
    TextView name;
    EditText mQuantity;
    Button mCalculate;
    Button mAddToList;
    TextView mGramsToCups;
    TextView mCupsToGrams;

片段的活动:

public class AddEditRecipeActivity extends AppCompatActivity implements AddEditRecipeActivityFragment.OnSaveClicked 

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_add_edit_recipe);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    AddEditRecipeActivityFragment fragment = new 
AddEditRecipeActivityFragment();
    Bundle arguments = getIntent().getExtras();
    fragment.setArguments(arguments);

    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction fragmentTransaction = 
fragmentManager.beginTransaction();
    fragmentTransaction.replace(R.id.fragment, fragment);
    fragmentTransaction.commit();


@Override
public void onSaveClicked() 
    finish();

您可以看到启动活动的按钮 - 是否需要从中拉出光标信息?

public class SearchActivity extends AppCompatActivity 
   private static final String TAG = "SearchActivity";

private Cursor mCursor;
private CustomAdapter mCustomAdapter;
private GroceriesContract mGroceriesContract;
ListView mListView;


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


    mGroceriesContract = new GroceriesContract(this);
    mCursor = mGroceriesContract.getGroceryList();
    mCustomAdapter = new CustomAdapter(SearchActivity.this, mCursor, 0);
    mListView = (ListView) findViewById(R.id.lstStudent);
    mListView.setAdapter(mCustomAdapter);



@Override
public boolean onCreateOptionsMenu(Menu menu) 

    getMenuInflater().inflate(R.menu.options_menu, menu);
    SearchManager manager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
    SearchView search = (SearchView) menu.findItem(R.id.search).getActionView();
    search.setSearchableInfo(manager.getSearchableInfo(getComponentName()));

    getSupportActionBar().setDisplayShowTitleEnabled(false);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);


    search.setOnQueryTextListener(new SearchView.OnQueryTextListener() 
        @Override
        public boolean onQueryTextSubmit(String query) 
            Log.d(TAG, "onQueryTextSubmit: on");
            mCursor = mGroceriesContract.getGroceryName(query);
            if (mCursor == null) 
                Toast.makeText(SearchActivity.this, "No records found", Toast.LENGTH_SHORT).show();
             else 
                Toast.makeText(SearchActivity.this, mCursor.getCount() + " records found!", Toast.LENGTH_SHORT).show();
            

            mCustomAdapter.swapCursor(mCursor);

            return false;

        

        @Override
        public boolean onQueryTextChange(String newText) 
            Log.d(TAG, "onQueryTextChange: ");
            mCursor = mGroceriesContract.getGroceryName(newText);
            if (mCursor != null) 
                mCustomAdapter.swapCursor(mCursor);
            
            return false;
        
    );


    return true;



@Override
protected void onResume() 
    super.onResume();
 

我想知道这个问题是否实际上是由于没有从启动此活动的活动传递数据,然后导致启动 AddGroceryItemFragment

这个初始类扩展了 CursorAdapter:

public class CustomAdapter extends CursorAdapter 
TextView txtId,txtName, txtDescription;
private LayoutInflater mInflater;
private Context mContext;

public CustomAdapter(Context context, Cursor c, int flags) 
    super(context, c, flags);
    mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);



@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) 
    View view    =    mInflater.inflate(R.layout.item, parent, false);
    ViewHolder holder  =   new ViewHolder();
    holder.txtId    =   (TextView)  view.findViewById(R.id.txtId);
    holder.txtName    =   (TextView)  view.findViewById(R.id.txtName);
    holder.txtDescription =   (TextView)  view.findViewById(R.id.txtEmail);
    holder.btnaddToRecipe = (Button) view.findViewById(R.id.add);
    view.setTag(holder);


    return view;


@Override
public void bindView(View view, final Context context, final Cursor cursor) 

    ViewHolder holder  =   (ViewHolder)    view.getTag();
    holder.txtId.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns._ID)));
    holder.txtName.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns.GROCERIES_NAME)));
    holder.txtDescription.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns.GROCERIES_DESCRIPTION)));

    holder.btnaddToRecipe.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View view) 
            Intent intent = new Intent(context, AddGroceryItemActivity.class);
            context.startActivity(intent);
        
    );



static class ViewHolder 
    TextView txtId;
    TextView txtName;
    TextView txtDescription;
    Button btnaddToRecipe;
 

新编辑: 感谢您的回复 MikeT。

您写的内容在传递数据方面是有意义的,但是我每次仍然得到相同的结果。我在您编写查询时更改了查询,并在意图上添加了 putExtra()。然后,我检索您在片段中编写的 id,创建一个包对象,将字符串放入包中并使用 setArguments 方法将其添加到包中。我执行事务等并启动片段。然后从片段中,我创建了一个新字符串并调用 getArguments().getString("id")。将 whereargs 设置为新字符串并按照您所说的编写查询。

我认为这与我的光标代码的编写方式有关。我意识到 mCupsToGrams 上有一个错字 - 应该是 GROCERIES_CUPSTOGRAMS。但这与问题无关。

当我记录在我的 onClick 方法中传递的数据时,无论我按什么按钮,都会传递相同的光标。我认为这是因为我必须将光标标记为 final 才能从匿名类访问它。那有意义吗?

【问题讨论】:

【参考方案1】:

看来AddGroceryItemFragment 会按照以下方式从表中提取由所有行组成的游标:-

SQLiteDatabase db = dbHelper.getReadableDatabase();
String selectQuery = "SELECT rowid as " +
        GroceriesContract.Columns._ID + ", " +
        GroceriesContract.Columns.GROCERIES_NAME + ", " +
        GroceriesContract.Columns.GROCERIES_DESCRIPTION + ", " +
        GroceriesContract.Columns.GROCERIES_GRAMSTOCUPS + ", " +
        GroceriesContract.Columns.GROCERIES_CUPSTOGRAMS +
        " FROM " + GroceriesContract.TABLE_NAME;
Cursor cursor = db.rawQuery(selectQuery, null);

然后它继续循环遍历每个提取的行,设置要显示的文本,从而最终显示最后提取的行的数据。

我相信您需要在查询中使用WHERE 子句,以便它可以选择适当的杂货项目,而不是最后提取的(可能是任何)杂货项目。

查询可能是:-

String[] columns = new String[]
    "rowid AS " +
        GroceriesContract.Columns._ID,
    GroceriesContract.Columns.GROCERIES_NAME,
    GroceriesContract.Columns.GROCERIES_DESCRIPTION,
    GroceriesContract.Columns.GROCERIES_GRAMSTOCUPS,
    GroceriesContract.Columns.GROCERIES_CUPSTOGRAMS
;
String whereclause = GroceriesContract.Columns._ID + "=?";
String[] whereargs = new String[]the_id_passed_to_the_fragment;
Cursor cursor =db.query(GroceriesContract.TABLE_NAME,columns,whereclause,whereargs,null,null,null);
注意事项 这使用首选的query 方法,而不是rawQuery query 变量 the_id_passed_to_the_fragment 顾名思义,正如您所说的那样,或者是因为我没有将有关用户选择的搜索结果的正确数据传递给新活动。和或我想知道这个问题是否实际上是由于没有从启动这个活动的活动传递数据,然后导致启动 AddGroceryItemFragment

你会跟随这个:-

if (cursor.moveToFirst()) 
    holder.name.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns.GROCERIES_NAME)));
    holder.mGramsToCups.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns.GROCERIES_GRAMSTOCUPS)));
    holder.mCupsToGrams.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns.GROCERIES_GRAMSTOCUPS)));

else 
    //... do something just in case Grocery Item wasn't found here.

cursor.close();

我相信您会通过沿以下行添加额外的意图来传递凝视活动的 id(请参阅已添加的 1 行):-

@Override
public void bindView(View view, final Context context, final Cursor cursor) 

    ViewHolder holder  =   (ViewHolder)    view.getTag();
    holder.txtId.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns._ID)));
    holder.txtName.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns.GROCERIES_NAME)));
    holder.txtDescription.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns.GROCERIES_DESCRIPTION)));

    holder.btnaddToRecipe.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View view) 
            Intent intent = new Intent(context, AddGroceryItemActivity.class);
            intent.putExtra("GROCERYITEMID",cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns._ID))); //<<<< ADDED
            context.startActivity(intent);
        
    );

您可以在已启动的活动中使用 :-

检索此内容
 String retrieved_id = getIntent().getStringExtra(
            "GROCERYITEMID");

然后,您需要将 retrieved_id 作为 the_id_passed_to_the_fragment 提供给片段。

关于评论:-

当我记录在我的 onClick 方法中传递的数据时,相同的光标是 无论我按什么按钮,都会通过。我想这是因为我 必须将光标标记为最终才能从匿名访问它 班级。这有意义吗?

您不必将cursor 标记为final,而是使用类似:-

@Override
public void bindView(View view, Context context, Cursor cursor) 

    ViewHolder holder  =   (ViewHolder)    view.getTag();
    holder.txtId.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns._ID)));
    holder.txtName.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns.GROCERIES_NAME)));
    holder.txtDescription.setText(cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns.GROCERIES_DESCRIPTION)));
    final String id_to pass = cursor.getString(cursor.getColumnIndex(GroceriesContract.Columns._ID));

    holder.btnaddToRecipe.setOnClickListener(new View.OnClickListener() 
        @Override
        public void onClick(View view) 
            Intent intent = new Intent(context, AddGroceryItemActivity.class);
            intent.putExtra("GROCERYITEMID",id_to pass); //<<<< ADDED
            context.startActivity(intent);
        
    );

【讨论】:

感谢您的回复。您写的内容在传递数据方面是有意义的,但是我仍然得到相同的结果。我在您编写查询时更改了查询,并在意图上添加了 putExtra()。然后,我检索您在片段中编写的 id,创建一个包对象,将字符串放入包中并使用 setArguments 方法将其添加到包中。我执行事务等并启动片段。然后从片段 @JCG 太好了。非常感谢您在已回答的问题上打勾。 抱歉,新手!我按了一个,但没有意识到有一个滴答声。再次感谢!

以上是关于在片段中显示适当的 SQLite 数据(相同的条目出现在不同的选择条目中)的主要内容,如果未能解决你的问题,请参考以下文章

如何在片段内的 recylerview 列表中显示 SQLite 数据库数据?

如何在片段类的列表视图中显示 SQLite 数据库?

如何使用光标和循环显示来自 sqlite 的片段的 recyclerview

如果 SQLite 为空或有记录,则更改片段中的视图

当sqlite android片段中的数据更改或删除时如何刷新recyclerview?

如何将 SQLite 数据库与片段结合起来?