FragmentPagerAdapter 第一个 Tab 显示错误数据
FragmetPagerAdapter first Tab showing wrong data
我正在尝试使用基于 Cursor
的动态创建的选项卡实现 FragmentPagerAdapter
,它从 SQLite 数据库列中检索不同的值。
然后 ListFragment
基于第二个 Cursor
加载数据,即 selects 数据,并使用基于选项卡名称的过滤器。
最后我添加了一个选项卡来包含 "All" 数据,而不是一个子集。
除了将正确的数据输入第一个 "All" sheet 之外,一切正常。 ListFragment onCreateLoader
永远不会达到 select "All" 并根据第二个选项卡的名称以某种方式在第一个和第二个选项卡中提取数据。
My code (filtered for relevance; hopefully not too much)
MainActivity
public class MainActivity extends AppCompatActivity {
// arraylist of tabs in which tab details are stored
private ArrayList<String> tabNames;
// to hold tabs data when first fetch from sqlite db
private Cursor tabCursor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(com.simsolec.flavorsaver.R.layout.activity_main);
getTabs();
// Create an adapter that knows which fragment should be shown on each page
FlavorFragmentPagerAdapter adapter = new FlavorFragmentPagerAdapter(
getSupportFragmentManager(), MainActivity.this, tabNames);
// Find the view pager that will allow the user to swipe between fragments
ViewPager mViewPager = findViewById(com.simsolec.flavorsaver.R.id.viewpager);
// Set the adapter onto the view pager
mViewPager.setAdapter(adapter);
// Give the TabLayout the ViewPager
TabLayout tabLayout = findViewById(com.simsolec.flavorsaver.R.id.sliding_tabs);
tabLayout.setupWithViewPager(mViewPager);
}
private void getTabs( ){
try{
String[] Projection = { FlavorEntry.COLUMN_FLAVOR_RANGE };
tabCursor = getContentResolver().query(
FlavorEntry.CONTENT_URI_DISTINCT,
Projection,
null,
null,
FlavorEntry.COLUMN_FLAVOR_RANGE );
tabNames = new ArrayList();
tabNames.add("All");
if (tabCursor != null && tabCursor.getCount() > 0) {
if(tabCursor.moveToFirst()) {
do{
String tabName;
tabName = tabCursor.getString(0);
tabNames.add(tabName);
}while (tabCursor.moveToNext());
}
tabCursor.close();
}
}catch (NullPointerException | SQLException e) {
}
finally {
tabCursor.close();
}
}
}
FragmentPagerAdapter
public class FlavorFragmentPagerAdapter extends FragmentPagerAdapter {
private Context context;
private ArrayList<String> mTabNames;
public FlavorFragmentPagerAdapter(FragmentManager fm, Context context, ArrayList<String> tabNames) {
super(fm);
this.context = context;
mTabNames = tabNames;
}
@Override
public int getCount() {
//return PAGE_COUNT;
return mTabNames.size();
}
@Override
public Fragment getItem(int position) {
// return FlavorListFragment.newInstance(position + 1);
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
String tabName = mTabNames.get(position);
return FlavorListFragment.newInstance(tabName);
}
@Override
public CharSequence getPageTitle(int position) {
//Generate title based on item position
//return tabTitles[position];
String tabName = mTabNames.get(position);
return tabName;
}
}
ListFragment
public class FlavorListFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>{
// The fragment argument representing the tab name & number for this fragment.
private static final String ARG_TAB_NAME ="tabName";
// Store the tabName for later use
private static String mTabName;
public static FlavorListFragment newInstance(String tabName) {
FlavorListFragment fragment = new FlavorListFragment();
mTabName = tabName;
Bundle args = new Bundle();
args.putString(ARG_TAB_NAME, tabName);
fragment.setArguments(args);
return fragment;
}
/** Identifier for the flavor data loader */
private static final int FLAVOR_LOADER = 0;
/** Adapter for the ListView */
FlavorCursorAdapter mCursorAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(com.simsolec.flavorsaver.R.layout.fragment_flavor_list,
container, false);
// Find the ListView which will be populated with the flavor data
ListView flavorListView = rootView.findViewById(com.simsolec.flavorsaver.R.id.flavor_list);
// Setup an Adapter to create a list item for each row of flavor data in the Cursor.
// There is no flavor data yet (until the loader finishes) so pass in null for the Cursor.
mCursorAdapter = new FlavorCursorAdapter(getActivity(), null);
flavorListView.setAdapter(mCursorAdapter);
// Kick off the loader
getLoaderManager().initLoader(FLAVOR_LOADER, null, this);
// Setup the item click listener
flavorListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
// Create new intent to go to {@link FlavorActivity}
Intent intent = new Intent(getContext(), FlavorActivity.class);
// Form the content URI that represents the specific flavor that was clicked on,
// by appending the "id" (passed as input to this method) onto the
// {@link FlavorEntry#CONTENT_URI}.
// For example, the URI would be "content://com.simsolec.flavorsaver/flavors/2"
// if the flavor with ID 2 was clicked on.
Uri currentFlavorUri = ContentUris.withAppendedId(FlavorEntry.CONTENT_URI, id);
// Set the URI on the data field of the intent
intent.setData(currentFlavorUri);
// Launch the {@link FlavorActivity} to display the data for the current flavor.
startActivity(intent);
}
});
return rootView;
}
@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
// Define a projection that specifies the columns from the table we care about.
String[] projection = {
FlavorEntry._ID,
FlavorEntry.COLUMN_FLAVOR_NAME,
FlavorEntry.COLUMN_DESCRIPTION_SHORT,
FlavorEntry.COLUMN_CUP_IMAGE,
FlavorEntry.COLUMN_RATING };
// This loader will execute the ContentProvider's query method on a background thread
String[] selectionArgs;
if (mTabName=="All") {
selectionArgs = new String[] {"*"};
} else {
selectionArgs = new String[] {mTabName};
}
String selection = FlavorEntry.COLUMN_FLAVOR_RANGE + " in (";
for (int s = 0; s < selectionArgs.length; s++) {
selection += "?, ";
}
selection = selection.substring(0, selection.length() - 2) + ")";
return new CursorLoader(getActivity(), // Parent activity context
FlavorEntry.CONTENT_URI, // Provider content URI to query
projection, // Columns to include in the resulting Cursor
selection, // No selection clause
selectionArgs, // No selection arguments
FlavorEntry.COLUMN_FLAVOR_NAME + " ASC"); // Default sort order
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Update {@link FlavorCursorAdapter} with this new cursor containing updated flavor data
mCursorAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// Callback called when the data needs to be deleted
mCursorAdapter.swapCursor(null);
}
}
有人能指出我正确的方向吗?
谢谢,
-Joost
从 Bundle 而不是 newInstance()
方法中设置 mTabName
的值,因为 mTabName 被定义为静态,因此从 mTabName
中删除静态关键字
public static FlavorListFragment newInstance(String tabName) {
FlavorListFragment fragment = new FlavorListFragment();
// mTabName = tabName;
Bundle args = new Bundle();
args.putString(ARG_TAB_NAME, tabName);
fragment.setArguments(args);
return fragment;
}
FlavorListFragment
的 OnCreateView
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(com.simsolec.flavorsaver.R.layout.fragment_flavor_list,
container, false);
Bundle b= getArguments();
//mTabName=b.getString(mTabName);
mTabName=b.getString(ARG_TAB_NAME);
}
我正在尝试使用基于 Cursor
的动态创建的选项卡实现 FragmentPagerAdapter
,它从 SQLite 数据库列中检索不同的值。
然后 ListFragment
基于第二个 Cursor
加载数据,即 selects 数据,并使用基于选项卡名称的过滤器。
最后我添加了一个选项卡来包含 "All" 数据,而不是一个子集。
除了将正确的数据输入第一个 "All" sheet 之外,一切正常。 ListFragment onCreateLoader
永远不会达到 select "All" 并根据第二个选项卡的名称以某种方式在第一个和第二个选项卡中提取数据。
My code (filtered for relevance; hopefully not too much)
MainActivity
public class MainActivity extends AppCompatActivity {
// arraylist of tabs in which tab details are stored
private ArrayList<String> tabNames;
// to hold tabs data when first fetch from sqlite db
private Cursor tabCursor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(com.simsolec.flavorsaver.R.layout.activity_main);
getTabs();
// Create an adapter that knows which fragment should be shown on each page
FlavorFragmentPagerAdapter adapter = new FlavorFragmentPagerAdapter(
getSupportFragmentManager(), MainActivity.this, tabNames);
// Find the view pager that will allow the user to swipe between fragments
ViewPager mViewPager = findViewById(com.simsolec.flavorsaver.R.id.viewpager);
// Set the adapter onto the view pager
mViewPager.setAdapter(adapter);
// Give the TabLayout the ViewPager
TabLayout tabLayout = findViewById(com.simsolec.flavorsaver.R.id.sliding_tabs);
tabLayout.setupWithViewPager(mViewPager);
}
private void getTabs( ){
try{
String[] Projection = { FlavorEntry.COLUMN_FLAVOR_RANGE };
tabCursor = getContentResolver().query(
FlavorEntry.CONTENT_URI_DISTINCT,
Projection,
null,
null,
FlavorEntry.COLUMN_FLAVOR_RANGE );
tabNames = new ArrayList();
tabNames.add("All");
if (tabCursor != null && tabCursor.getCount() > 0) {
if(tabCursor.moveToFirst()) {
do{
String tabName;
tabName = tabCursor.getString(0);
tabNames.add(tabName);
}while (tabCursor.moveToNext());
}
tabCursor.close();
}
}catch (NullPointerException | SQLException e) {
}
finally {
tabCursor.close();
}
}
}
FragmentPagerAdapter
public class FlavorFragmentPagerAdapter extends FragmentPagerAdapter {
private Context context;
private ArrayList<String> mTabNames;
public FlavorFragmentPagerAdapter(FragmentManager fm, Context context, ArrayList<String> tabNames) {
super(fm);
this.context = context;
mTabNames = tabNames;
}
@Override
public int getCount() {
//return PAGE_COUNT;
return mTabNames.size();
}
@Override
public Fragment getItem(int position) {
// return FlavorListFragment.newInstance(position + 1);
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
String tabName = mTabNames.get(position);
return FlavorListFragment.newInstance(tabName);
}
@Override
public CharSequence getPageTitle(int position) {
//Generate title based on item position
//return tabTitles[position];
String tabName = mTabNames.get(position);
return tabName;
}
}
ListFragment
public class FlavorListFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>{
// The fragment argument representing the tab name & number for this fragment.
private static final String ARG_TAB_NAME ="tabName";
// Store the tabName for later use
private static String mTabName;
public static FlavorListFragment newInstance(String tabName) {
FlavorListFragment fragment = new FlavorListFragment();
mTabName = tabName;
Bundle args = new Bundle();
args.putString(ARG_TAB_NAME, tabName);
fragment.setArguments(args);
return fragment;
}
/** Identifier for the flavor data loader */
private static final int FLAVOR_LOADER = 0;
/** Adapter for the ListView */
FlavorCursorAdapter mCursorAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(com.simsolec.flavorsaver.R.layout.fragment_flavor_list,
container, false);
// Find the ListView which will be populated with the flavor data
ListView flavorListView = rootView.findViewById(com.simsolec.flavorsaver.R.id.flavor_list);
// Setup an Adapter to create a list item for each row of flavor data in the Cursor.
// There is no flavor data yet (until the loader finishes) so pass in null for the Cursor.
mCursorAdapter = new FlavorCursorAdapter(getActivity(), null);
flavorListView.setAdapter(mCursorAdapter);
// Kick off the loader
getLoaderManager().initLoader(FLAVOR_LOADER, null, this);
// Setup the item click listener
flavorListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
// Create new intent to go to {@link FlavorActivity}
Intent intent = new Intent(getContext(), FlavorActivity.class);
// Form the content URI that represents the specific flavor that was clicked on,
// by appending the "id" (passed as input to this method) onto the
// {@link FlavorEntry#CONTENT_URI}.
// For example, the URI would be "content://com.simsolec.flavorsaver/flavors/2"
// if the flavor with ID 2 was clicked on.
Uri currentFlavorUri = ContentUris.withAppendedId(FlavorEntry.CONTENT_URI, id);
// Set the URI on the data field of the intent
intent.setData(currentFlavorUri);
// Launch the {@link FlavorActivity} to display the data for the current flavor.
startActivity(intent);
}
});
return rootView;
}
@Override
public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {
// Define a projection that specifies the columns from the table we care about.
String[] projection = {
FlavorEntry._ID,
FlavorEntry.COLUMN_FLAVOR_NAME,
FlavorEntry.COLUMN_DESCRIPTION_SHORT,
FlavorEntry.COLUMN_CUP_IMAGE,
FlavorEntry.COLUMN_RATING };
// This loader will execute the ContentProvider's query method on a background thread
String[] selectionArgs;
if (mTabName=="All") {
selectionArgs = new String[] {"*"};
} else {
selectionArgs = new String[] {mTabName};
}
String selection = FlavorEntry.COLUMN_FLAVOR_RANGE + " in (";
for (int s = 0; s < selectionArgs.length; s++) {
selection += "?, ";
}
selection = selection.substring(0, selection.length() - 2) + ")";
return new CursorLoader(getActivity(), // Parent activity context
FlavorEntry.CONTENT_URI, // Provider content URI to query
projection, // Columns to include in the resulting Cursor
selection, // No selection clause
selectionArgs, // No selection arguments
FlavorEntry.COLUMN_FLAVOR_NAME + " ASC"); // Default sort order
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Update {@link FlavorCursorAdapter} with this new cursor containing updated flavor data
mCursorAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// Callback called when the data needs to be deleted
mCursorAdapter.swapCursor(null);
}
}
有人能指出我正确的方向吗?
谢谢, -Joost
从 Bundle 而不是 newInstance()
方法中设置 mTabName
的值,因为 mTabName 被定义为静态,因此从 mTabName
public static FlavorListFragment newInstance(String tabName) {
FlavorListFragment fragment = new FlavorListFragment();
// mTabName = tabName;
Bundle args = new Bundle();
args.putString(ARG_TAB_NAME, tabName);
fragment.setArguments(args);
return fragment;
}
FlavorListFragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(com.simsolec.flavorsaver.R.layout.fragment_flavor_list,
container, false);
Bundle b= getArguments();
//mTabName=b.getString(mTabName);
mTabName=b.getString(ARG_TAB_NAME);
}