Android - 标签#3正在清除标签#1的列表视图。
我有一个非常奇怪的问题,不会产生任何错误,所以它非常难以排除故障(至少对我而言)。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>
我认为这是一个视图寻呼机的默认功能,当时设定的适配器视图寻呼机负荷两个片段的,当您移动片段1至3,那么它将释放片段1和明智反之亦然,
如果要加载所有的片段在第一时间超过写行后setAdapter一个
view_pager_container.setOffscreenPageLimit(3);
setOffscreenPageLimit()此方法在当时加载所有三个片段,或者再也不会初始化。
可能会有帮助。
谢谢。这解决了眼前的问题,但我觉得我仍然没有做到正确或有效的工作。例如,我在使用ArrayAdapter和listview之前设置了选项卡,并且从未遇到过这个问题,或者必须添加您提到的代码才能正常加载每个选项卡。 – Dallas
我知道了,你有什么问题吗? –
在ViewPager中,总是当前页面,左侧页面和右侧页面(片段)都是实时的。每当你点击Tab 3时,Tab 1中的片段将被破坏!当你回到Tab 1时,Tab 1中的片段将被重新创建。
此外,我没有看到“notifyDataSetChanged()”在IngredientsFragment的onViewCreated()片段中被调用。我的意思是你应该再次从CursorAdapter加载数据。
感谢您的建议。你能否使用notifyDataSetChanged()详细说明你想要的? – Dallas
我建议不要装在同一时间,性能方面的原因,但如果你想这样做,我建议你重新定义你的FragmentStatePagerAdapter为getItem()函数
你会如何建议我改进getItem()函数?每个选项卡的每个片段都会有很大不同。我对碎片很陌生。 – Dallas
作为解释页面您没有添加代码的限制应该加载当前页面的任一侧。
你可以试试这个两个解:
- 只是increaments值2(即setOffscreenPageLimit(2))
- 添加这setUserVisibleHint方法设置适配器列表操作的代码。
对不起,我张贴在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);
我还注意到,当我关闭应用程序,然后重新打开标签1上的列表视图项目消失。我在生命周期方面做了非常错误的事情,但我似乎无法弄清楚什么。 – Dallas