I have created a RecyclerView to show each node that I have connected. In the RecyclerView I have added two buttons and one TextView. The TextView will show the current status of the node i.e. whether the node in currently on or off. The nodes are sending their current status over MQTT, I am able to detect the current status of every node on my app but I am unable to update the TextView according to it. How can I update the TextView?
I have tried adding new item and deleting the previous one, but none of them works for me. I have added the code where I am detecting from which node the status message is coming.
//From this section I am getting details of my all node stored into the database
public void addData()
{
pumpList = new ArrayList<>();
StringRequest stringRequest = new StringRequest(Request.Method.GET, REQUEST_URL,
new Response.Listener<String>()
{
#Override
public void onResponse(String response)
{
try
{
JSONArray pumpData = new JSONArray(response);
for(int i = 0; i < pumpData.length(); i++)
{
JSONObject pump = pumpData.getJSONObject(i);
String name = pump.getString("name");
String device_id = pump.getString("device_id");
String stat = pump.getString("stat");
Log.d("HTTP",String.valueOf(name));
Log.d("HTTP",String.valueOf(device_id));
Log.d("HTTP",String.valueOf(stat));
pumpList.add(new pumpData(name,device_id,stat));
}
pumpAdapter adapter = new pumpAdapter(getActivity(),pumpList);
recyclerView.setAdapter(adapter);
progressDialog.dismiss();
}
catch (JSONException e)
{
e.printStackTrace();
progressDialog.dismiss();
}
}
},
new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error)
{
Toast.makeText(getActivity(),error.getMessage(),Toast.LENGTH_SHORT).show();
progressDialog.dismiss();
}
});
Volley.newRequestQueue(getActivity()).add(stringRequest);
}
//When I get a message over MQTT then I am showing from which device the MQTT Message is Coming from
public void changeDataByFiltering(String MQTT_TOPIC, String MQTT_PAYLOAD)
{
for(pumpData pD: pumpList)
{
insertStringSubscribe INSSUB = new insertStringSubscribe();
String mqtt_topic_from_list = INSSUB.insertString(pD.getDeviceID());
if(mqtt_topic_from_list.trim().toLowerCase().equals(MQTT_TOPIC.trim().toLowerCase()))
[enter image description here][1]{
if(MQTT_PAYLOAD.trim().toLowerCase().equals(payloadON.trim().toLowerCase()))
{
Toast.makeText(mCtx, pD.getName()+": ON",Toast.LENGTH_SHORT).show();
}
if(MQTT_PAYLOAD.trim().toLowerCase().equals(payloadOFF.trim().toLowerCase()))
{
Toast.makeText(mCtx, pD.getName()+": OFF",Toast.LENGTH_SHORT).show();
}
}
}
}
I assume that we have a List<String> data as our data source and we have rvadapter which is our RecyclerView.Adapter . and we will do as below to update an item:
data.set(position,"newdata");
rvadapter.notifyItemChanged(position);
Also, you can change the range of items. and insert new item or delete item but have to call notify... related function in rvadapter
but if you recreate the data for example :
data = new ... then you have to use notifydatasetchanged;
Related
I am trying to get all the data from the first document and move to the next document and do the same.
CollectionReference fstore = fs.collection("Diagnostics").document(email).collection("Date");
fstore.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot documentSnapshot) {
if(!documentSnapshot.isEmpty()){
for (DocumentSnapshot documentSnapshots : documentSnapshot) {
String date = documentSnapshots.getId();
String faultcodes = documentSnapshots.getString("Code");
String description = documentSnapshots.getString("Description");
TroubleCodes pastsc = new TroubleCodes(date,faultcodes,description);
pastscan.add(pastsc);
pastscansdpt.setAdapter(new PastScanAdapter(pastscan, PastScanpage.this));
}
}
else{
TroubleCodes nosc = new TroubleCodes("No Diagnosis Scans",null, null);
pastscan.add(nosc);
pastscansdpt.setAdapter(new PastScanAdapter(pastscan, PastScanpage.this));
}
}
});
Instead of creating and setting adapter for RecyclerView or ListView for each document over and over again, create your adapter and set it for RecyclerView or ListView with empty pastscan List just only one time. Then get your data, add in to list and notify the adapter.
pastscansdpt.setAdapter(new PastScanAdapter(pastscan, PastScanpage.this));
CollectionReference fstore = fs.collection("Diagnostics/" + email + "/Date");
fstore.get().addOnSuccessListener(queryDocumentSnapshots -> {
//Clear your list otherwise whenever this method triggers it'll add same documents over and over again.
pastscan.clear();
if (!queryDocumentSnapshots.isEmpty()) {
for (DocumentSnapshot document : queryDocumentSnapshots) {
if (document.exists()) {
//According to your codes your document data structure is same as TroubleCodes.
//So you don't need to get all fields one by one.
TroubleCodes pastsc = document.toObject(TroubleCodes.class);
//Add each document in to your list.
pastscan.add(item);
}
}
} else {
TroubleCodes nosc = new TroubleCodes("No Diagnosis Scans", null, null);
pastscan.add(nosc);
}
//Notify your adapter.
adapter.notifyDataSetChanged();
});
I am getting data from server as json. Everything works but notifyDataSetChanged is not working.
BackGroundTask backGroundtask = new BackGroundtask();
backGroundTask.execute(arrayList);
private class BackGroundWorkeroneSignup extends AsyncTask<List<CheckingDTO>,CheckingDTO, CheckingDTO> {
#Override
public void onResponse(JSONObject response) {
CheckingDTO check = new CheckingDTO(email_c+"=="+pass_c,email_c,pass_c,email_c,pass_c);
arrayList.add(checkingDTO);
adapterActivity = new HistoryAdapter(arrayList);
recyclerView.setAdapter(adapterActivity);
#Override
protected void onPostExecute(CheckingDTO data) {
super.onPostExecute(data);
arrayList.clear();
List<CheckingDTO> list = new ArrayList<>();
list.add(data);
adapterActivity = new HistoryAdapter(list);
adapterActivity.notifyDataSetChanged();
}
I'm posting the relevant code that I've sent you in the email.
oncreate method
recyclerView = (RecyclerView) view.findViewById(R.id.recyclerview);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(view.getContext()));
adapterActivity = new HistoryAdapter(arrayList);
recyclerView.setAdapter(adapterActivity);
backGroundWorkeroneSignup = new BackGroundWorkeroneSignup();
backGroundWorkeroneSignup.execute(arrayList);
background method:
try {
JSONArray jsonArray = response.getJSONArray("get_request");// this is your array containing data
for (int i=0;i<jsonArray.length();i++) {
JSONObject jobj = jsonArray.getJSONObject(i);
String id = jobj.getString("id");
String email_c =jobj.getString("pick_lat");
String pass_c = jobj.getString("pick_lon");
checkingDTO = new CheckingDTO(email_c+"=="+pass_c,email_c,pass_c,email_c,pass_c);
CheckingDTO check = new CheckingDTO(email_c+"=="+pass_c,email_c,pass_c,email_c,pass_c);
arrayList.add(check);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
on PostExecute
adapterActivity.notifyDataSetChanged();
In First Part Notice the recyclerView.setAdapter(adapterActivity);
In Background Mode:
when you loop in Array always remember: index starts from 0 therefore it's always less then size of array i.e. for (int i=0;i<jsonArray.length();i++)
You should always create new object of Model class in loop for and then add it in loop. There in no need of calling the notifydatasetchanged in loop.
In onPostExecute: we call the notifydatasetchanged only because we've already added all the elements in the list.
hope that explains all of your queries. let me know if you have confusion in any case
I have created a listview which will display some youtube video list (title, thumbnail, videocode) from json using volley library. List is displayed as I expected. Then I implemented onclick listener for list view. Here is the code
// Creating volley request obj
JsonArrayRequest movieReq = new JsonArrayRequest(url,
new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
Log.d(TAG, response.toString());
hidePDialog();
// Parsing json
for (int i = 0; i < response.length(); i++) {
try {
JSONObject obj = response.getJSONObject(i);
Movie movie = new Movie();
movie.setTitle(obj.getString("title"));
movie.setThumbnailUrl(obj.getString("image"));
movie.setPYear(obj.getString("time"));
videocode = (obj.getString("videocode"));
//movie.setRating(((Number) obj.get("rating"))
// .doubleValue());
//movie.setYear(obj.getInt("releaseYear"));
// Genre is json array
// JSONArray genreArry = obj.getJSONArray("genre");
for (int j = 0; j < genreArry.length(); j++) {
genre.add((String) genreArry.get(j)); }
//movie.setGenre(genre);
// adding movie to movies array
movieList.add(movie);
} catch (JSONException e) {
e.printStackTrace();
}
}
// notifying list adapter about data changes
// so that it renders the list view with updated data
adapter.notifyDataSetChanged();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
hidePDialog();
}
});
// Adding request to request queue
AppController.getInstance().addToRequestQueue(movieReq);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent videoplayer = new Intent(Videos.this, VideoPlayer.class);
//String videocode = null;
videoplayer.putExtra("videocode", videocode);
startActivity(videoplayer);
finish();
}
});
So that after clicking on list item, another activity opens and plays the video. To play the video, youtube video code is required, that I am getting from Json and using putExtra I am transferring value to player activity.
The problem I am facing
Clicking on anyvideo plays in listview plays 1st video only. Means suppose list is showing 2 videos - Video1 and Video2. Naturally, clicking on video1 should play video1 and clicking on video2 should play video 2. But what happening is either I click on Video1 or Video2 or Video3, Player is playing video1 only..
Here is The JSON file
http://angelqr.cf/api.php
You have to get the videocode from the movielist. At first add the videocode for every movie individually.
movie.setVideocode(obj.getString("videocode"));
//videocode = (obj.getString("videocode"));
Then make a function for fetching the particular movie's videocode.
public String getVideocode(int position) {
return movieList.get(position).getVideocode();
}
Then call it from your listener's code.
videoplayer.putExtra("videocode", getVideocode(position));
I have this android code which bring a JSON from a server and fill an ArrayList from that JSON
I checked the size of the ArrayList "meals" inside the onresponse void it gives me 1 but when i check it after the StringRequest object i get 0 items .
meals is defined in global scope and initialized inside the oncreateview function
The Code:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
Log.i("debug","on create view");
View view =inflater.inflate(R.layout.fragment_meal_list,container,false);
ListView List ;
meals=new ArrayList<meal>();
String url="http://syriankitchen.tk/get_recent.php";
StringRequest mealsrequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try{
JSONObject object= new JSONObject(response);
JSONArray mealsArray = object.getJSONArray("result");
for(int i=0;i<mealsArray.length();i++){
JSONObject cur = mealsArray.getJSONObject(i);
int id= cur.getInt("id");
String name= cur.getString("name");
String description = cur.getString("description");
int price = cur.getInt("price");
meals.add(new meal(id,name,price,description));
}
Log.i("debug","meals size = "+meals.size());
}
catch(JSONException e){
e.printStackTrace();
}
}
},new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getActivity(),error.getMessage(),Toast.LENGTH_SHORT).show();
}
});
Volley.newRequestQueue(getActivity()).add(mealsrequest);
ArrayList<String> strs=new ArrayList<String>();
String mealsnames[]=new String[meals.size()];
for(int i=0;i<meals.size();i++)strs.add(meals.get(i).getName());
strs.toArray(mealsnames);
Log.i("debug","meals ou size "+meals.size());
CustomList adapter = new CustomList(getActivity(),mealsnames,meals);
List = (ListView)view.findViewById(R.id.list);
List.setAdapter(adapter);
The problem here is about understanding how asynchronous tasks work. When you are adding a volley request to the queque, it will run in background thread (off the main thread) and control will pass to the next line.
So, after this:
Volley.newRequestQueue(getActivity()).add(mealsrequest);
control passes to this:
ArrayList<String> strs=new ArrayList<String>();
String mealsnames[]=new String[meals.size()];
Now since meals is updated on the background thread, you are not able to get the data by the time control reaches String mealsnames[]=new String[meals.size()];
So you will get zero size (meals.size()) here.
Try to move this portion of the code into onResponse.
Try like this:
public void updateData(){
ArrayList<String> strs=new ArrayList<String>();
String mealsnames[]=new String[meals.size()];
for(int i=0;i<meals.size();i++)strs.add(meals.get(i).getName());
strs.toArray(mealsnames);
Log.i("debug","meals ou size "+meals.size());
CustomList adapter = new CustomList(getActivity(),mealsnames,meals);
List = (ListView)view.findViewById(R.id.list);
List.setAdapter(adapter);
}
and call this method from onResponse:
#Override
public void onResponse(String response) {
try{
JSONObject object= new JSONObject(response);
JSONArray mealsArray = object.getJSONArray("result");
for(int i=0;i<mealsArray.length();i++){
JSONObject cur = mealsArray.getJSONObject(i);
int id= cur.getInt("id");
String name= cur.getString("name");
String description = cur.getString("description");
int price = cur.getInt("price");
meals.add(new meal(id,name,price,description));
}
Log.i("debug","meals size = "+meals.size());
updateData();
}
catch(JSONException e){
e.printStackTrace();
}
}
When you write this -
Volley.newRequestQueue(getActivity()).add(mealsrequest);
That means you are making an asynchronous call and that mealsrequest will run on another thread.
You are printing -
Log.i("debug","meals ou size "+meals.size());
just after you make your mealsrequest. When control reaches this statement your network request is not completed yet. So apparently, you don't have anything in your list. Your list will be populated in onResponse() only, since that method is executed after the network request gets completed.
I am trying to use parse to set comments for a specific post , I already have a Post class and a Comment class in the parse.com Data , anyway I tried to set a comment inside a column in the class and then get it , but the problem is , I can only get 1 comment per post , how to do that , is my question , I tried one to many relations , but it didn't work , I tried a pointer row in the Meal class that points to the Comment class , but I didn't know what to do then , here is some sample code :
public void addTheComment() {
// Create the Post object
ParseObject post = new ParseObject("Post");
post.put("textContent", txtComment.getText().toString());
// Create an author relationship with the current user
post.put("comment", getCurrentMeal());
// Save the post and return
post.saveInBackground(new SaveCallback () {
#Override
public void done(ParseException e) {
if (e == null) {
setResult(RESULT_OK);
finish();
} else {
Toast.makeText(getApplicationContext(),
"Error saving: " + e.getMessage(),
Toast.LENGTH_SHORT)
.show();
}
}
});
this adds a comment from edit text through out a button when pressed
and here is the list that shows the comments :
private void updateComments() {
ParseQueryAdapter<ParseObject> adapter =
new ParseQueryAdapter<ParseObject>(this, new ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery<ParseObject> create() {
// Here we can configure a ParseQuery to our heart's desire.
ParseQuery query = new ParseQuery("Post");
query.whereEqualTo("comment", getCurrentMeal());
return query;
}
});
adapter.setTextKey("comment");
adapter.setImageKey("photo");
ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter);
}
and :
public Meal getCurrentMeal() {
return meal;
}
private void updateComments() {
ParseQueryAdapter<ParseObject> adapter =
new ParseQueryAdapter<ParseObject>(this, new ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery<ParseObject> create() {
// Here we can configure a ParseQuery to our heart's desire.
ParseQuery query = new ParseQuery("Comment");
query.whereContainedIn("parent", Arrays.asList(mealId));
return query;
}
});
adapter.setTextKey("content");
// adapter.setImageKey("photo");
ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter);
}
and when pressing the button (activate the method addTheComment) it adds the text from the edit text (txtComment)to insert it into the Comment section where you make a relation to the Post class.
public void addTheComment() {
// Create the comment
ParseObject myComment = new ParseObject("Comment");
myComment.put("content", txtComment.getText().toString());
// Add a relation between the Post with objectId "1zEcyElZ80" and the comment
myComment.put("parent", ParseObject.createWithoutData("Meal", mealId));
// This will save both myPost and myComment
myComment.saveInBackground();
}