Android - 选项卡#3 正在清除选项卡#1 中的列表视图。

问题描述 投票:0回答:5

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

我的应用程序有 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>

android android-fragments tabs cursor kotlin
5个回答
1
投票

我认为这是 view-pager 的默认功能,在设置 Adapter view-pager 时加载 Two Fragments,当您将片段 1 移动到 3 时,它将释放片段 1,反之亦然,

如果您想第一次加载所有片段,请在 setAdapter 之后 write

一行
view_pager_container.setOffscreenPageLimit(3);

setOffscreenPageLimit() 此方法会在当时加载所有三个片段,或者不再初始化。

可能会有帮助。


1
投票

解释您的代码时未添加应加载当前页面两侧的页面限制。

setOffscreenPageLimit(int)

您可以尝试这两种解决方案:

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

0
投票

在 ViewPager 中,当前页面、左页面和右页面(片段)始终处于活动状态。每当您单击选项卡 3 时,选项卡 1 中的片段就会被销毁!当您返回选项卡 1 时,选项卡 1 中的片段将再次创建。

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


0
投票

出于性能原因,我建议不要同时加载所有内容,但如果您想这样做,我建议您在 FragmentStatePagerAdapter 上重新定义 getItem() 函数


0
投票

抱歉,我在 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 pager :

 // set adapter
mPager.setAdapter(mPagerAdapter);
tabs.setupWithViewPager(mPager);
© www.soinside.com 2019 - 2024. All rights reserved.