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 没有清楚地显示这一点,但至少现在解决了。