Android – Tab#3正在清除Tab#1中的列表视图。

我有一个非常奇怪的问题,不会产生任何错误,所以它很难排除故障(至少对我来说)。

我的应用程序有3个标签。 标签1有一个片段内的列表视图,其他两个标签基本上是空的占位符片段。 当我点击选项卡1,然后选项卡2,然后返回到选项卡1,我的列表视图保持按预期。 但是,如果我点击标签3然后点击标签1,我的列表视图消失。 我看到表2和表3之间没有区别,这将导致这一点。

我已经从我的应用程序添加了相关的代码。 请让我知道是否需要更多。

任何帮助和建议将不胜感激!

我的主要活动:

var mCursorAdapter: DbCursorAdapter? = null class CatalogActivity : AppCompatActivity(), LoaderManager.LoaderCallbacks<Cursor> { private lateinit var mFragmentPagerAdapter: FragmentPagerAdapter override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_catalog) setSupportActionBar(toolbar) // Create the adapter that will return a fragment for each of the three // primary sections of the activity. mFragmentPagerAdapter = FragmentPagerAdapter(supportFragmentManager) // Set up the ViewPager with the sections adapter. view_pager_container.adapter = mFragmentPagerAdapter view_pager_container.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs)) tabs.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(view_pager_container)) // Setup FAB to open EditorActivity fab_button.setOnClickListener { val intent = Intent(this@CatalogActivity, EditorActivity::class.java) startActivity(intent) } // Kick off the loader loaderManager.initLoader(INGREDIENT_LOADER, null, this) } /** * Helper method to insert hardcoded ingredient data into the database. For debugging purposes only. */ private fun insertIngredient() { // Create a ContentValues object where column names are the keys, // and Rittenhouse Rye Whiskey attributes are the values. val values = ContentValues() values.put(IngredientEntry.COLUMN_INGREDIENT_NAME, "Rittenhouse Rye") values.put(IngredientEntry.COLUMN_INGREDIENT_DESCRIPTION, "Earthly with a sweet finish.") values.put(IngredientEntry.COLUMN_INGREDIENT_CATEGORY, IngredientEntry.CATEGORY_WHISKEY) values.put(IngredientEntry.COLUMN_INGREDIENT_WEIGHT, 1) // Insert a new row for Rittenhouse Rye Whiskey into the provider using the ContentResolver. // Use the {@link IngredientEntry#CONTENT_URI} to indicate that we want to insert // into the ingredients database table. // Receive the new content URI that will allow us to access Rittenhouse's data in the future. contentResolver.insert(IngredientEntry.CONTENT_URI, values) } /** * Helper method to delete all ingredients in the database. */ private fun deleteAllIngredients() { val rowsDeleted = contentResolver.delete(IngredientEntry.CONTENT_URI, null, null) Log.v("CatalogActivity", rowsDeleted.toString() + " rows deleted from ingredient database") } override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the menu options from the res/menu/menu_catalog.xml file. // This adds menu items to the app bar. menuInflater.inflate(R.menu.menu_catalog, menu) return true } override fun onOptionsItemSelected(item: MenuItem): Boolean { // User clicked on a menu option in the app bar overflow menu when (item.itemId) { // Respond to a click on the "Insert dummy data" menu option R.id.action_insert_dummy_data -> { insertIngredient() return true } // Respond to a click on the "Delete all entries" menu option R.id.action_delete_all_entries -> { deleteAllIngredients() return true } } return super.onOptionsItemSelected(item) } override fun onCreateLoader(i: Int, bundle: Bundle?): Loader<Cursor> { // Define a projection that specifies the columns from the table we care about. val projection = arrayOf(IngredientEntry._ID, IngredientEntry.COLUMN_INGREDIENT_NAME, IngredientEntry.COLUMN_INGREDIENT_DESCRIPTION) // This loader will execute the DbContentProvider's query method on a background thread return CursorLoader(this, // Parent activity context IngredientEntry.CONTENT_URI, // Provider content URI to query projection, null, null, null)// Columns to include in the resulting Cursor // No selection clause // No selection arguments // Default sort order } override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor) { // Update {@link DbCursorAdapter} with this new cursor containing updated ingredients data mCursorAdapter?.swapCursor(data) } override fun onLoaderReset(loader: Loader<Cursor>) { // Callback called when the data needs to be deleted mCursorAdapter?.swapCursor(null) } companion object { /** Identifier for the ingredients data loader */ private val INGREDIENT_LOADER = 0 } } 

我的成分片段:

 class IngredientsFragment : Fragment() { override fun onAttach(context: Context?) { super.onAttach(context) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_ingredient, container, false) } override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // Set empty view on the ListView, so that it only shows when the ingredient_list_view has 0 items. ingredient_list_view.emptyView = empty_view // Setup an Adapter to create a ingredient_list_view item for each row of ingredient data in the Cursor. // There is no ingredient data yet (until the loader finishes) so pass in null for the Cursor. mCursorAdapter = DbCursorAdapter(context, null) ingredient_list_view.adapter = mCursorAdapter // Setup the item click listener ingredient_list_view.onItemClickListener = AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, _: Int, id: Long -> // Create new intent to go to {@link EditorActivity} val intent = Intent(context, EditorActivity::class.java) // Form the content URI that represents the specific ingredient that was clicked on, // by appending the "id" (passed as input to this method) onto the // {@link IngredientEntry#CONTENT_URI}. // For example, the URI would be "content://onCreateDesigns.com.CraftCocktailRecipes.ingredients/ingredients/2" // if the ingredient with ID 2 was clicked on. val currentUri = ContentUris.withAppendedId(DbContract.IngredientEntry.CONTENT_URI, id) // Set the URI on the data field of the intent intent.data = currentUri // Launch the {@link EditorActivity} to display the data for the current ingredient. startActivity(intent) } } override fun onDetach() { super.onDetach() } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) } } 

我的适配器:

 class FragmentPagerAdapter(fm: FragmentManager) : SmartFragmentStatePagerAdapter(fm) { override fun getItem(position: Int): Fragment { return when (position) { 0 -> IngredientsFragment() 1 -> RecipesFragment() else -> FavoritesFragment() } } override fun getCount(): Int { // Show 3 total pages. return 3 } } 

我的成分片段:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="onCreateDesigns.com.CraftCocktailRecipes.IngredientsFragment"> <ListView android:id="@+id/ingredient_list_view" android:layout_width="match_parent" android:layout_height="match_parent"/> <!-- Empty view for ingredient_list_view list --> <RelativeLayout android:id="@+id/empty_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"> <ImageView android:id="@+id/empty_shelter_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:src="@drawable/ic_empty_shelter" android:contentDescription="@string/empty_shelter" /> <TextView android:id="@+id/empty_title_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/empty_shelter_image" android:layout_centerHorizontal="true" android:fontFamily="sans-serif-medium" android:paddingTop="16dp" android:text="@string/empty_view_title_text" android:textAppearance="?android:textAppearanceMedium"/> <TextView android:id="@+id/empty_subtitle_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/empty_title_text" android:layout_centerHorizontal="true" android:fontFamily="sans-serif" android:paddingTop="8dp" android:text="@string/empty_view_subtitle_text_ingredients" android:textAppearance="?android:textAppearanceSmall" android:textColor="#A2AAB0"/> </RelativeLayout> 

我认为这是一个视图分页器的默认功能,在这个时候设置适配器视图分页器加载两个分片 ,当你移动片段1到3,然后它会释放片段1,反之亦然,

如果要在第一次加载所有的片段,而不是在setAdapter之后写入一行

 view_pager_container.setOffscreenPageLimit(3); 

setOffscreenPageLimit()这个方法在那个时候加载你所有的三个片断,或者再也不会初始化。

可能会有帮助。

由于解释你的代码没有添加要加载当前页面的任何一方的页面的限制。

setOffscreenPageLimit(INT)

你可以试试这个两个解决方案:

  1. 只是递增值2(即setOffscreenPageLimit(2))
  2. 添加在setUserVisibleHint方法中设置适配器的列表操作的代码。

在ViewPager中,总是当前页面,左侧页面和右侧页面(片段)都是实时的。 每当你点击Tab 3时,Tab 1中的片段将被破坏! 当你回到Tab 1时,Tab 1中的片段将被重新创建。

此外,我没有看到“notifyDataSetChanged()”在IngredientsFragment的onViewCreated()片段中被调用。 我的意思是你应该再次从CursorAdapter加载数据。

为了提高性能,我建议不要同时加载所有内容,但是如果你想这样做,我建议你重新定义你的FragmentStatePagerAdapter上的getItem()函数

抱歉,我在java上发布了这个示例,但是在Android Studio上复制粘贴时,会自动翻译Kotlin语言:

 private class MyDataViewPagerAdapter extends FragmentStatePagerAdapter { private MyDataViewPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { switch (position) { case PAGE_ONE: return FragmentOne.newInstance(); case PAGE_TWO: return FragmentTwo.newInstance(); case PAGE_Three: default: return FragmentThree.newInstance(); } } @Override public CharSequence getPageTitle(int position) { switch (position) { case PAGE_ONE: return "PAGE_ONE"; case PAGE_TWO: return "PAGE_ONE"; case PAGE_Three: default: return "PAGE_ONE"; } } @Override public int getCount() { return TOTAL_PAGE_COUNT; } } 

在你的活动中:

使用它来链接TabLyout和View寻呼机:

  // set adapter mPager.setAdapter(mPagerAdapter); tabs.setupWithViewPager(mPager);