2017-08-29 97 views
0

我有一个非常奇怪的问题,不会产生任何错误,所以它非常难以排除故障(至少对我而言)。Android - 标签#3正在清除标签#1的列表视图。

我的应用程序有3个选项卡。选项卡1在片段内有一个列表视图,其他两个选项卡基本都是空的占位符片段。当我点击Tab 1,然后点击Tab 2,然后回到Tab 1时,我的列表视图保持不变。但是,如果我点击Tab 3然后点击Tab 1,我的列表视图就会消失。我发现Tab 2和Tab 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([email protected], 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> 

+0

我还注意到,当我关闭应用程序,然后重新打开标签1上的列表视图项目消失。我在生命周期方面做了非常错误的事情,但我似乎无法弄清楚什么。 – Dallas

回答

1

我认为这是一个视图寻呼机的默认功能,当时设定的适配器视图寻呼机负荷两个片段的,当您移动片段1至3,那么它将释放片段1和明智反之亦然,

如果要加载所有的片段在第一时间超过行后setAdapter一个

view_pager_container.setOffscreenPageLimit(3); 

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

可能会有帮助。

+0

谢谢。这解决了眼前的问题,但我觉得我仍然没有做到正确或有效的工作。例如,我在使用ArrayAdapter和listview之前设置了选项卡,并且从未遇到过这个问题,或者必须添加您提到的代码才能正常加载每个选项卡。 – Dallas

+0

我知道了,你有什么问题吗? –

0

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

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

+0

感谢您的建议。你能否使用notifyDataSetChanged()详细说明你想要的? – Dallas

0

我建议不要装在同一时间,性能方面的原因,但如果你想这样做,我建议你重新定义你的FragmentStatePagerAdapter为getItem()函数

+0

你会如何建议我改进getItem()函数?每个选项卡的每个片段都会有很大不同。我对碎片很陌生。 – Dallas

1

作为解释页面您没有添加代码的限制应该加载当前页面的任一侧。

setOffscreenPageLimit(int)

你可以试试这个两个解:

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

对不起,我张贴在Java,但在复制粘贴在Android工作室,这将是自动翻译的科特林语言此示例:

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和查看寻呼机:

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