0

I have a list of posts built using a RecyclerView. The classes that I have for this scenario are a fragment, the adapter and the view holder. When the fragment is loaded I get the list of posts from an API call using okhttp and pass the list to the adapter.

For each item in the list I have a context menu which I'm defining in the view holder like this.

@Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
        menu.setHeaderTitle("Actions");

        if (!post.isRemoved()) {
            menu.add(Menu.NONE, 1, 1, "Move to Trash")
                    .setOnMenuItemClickListener(onTrashMenu);
        }
        else {
            menu.add(Menu.NONE, 1, 1, "Delete")
                    .setOnMenuItemClickListener(onDeleteMenu);

            menu.add(Menu.NONE, 2, 2, "Restore")
                    .setOnMenuItemClickListener(onRestoreMenu);
        }
    }

Also, every listener is in the view holder class. For example:

private final MenuItem.OnMenuItemClickListener onDeleteMenu = item -> {
        OkHttpClient client = new OkHttpClient();
        String url = "SOME_URL";

        Request request = new Request.Builder()
                .url(url)
                .delete()
                .header("SOME_HEADER")
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                Log.e("POSTS_VIEW_HOLDER", e.getMessage());
                Snackbar.make(PostViewHolder.super.itemView, "Failed to remove post.", Snackbar.LENGTH_SHORT)
                        .show();
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                Snackbar.make(PostViewHolder.super.itemView, "Post removed.", Snackbar.LENGTH_SHORT)
                        .show();
            }
        });

        return true;
    };

I've tried using an interface in the way described here.

Adapter's constructor requires the interface as an argument. And then I pass it further to the view holder when I create it.

public PostsAdapter(Post[] posts, AdapterInterface adapterInterface) {
        this.posts = posts;
        this.adapterInterface = adapterInterface;
    }

@NonNull
    @Override
    public PostViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View postItemView = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.post_item, viewGroup, false);

        return new PostViewHolder(postItemView, adapterInterface);
    }

Passed from the fragment like this:

postsAdapter = new PostsAdapter(null, this::loadPosts);

The loadPosts() method uses okhttp and in the callback sets the adapter's data set and calls .notifyDataSetChanged().

When calling the method from the interface in the view holder I got this:

only the original thread that created a view hierarchy can touch its views

So I used a handler to get around it:

private Handler mHandler = new Handler(Looper.getMainLooper());

mHandler.post(() -> {
                    adapterInterface.dataSetChanged();
                });

But now, whenever this method is called, nothing happens. I would like to know if what I've done makes some sense and also, if there's a better way (or, at least, one that's working) to go about this.

Edit

loadPosts() implementation:

public void loadPosts() {
        progressBar.setVisibility(View.VISIBLE);
            Request request = new Request.Builder()
                    .url(url)
                    .build();

        this.client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e(tag, e.getMessage());
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    final Post[] posts = gson.fromJson(response.body().string(), Post[].class);

                    mHandler.post(() -> {
                        postsAdapter.setPosts(posts);
                        postsAdapter.notifyDataSetChanged();
                        progressBar.setVisibility(View.INVISIBLE);
                    });
                }
        });
    }
Xyntell
  • 155
  • 1
  • 14

0 Answers0