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

Display appropriate SQLite data in fragment (same entry is appearing for different chosen entry)

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

现在我选择了按钮 btnaddToRecipe 来启动 new activity AddGroceryItemActivity 被用户点击后(请参阅 CustomAdapter activity 了解该代码)。

这个新的 activity 将打开其 片段 ,其中将进行一些计算,当我开始使用它时,一个新的数据结构将是 created/modified 以允许用户将该杂货项目添加到具有所需项目数量的数据结构中。

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

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

问题:

当我转到 select 任何搜索结果时,点击 btnaddToRecipe 我会在新的 activity 中打开 same 搜索结果( AddGroceryItemActivity,它承载 AddGroceryItemFragment) 和我的数据库条目之一——它与我选择的条目不正确地匹配。这与我选择的 EVERY 选项相同。

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

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

要显示的片段class:

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();
}

}

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

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();
 }
}

我想知道这个问题是否真的是由于没有从 activity 传递数据而导致的 activity 然后导致启动 AddGroceryItemFragment

这个初始 class 扩展了 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,创建一个 bundle 对象,将字符串放入 bundle 中并使用 setArguments 方法将其添加到 bundle 中。我执行事务等并启动片段。然后从片段中,我创建了一个新字符串并调用了 getArguments().getString("id")。将 whereargs 设置为新字符串并按照您所说的编写查询。

我认为这是我的游标代码的编写方式。我发现 mCupsToGrams 上有错字——应该是 GROCERIES_CUPSTOGRAMS。但这与问题无关。

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

AddGroceryItemFragment 似乎从 table 中提取了一个由所有行组成的 Cursor,按照 :-

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 子句,以便它可以 select 适当的杂货项目而不是最后提取的(可能是任何)杂货项目。

查询可以是:-

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 顾名思义,正如您所说 或者是因为我没有传递正确的数据用户选择了哪个搜索结果,到新的activity.和/或我想知道这个问题是否真的是没有从activity传递数据的结果启动此 activity 然后导致启动 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();

我相信您会通过添加额外的意图(请参阅已添加的 1 行)来传递凝视 activity 中的 ID: -

@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);
        }
    });
}

您在开始的 activity 中使用 :-

检索它
 String retrieved_id = getIntent().getStringExtra(
            "GROCERYITEMID");

然后您需要使 retrieved_id 可用于片段,如 the_id_passed_to_the_fragment.

关于评论:-

When I logd the data passed in my onClick method, the same cursor is being passed no matter what button I press. I think this is because I have to mark cursor as final in order to access it from the anonymous class. Does that make sense?

您不必将 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);
        }
    });
}