Issue
I'm trying out Volley and so it's working pretty great for my project. I can add things and move information around, but I need the app to refresh or update itself when a new item is added to the list, and I personally would like to do it as smooth as Whatsapp.
How can I achieve this? I had another project where I used AsyncTask
, but I don't know if this should be the approach to take here. I'm kinda new to Android development and this is taking a little over my knowledge with Volley.
Could you help me and point me at the right direction, please?
Below is the code for my adapter, my main activity and where I make the posts. I believe this refresh should be done in one of these 3 classes.
If you could help me it would be a greate learning step in my knowledge. I appreciate those who are willing to help!
Thank you! :)
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);
}
}
My Adapter
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);
}
}
}
});
}
}
}
Activity to Create the Posts
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();
}
}
}
Solution
The question is not subjected to an specific programming issue, rather it points to an application architecture. However, I am writing this answer to share some of my experience on working with such applications.
As far as I could understand from your question, you want to show posts in your application in a feed using a RecyclerView
. The RecyclerView
needs to be updated, when a user creates a post/product from the application or someone else creates a post/product. If I have understood correctly, then you need to keep following things in mind.
- You are calling the
loadProducts();
function in theonCreate
function of yourMainActivity
which is correct. The application should load all the items that needs to be shown in theRecyclerView
when it launches. So the initialization part is completely okay. - Now the part with the update. You can follow several different methodologies here based upon your convenience. The question of doing it right or wrong is mostly based on your application requirement, hence I am giving a brief of them all.
- Firstly, you can think of a pull data from server on demand model like Facebook. The initial products are already loaded in your
RecyclerView
. When the user wants to see if there is any update there, s/he might pull down theRecyclerView
to refresh the data. I guess you have thought of this already, I am just covering all available options. - Then you might consider pull data from server using a background service, which will call the
loadProducts
function after every 60 seconds or any time interval that you might consider calling safe based on your application requirement. When new data is available on your each pull request, update theRecyclerView
accordingly using thenotifyDataSetChanged
method. - The other option which requires a server side implementation as well is based on push notification. When a push is received in your application, you will call the
loadProducts
function and will update theRecyclerView
accordingly. The push is neither real-time nor reliable. However, it might save you a lot of API calls. - Another available option that you have is implementing Websocket both in your application and server side. The development and the performance is costly. However, this ensures your data is updating in real time.
- Last, but not the least, you can take a look at the Firebase database offered by Google which has a exact same implementation that you want in your case. It updates in real time as the backend architecture uses a Websocket, but its easier and simpler to integrate within your application.
I just have gave you some ideas. Hope these might help you.
Update
Based on your comment, I think you did not get me clearly. You cannot get the push notification after each x minutes from your server side, because in that case you need to keep the track of the update of your posts in each of your application which is installed in your users' device - which is a horrible design.
You need to pick one. If you want to refresh your data in every x minute, then I would suggest to keep a Handler
or a background Service
in your application which will call loadProducts
function after every x minutes and will update your data.
If you are planning to implement push notification based updating, then you send a push to the devices connected on each of your new data inserted in server side. And when the push is received in the application side, you need to update the list accordingly with the updated data. Hope thats clearer now.
Answered By - Reaz Murshed
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.