我的应用程序现在正在使用两个列表。一个是对象列表,另一个是同一对象列表。我的Activity中有一个方法,它将Object列表转换为对象列表。我的适配器通过这个调用传递列表列表:
mAdapter.swap(transformList(pipe.mList));
方法swap
负责将转换后的列表传递给我的适配器:
public void swap(List<List<Feed>> feedList) {
if (finallist == null) {
finallist = new ArrayList<>();
}
finallist.clear();
finallist.addAll(feedList);
}
转换会检查一行中是否有图像并将所有图像放在一个列表中(我正在尝试实现类似于WhatsApp图像分组的内容)。所以我有一堆消息,它们可以是短信,文件,图像等。如果是最后一封,我将它们分组到一个列表中。
让我以一个场景为例:
我原始数组中有四张图片和一条短信息。转换将所有四个图像放入一个对象列表中,并将另一个对象列表中的文本消息放入其中(两者都插入到我的列表列表中)。
我想到了两种处理这种转换的方法:1 - 在Adapter内部进行,2 - 在我的Activity中执行并将修改后的列表传递给Adapter。这些解决方案中的每一个都产生了不同的问题。
按照1中的步骤,我能够以我想要的方式显示所有内容。分组工作得很好!问题是如果原始数组的长度等于30,并且转换后的数组的长度减少到12. RecyclerView会将所有剩余的18个项目显示为空状态(因此在转换后它不是&# 39;正确处理删除物品。)
按照2中的步骤,我无法显示所有内容。只是我的数组的第一个元素。我会收到IndexOutOfBoundsException in RecyclerView happens java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder
错误消息。但我无法确定问题所在。我在这里查了很多问题,但没有一个能帮助我。
这是我的Adapter类:
public class FeedAdapter extends BaseSkeletonAdapter<Feed> implements FeedHolder.FeedHolderListener{
private static final int HOLDER_COMMENT = 1;
private static final int HOLDER_IMAGE = 2;
private static final int HOLDER_FILE = 3;
private static final int HOLDER_AUDIO = 4;
private static final int HOLDER_MARKER = 5;
private static final int HOLDER_EMPTY = 6;
private static final int HOLDER_GROUP = 7;
private final FeedItemListener mListener;
private final int mAvatarSize;
private final String mUserId;
private final int mPictureSize;
private final int mSkeletonColor;
public static List<List<Feed>> finallist;
public FeedAdapter(FeedItemListener listener, String userId, int avatarSize, int pictureSize, int skeletonColor) {
super(2);
mListener = listener;
mUserId = userId;
mAvatarSize = avatarSize;
mPictureSize = pictureSize;
mSkeletonColor = skeletonColor;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType){
case HOLDER_COMMENT:
case HOLDER_IMAGE:
case HOLDER_FILE:
case HOLDER_MARKER:
case HOLDER_AUDIO:
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_feed, parent, false);
return new FeedHolder(view, this, mPictureSize);
case HOLDER_GROUP:
System.out.println("É um grupo!!!");
View viewGroup = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_feed_group,parent,false);
return new FeedHolder(viewGroup, this, mPictureSize);
case HOLDER_EMPTY:
default:
View empty = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_empty, parent, false);
return new EmptyPlaceholderViewHolder(empty, R.string.placeholder_feed_empty_title, R.string.placeholder_feed_empty_description, R.drawable.ic_feed_placeholder);
}
}
@Override
protected void onBind(RecyclerView.ViewHolder holder, int position) {
if(!(holder instanceof EmptyPlaceholderViewHolder)){
//Feed feed = finallist.get(position).get(0);
if (holder instanceof FeedHolder) {
if (position < finallist.size()) {
if (mUserId.equals(finallist.get(position).get(0).getCreatedById())) {
((FeedHolder) holder).onBind(finallist.get(position), mUserId, mAvatarSize);
} else {
((FeedHolder) holder).onBind(finallist.get(position), mUserId, mAvatarSize);
}
}
}
}
}
@Override
protected void onBind(RecyclerView.ViewHolder holder, int position, List<Object> payloads) {
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
}else {
if (holder instanceof FeedHolder) {
((FeedHolder) holder).onBind(finallist.get(position), payloads, mUserId, mAvatarSize);
}
}
}
@Override
protected void setHolderSkeleton(RecyclerView.ViewHolder holder) {
if (holder instanceof FeedHolder) {
((FeedHolder) holder).setHolderSkeleton(R.drawable.rounded_skeleton, mSkeletonColor);
}
}
@Override
protected void clearHolderSkeleton(RecyclerView.ViewHolder holder) {
if (holder instanceof FeedHolder) {
((FeedHolder) holder).clearHolderSkeleton();
}
}
@Override
public int getItemViewType(int position) {
if(mSkeletonMode){
return HOLDER_COMMENT;
} if (finallist != null && finallist.size() > 0 && position >= 0 && position < finallist.size()) {
System.out.println("Tamanho total: " + finallist.size());
if (finallist.get(position).size() > 1) {
System.out.println("Tamanho do grupo: " + finallist.get(position).size());
return HOLDER_GROUP;
} else {
Feed feed = finallist.get(position).get(0);
if (feed != null) {
String type = feed.getFeedType();
if (type != null) {
switch (type) {
case FEED_IMAGE:
return HOLDER_IMAGE;
case FEED_AUDIO:
return HOLDER_AUDIO;
case FEED_FILE:
return HOLDER_FILE;
case FEED_MARKER:
return HOLDER_MARKER;
case FEED_COMMENT:
default:
return HOLDER_COMMENT;
}
}
}
}
return HOLDER_COMMENT;
}else {
System.out.println("Tá vazia!");
return HOLDER_EMPTY;
}
}
public List<Feed> getItems() {
return returnList(finallist);
}
public List<List<Feed>> getListItems() {
return finallist;
}
public void swap(List<List<Feed>> feedList) {
if (finallist == null) {
finallist = new ArrayList<>();
}
finallist.clear();
finallist.addAll(feedList);
}
@Override
public void toggleLike(final int pos){
if(mListener != null && pos >= 0 && pos < finallist.size()){
mListener.toggleLike(finallist.get(pos).get(0));
}
}
@Override
public void onLongClick(final int pos, final View v) {
if (mListener != null && pos >= 0 && pos < finallist.size()) {
mListener.onLongClick(finallist.get(pos).get(0), v);
}
}
@Override
public int onAudioActionClicked(final int pos, final int progress) {
if (mListener != null) {
return mListener.onAudioActionClicked(pos, finallist.get(pos).get(0), progress);
}else {
return 0;
}
}
@Override
public void onClick(int pos) {
if (finallist!=null && pos >= 0 && pos<finallist.size()) {
Feed feed = finallist.get(pos).get(0);
if (feed != null && mListener != null) {
mListener.onClick(feed);
}
}
}
public interface FeedItemListener {
void toggleLike(@NonNull Feed feed);
void onLongClick(@NonNull Feed feed, @NonNull View v);
void onClick(@NonNull Feed feed);
int onAudioActionClicked(int pos, @NonNull Feed feed, final int progress);
}
private void transformList(List<Feed> mItems) {
finallist = new ArrayList<>();
for (int i = 0; i< mItems.size();i++) {
List<Feed> feed = new ArrayList<>();
feed.add(mItems.get(i));
finallist.add(feed);
}
int j = 0;
List<String> list = new ArrayList<>();
List<Integer> indexList = new ArrayList<>();
//System.out.println("Tamanho: " + mItems.size());
for (int i = 0; i < mItems.size(); i++) {
if (!mItems.get(i).getFeedType().equals("filePicture")) {
if (j >= 4) {
String temp = "";
for (int k = 0; k < j; k++) {
temp = temp + "->" + Integer.toString(i - (k+1));
if (k != 0) {
finallist.get(i - 1).add(finallist.get(i - (k + 1)).get(0));
indexList.add(i - (k+1));
}
}
list.add(temp);
}
j = 0;
} else {
j = j + 1;
}
if (i == mItems.size()-1) {
//System.out.println("Imagem por ultimo!");
if (j >= 4) {
//System.out.println("Grupo vem por ultimo!");
String temp = "";
for (int k = 0; k < j; k++) {
temp = temp + "->" + Integer.toString(i - (k));
if (k != 0) {
finallist.get(i).add(finallist.get(i - (k)).get(0));
indexList.add(i - (k));
}
}
list.add(temp);
}
}
}
Collections.sort(indexList);
int aux = 0;
for (int i = 0; i < indexList.size();i++) {
//System.out.println("Valor da posição: " + indexList.get(i)+ "\nTipo: "+ finallist.get((indexList.get(i).intValue())+aux).get(0).getFeedType()
// +"\nValor da posição + i: " + (indexList.get(i)+aux) + "\nAux: " + aux);
finallist.remove((indexList.get(i).intValue())+aux);
//notifyItemRangeRemoved(0, finallist.size());
//notifyDataSetChanged();
aux = aux - 1;
}
/*for (int i = 0; i< finallist.size(); i++){
if (finallist.get(i).size() > 1) {
System.out.println("groupImage: " + finallist.get(i).size());
} else {
System.out.println(finallist.get(i).get(0).getFeedType());
}
}*/
//returnList(finallist);
notifyItemRangeRemoved(0, returnList(finallist).size() - finallist.size() - 1);
//notifyItemRangeInserted(0, finallist.size());
}
public List<Feed> returnList(List<List<Feed>> lists) {
List<Feed> list = new ArrayList<>();
if (lists != null) {
for (int i = 0; i < lists.size(); i++) {
if (lists.get(i).size() > 1) {
for (int j = 0; j < lists.get(i).size(); j++) {
list.add(lists.get(i).get(j));
}
} else {
list.add(lists.get(i).get(0));
}
}
System.out.println("Tamanho de list: " + list.size());
}
return list;
}
}
这是我的活动:
public abstract class FeedActivity extends UltraBaseActivity implements FeedAdapter.FeedItemListener, AudioManager.OnAudioFocusChangeListener, MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {
private static final String EXTRA_PROJECT_ID = "extra_project_id";
private static final String EXTRA_PROJECT_NAME = "extra_project_name";
private static final String EXTRA_RESOURCE_ID = "extra_resource_id";
private static final String EXTRA_RESOURCE_NAME = "extra_resource_name";
private static final String EXTRA_RESOURCE_KIND = "extra_resource_kind";
@BindView(R.id.swipeLayout) SwipeRefreshLayout mRefreshLayout;
@BindView(R.id.recyclerView) RecyclerView mRecyclerView;
@BindView(R.id.feedCreateFragment) View mFeedCreateLayout;
@BindView(R.id.mic) ImageView mMicView;
private WeakReference<FeedCreateFragment> mFeedCreateFragment;
protected FeedViewModel mViewModel;
protected FeedAdapter mAdapter;
private Feed mLongClick;
private Toolbar mToolbar;
protected int mScrollTo = -1;
protected WrapContentLinearLayoutManager mLayoutManager;
private String mPlayingFeedId;
private int mPlayingPos;
private int mActionResourcePause = R.drawable.ic_pause_black_24dp;
private int mActionResourcePlay = R.drawable.ic_play_black_24dp;
private MediaPlayer mPlayer;
private AudioManager mAudioManager;
protected Handler mAudioHandler;
protected Runnable mUpdateAudioHolderRunnable = new Runnable() {
@Override
public void run() {
try {
if (mPlayer != null && mPlayer.isPlaying()) {
notifyAdapterAudioUpdate(mPlayer.getCurrentPosition(), mActionResourcePause);
mAudioHandler.postDelayed(this, 100);
} else {
mAudioHandler.removeCallbacks(mUpdateAudioHolderRunnable);
}
} catch (IllegalStateException e){
MyLog.e(TAG, "Error while updating seed bar", e);
mAudioHandler.removeCallbacks(mUpdateAudioHolderRunnable);
}
}
};
public static void start(@NonNull Context context, @NonNull String projectId, @NonNull String projectName, @NonNull String resourceId, @NonNull String resourceName, @NonNull String resourceKind){
Intent intent = setIntent(context, projectId, projectName, resourceId, resourceName, resourceKind);
if (intent == null) return;
context.startActivity(intent);
}
public static void startForResult(@NonNull Fragment fragment, @NonNull String projectId, @NonNull String projectName, @NonNull String resourceId, @NonNull String resourceName, @NonNull String resourceKind){
Intent intent = setIntent(fragment.getContext(), projectId, projectName, resourceId, resourceName, resourceKind);
if (intent == null) return;
fragment.startActivityForResult(intent, Constants.Intents.INTENT_REQUEST_VIEW_FEED);
}
@Nullable
protected static Intent setIntent(@NonNull Context context, @NonNull String projectId, @NonNull String projectName, @NonNull String resourceId, @NonNull String resourceName, @NonNull String resourceKind) {
Intent intent;
if (resourceKind.equals(Task.ROUTE)) {
intent = new Intent(context, FeedTaskActivity.class);
}else if(resourceKind.equals(Chat.ROUTE)){
intent = new Intent(context, FeedChatActivity.class);
} else {
MyLog.e(TAG, "Error invalid resource Kind - " + resourceKind);
return null;
}
intent.putExtra(EXTRA_PROJECT_ID, projectId);
intent.putExtra(EXTRA_PROJECT_NAME, projectName);
intent.putExtra(EXTRA_RESOURCE_ID, resourceId);
intent.putExtra(EXTRA_RESOURCE_NAME, resourceName);
intent.putExtra(EXTRA_RESOURCE_KIND, resourceKind);
return intent;
}
public FeedActivity() {
super(R.layout.activity_feed);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
isLogged();
init(getIntent(), savedInstanceState);
super.onCreate(savedInstanceState);
initAdapter();
mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
mAudioHandler = new Handler();
mViewModel.subscribe()
.compose(this.<Resource<List<Feed>>>bindUntilEvent(ActivityEvent.DESTROY))
.flatMap(flatMapDiffUtils())
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(onNext(), onError(), onCompleted());
}
@NonNull
private Func1<Resource<List<Feed>>, Observable<FeedViewModel.Pipe>> flatMapDiffUtils() {
return new Func1<Resource<List<Feed>>, Observable<FeedViewModel.Pipe>>() {
@Override
public Observable<FeedViewModel.Pipe> call(Resource<List<Feed>> r) {
if (mViewModel.hasResource()) {
List<Feed> old = mAdapter.getItems();
MyLog.i(TAG, "New length: " + (r.data != null ? r.data.size() : 0) + " - Old: " + old.size());
final FeedDiffCallback cb = new FeedDiffCallback(old, r.data, mUser.getId());
final DiffUtil.DiffResult result = DiffUtil.calculateDiff(cb);
return Observable.just(new FeedViewModel.Pipe(r.data, result, r.status == Status.LOADING && (r.data ==null || r.data.size() == 0)));
} else {
MyLog.i(TAG, "Loading resource from server");
return Observable.empty();
}
}
};
}
private Action1<? super FeedViewModel.Pipe> onNext() {
return new Action1<FeedViewModel.Pipe>() {
@Override
public void call(FeedViewModel.Pipe pipe) {
if (pipe != null) {
initFeedFragment();
mRefreshLayout.setRefreshing(false);
pipe.mDiffResult.dispatchUpdatesTo(mAdapter);
mAdapter.setSkeletonMode(pipe.mSkeletonMode);
//List<List<Feed>> list = new ArrayList<>();
//list = tranformList(pipe.mList);
mAdapter.swap(transformList(pipe.mList));
System.out.println("Tamanho desse troço: " + transformList(pipe.mList).size());
//mAdapter.notifyDataSetChanged();
//mAdapter.notifyItemRangeRemoved(0, pipe.mList.size());
if (mScrollTo == -1) {
mRecyclerView.scrollToPosition(mAdapter.getItemCount()-1);
}else {
mRecyclerView.scrollToPosition(mScrollTo);
}
updateMenuOptions();
showLoading(false);
}
}
};
}
protected Action0 onCompleted() {
return new Action0() {
@Override
public void call() {
MyLog.i(TAG, "Finishing feed activity");
finish();
}
};
}
protected Action1<Throwable> onError() {
return new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
MyLog.e(TAG, "Error", throwable);
}
};
}
@Override
protected void initToolbar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
if(mToolbar !=null) {
if (mViewModel != null) {
mToolbar.setTitle(mViewModel.getProjectName());
mToolbar.setSubtitle(mViewModel.getResourceName());
}
mToolbar.setSubtitleTextColor(ContextCompat.getColor(this, R.color.palette_black));
mToolbar.setNavigationIcon(R.drawable.ic_action_back_black);
}
setSupportActionBar(mToolbar);
if (mToolbar != null) {
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
}
}
protected void updateTitle(){
if(mToolbar !=null && mViewModel != null) {
mToolbar.setTitle(mViewModel.getProjectName());
mToolbar.setSubtitle(mViewModel.getResourceName());
}
}
@Override
protected void userUpdated(User user) { }
private void init(Intent i, Bundle b){
if (i != null) {
initViewModel(
i.getStringExtra(EXTRA_PROJECT_ID),
i.getStringExtra(EXTRA_PROJECT_NAME),
i.getStringExtra(EXTRA_RESOURCE_ID),
i.getStringExtra(EXTRA_RESOURCE_NAME),
i.getStringExtra(EXTRA_RESOURCE_KIND));
}else if(b != null){
initViewModel(
b.getString(EXTRA_PROJECT_ID),
b.getString(EXTRA_PROJECT_NAME),
b.getString(EXTRA_RESOURCE_ID),
b.getString(EXTRA_RESOURCE_NAME),
b.getString(EXTRA_RESOURCE_KIND));
}else {
MyLog.i(TAG, "Error while initializing view model");
finish();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(EXTRA_PROJECT_ID, mViewModel.getProjectId());
outState.putString(EXTRA_PROJECT_NAME, mViewModel.getProjectName());
outState.putString(EXTRA_RESOURCE_ID, mViewModel.getResourceId());
outState.putString(EXTRA_RESOURCE_NAME, mViewModel.getResourceName());
outState.putString(EXTRA_RESOURCE_KIND, mViewModel.getResourceKind());
}
private void initAdapter(){
mAdapter = new FeedAdapter(
this,
mUser.getId(),
getResources().getDimensionPixelSize(R.dimen.task_avatar_size),
(int) (AndroidUtils.getScreenWidth(this) * 0.6),
ContextCompat.getColor(this, R.color.bg_skeleton)
);
mRefreshLayout.setColorSchemeResources(R.color.yellow, android.R.color.darker_gray, R.color.yellow_edit_note, android.R.color.background_dark);
mRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
mScrollTo = -1;
mViewModel.reload();
}
});
mLayoutManager = new WrapContentLinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
}
private void initFeedFragment(){
if(!(mFeedCreateFragment != null && mFeedCreateFragment.get() != null && getSupportFragmentManager().findFragmentById(R.id.feedCreateFragment) instanceof FeedCreateFragment)){
mFeedCreateFragment = new WeakReference<>(FeedCreateFragment.newInstance(mViewModel.getProjectId(), mViewModel.getResourceId(), mViewModel.getResourceKind(), mViewModel.getResourceUsers()));
getSupportFragmentManager()
.beginTransaction()
.add(R.id.feedCreateFragment, mFeedCreateFragment.get())
.commitAllowingStateLoss();
if (mViewModel.canCreateFeed()) {
mFeedCreateLayout.setVisibility(View.VISIBLE);
}else {
mFeedCreateLayout.setVisibility(View.GONE);
}
}
}
protected abstract void initViewModel(String projectId, String projectName, String resourceId, String resourceName, String resourceKind);
protected abstract void updateMenuOptions();
}
这是错误的一部分(文本达到最大大小):
10-18 17:29:14.702 23722-23722/com.construct.test E/WrapContentLinearLayoutManager: IndexOutOfBoundsException in RecyclerView happens
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{615b449 position=3 id=-1, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached no parent}
at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5297)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5479)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5440)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5436)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2224)
at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1551)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1511)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:595)
at com.construct.v2.adapters.WrapContentLinearLayoutManager.onLayoutChildren(WrapContentLinearLayoutManager.java:20)
答案 0 :(得分:0)
我的问题是由我BaseSkeletonAdapter<Feed>
扩展的FeedAdapter
引起的。 BaseSkeletonAdapter
使用的是原始列表,而不是我必须使用的列表列表。所以我创建了一个新的类SkeletonAdapterFeed,它基本上等于前一个,但是新的类正在接收列表列表而不仅仅是列表。
我知道这听起来有点令人困惑。我对我现在正在工作的项目没有充分的理解,所以这就是为什么我不了解课程的所有内容等。