Android - Use Broadcast Receiver to reload activity - android

I am developing an android application and I have one activity which shows all the tables in a restaurant. Within this activity, there is a method to change the table color (the table is just a button) based on whether a customer is at the table.
On the customer's screen, when they select their table, my MYQSL database is updated and the user is now assigned to the table.
Now, when I go to open the map screen (note: this is used by waiters on the app, it cant be accessed by customers), the table will be a different color (it checks the table status in the db, if the table is assigned it is a different color).
However, the only way to get the updated map is by reloading the map activity. I want the map activity to update automatically using a BroadcastReceiver() but I am struggling to find a tutorial on how to implement this. When a customer clicks a table to assign themselves to it, I want the broadcast to be sent, automatically reloading the map activity... Is this possible? And if so, how do I implement it?
EDIT: The waiter and customer are using the same application but on different devices
The ChooseTable activity has an on click listener for each table which results in the following method being called:
private void assignUserToTable(final int table, final String userid) {
String url = "hidden";
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
if (response.trim().equals("success")) {
Toast.makeText(ChooseTable.this, "Welcome!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(ChooseTable.this, "Oops, something went wrong!", Toast.LENGTH_LONG).show();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(ChooseTable.this, "Error! " + error.toString(), Toast.LENGTH_LONG).show();
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("table_id", String.valueOf(table));
params.put("user", userid);
return params;
}
};
MySingleton.getInstance(this).addToRequestQueue(stringRequest);
}
The waiter map view looks has the following method which checks the table status on the activity being loaded:
private void checkTables(){
String url = "hidden";
StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try{
JSONObject jsonObject = new JSONObject(response);
String success = jsonObject.getString("success");
JSONArray jsonArray = jsonObject.getJSONArray("toggles");
if(success.equals("1")){
for(int i=0; i<jsonArray.length(); i++){
JSONObject object = jsonArray.getJSONObject(i);
String tableid = object.getString("tableid");
if(Tbl1.getTag().equals(tableid)){
Tbl1.setBackgroundColor(ContextCompat.getColor(WaitingStaffMapScreen.this, R.color.tableReq));
} else if(Tbl2.getTag().equals(tableid)){
Tbl2.setBackgroundColor(ContextCompat.getColor(WaitingStaffMapScreen.this, R.color.tableReq));
} else if(Tbl3.getTag().equals(tableid)){
Tbl3.setBackgroundColor(ContextCompat.getColor(WaitingStaffMapScreen.this, R.color.tableReq));
} else if(Tbl4.getTag().equals(tableid)){
Tbl4.setBackgroundColor(ContextCompat.getColor(WaitingStaffMapScreen.this, R.color.tableReq));
} else if(Tbl5.getTag().equals(tableid)){
Tbl5.setBackgroundColor(ContextCompat.getColor(WaitingStaffMapScreen.this, R.color.tableReq));
} else if(Tbl6.getTag().equals(tableid)){
Tbl6.setBackgroundColor(ContextCompat.getColor(WaitingStaffMapScreen.this, R.color.tableReq));
} else if(Tbl7.getTag().equals(tableid)){
Tbl7.setBackgroundColor(ContextCompat.getColor(WaitingStaffMapScreen.this, R.color.tableReq));
} else if(Tbl8.getTag().equals(tableid)){
Tbl8.setBackgroundColor(ContextCompat.getColor(WaitingStaffMapScreen.this, R.color.tableReq));
}
}
}
} catch (JSONException e) {
e.printStackTrace();
Toast.makeText(WaitingStaffMapScreen.this, "Oops, something went wrong!", Toast.LENGTH_LONG).show();
}
}
},new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(WaitingStaffMapScreen.this, "Error! " +error.toString(), Toast.LENGTH_LONG).show();
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("table_id", "0");
return params;
}
};
MySingleton.getInstance(this).addToRequestQueue(stringRequest);
}
Essentially I want some means of reloading the map screen activity when a table button has been clicked.

Since everything is running on separate devices, what I would do is implement firebase cloud messaging:
https://firebase.google.com/docs/cloud-messaging/android/client
When the application is started, the device receives a token.
When the device receives this token, you will POST it to your database(assuming you have a table of devices) under a new column(ie: FirebaseToken) for that device row.
When the table status is updated(ie: a user selects a table), and that reaches out to the server, you will have a query that goes through each device registered to the business, and sends a push notification.
Then on the android app, you will have a firebase service running that receives the push notification(ie:)
public class MyFirebaseMessagingService extends FirebaseMessagingService
{
NotificationManager notificationManager;
#Override public void onMessageReceived(RemoteMessage remoteMessage)
{
Map<String,String> data = remoteMessage.getData();
if (data.get("title").equals("Update Tables")) {
//Call logic to update the adapter
}
}
}
Very general gist of it. Relatively easy to implement. Any questions, I can do my best to clarify.
As the below comment said, using group messaging is best. I didn't know how many devices each business would have, so was trying to keep it as simple as possible.
Here is a server side example. This will simply send a push notification to the phone, and will be received in the FirebaseMessagingService class you extended.
public bool SendMessage(string firebaseTokenId, FirebaseMessages type)
{
httpWebRequest = (HttpWebRequest)WebRequest.Create("http://fcm.googleapis.com/fcm/send");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Headers.Add("Authorization", "your key");
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
var messageToSend = new Message()
{
to = firebaseTokenId,
data = new DataPayload()
{
title = firebaseMessages[type].title,
message = firebaseMessages[type].body,
}
};
string json = JsonConvert.SerializeObject(messageToSend, Formatting.Indented);
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
}
public enum FirebaseMessages
{
UpdateTables
}
public class Message
{
public DataPayload data {get;set;}
public string to { get; set; }
}
public class DataPayload
{
public string title { get; set; }
public string message { get; set; }
}
//on the on receive, this is a datapayload(not notification), so no push intent will ever be shown, hence you can leave the body null.
firebaseMessages.Add(FirebaseMessages.MessageReceived, new FirebaseMessage() { title = "Table Update", body = ""});

Related

Creating a real time notification from android service

I am creating an application which shows the notification as soon as I post a new post on wordpress site.
Now the notification is generated as soon as I put a post on the wordpress site.
But after 40-45 minutes the app gets crashed and gets killed in the background with the following error:-
the error that showed after the app crashes
I have tried many solutions none of it worked.
I don't want to use firebase for the notification.
I have to fetch the data in real time from the wordpress and then create the notification.
This is the following code for generating the notification:-
private void setupNotificationListener(){
StringRequest request = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String s) {
flag=1;
//System.out.println(flag);
gson = new Gson();
list = (List) gson.fromJson(s, List.class);
postTitle = new String[list.size()];
postContent=new String[list.size()];
System.out.println("shiv class:"+list.size());
for(int i=0;i<list.size();++i) {
mapPost = (Map<String, Object>) list.get(i);
mapTitle = (Map<String, Object>) mapPost.get("title");
postTitle[i] = (String) mapTitle.get("rendered");
mapContent = (Map<String, Object>) mapPost.get("content");
postContent[i] = (String) mapContent.get("rendered");
}
if(!alreadyNotified(postTitle[0])){
Log.d("not notified","");
createNotif(postContent[0],postTitle[0]);
saveNotificationKey(postTitle[0]);
}else{
System.out.print("already notified");
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
Log.d("Error","Error");
}
});
rQueue = Volley.newRequestQueue(NotifierService.this);
rQueue.add(request);
NotifierService.getInstance().getRequestQueue().getCache().clear();
}
You create the requestQueue from a timer, so every 5 seconds. And within your executed code you create always a new request queue. This won't work you should keep the requestQueue as final global variable and create it only once in your constructor.
public class NotifierService extends Service {
private final RequestQueue rQueue;
NotifierService() {
this.rQueue = Volley.newRequestQueue(this);
}
private void setupNotificationListener() {
// do your request handling
}
}
The OutOfMemoryError might occur because you create so many objects which are not correctly garbage collected

retrofit gives 500 internal server error when I add only one item, but postman response works fine

I am trying to debug this issue about "Http 500 internal access error" .For that the code is as shown below:
private void submitOrder() {
List<String> itemIds = new ArrayList<>();
List<Integer> itemQuantity = new ArrayList<>();
for (FoodTruckItem foodTruckItem : foodTruckItemList) {
itemIds.add(foodTruckItem.getItemId());
itemQuantity.add(foodTruckItem.getItemQuantityOrdered());
}
if (InternetConnection.checkConnection(this)) {
Observable<GenericResponse> results = RetroClient.getApiService()
.submitOrder("******", "", total,
"anywhere", "", "*****", itemIds, itemQuantity,
foodtruckInfo.getFoodTruckId());
results.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<GenericResponse>() {
#Override
public void onCompleted() {
unsubscribe();
}
#Override
public void onError(Throwable e) {
Toast.makeText(MyCartActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
#Override
public void onNext(GenericResponse response) {
showOrderCompleteFragment();
}
});
} else {
}
}
Here, what happens is when I send webservice with 2 items this works fine, but for one item it gives 500 internal server error. But for every case postman successfully creates order
The postman response is as shown below:
I think you need to use Map for itemIds and itemQuantity instead of List<String>/List<Integer> as below :
Define below parameter in RetroClient.getApiService().submitOrder()
#FieldMap Map<String, String> itemIdsMap
#FieldMap Map<String, String> itemQuantityMap
Now pass itemIds and itemQuantity value as below :
Map<String, String> itemIdsMap = new HashMap<>();
Map<String, String> itemQuantityMap = new HashMap<>();
String itemIds = "item_id[%d]";
String itemQuantity = "item_quantity[%d]";
for (int i = 0; i < foodTruckItemList.size(); i++) {
itemIdsMap.put(String.format(itemIds, i), foodTruckItemList.get(i).getItemId());
itemQuantityMap.put(String.format(itemQuantity, i), foodTruckItemList.get(i).getItemQuantityOrdered());
}

My Data is Not Stored in Database

I am making a simple register app where user sign up and data store in the My Mydatabase like usename, name, age, passsword
I already created database table in phpMyAdmin and I uploaded Register.php file into my server I check Register.php file their is no error it works great (I use postman app that act as app to send sign up details to the server it actually work my database is storing the values send by the postman app but when I use android app and sign up data is not storing in my database)
They should be some mistake in my code but error is not showing I take entire day to solve the problem not still not found.
I am referring to this tutorial https://www.youtube.com/watch?v=T7Z4GVFaT4A&list=PLe60o7ed8E-TztoF2K3y4VdDgT6APZ0ka&index=4
I am using volley networking library in my gradle file
Here Register Activity where user enter username, name, age, password is store and send back to another activity to send server
It is linked with xml file whre user can sign up
public class RegisterActivity extends AppCompatActivity {
EditText username , name , pass , age;
Button r_button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
username = (EditText)findViewById(R.id.username_et);
name = (EditText)findViewById(R.id.name_et);
pass = (EditText)findViewById(R.id.pass_et);
age = (EditText)findViewById(R.id.age_et);
r_button = (Button)findViewById(R.id.register_button);
r_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String usname = username.getText().toString();
String nam = name.getText().toString();
String password = pass.getText().toString();
int ages = Integer.parseInt(age.getText().toString());
Response.Listener<String> responselistner = new Response.Listener<String>(){
#Override
public void onResponse(String response) {
try {
JSONObject jsonResponse = new JSONObject(response);
boolean success = jsonResponse.getBoolean("success");
if(success)
{
Intent intent = new Intent(RegisterActivity.this,LoginActivity.class);
startActivity(intent);
//after successfull sign up it redirect to login page
}
else
{
AlertDialog.Builder builder = new AlertDialog.Builder(RegisterActivity.this);
builder.setMessage("Registration failed")
.setNegativeButton("retry",null)
.create()
.show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
};
RegisterRequest registerRequest = new RegisterRequest(nam, usname,ages,password , responselistner);
RequestQueue requestQueue = Volley.newRequestQueue(RegisterActivity.this);
requestQueue.add(registerRequest);
}
});
}
}
Here is my class RegisterRequest
public class RegisterRequest extends StringRequest {
private static final String REGISTER_REQUEST_URL ="http://fgeeges.esy.es/Register.php";
private Map<String, String> params;
public RegisterRequest(String name , String username , int age , String password , Response.Listener<String> listener)
{
super(Method.POST, REGISTER_REQUEST_URL , listener ,null);
params = new HashMap<>();
params.put("name ",name);
params.put("username",username);
params.put("age" ,age+"");
params.put("password",password);
}
}
Add
#Override
public Map<String, String> getParams(){
return params;
}
in the RegisterRequest Class.

How to put volley coding in main acitivity.java

This Android app is using Android Studio. The function is to scan and display data from the beacon/eddystone. The app already functions and after the scanning stops, the data saves to the local file. I need to transfer the data to the server. How can i insert the volley coding to the mainacitivity.java. I tried to put under the stopscanning button, but it shows error. Im really beginners to learn about android studio.
Here is the coding:
private void stopScanning(Button scanButton) {
try {
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
// TODO - OK, what now then?
}
String scanData = logString.toString();
if (scanData.length() > 0)
{
public class MainActivity extends AppCompatActivity {
//The values of these variables will be fetched by the file(Where you will store data)
private String PREFERENCE_SCANINTERVAL = "scanInterval";
private String PREFERENCE_TIMESTAMP = "timestamp";
private String PREFERENCE_POWER = "power";
private String PREFERENCE_PROXIMITY = "proximity";
private String PREFERENCE_RSSI = "rssi";
private String PREFERENCE_MAJORMINOR = "majorMinor";
private String PREFERENCE_UUID = "uuid";
private String PREFERENCE_INDEX = "index";
private String PREFERENCE_LOCATION = "location";
private String PREFERENCE_REALTIME = "realTimeLog";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String url = "http://beaconscanner.byethost33.com/beaconscanner.php";//This is the url of your server where you will be sending the data to.
//StringRequest is a class in the Volley Library.
//The constructor of this class has four parameters.
// 1 parameter is Request.Method.POST =this specifies the method type, That is post.
//2 parameter is the url you will be sending the request to.That is the server
//3 parameter is the response listener , It will listen for any response from your server . you will be able to fetch the response from the server using this.
//4 parameter is the error listener, it will listen for any error's during the connection or etc.
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//Here you will be able to fetch the response coming from the server.
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
})
//This is the method we override.
{
//This is method is used to send the data to the server for post methods. This method returns all the data you want to send to server. This is how you send data using Volley.
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String,String> params = new HashMap<String, String>();
params.put("scanInterval",PREFERENCE_SCANINTERVAL);
params.put("timestamp",PREFERENCE_SCANINTERVAL);
params.put("power",PREFERENCE_POWER);
params.put("proximity",PREFERENCE_PROXIMITY);
params.put("rssi",PREFERENCE_RSSI);
params.put("majorMinor",PREFERENCE_MAJORMINOR);
params.put("uuid",PREFERENCE_UUID);
params.put("index",PREFERENCE_INDEX);
params.put("location",PREFERENCE_LOCATION);
params.put("realTimelog",PREFERENCE_REALTIME);
return params;
}
};//The constructor ends here.
Volley.newRequestQueue(this).add(request);// This is the main potion of this code. if you dont add this you will not be able to send the request to your server. this helps you to send it.
}
}
// Write file
fileHelper.createFile(scanData);
// Display file created message.
Toast.makeText(getBaseContext(),
"File saved to:" + getFilesDir().getAbsolutePath(),
Toast.LENGTH_SHORT).show();
scanButton.setText(MODE_STOPPED);
} else {
// We didn't get any data, so there's no point writing an empty file.
Toast.makeText(getBaseContext(),
"No data captured during scan, output file will not be created.",
Toast.LENGTH_SHORT).show();
scanButton.setText(MODE_STOPPED);
}
}
Please add your stacktrace. Also I guess that you want to send the data using the body not the params :). In that case, call the request using the following signature:
new JsonObjectRequest(Request.Method.POST, url, new JSONObject(bodyData), new Response.Listener<JSONObject>() { }
public void sendMyData(HashMap map) {
String url = "http://"....";
StringRequest request = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
progressBar.setVisibility(View.INVISIBLE);
try {// to receive server response, in this example it's jsonArray
JSONArray jsonArray = new JSONArray(response);
//code
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
}) {
#Override
public String getBodyContentType() { // if your server uses java restfull webservice , you have to override this content type
return "application/json";
}
#Override
protected Map<String, String> getParams() throws AuthFailureError {// parameters which should server receive
Map<String, String> parameters =map;
return parameters;
}
};
requestQueue.add(request);
}

JSON Download # onCreateView leaves recyclerView empty

if (isConnected()) {
Event eInstance = new Event();
theEvents = eInstance.downloadEvents(eventsNightlife, getActivity());
rAdapter = new RecyclerAdapter(theEvents);
recyclerView.setAdapter(rAdapter);
progrsBar.setVisibility(View.GONE);
....
This is part of the code that runs at "onCreateView". The method downloadEvents uses Volley to download JSON data, extract it and return a list of items (theEvents). Now when my app starts, the recycler view is empty. If I go to my home screen out of the app and then run my app again, this time the data sometimes gets downloaded.
I debugged step by step, and at first launch (i mean when the app is not just resuming), theEvents is empty, so the download didn't return or manage to return anything...
Suggestions on how to execute things before the UI has been shown to the user or what actually needs to be done to approach this task better?
Also, I use a swipeRefreshLayout and at its onRefresh method I do:
public void onRefresh() {
Event eInstance = new Event();
theEvents = eInstance.downloadEvents(eventsNightlife, getActivity());
rAdapter.notifyDataSetChanged();
swipeRefreshLayout.setRefreshing(false);
}
but it doesn't work. I also tried to
rAdapter = new RecyclerAdapter(theEvents);
rAdapter.notifyDataSetChanged();
recyclerView.swapAdapter(rAdapter, false);
still not working.
EDIT: My downloadEvents method implementing Volley:
public List<Event> downloadEvents(String urlService, Context context) {
eventsList = new ArrayList<>();
RequestQueue requestQueue = Volley.newRequestQueue(context);
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest
(Request.Method.GET, urlService, null, new Response.Listener<JSONArray>() {
#Override
public void onResponse(JSONArray response) {
try {
String durationStr = null;
for (int i = 0; i < response.length(); i++) {
JSONObject eventJson = response.getJSONObject(i);
String title = eventJson.getString("EventTitle");
String body = eventJson.getString("EventBody");
String date = eventJson.getString("EventDate");
String time = eventJson.getString("EventTime");
int duration = Integer.parseInt(eventJson.getString("EventDuration"));
if (duration > 60) {
durationStr = "Duration: " + duration / 60 + " h";
} else if (duration < 60) {
durationStr = "Duration: " + duration + " m";
}
String place = eventJson.getString("EventPlace");
String organ = eventJson.getString("Organization");
Event event = new Event(title, body, date, time, durationStr, place, organ);
eventsList.add(event);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e("VOLLEY ERROR", "" + error);
}
}
);
requestQueue.add(jsonArrayRequest);
return eventsList;
}
You can use EventBus for your purpose that is a simple and truth way.
Here, i write an example for how to use EventBus with volley.
Consider that i want to download some data.
This is the class that my download methods is inside it (you can add more methods to it in the future):
Im used volley to download my data:
// Download methods is inside volley
public class MyDownloader{
public static void downloadData(){
DownloadDataEvent dlDataEvent=new DownloadDataEvent();
List<String> myResult=new ArrayList<>();
...
#Override
public void onResponse(JSONArray response) {
super.onResponse(response);
if(respone!=null){
// Do what i want with my received data
dlDataEvent.setData(response);
}
// Post my event by EventBus
EventBus.getDefault().post(dlDataEvent);
...
}
}
}
This is my event:
public class DownloadDataEvent{
private JSONArray mData;
public void setData(JSONArray data){
mData=data;
}
public JSONArray setData(){
return mData;
}
}
Now i want to use my downloadData() method inside my MainActivity:
(I called my downloadData method inside onCreate.)
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
...
// I have to register this class for EventBus subscriber:
if(!EventBus.getDefault().isRegister(this)){
EventBus.getDefault().registerSticky(this);
}
// Call my downloadData method
if(isConnected()){
MyDownloader.downloadData();
}
}
// And for receive the data through EventBus, i have to create a
// method (subscriber) in this template:
public void onEventMainThread(DownloadDataEvent downloadDataEvent){
JSONArray result=downloadDataEvent.getData();
// Do what i want with my received data
}
}
you can create more than one subscriber every where you want to use received data.
I passed JSONArray to my DownloadDataEvent that it is not good. you can deserialize your received data and pass it to your DownloadDataEvent.
I used Volley to download data
Maybe my descriptions were confusing, but EventBus is a well-known library and is very easy to use.

Categories

Resources