【问题标题】:Android ListView not being displayed/refreshing and getView not working properlyAndroid ListView 未显示/刷新且 getView 无法正常工作
【发布时间】:2016-10-09 17:27:15
【问题描述】:

目标:我有一个活动,在两个片段中。想法是通信两个片段,选择一个类别并更新其项目列表。在活动加载时,默认情况下确定一个类别。

问题: 在加载活动时,ItemsFragment 不显示/更新 itemsLisView。即使列表有五个项目,ItemAdapter 的 getView 方法也只被调用了两次。

事实:

  1. 项目列表在传递给适配器之前已正确完成
  2. 中断代码,不确定为什么或是否重要,ItemsFragment 在 CategoriesFragments 之前被渲染/调用。我发现这很奇怪,因为 CategoriesFragments 位于 ItemsFragment 之上。这就是我写if (getArguments() != null) 的原因。在我得到空指针异常之前。

研究:关于这两个主题都有很多问题。

  1. Android ListView not refreshing after notifyDataSetChanged with data as Map
  2. ListFragment Not Rendering and getView() in Adapter Not Being Called
  3. Android getView() not being called properly?
  4. BaseAdapter notifyDatasetChanged() called but getView() is never called

这些是我经历的一些链接示例(数千个),试图为我的案例找到解决方案。不幸的是,它们都不起作用。

我已经遇到这个问题将近 5 天了,我想我在这里错过了一些 Android 概念。这与 Java 编程无关,或者至少我希望如此。

问题:

  1. 为什么 ItemsFragment 在活动加载时不显示项目列表? (这可能解决了更新问题)
  2. 为什么 ItemAdapter 只调用 getView 两次,即使正确地为他提供了更多项目的 Items List?

如需任何进一步需要的信息,请不要介意询问。 提前感谢您的帮助。


编辑 - MCVE:

activity_triple_list:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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"
    android:fitsSystemWindows="true"
    tools:context=".controller.activities.Lists">

    <include layout="@layout/content_triple_list" />
</android.support.design.widget.CoordinatorLayout>

content_triple_list:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v4.view.ViewPager
        android:id="@+id/listsPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v4.view.PagerTabStrip
            android:id="@+id/pager_header"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="top"
            android:paddingBottom="4dp"
            android:paddingTop="4dp" />

    </android.support.v4.view.ViewPager>
</LinearLayout>

fragment_categories:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/categoriesFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TableLayout
        android:id="@+id/categoriesTable"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:stretchColumns="4">

        <TableRow
            android:layout_width="fill_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="5dp"
            android:gravity="center_horizontal">

            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_column="0"
                android:layout_marginLeft="13dp"
                android:layout_marginRight="13dp"
                android:orientation="vertical">

                <TextView
                    android:id="@+id/category1"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="5dp"
                    android:text="CATEGORY 1"
                    android:textAlignment="center"
                    android:textAppearance="?android:attr/textAppearanceSmall" />
            </LinearLayout>

        </TableRow>

    </TableLayout>
</LinearLayout>

fragment_items:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@id/itemsFragment"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/itemsListView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:divider="@null" />

</LinearLayout>

content_row_choose_item:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/custom_row"
    android:orientation="vertical"
    android:paddingBottom="5dp"
    android:paddingLeft="15dp"
    android:paddingTop="5dp">

    <TextView
        android:id="@+id/itemName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="TEST"
        android:textAppearance="?android:attr/textAppearanceLarge" />
</LinearLayout>

custom_row:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" android:background="#2fff00">    
    <item android:drawable="@color/colorPrimary" android:state_pressed="true" /> <!-- pressed -->       
</selector>

ApplicationUtils:

public final class ApplicationUtils extends Application {

    private static Context context;

    public void onCreate() {
        super.onCreate();
        ApplicationUtils.context = getApplicationContext();
    }

    public static Context getContext() {
        return ApplicationUtils.context;
    }

    public static String getJavaPackageName() {
        return ApplicationUtils.context.getPackageName();
    }

    public static Resources getAppResources() {
        return getContext().getResources();
    }

    public static String getResouceName(Integer id) {
        return getAppResources().getResourceName(id);
    }

    public static String getResourceString(Integer id) {
        return getAppResources().getString(id);
    }

    public static int getResourceId(String variableName, String resourceName, String packageName) {
        try {
            return getContext().getResources().getIdentifier(variableName, resourceName, packageName);
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
    }
}

列表:

public class Lists extends AppCompatActivity implements CategoriesFragment.OnHeadlineSelectedListener {

    private String listName;

    public void onItemSelected(String currentCategory) {

        ItemsFragment itemsCallBackFragment = (ItemsFragment) getSupportFragmentManager().findFragmentById(R.id.itemsFragment);

        if (itemsCallBackFragment != null) {
            itemsCallBackFragment.updateArticleView(currentCategory);
        } else {
            ItemsFragment itemFragment = new ItemsFragment();
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

            transaction.replace(R.id.itemsFragment, itemFragment);
            transaction.addToBackStack(null);

            transaction.commit();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_triple_list);

        setListsAdapter();
    }

    private void setListsAdapter() {
        ViewPager tripleListViewPager = (ViewPager) findViewById(R.id.listsPager);
        FragmentPagerAdapter tripleListFragmentAdapt = new ListsPagerAdapter(getSupportFragmentManager(), "LIST NAME", ApplicationUtils.getContext());
        tripleListViewPager.setAdapter(tripleListFragmentAdapt);
    }
}

ListsPagerAdapter:

public class ListsPagerAdapter extends FragmentPagerAdapter {

    private static int NUM_TABS = 1;
    private String listName;
    private Context listsContext;

    public ListsPagerAdapter(FragmentManager fm, String newListName, Context listsContext) {
        super(fm);
        setListName(newListName);
        setListsContext(listsContext);
    }

    // Returns total number of pages
    @Override
    public int getCount() {
        return NUM_TABS;
    }

    // Returns the fragment to display for that page
    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return NewItemPagerFragment.newInstance();
            default:
                return null;
        }
    }

    // Returns the page title for the top indicator
    @Override
    public CharSequence getPageTitle(int position) {
        switch (position) {
            case 0:
                return listsContext.getResources().getString(R.string.lists_tab_newItem, getListName());
            default:
                return "$value";
        }
    }

    public String getListName() {
        return listName;
    }

    public void setListName(String listName) {
        this.listName = listName;
    }

    public Context getListsContext() {
        return listsContext;
    }

    public void setListsContext(Context listsContext) {
        this.listsContext = listsContext;
    }
}

类别片段:

public class CategoriesFragment extends Fragment {


    private List<Integer> categoryIds = new ArrayList<>();
    private String currentCategory;
    private View categoriesView;

    OnHeadlineSelectedListener itemCallback;

    public interface OnHeadlineSelectedListener {
        void onItemSelected(String categoryName);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            itemCallback = (OnHeadlineSelectedListener) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        categoriesView = inflater.inflate(R.layout.fragment_categories, container, false);
        categoriesView.setId(R.id.categoriesFragment);
        return categoriesView;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        setCategoriesListener();
        setDefaultSelectedCategory();
    }

    private void setCategoriesListener() {
        categoryIds.add(R.id.category1);

        for (Integer id : categoryIds) {
            setListener(id);
        }
    }

    private void setListener(final int categoryId) {
        final ImageView categoryImg = (ImageView) categoriesView.findViewById(categoryId);

        categoryImg.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                removePreviousSelectedCategory(categoryImg);
                selectCategory(categoryId, categoryImg);
                loadItemList();
            }
        });
    }

    private void removePreviousSelectedCategory(ImageView categoryImg) {
        for (Integer id : categoryIds) {
            final ImageView imgView = (ImageView) categoriesView.findViewById(id);

            if (imgView.getTag() != null) {
                String previousSelectedCategory = (String) imgView.getTag();
                if (StringUtils.contains(previousSelectedCategory, Application.SELECTED)) {
                    previousSelectedCategory = previousSelectedCategory.replace(Application.SELECTED, "");
                    categoryImg.setTag(previousSelectedCategory);

                    Integer previousSelectedCategoryId = ApplicationUtils.getResourceId(previousSelectedCategory, Application.RES_DRAWABLE, ApplicationUtils.getJavaPackageName());
                    imgView.setImageResource(previousSelectedCategoryId);
                }
            }
        }
    }

    private void selectCategory(int categoryId, ImageView categoryImg) {
        String newSelectedCategory = ApplicationUtils.getResouceName(categoryId) + Application.SELECTED;
        setCurrentCategory(newSelectedCategory);

        newSelectedCategory = newSelectedCategory.replace(Application.META_INFO_ID, "");
        categoryImg.setTag(newSelectedCategory);

        Integer currentCategoryId = ApplicationUtils.getResourceId(newSelectedCategory, Application.RES_DRAWABLE, ApplicationUtils.getJavaPackageName());
        categoryImg.setImageResource(currentCategoryId);
    }

    public String getCurrentCategory() {
        return currentCategory;
    }

    public void setCurrentCategory(String currentCategory) {
        this.currentCategory = currentCategory;
    }

    private void loadItemList() {
        itemCallback.onItemSelected(getCurrentCategory());
    }

    private void setDefaultSelectedCategory() {
        Integer categoryId = R.id.category1;
        final ImageView categoryImg = (ImageView) categoriesView.findViewById(categoryId);
        selectCategory(categoryId, categoryImg);
        loadItemList();
    }
}

ItemsFragment:

public class ItemsFragment extends Fragment {

    private View itemsFragmentView;
    private ListView itemsListView;
    private ItemAdapter itemsListAdapter;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        itemsFragmentView = inflater.inflate(R.layout.fragment_items, container, false);
        itemsListView = (ListView) itemsFragmentView.findViewById(R.id.itemsListView);

        setItemsListAdapter();
        return itemsFragmentView;
    }

    public void updateArticleView(String categoryName) {
        getSelectedCategoryList();
    }

    private void getSelectedCategoryList() {
        List<String> testList = new ArrayList<>();

        testList.add("TEST ITEM");
        itemsListAdapter.update(testList);
    }

    private void setItemsListAdapter() {
        itemsListAdapter = new ItemAdapter(getActivity(), R.layout.fragment_items, new ArrayList<String>());
        itemsListView.setAdapter(itemsListAdapter);
    }
}

ItemAdapter:

public class ItemAdapter extends ArrayAdapter<String> {

    private List<String> items = new ArrayList<>();
    private LayoutInflater rowInflater;

    public ItemAdapter(Context context, int resource, List<String> itemsList) {
        super(context, resource, itemsList);
        this.items = itemsList;
        this.rowInflater = LayoutInflater.from(context);
    }

    private class ItemHolder {
        TextView itemNameView;
    }

    @Override
    public View getView(int position, View rowView, ViewGroup parent) {

        ItemHolder itemHolder;

        if (rowView == null) {
            rowView = rowInflater.inflate(R.layout.content_row_choose_item, parent, false);

            itemHolder = new ItemHolder();
            itemHolder.itemNameView = (TextView) rowView.findViewById(R.id.itemName);

            rowView.setTag(itemHolder);
        } else {
            itemHolder = (ItemHolder) rowView.getTag();
        }

        String itemName = getItem(position);
        if (StringUtils.isNotEmpty(itemName) && itemHolder.itemNameView != null) {
            itemHolder.itemNameView.setText(itemName);
            System.out.println("ITEM NAME ### " + itemHolder.itemNameView.getText());
        }

        return rowView;
    }

    public void update(List<String> items) {
        this.items.clear();
        this.items.addAll(items);
        this.notifyDataSetChanged();
    }


    public List<String> getItems() {
        return items;
    }
}

【问题讨论】:

  • 不要这样做.. this.items = items;.相反,请尝试this.items.clear(); this.items.addAll(items)
  • @cricket_007 我试过这样做,但是由于在适配器的实例化中引用了 ItemList,如果我清除一次列表,那么一切都会消失。
  • @cricket_007 根据你所说的,我想在getSelectedCategory 中创建一个本地列表并传递给适配器,但仍然不起作用......
  • 如果你设置this.items = items,同样的事情也会发生。我的观点是你不应该取消引用数组列表
  • 没有阅读完整的代码,但发现了一个错误,不知道它是否与您的问题有关:您不能从片段的onCreateView调用getActivity(),因为片段是还不能保证附加,因此 getActivity 可能为空

标签: android listview android-fragments android-adapter


【解决方案1】:

随机刺杀……

如果使用ListFragment,则fragment_items.xml 需要 ListViewandroid:id="@android:id/list"

您甚至尝试使用该 ID 加载 ListView。

itemsFragmentView = inflater.inflate(R.layout.fragment_items, container, false);
itemsListView = (ListView) itemsFragmentView.findViewById(android.R.id.list);

但是,你有android:id="@+id/itemsListView"

fragment_items:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@id/itemsFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/itemsListView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:divider="@null" />
</LinearLayout>

如果使用 ListFragment,则无需实现自己的 XML 布局文件。话虽如此,onCreateView 不需要实现。请改用onActivityCreated

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    itemsListView = getListView();
    itemsListAdapter = new ItemAdapter(getActivity());
    setListAdapter(itemsListAdapter);
    super.onActivityCreated(savedInstanceState);
}

现在,如果您想向适配器添加项目,我通常建议您只使用ArrayAdapter&lt;String&gt;。这将为您提供一个add(String object) 方法,该方法将添加到基础列表并通知更新。

关于getView的问题,真的不好说。我真的不知道你为什么需要ItemAdapter,因为默认的ArrayAdapter&lt;String&gt; 将工作假设你传递一个带有android:id="@android:id/text1 的布局,例如使用android.R.layout.simple_list_item_1 代替R.layout.content_row_choose_item

所以,这看起来像。

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    itemsListView = getListView();
    ArrayAdapter<String> itemsListAdapter = new ArrayAdapter<String>(
          getActivity(), android.R.layout.simple_list_item_1);
    setListAdapter(itemsListAdapter);

    adapter.add("Hello");
    adapter.add("World");

    super.onActivityCreated(savedInstanceState);
}

【讨论】:

  • “你甚至试图用那个 id 加载 ListView”——我需要提供另一个 MCV——在我的代码中这已经实现了。我从我的 cel 中回答,所以很快就放弃了 ArrayAdapter,因为我需要一个自定义背景到我的 ListView - 一切正常,直到我从 ArrayAdapter 更改为 BaseAdapter。明天我会仔细查看您的答案,感谢您的支持 - 在遇到此问题 7 天后,这里没有答案,我几乎要放弃了
  • ArrayAdapter 将允许您定义自定义背景...也许您应该让代码处于工作状态,然后问这个问题?
  • 嘿伙计,很抱歉我延迟发布此 MCVE - 我想您现在拥有重现该问题的一切。我必须说我以为我已经提交了我的代码的最后一个工作状态,但不幸的是我没有,这意味着现在我必须修复它。我犯了一个小错误,说我需要这个来自定义行布局。实际上我需要一个自定义适配器。为了将来的目的,我可能会使用图像视图和其他组件。 Android提供的简单布局并不能帮助我定制一些我现在需要的东西,例如android:divider="@null",至少就我的测试而言......
  • 对不起,我不会为了搜索错误而下载你的项目。
  • 我正在用你问的 MCVE 重写问题,如果它有帮助 - 如果你仍然不想更进一步,那么感谢你花时间支持我和其他人可能会遇到此错误的程序员
【解决方案2】:

给定的 MCVE 工作正常。经过 7 天的调试和取消注释代码后,我找到了问题的答案。

我的列表已正确更新,但由于第二个 ItemsFragemntLists 活动加载时被初始化,因此未呈现。第二个片段覆盖了第一个片段,这就是为什么我没有看到我的列表正在显示/刷新。

列表:

第一个创建的片段:

private void setListsAdapter() {
                ViewPager tripleListViewPager = (ViewPager) findViewById(R.id.listsPager);
                FragmentPagerAdapter tripleListFragmentAdapt = new ListsPagerAdapter(getSupportFragmentManager(), "LIST NAME", ApplicationUtils.getContext());
                tripleListViewPager.setAdapter(tripleListFragmentAdapt);       }

ListsPagerAdapter 内部,有人调用CategoriesFragmentItemsFragment 填充我的ViewPager (NewItemPagerFragment)。

第二个创建的片段 - 覆盖:

        ItemsFragment itemFragment = new ItemsFragment();
        FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();

        transaction.replace(R.id.itemsFragment, itemFragment);
        transaction.addToBackStack(null);

        transaction.commit();

我试图断点我的代码,之前在 Facts 中提到的问题范围,但有时这真的很痛苦。我萌生了使用Log.d(TAG_KEY, TAG_NAME); 的想法,这就是我找到答案的时候:我意识到ItemsFragment 在Activity 加载时被调用了两次。

我在我的项目中搜索了new ItemsFragment,发现在我的NewItemPagerFragment onCreate 中,ItemsFragment 被调用了。在CategoriesFragment之前也是这样:

NewItemPagerFragment:

    Fragment itemsFragment = new ItemsFragment();
    FragmentManager fm1 = getChildFragmentManager();
    FragmentTransaction ft1 = fm1.beginTransaction();
    ft1.replace(R.id.itemsFragment, itemsFragment);
    ft1.commit();


    Fragment categoriesFragment = new CategoriesFragment();
    FragmentManager fm = getChildFragmentManager();
    FragmentTransaction ft = fm.beginTransaction();
    ft.replace(R.id.categoriesFragment, categoriesFragment);
    ft.commit();

这解释了事实 2.。在NewItemPagerFragment 上评论/删除此呼叫后,问题就消失了。

底线是: 确保您的列表正确地完成/更新,如他的回答中提到的notifyDataSetChanged cricket_007以及我在互联网上阅读的其他数千篇文章。同样重要的是,请确保您没有覆盖两次调用其初始化的片段

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-17
    • 2022-11-05
    • 1970-01-01
    相关资源
    最近更新 更多