2016-10-09 87 views
2

目標:我有一個活動,並在兩個片段之內。理想是傳達這兩個片段,選擇一個類別並更新其項目列表。在活動加載中,類別默認爲結算。Android ListView不顯示/刷新和getView無法正常工作

問題:在活動加載時,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; 
    } 
} 

CategoriesFragment:

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; 
    } 
} 
+0

不要這樣做..'this.items =項目;'。相反,嘗試'this.items.clear(); this.items.addAll(items)' –

+0

@ cricket_007我試過這樣做,但由於ItemList是在Adapter的實例化中引用的,所以如果我清除一次該列表,那麼一切都會消失。 –

+0

@ cricket_007基於你說我帶着想法在'getSelectedCategory'內創建一個本地列表並傳遞給Adapter,仍然不起作用的想法... –

回答

0

給定的MCVE工作正常。經過7天的調試和取消註釋代碼,我找到了解決問題的答案。

我的清單正確更新,但未呈現,因爲第二個ItemsFragemnt正在初始化爲Lists活動負載。這第二個片段覆蓋了第一個片段,這就是爲什麼我沒有正在顯示/刷新我的列表。

列表:

首先創建片段:

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

裏面ListsPagerAdapter有一個電話來填充我的ViewPagerNewItemPagerFragment)與CategoriesFragmentItemsFragment

二創建片段 - 覆蓋:

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

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

     transaction.commit(); 

我試圖斷點我的代碼,在事實的問題範圍前面提到的,但有時這是真的很痛苦。我想到了使用Log.d(TAG_KEY, TAG_NAME);的想法,當時我發現答案:我意識到ItemsFragment在Activity加載時被調用兩次。

我在我的項目中搜索了new ItemsFragment,看到裏面我的NewItemPagerFragmentonCreateItemsFragment被調用。之前也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。不要少,確保你沒有覆蓋片段調用其初始化兩次

0

隨機刺...

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

你甚至試圖加載ListView與該ID。

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<String>。這將爲您提供一個add(String object)方法,該方法將添加到底層列表並通知更新。

關於getView的問題,實在說不出來。我真的不知道爲什麼你需要ItemAdapter因爲默認ArrayAdapter<String>將使用android.R.layout.simple_list_item_1工作假設你android:id="@android:id/text1通過它的佈局,例如代替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); 
} 
+0

「你甚至試圖加載ListView與該ID」 - 我需要提供另一個MCV - 在我的代碼這已經實施。我從我的cel回答,所以不久就回復了放棄ArrayAdapter,因爲我需要一個自定義背景到我的ListView - 一切工作,直到我從ArrayAdapter更改爲BaseAdapter。我會明天再看看你的答案,謝謝你的支持 - 在這個問題7天之後,沒有答案,我幾乎放棄了 –

+0

ArrayAdapter將允許你定義一個自定義的背景......也許你應該已經離開代碼在工作狀態,然後詢問有關? –

+0

嘿,對不起,我遲遲沒有發佈這個MCVE - 我想你現在已經擁有了重現問題的一切。我必須說我認爲我已經完成了我代碼的最後一個工作狀態,但不幸的是我沒有,這意味着現在我必須修復它。我犯了一個簡短的錯誤,說我需要這個自定義行佈局。其實我需要一個自定義適配器。爲了將來的目的,我可能會使用Image Views和其他組件。由Android提供的簡單佈局不會幫助我自定義一些我現在需要的東西,例如'android:divider =「@ null」',至少就我測試過的我而言... –