像Whatsapp一样使RecyclerView更新

时间:2018-03-22 18:42:08

标签: java android android-asynctask android-volley

我正在尝试排球,所以它对我的项目非常有用。我可以添加内容并移动信息,但我需要在将新项目添加到列表时刷新或更新自己,我个人希望像Whatsapp一样顺利。

我怎样才能做到这一点?我有另一个项目,我使用AsyncTask,但我不知道这是否应该采取这种方法。我对Android开发有点新意,这对Volley有点了解。

你能帮助我并指出正确的方向吗?

以下是我的适配器的代码,我的主要活动以及我发布帖子的位置。我相信这个刷新应该在这3个类中的一个中完成。

如果你能帮助我,那将是我所知道的一个重要的学习步骤。我感谢那些愿意帮助的人!

谢谢! :)

MainActivity

public class MainActivity extends AppCompatActivity implements NewsAdapter.OnItemClickListener{

    //variable to hold the information that we want to pass to another activity
    public static final String EXTRA_NEWS = "newspost";

    private TextView textviewUsername, textviewUserEmail;
    ArrayList<News> newsArrayList;
    private LinearLayoutManager mLayoutManager;
    RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (!SharedPrefManager.getInstance(this).isLoggedIn()){
            startActivity(new Intent(this, LoginActivity.class));
            finish();
        }

        textviewUsername = findViewById(R.id.txtViewusername);
        textviewUserEmail = findViewById(R.id.txtViewUserEmail);
        textviewUsername.setText(SharedPrefManager.getInstance(this).getUser().getUsername());
        textviewUserEmail.setText(SharedPrefManager.getInstance(this).getUser().getEmail());
        recyclerView = findViewById(R.id.recylerView);

        mLayoutManager = new LinearLayoutManager(getApplicationContext());

        //Invert the view of the list
        mLayoutManager.setReverseLayout(true);
        mLayoutManager.setStackFromEnd(true);
        recyclerView.setLayoutManager(mLayoutManager);

        recyclerView.setHasFixedSize(true);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        newsArrayList = new ArrayList<>();

        loadProducts();
    }

    private void loadProducts() {

        /*
        * Creating a String Request
        * The request type is GET defined by first parameter
        * The URL is defined in the second parameter
        * Then we have a Response Listener and a Error Listener
        * In response listener we will get the JSON response as a String
        * */
        JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, Constants.URL_SHOW_NEWS, null,
                new Response.Listener<JSONObject>() {
                    @Override
                    public void onResponse(JSONObject response) {
                        try {
                            //converting the string to json array object
                            JSONArray jsonArray = response.getJSONArray("news");

                            //traversing through all the object
                            for (int i = 0; i < jsonArray.length(); i++) {
                                //getting product object from json array
                                JSONObject jsnews = jsonArray.getJSONObject(i);
                                //adding the product to product list
                                String post = jsnews.getString("noticia");
                                newsArrayList.add(new News(post));
                            }

                            //creating adapter object and setting it to recyclerview
                            NewsAdapter adapter = new NewsAdapter(MainActivity.this, newsArrayList);
                            recyclerView.setAdapter(adapter);
                            /* ------ SETTING OUR ADAPTER TO OUR ONCLICKLISTERNER ---------*/
                            adapter.setOnClickListener(MainActivity.this);

                        } catch (JSONException e) {
                            Toast.makeText(getApplicationContext(), "Parou aqui", Toast.LENGTH_LONG).show();
                        }
                    }
                },
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Toast.makeText(getApplicationContext(), "Algo de errad nao esta certo", Toast.LENGTH_LONG).show();
                    }
                });

        //adding our stringrequest to queue
        Volley.newRequestQueue(this).add(request);
    }


    public void post(View view){
        startActivity(new Intent(this, PostNews.class));
    }

    @Override
    public void onItemClick(int position) {
        /* -------------- DO WHATEVER YOU WANT WITH THE CLICK EVENT HERE------------------ */
        Intent newsDetail = new Intent(this, NewsDetailActivity.class);
        News clickedNews = newsArrayList.get(position);

        newsDetail.putExtra(EXTRA_NEWS, clickedNews.getNews_post());

        startActivity(newsDetail);
    }
}

我的适配器

public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.NewsAdapterViewHolder> {

        private Context context;
        private ArrayList<News> newsArrayList;
        //creating a listener for the interface with the same name as our interface
        private OnItemClickListener xListener;

        //making our own custom onClickListener
        public interface OnItemClickListener {
            void onItemClick(int position);
        }

        public void setOnClickListener(OnItemClickListener listener){
            //used to simulate the onItemClick of a listview
            xListener = listener;
        }

        public NewsAdapter(Context context, ArrayList<News> newsArrayList) {
            this.context = context;
            this.newsArrayList = newsArrayList;
        }

        @Override
        public NewsAdapterViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(context).inflate(R.layout.news_list, parent, false);
            return new NewsAdapterViewHolder(v);
        }

        @Override
        public void onBindViewHolder(NewsAdapterViewHolder holder, int position) {
            News currentNews = newsArrayList.get(position);

            String post = currentNews.getNews_post();

            holder.txtNoticia.setText(post);
        }

        @Override
        public int getItemCount() {
            return newsArrayList.size();
        }

        public class NewsAdapterViewHolder extends RecyclerView.ViewHolder{
            public TextView txtNoticia;

            public NewsAdapterViewHolder(View itemView) {
                super(itemView);
                txtNoticia = itemView.findViewById(R.id.txtnewsPost);

                //creating the option for when we click on something to work
                //-------------------------WARNING--------------------------//
                /*THIS IS A TRICK TO USE onItemClick AS YOU WOULD USE IN A LIST VIEW
                * IT'S BETTER TO USE HERE (ACCORDING TO THE TUTORIAL THAN USING ON THE *-onBindViewHolder-*)*/
                itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        if (xListener != null) {
                            int position = getAdapterPosition();
                            //noposition to make sure the position is still valid
                            if (position != RecyclerView.NO_POSITION){
                                //onItemclick is the method that we created on the interface
                                xListener.onItemClick(position);
                            }
                        }
                    }
                });
            }
        }

    }

创建帖子的活动

public class PostNews extends AppCompatActivity {

        private Button btnpostar;
        private EditText editTextNewsPost;
        private ProgressBar progressBar;
        SharedPrefManager sharedPrefManager;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_post_news);

            editTextNewsPost = findViewById(R.id.EditTextNewsPost);
            btnpostar = findViewById(R.id.btnPostar);
            progressBar = findViewById(R.id.progressBar3);
            progressBar.setVisibility(View.GONE);


        }

        public void salvarNoticia(View view) {

            final User user = sharedPrefManager.getInstance(this).getUser();
            final String post = editTextNewsPost.getText().toString();

            if (!post.equals("")) {

                progressBar.setVisibility(View.VISIBLE);

                StringRequest stringRequest = new StringRequest(Request.Method.POST,
                        Constants.URL_REGISTER_NEWS,
                        new Response.Listener<String>() {
                            @Override
                            public void onResponse(String response) {
                                progressBar.setVisibility(View.GONE);

                                try {


                                    JSONObject jsonObject = new JSONObject(response);

                                    Toast.makeText(getApplicationContext(), jsonObject.getString("message"),
                                            Toast.LENGTH_LONG).show();



                                } catch (JSONException e) {
                                    Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
                                }


                            }
                        }, new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {

                        progressBar.setVisibility(View.GONE);
                        Toast.makeText(getApplicationContext(), "Erro: " + error.getMessage(), Toast.LENGTH_LONG).show();
                    }
                }) {
                    @Override
                    protected Map<String, String> getParams() throws AuthFailureError {

                        Map<String, String> params = null;
                            params = new HashMap<>();
                            params.put("news_post", post);
                            params.put("user_FK", String.valueOf(user.getId()));
                            return params;
                    }
                };

                RequestHandler.getInstance(getApplicationContext()).addToRequestQueue(stringRequest);

            } else {
                Toast.makeText(getApplicationContext(), "Por favor, não poste nada em branco", Toast.LENGTH_LONG).show();
            }

        }
    }

1 个答案:

答案 0 :(得分:3)

这个问题不受特定编程问题的影响,而是指向应用程序架构。但是,我正在写这个答案,分享我使用这些应用程序的一些经验。

据我所知,您希望使用RecyclerView在Feed中显示应用中的帖子。当用户从应用程序创建帖子/产品或其他人创建帖子/产品时,需要更新RecyclerView。如果我理解正确,那么你需要记住以下事项。

  • 您正在调用loadProducts(); onCreate函数中的MainActivity函数,该函数是正确的。应用程序应加载启动时需要在RecyclerView中显示的所有项目。所以初始化部分完全没问题。
  • 现在是更新的部分。您可以根据自己的方便,遵循几种不同的方法。做对或错的问题主要取决于您的申请要求,因此我简要介绍了所有这些要求。
  • 首先,您可以考虑来自Facebook等服务器点播模式的拉取数据。初始产品已加载到RecyclerView。当用户想要查看是否有任何更新时,他/她可能会下拉RecyclerView来刷新数据。我想你已经想到了这一点,我只是涵盖了所有可用的选项。
  • 然后您可以考虑使用后台服务从服务器提取数据,后台服务将在每60秒或您可能根据应用程序要求考虑安全的任何时间间隔内调用loadProducts函数。当您的每个拉取请求都有新数据时,请使用RecyclerView方法相应地更新notifyDataSetChanged
  • 另一个需要服务器端实现的选项是基于推送通知。在您的应用程序中收到推送后,您将调用loadProducts函数并相应地更新RecyclerView。推动既不是实时也不可靠。但是,它可能会为您节省大量的API调用。
  • 您拥有的另一个可用选项是在应用程序和服务器端实现Websocket。开发和性能成本很高。但是,这可确保您的数据实时更新。
  • 最后,但并非最不重要,您可以查看Google提供的Firebase数据库,该数据库具有您在案例中所需的完全相同的实现。它在后端架构使用Websocket时实时更新,但在应用程序中集成更容易,更简单。

我刚给你一些想法。希望这些可以帮到你。

<强>更新

根据你的评论,我认为你没有清楚地告诉我。从服务器端开始每隔x分钟就无法获得推送通知,因为在这种情况下,您需要在用户设备中安装的每个应用程序中跟踪帖子更新的跟踪 - 这是一个可怕的设计。

你需要选一个。如果您想每x分钟刷新一次数据,那么我建议您在应用程序中保留Handler或后台Service,每x分钟后调用一次loadProducts功能更新您的数据。

如果您计划实施基于推送通知的更新,则将推送发送到连接在服务器端插入的每个新数据上的设备。当在应用程序端收到推送时,您需要使用更新的数据相应地更新列表。希望现在更清楚了。