Android Smack MVP片段
Android Smack with MVP fragment
我正在使用 smack(XMPP 库)和 Mosby's MvpFagment
在列表视图中显示用户名册(his/her 连接)。
我得到了以下代码,它在不同的片段中工作,只是使用 Retrofit 库进行网络调用:
public void loadListData(final List<NeighbourListItemModel> itemsList) {
Log.e("list", itemsList.size() + "");
listViewAdapter.clear();
listViewAdapter.addThemAll(itemsList);
listViewAdapter.notifyDataSetChanged();
}
由 RosterListener
使用 roster.addRosterListener(new RosterListener() { .. });
调用
NeighbourListItemModel
只是一个简单的 POJO class 有一些 getter 和 setts。
但是,这会产生 AbstractXMPPConnection﹕ Exception in async packet listener
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
错误,可能是因为 XMP 连接在其自己的线程中运行。
现在,如果我将代码更改为以下内容:
@Override
public void loadListData(final List<NeighbourListItemModel> itemsList) {
Log.e("list", itemsList.size() + "");
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
listViewAdapter.clear();
listViewAdapter.addThemAll(itemsList);
listViewAdapter.notifyDataSetChanged();
}
});
}
我收到 java.lang.NullPointerException: Attempt to invoke virtual method 'int getLayout()' on a null object reference
错误。其中 getLayout 定义在:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolderAbstractClass viewHolder;
if (null == convertView || null == convertView.getTag()) {
viewHolder = getItem(position).getDefaultViewHolder(mItemType);
convertView = LayoutInflater.from(getContext()).inflate(viewHolder.getLayout(), null);
viewHolder.findViewsById(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolderAbstractClass) convertView.getTag();
}
BaseModel previousItem = position > 0 ? getItem(position - 1) : null;
viewHolder.setup(getItem(position), previousItem, mCaller.getContext(), position);
return convertView;
}
视图持有者摘要class没什么特别的:
public abstract class ViewHolderAbstractClass {
abstract public int getLayout();
abstract public void findViewsById(View view);
abstract public void initializeComponentBehavior(BaseModel item, Context context, int position);
public void setup(BaseModel item, BaseModel previous_item, Context context, int position) {
initializeComponentBehavior(item, context, position);
}
}
显然 viewHolder
变量为空,但我不知道为什么。我的适配器定义为 new BaseListAdapter(this, R.layout.neighbours_list_item, new ArrayList<ChatItemModel>(), Constants.DATA_TYPE.CHAT);
正如我所说,当我使用 Retrofit 进行调用时,以前的代码可以正常工作,但我怀疑 XMPP 运行 在它自己的线程中让我很头疼。
1) 我认为这段代码 viewHolder = getItem(position).getDefaultViewHolder(mItemType)
是可疑的。代码似乎正在缓存 ViewHolder
class,问题是您无法缓存或保存 UI ID。我相信您注意到其他开发人员只是创建了一个 ViewHolder
.
的实例
除此之外,请 post getDefaultViewHolder 的代码。
2) 另外,我怀疑 findViewsById
() 方法无法工作,因为它似乎试图缓存 UI ID 以找到正确的视图对象。
** 这个缓存 UI ID 的问题现在更加明显 (!) 因为您是在单独的线程上获取 ID。
不过,您可以在单独的 UI 线程中更新 UI 视图。您可以在单独的线程上获取 UI ID,但不要缓存它,立即使用它。
问题是 Constants.DATA_TYPE itemType
指的是另一个模型而不是 NeighbourListItemModel
,这导致空值 return。 stacktrace 没有清楚地显示这一点,但至少现在解决了。
我正在使用 smack(XMPP 库)和 Mosby's MvpFagment
在列表视图中显示用户名册(his/her 连接)。
我得到了以下代码,它在不同的片段中工作,只是使用 Retrofit 库进行网络调用:
public void loadListData(final List<NeighbourListItemModel> itemsList) {
Log.e("list", itemsList.size() + "");
listViewAdapter.clear();
listViewAdapter.addThemAll(itemsList);
listViewAdapter.notifyDataSetChanged();
}
由 RosterListener
使用 roster.addRosterListener(new RosterListener() { .. });
NeighbourListItemModel
只是一个简单的 POJO class 有一些 getter 和 setts。
但是,这会产生 AbstractXMPPConnection﹕ Exception in async packet listener
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
错误,可能是因为 XMP 连接在其自己的线程中运行。
现在,如果我将代码更改为以下内容:
@Override
public void loadListData(final List<NeighbourListItemModel> itemsList) {
Log.e("list", itemsList.size() + "");
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
listViewAdapter.clear();
listViewAdapter.addThemAll(itemsList);
listViewAdapter.notifyDataSetChanged();
}
});
}
我收到 java.lang.NullPointerException: Attempt to invoke virtual method 'int getLayout()' on a null object reference
错误。其中 getLayout 定义在:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolderAbstractClass viewHolder;
if (null == convertView || null == convertView.getTag()) {
viewHolder = getItem(position).getDefaultViewHolder(mItemType);
convertView = LayoutInflater.from(getContext()).inflate(viewHolder.getLayout(), null);
viewHolder.findViewsById(convertView);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolderAbstractClass) convertView.getTag();
}
BaseModel previousItem = position > 0 ? getItem(position - 1) : null;
viewHolder.setup(getItem(position), previousItem, mCaller.getContext(), position);
return convertView;
}
视图持有者摘要class没什么特别的:
public abstract class ViewHolderAbstractClass {
abstract public int getLayout();
abstract public void findViewsById(View view);
abstract public void initializeComponentBehavior(BaseModel item, Context context, int position);
public void setup(BaseModel item, BaseModel previous_item, Context context, int position) {
initializeComponentBehavior(item, context, position);
}
}
显然 viewHolder
变量为空,但我不知道为什么。我的适配器定义为 new BaseListAdapter(this, R.layout.neighbours_list_item, new ArrayList<ChatItemModel>(), Constants.DATA_TYPE.CHAT);
正如我所说,当我使用 Retrofit 进行调用时,以前的代码可以正常工作,但我怀疑 XMPP 运行 在它自己的线程中让我很头疼。
1) 我认为这段代码 viewHolder = getItem(position).getDefaultViewHolder(mItemType)
是可疑的。代码似乎正在缓存 ViewHolder
class,问题是您无法缓存或保存 UI ID。我相信您注意到其他开发人员只是创建了一个 ViewHolder
.
除此之外,请 post getDefaultViewHolder 的代码。
2) 另外,我怀疑 findViewsById
() 方法无法工作,因为它似乎试图缓存 UI ID 以找到正确的视图对象。
** 这个缓存 UI ID 的问题现在更加明显 (!) 因为您是在单独的线程上获取 ID。
不过,您可以在单独的 UI 线程中更新 UI 视图。您可以在单独的线程上获取 UI ID,但不要缓存它,立即使用它。
问题是 Constants.DATA_TYPE itemType
指的是另一个模型而不是 NeighbourListItemModel
,这导致空值 return。 stacktrace 没有清楚地显示这一点,但至少现在解决了。