未调用适配器中的 ListFragment 和 getView() [英] ListFragment Not Rendering and getView() in Adapter Not Being Called
问题描述
据我所知,这可能是因为我的 ListView 没有显示,我已经验证 getCount 返回的值不是零,但我看不出我做错了什么.
From what I can gather it appears that this might be because my ListView is not being displayed, I've verified that getCount is returning a value not zero, but I can't see what I'm doing wrong.
一切都加载并表现得像在工作,但 ListView 从未出现,我在 mix.xml 中的片段引用上添加了背景色,它在那里并占据全屏,但是当我在 ListView 上设置背景色时它没有出现,就好像它根本没有被渲染.
Everything loads and acts like it's working but the ListView never appears, I put a background color on the fragment reference in mixed.xml and it is there and taking up the full screen, but when I set a background color on my ListView it does not appear, it's like it's not being rendered at all.
更奇怪的是,我的适配器中没有调用 getView,这是我移植到片段的常规活动中的所有工作代码.
More odd, getView is not being called in my adapter, and this is all working code from regular activities that I ported to fragments.
我试过调用notifyDataSetChanged,它没有改变任何东西,调试显示适配器充满了数据,getCount确实返回了一个大于0的准确计数.
I've tried calling notifyDataSetChanged which didn't changed anything, debugging shows the adapter is filled with data and getCount is indeed returning an accurate count greater than 0.
感谢您的帮助,我被卡住了.
Thanks for any help, I'm stuck.
项目是开放的,可以在这里查看 http://code.google.com/p/shack-droid/source/browse/#svn%2FTrunk 但我也在此处包含了相关代码.
Project is open and can be viewed here http://code.google.com/p/shack-droid/source/browse/#svn%2FTrunk but I'm also including the pertinent code here.
这是 ListFragment:
This is the ListFragment:
public class FragmentTopicView extends ListFragment implements ShackGestureEvent {
private ArrayList<ShackPost> posts;
private String storyID = null;
private String errorText = "";
private Integer currentPage = 1;
private Integer storyPages = 1;
private String loadStoryID = null;
private Boolean threadLoaded = true;
private Hashtable<String, String> postCounts = null;
private AdapterLimerifficTopic tva;
public FragmentTopicView() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.topics, null);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final ShackGestureListener listener = Helper.setGestureEnabledContentView(R.layout.topics, getActivity());
if (listener != null) {
listener.addListener(this);
}
if (savedInstanceState == null) {
// get the list of topics
GetChattyAsyncTask chatty = new GetChattyAsyncTask(getActivity());
chatty.execute();
}
ListView lv = getListView();
lv.setOnScrollListener(new OnScrollListener() {
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// start loading the next page
if (threadLoaded && firstVisibleItem + visibleItemCount >= totalItemCount && currentPage + 1 <= storyPages) {
// get the list of topics
currentPage++;
GetChattyAsyncTask chatty = new GetChattyAsyncTask(getActivity());
chatty.execute();
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
});
}
class GetChattyAsyncTask extends AsyncTask<String, Void, Void> {
protected ProgressDialog dialog;
protected Context c;
public GetChattyAsyncTask(Context context) {
this.c = context;
}
@Override
protected Void doInBackground(String... params) {
threadLoaded = false;
try {
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(c);
final String feedURL = prefs.getString("shackFeedURL", getString(R.string.default_api));
final URL url;
if (loadStoryID != null) {
if (currentPage > 1)
url = new URL(feedURL + "/" + loadStoryID + "." + currentPage.toString() + ".xml");
else
url = new URL(feedURL + "/" + loadStoryID + ".xml");
}
else {
if (currentPage > 1)
url = new URL(feedURL + "/" + storyID + "." + currentPage.toString() + ".xml");
else
url = new URL(feedURL + "/index.xml");
}
// Get a SAXParser from the SAXPArserFactory.
final SAXParserFactory spf = SAXParserFactory.newInstance();
final SAXParser sp = spf.newSAXParser();
// Get the XMLReader of the SAXParser we created.
final XMLReader xr = sp.getXMLReader();
// Create a new ContentHandler and apply it to the XML-Reader
SaxHandlerTopicView saxHandler = new SaxHandlerTopicView(c, "topic");
xr.setContentHandler(saxHandler);
// Parse the xml-data from our URL.
xr.parse(new InputSource(HttpHelper.HttpRequestWithGzip(url.toString(), c)));
// Our ExampleHandler now provides the parsed data to us.
if (posts == null) {
posts = saxHandler.GetParsedPosts();
}
else {
ArrayList<ShackPost> newPosts = saxHandler.GetParsedPosts();
newPosts.removeAll(posts);
posts.addAll(posts.size(), newPosts);
}
storyID = saxHandler.getStoryID();
storyPages = saxHandler.getStoryPageCount();
if (storyPages == 0) // XML returns a 0 for stories with only
// one page
storyPages = 1;
}
catch (Exception ex) {
// TODO: implement error handling
}
return null;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
if (currentPage == 1)
dialog = ProgressDialog.show(getActivity(), null, "Loading Chatty", true, true);
else
SetLoaderVisibility(View.VISIBLE);
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
ShowData();
SetLoaderVisibility(View.GONE);
try {
dialog.dismiss();
}
catch (Exception e) {
}
}
}
private void ShowData() {
if (posts != null) {
Hashtable<String, String> tempHash = null;
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
final String login = prefs.getString("shackLogin", "");
final int fontSize = Integer.parseInt(prefs.getString("fontSize", "12"));
try {
postCounts = GetPostCache();
}
catch (Exception ex) {
}
if (postCounts != null)
tempHash = new Hashtable<String, String>(postCounts);
if (tva == null) {
tva = new AdapterLimerifficTopic(getActivity(), R.layout.lime_topic_row, posts, login, fontSize, tempHash);
setListAdapter(tva);
}
else {
tva.SetPosts(posts);
tva.notifyDataSetChanged();
}
final ListView lv = getListView();
lv.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
menu.setHeaderTitle("Options");
menu.add(0, 1, 0, "Copy Post Url to Clipboard");
menu.add(0, 2, 0, "Watch Thread");
menu.add(0, 3, 0, "Thread Expires In?");
menu.add(0, 4, 0, "Shacker's Chatty Profile");
}
});
// update the reply counts for the listing of topics
try {
UpdatePostCache();
}
catch (Exception e) {
}
}
else {
if (errorText.length() > 0) {
try {
new AlertDialog.Builder(getActivity()).setTitle("Error").setPositiveButton("OK", null).setMessage(errorText).show();
}
catch (Exception ex) {
// could not create a alert for the error for one reason
// or another
Log.e("ShackDroid", "Unable to create error alert ActivityTopicView:468");
}
}
}
threadLoaded = true;
}
}
这是我的 FragmentActivity:
Here's my FragmentActivity:
public class FragmentActivityTopic extends FragmentActivity {
@Override
protected void onCreate(Bundle arg) {
// TODO Auto-generated method stub
super.onCreate(arg);
setContentView(R.layout.mixed);
}
}
这是我正在使用的适配器,如上所述,没有调用 getView:
This is the Adapter I'm using, and as mentioned above getView is not being called:
public class AdapterLimerifficTopic extends BaseAdapter {
// private Context context;
private List<ShackPost> topicList;
private final int rowResouceID;
private final String shackLogin;
private final Typeface face;
private final int fontSize;
private final Hashtable<String, String> postCache;
private final String showAuthor;
private final Resources r;
private int totalNewPosts = 0;
LayoutInflater inflate;// = LayoutInflater.from(context);
public AdapterLimerifficTopic(Context context, int rowResouceID, List<ShackPost> topicList, String shackLogin, int fontSize, Hashtable<String, String> postCache) {
this.topicList = topicList;
this.rowResouceID = rowResouceID;
this.shackLogin = shackLogin;
this.fontSize = fontSize;
this.postCache = postCache;
this.r = context.getResources();
face = Typeface.createFromAsset(context.getAssets(), "fonts/arial.ttf");
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
showAuthor = prefs.getString("showAuthor", "count");
inflate = LayoutInflater.from(context);
}
public void SetPosts(List<ShackPost> posts)
{
topicList = posts;
}
@Override
public int getCount() {
return topicList.size();
}
@Override
public Object getItem(int position) {
return topicList.get(position);
}
@Override
public long getItemId(int position) {
// return position;
final ShackPost post = topicList.get(position);
return Long.parseLong(post.getPostID());
}
static class ViewHolder {
TextView posterName;
TextView datePosted;
TextView replyCount;
TextView newPosts;
TextView postText;
TextView viewCat;
RelativeLayout topicRow;
ImageView postTimer;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TextView tmp;
// final View v;
ViewHolder holder;
final ShackPost post = topicList.get(position);
if (convertView == null) {
convertView = inflate.inflate(rowResouceID, parent, false);
holder = new ViewHolder();
holder.posterName = (TextView) convertView.findViewById(R.id.TextViewLimeAuthor);
holder.datePosted = (TextView) convertView.findViewById(R.id.TextViewLimePostDate);
holder.replyCount = (TextView) convertView.findViewById(R.id.TextViewLimePosts);
holder.newPosts = (TextView) convertView.findViewById(R.id.TextViewLimeNewPosts);
holder.postText = (TextView) convertView.findViewById(R.id.TextViewLimePostText);
holder.viewCat = (TextView) convertView.findViewById(R.id.TextViewLimeModTag);
// holder.topicRow = (RelativeLayout) convertView.findViewById(R.id.TopicRow);
// holder.postTimer = (ImageView) convertView.findViewById(R.id.ImageViewTopicTimer);
// holder.posterName.setTypeface(face);
// holder.datePosted.setTypeface(face);
// holder.replyCount.setTypeface(face);
// holder.newPosts.setTypeface(face);
holder.postText.setTextSize(TypedValue.COMPLEX_UNIT_SP, fontSize);
// holder.postText.setTypeface(face);
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
// holder.postTimer.setImageResource(Helper.GetTimeLeftDrawable(post.getPostDate()));
//
holder.posterName.setText(post.getPosterName());
//
// if (shackLogin.equalsIgnoreCase(post.getPosterName()))
// holder.posterName.setTextColor(Color.parseColor("#00BFF3"));
// else
// holder.posterName.setTextColor(Color.parseColor("#ffba00"));
//
holder.datePosted.setText(Helper.FormatShackDateToTimePassed(post.getPostDate()));
holder.replyCount.setText(post.getReplyCount());
//
// if (showAuthor.equalsIgnoreCase("count") && post.getIsAuthorInThread())
// holder.replyCount.setTextColor(Color.parseColor("#0099CC"));
// else
// holder.replyCount.setTextColor(Color.parseColor("#FFFFFF"));
// clipped code
holder.postText.setText(preview);
// if (showAuthor.equalsIgnoreCase("topic") && post.getIsAuthorInThread()) {
// final Drawable d = r.getDrawable(R.drawable.background_gradient_blue);
// holder.topicRow.setBackgroundDrawable(d);
// }
// else
// holder.topicRow.setBackgroundDrawable(null);
// TODO: clean this up a little / also replicated in ShackDroidThread ick
final String postCat = post.getPostCategory();
holder.viewCat.setVisibility(View.VISIBLE);
if (postCat.equals("offtopic")) {
holder.viewCat.setText("offtopic");
holder.viewCat.setBackgroundColor(Color.parseColor("#444444"));
}
else if (postCat.equals("nws")) {
holder.viewCat.setText("nws");
holder.viewCat.setBackgroundColor(Color.parseColor("#CC0000"));
}
else if (postCat.equals("political")) {
holder.viewCat.setText("political");
holder.viewCat.setBackgroundColor(Color.parseColor("#FF8800"));
}
else if (postCat.equals("stupid")) {
holder.viewCat.setText("stupid");
holder.viewCat.setBackgroundColor(Color.parseColor("#669900"));
}
else if (postCat.equals("informative")) {
holder.viewCat.setText("interesting");
holder.viewCat.setBackgroundColor(Color.parseColor("#0099CC"));
}
else
holder.viewCat.setVisibility(View.GONE);
return convertView;
}
public int getTotalNewPosts() {
return totalNewPosts;
}
}
和相关的 XML:
mixed.xml(这是片段的布局,现在只有一个)
mixed.xml (this is the layout for the fragments, only the one for now)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:id="@+id/LinearLayoutMixed">
<fragment
android:id="@+id/MixedThreads"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
class="com.stonedonkey.shackdroid.FragmentTopicView"
>
</fragment>
</LinearLayout>
Topics.xml(包含 ListView 以及滑动托盘和其他一些东西.
Topics.xml (this contains the ListView as well as a sliding tray and some other stuff.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="@+id/TopicLoader"
android:divider="#333333"
android:dividerHeight="1dip"
android:textColor="#FFFFFF"
/>
<RelativeLayout
android:id="@+id/TopicLoader"
android:layout_width="fill_parent"
android:layout_height="35dip"
android:layout_alignParentBottom="true"
android:gravity="center_horizontal"
android:visibility="gone"
android:layout_marginTop="5dip" >
<TextView
android:id="@+id/TextViewTopicLoaderText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="Loading"
>
</TextView>
<ImageView
android:id="@+id/ImageViewTopicLoader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/TextViewTopicLoaderText"
android:src="@drawable/ic_action_refresh"
android:layout_alignBottom="@+id/TextViewTopicLoaderText"
/>
</RelativeLayout>
<SlidingDrawer
android:id="@+id/SlidingDrawer01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@+id/TopicLoader"
android:animateOnClick="true"
android:content="@+id/bookMarkParent"
android:handle="@+id/TextViewTrayHandle"
android:orientation="vertical"
android:paddingTop="200dip"
android:visibility="gone" >
<TextView
android:id="@+id/TextViewTrayHandle"
android:layout_width="fill_parent"
android:layout_height="35dip"
android:background="@drawable/darkgrey_gradient"
android:focusable="false"
android:focusableInTouchMode="false"
android:gravity="center_vertical" >
</TextView>
<RelativeLayout
android:id="@id/bookMarkParent"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ListView
android:id="@+id/ListViewWatchedThreads"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="#333333"
android:dividerHeight="1dip"
android:textColor="#FFFFFF" >
</ListView>
</RelativeLayout>
</SlidingDrawer>
</RelativeLayout>
最后是lime_topic_row,这是我为上述布局中的 ListView 自定义的行布局:
and finally lime_topic_row which is my custom row layout for the ListView in the above layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FF0000" >
<TextView
android:id="@+id/TextViewLimeModTag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#FF0000"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10dip"
android:textColor="#000000"
android:padding="2dip"
android:textSize="10dip"
/>
<TextView
android:id="@+id/TextViewLimePostText"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minHeight="20dip"
android:padding="10dip"
android:layout_below="@+id/TextViewLimeModTag"
android:textColor="#FFFFFF" />
<TextView
android:id="@+id/TextViewLimeAuthor"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/TextViewLimePostText"
android:paddingBottom="10dip"
android:paddingLeft="10dip"
android:textColor="#0099CC" />
<TextView
android:id="@+id/TextViewPosted"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/TextViewLimePostText"
android:layout_toRightOf="@+id/TextViewLimeAuthor"
android:paddingBottom="10dip"
android:text=" posted " />
<TextView
android:id="@+id/TextViewLimePostDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/TextViewLimePostText"
android:layout_toRightOf="@+id/TextViewPosted"
android:paddingBottom="10dip"
android:paddingRight="10dip"
android:textColor="#FF8800" />
<TextView
android:id="@+id/TextViewLimePosts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/TextViewLimePostDate"
android:layout_marginRight="3dip"
android:layout_below="@+id/TextViewLimePostText"
android:layout_marginBottom="15dip"
android:layout_toLeftOf="@+id/TextViewLimeNewPosts"
android:background="#BBBBBB"
android:padding="3dip"
android:minWidth="25dip"
android:gravity="center"
android:textColor="#000000" />
<TextView
android:id="@+id/TextViewLimeNewPosts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/TextViewLimePostDate"
android:layout_below="@+id/TextViewLimePostText"
android:layout_marginBottom="15dip"
android:layout_marginRight="10dip"
android:background="#669900"
android:padding="3dip"
android:minWidth="25dip"
android:gravity="center"
android:layout_alignParentRight="true"
android:textColor="#000000" />
</RelativeLayout>
推荐答案
我想我发现了问题.出现此问题的原因是您在 FragmentTopicView
中的 onActivityCreated
方法开始时设置的 ShackGestureListener
:
I think I found the problem. The issue appears because of the ShackGestureListener
that you setup at the start of the onActivityCreated
method in the FragmentTopicView
:
final ShackGestureListener listener = Helper.setGestureEnabledContentView(R.layout.topics, getActivity());
if (listener != null) {
listener.addListener(this);
}
在 setGestureEnabledContentView()
方法中,您检查用户是否在首选项中启用了手势,或者 android 版本是否大于 3.无论哪种方式,true
或 false
您为 FragmentActivityTopic
再次 设置内容视图(使用 FragmentTopicView
的布局).不幸的是,再次设置内容视图将覆盖当前布局,该布局包含带有数据的 ListView
(ListView
可以毫无问题地填充).当您运行那些 AsyncTasks
以获取数据时,最后将数据设置在正确的 ListView
(由 getListView
返回)上,因为 getListView
将持有对在 onCreateView
方法中设置的旧的正确 ListView
的引用,但你看不到任何东西,因为在 >setGestureEnabledContentView
你覆盖了这个 ListView
.
In the setGestureEnabledContentView()
method you check to see if the user enabled the gestures in the preferences or if the android version is bigger then 3. Either way, true
or false
you set the content view for the FragmentActivityTopic
again(with the layout of the FragmentTopicView
). Setting the content view again will, unfortunately, cover the current layout which holds the ListView
with data(ListView
that populates with no problems). When you run those AsyncTasks
to get the data, at the end you set the data on the correct ListView
(returned by getListView
) because the getListView
will hold a reference to the old correct ListView
which was set in the onCreateView
method, but you don't see anything because in the setGestureEnabledContentView
you cover this ListView
.
如果您在 Helper
和 HelperAPI4
类中简单注释掉(或删除)为活动设置内容视图的行,则很容易看到这种行为.查看您的 ListView
是否被覆盖的另一种方法是,例如使用 getListView<为
ListView
(tva) 设置适配器/code> 并使用 getActivity().findViewById(android.R.id.list)
(我已经在选择您的菜单项之一时完成了此操作,因此我可以控制何时更换适配器):
This behavior is easy to see if you simple comment out(or remove) the lines that set the content view for the activity in the Helper
and HelperAPI4
classes. Another way to see that your ListView
is covered is, for example to set the adapter for the ListView
(tva) using getListView
and using the getActivity().findViewById(android.R.id.list)
(I've done this on selecting one of your menus items, so I can control when I replace the adapter):
@Override
public boolean onOptionsItemSelected(MenuItem item) {
Intent intent;
switch (item.getItemId())
{
case R.id.topic_menu_newpost: // Launch post form
//this doesn't work as the getListView will return a reference to the old ListView
ListView lv = getListView();
lv.setAdapter(tva);
// this will work as you get a reference to the new ListView on top
ListView lv = (ListView) getActivity().findViewById(android.R.id.list);
lv.setAdapter(tva);
我不知道推荐什么作为解决方案,因为我不太明白你在做什么,但我怀疑它是否需要再次为活动设置内容视图(你应该从这里开始工作).
I don't know what to recommend as a solution as I don't quite understand what you're doing, but I doubt that it requires to set the content view for the activity again(and you should work from this).
这篇关于未调用适配器中的 ListFragment 和 getView()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!