So I'm completely lost on this one, it might be obvious solution or I'm just trying somethin that's not possible but here it is.
I have two classes one is being used as e listener class and second one is the one that handles queue(i will only include relevant code).
Handler class:
public void check() {
for (Queueable queueable : queue) {
if (!doesReceiverHavePlayers(queueable)) continue;
}
}
private boolean doesReceiverHavePlayers(Queueable queueable) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("PlayerCount");
out.writeUTF(queueable.getReceiver());
Player player = Iterables.getFirst(Bukkit.getOnlinePlayers(), null);
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
return /*response*/ > 0;
}
Listener class:
#Override
public void onPluginMessageReceived(String channel, #NotNull Player player, byte[] message) {
if (!channel.equals("BungeeCord")) return;
ByteArrayDataInput in = ByteStreams.newDataInput(message);
String subChannel = in.readUTF();
switch (subChannel) {
case "PlayerCount":
int response = in.readInt();
break;
}
}
The check method is called every 5 seconds and doesReceiverHavePlayers requests player count from a certain server to see if there are any players on it, but the 'response' arrives in the listener class onPluginMessageReceived method. But as you can see I'm trying to use response in the doesReceiverHavePlayers method and return boolean value. Is there any way I can achieve this and how should I do it?
In onPluginMessageReceived store the result in a ConcurrentHashMap and then lookup the value in doesReceiverHavePlayers instead of making a blocking call.
Something like this:
ConcurrentHashMap<String, Integer> playerCounts = new ConcurrentHashMap<>();
void onPluginMessageReceived() {
playerCounts.put(subChannel, response);
}
boolean doesReceiverHavePlayers() {
return playerCounts.get(queueable.getReceiver()) > 0;
}
Related
I have an issue with android studio and the retrofit library and the way in which it processes the data.
I have a simple flow of operation I would like:
Request single item from database on server(fetch request)
Wait for callback to confirm it has been received by the app
Add another request(Loop)
Stop adding requests when all data is sent
The issue I have is my onResponse callback for my fetch result does not run until all my requests are sent. Then all the responses are errors. ( If I call a single item(1 from the database)) the call back runs fine.
How do I force it to send one request and wait until that response before sending another?
Loop code
private void Pull_data_loop(int total_entries){
//int current_data_point = 0;
boolean datum_processing = false;
for (int i = 1; i <= total_entries; i++) {
Add_single_datam(i);//Call until all entries are fetched from the server
}
}
Fetch code- Not running callback need to wait for this callback before sending next request
private void Add_single_datam(int id)
{
HashMap<String, String> map = new HashMap<>();
map.put("Id_request", Integer.toString(id));//The ID value
Call<Fetch_result> call = retrofitInterface.executeGet_data(map);//Run the post
call.enqueue(new Callback<Fetch_result>() {
#Override
public void onResponse(Call<Fetch_result> call, Response<Fetch_result> response) {
if (response.code() == 200)//Successful login
{
D1= response.body().getD1_String();
D2= response.body().getD2_String();
boolean result = BLE_DB.addData_Downloaded(D1, D2);//Add data
if (result == true) {
Log.d(TAG, "data_changes: Added data correctly");
}
if (result == false) {
Log.d(TAG, "data_changes: did not add data correctly");
}//false
} else if (response.code() == 404) {
Utils.toast(getApplicationContext(), "Get data fail");//Pass information to the display
}
}
#Override
public void onFailure(Call<Fetch_result> call, Throwable t) {
Utils.toast(getApplicationContext(), "Get data error");
}
});
}
Note:
I am using a node js server for my requests. I send the Id and it returns that Id in the database.
You could send a callBack instance to your Add_single_datam then in your retrofit response, send to that callback success.
Then in that callBack you would have iteravel i and you could see if you reached the end of total_entries added +1 in i and make request again, or just stop.
use some threading solutions like RxJava or Coroutines or AsyncTask. The reason it's not following the rule is because of there are two threads on which work is getting distributed so in order to get it make it work in sync, we have to use some threading solutions mentioned above and execute this for loop on the background thread and make it like a synchronous call and get all the results and finally switch back to main thread with the results.
If you are familiar with the AsynTask.
private class FetchDataTask extends AsyncTask<Int, Integer, List<Fetch_result>> {
protected Long doInBackground(Int... total_entries) {
List<Fetch_result> allResults = new ArrayList<Fetch_result>();
for (int i = 1; i <= total_entries[0]; i++) {
HashMap<String, String> map = new HashMap<>();
map.put("Id_request", Integer.toString(total_entries[0]));
Fetch_result response = retrofitInterface.executeGet_data(map).execute().body();
allResults.add(response);
}
return allResults;
}
protected void onProgressUpdate(Integer... progress) {
//show progress
}
protected void onPostExecute(List<Fetch_result> result) {
//do something on main thread, in loop on result
D1= result[0].getD1_String();
D2= result[0].getD2_String();
boolean result = BLE_DB.addData_Downloaded(D1, D2);//Add data
if (result == true) {
Log.d(TAG, "data_changes: Added data correctly");
}
if (result == false) {
Log.d(TAG, "data_changes: did not add data correctly");
}//false
}
}
now call like this.
new FetchDataTask().execute(total_entries);
I am making an app that takes a JSON document as input and displays the information in a user-friendly way. The app will also send a push notification if certain information is outside certain parameters. The problem I am running into is that the information needs to be very up-to-date, this means the app receives a new JSON every 10 seconds. That makes the app send a push notification every 10 seconds, which is way too often. Is there a way for me to either specify a break period where the app will not send a notification if it has recently sent one? Or could I make it so if the user doesn't clear the notification, it doesn't send a new one?
I am relatively new to programming in general, and really new to Android-Studio. I have looked on the Android Developers page for NotificationManager to see if there was something there, but I was unable to find anything.
if variable1") < variable1MinValue || variable1 > variable1MaxValue||
variable2 < variable2MinValue|| variable2 > variable2MaxValue){
NotificationManager notif=
(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
Notification notify=new Notification.Builder
(getApplicationContext()).setContentTitle("ERROR: value
Error").setContentText("Please see app for more information.").
setSmallIcon(R.drawable.error_notif).setSound(soundUri).build();
notify.flags |= Notification.FLAG_AUTO_CANCEL;
notif.notify(0, notify);
I am making this app for my business, so I can't leave anything company specific in the program. If there is anything I need to clarify, please let me know!
I am hoping to be able to get it to only send the notification a few times every hour at the fastest. Ideally, maybe once every 30 minutes to an hour.
If you're on desktop, you could look at Google Guava, which has many caching utilities, including the ability to create entries with eviction times. Using that, you could add entries with an eviction of 10 minutes. Then, when a new JSON comes in, you can check if it exists in the cache. If no, send the notification, if yes, reset the eviction time for it.
You could also write your own EvictionMap. Extend ConcurrentHashMap, and in the constructor create a thread and start it. Inside the thread, you can check X seconds (sounds like every 5 seconds for you) and evict entries. The Map would require <User, long> where the long is the eviction time. You can create your own put() and get() and maybe a touch() which would reset the eviction time to System.getCurrentMillis();
(I just found a version I had used years ago. It could use some improvement with how it manages the Thread)
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class EvictionList<K>
{
private final ConcurrentHashMap<K, Long> evictionList = new ConcurrentHashMap<K, Long>();
private long evictionTime;
private final EvictionThread t;
public EvictionList(int evictionTimeInSeconds)
{
this.evictionTime = evictionTimeInSeconds * 1000;
t = new EvictionThread(this, evictionTime);
Thread thread = new Thread(t);
thread.start();
}
public void touch(K o)
{
evictionList.put(o, System.currentTimeMillis());
}
public void evict()
{
long current = System.currentTimeMillis();
for (Iterator<K> i=evictionList.keySet().iterator(); i.hasNext();)
{
K k = i.next();
if (current > (evictionList.get(k) + evictionTime) )
{
i.remove();
}
}
}
public void setEvictionTime(int timeInSeconds)
{
evictionTime = timeInSeconds * 1000;
t.setEvictionTime(evictionTime);
}
public Set<K> getKeys()
{
return evictionList.keySet();
}
public void stop()
{
t.shutDown();
}
#Override
protected void finalize()
{
t.shutDown();
}
private class EvictionThread implements Runnable
{
private volatile long evictionTime;
private EvictionList list;
private volatile boolean shouldRun = true;
private EvictionThread(EvictionList list, long evictionTime)
{
this.list = list;
this.evictionTime = evictionTime;
}
public void shutDown()
{
shouldRun = false;
}
public void setEvictionTime(long time)
{
evictionTime = time;
}
public void run()
{
while (shouldRun)
{
try
{
Thread.sleep(evictionTime);
}
catch (Exception ex) {}
list.evict();
}
}
}
}
so, here is my today problem:
First of all, please note that I do NOT have the Matlab parallel toolbox available.
I am running java code witch interact with Matlab. Sometime Matlab directly call some java functions, sometimes it is the opposite. In this case, we use a notification system which comes from here:
http://undocumentedmatlab.com/blog/matlab-callbacks-for-java-events
We then address the notification in proper callbacks.
Here is a simple use case:
My user select a configuration file using the java interface, loaded into Matlab.
Using an interface listener, we notify Matlab that the configuration file has been selected, it then run a certain number of functions that will analyzes the file
Once the analysis is done, it is pushed into the java runtime, which will populate interface tables with the result. This step involve that matlab will call a java function.
Finally, java request the interface to be switched to an arbitrary decided tab.
This is the order of which things would happen in an ideal world, however, here is the code of the listener actionPerformed method:
#Override
public void actionPerformed(ActionEvent arg0) {
Model wModel = controller.getModel();
Window wWindow = controller.getWindow();
MatlabStructure wStructure = new MatlabStructure();
if(null != wModel) {
wModel.readMatlabData(wStructure);
wModel.notifyMatlab(wStructure, MatlabAction.UpdateCircuit);
}
if(null != wWindow) {
wWindow.getTabContainer().setSelectedComponent(wWindow.getInfosPannel());
}
}
What happen here, is that, when the notifyMatlab method is called, the code does not wait for it to be completed before it continues. So what happen is that the method complete and switch to an empty interface page (setSelectedComponent), and then the component is filled with values.
What I would like to, is for java to wait that my notifyMatlab returns a "I have completed !!" signal, and then pursue. Which involves asynchrounous code since Matlab will code java methods during its execution too ...
So far here is what I tried:
In the MatlabEventObject class, I added an isAcknowledge member, so now the class (which I originaly found in the above link), look like this (I removed all unchanged code from the original class):
public class MatlabEventObject extends java.util.EventObject {
private static final long serialVersionUID = 1L;
private boolean isAcknowledged = false;
public void onNotificationReceived() {
if (source instanceof MatlabEvent) {
System.out.println("Catched a MatlabEvent Pokemon !");
MatlabEvent wSource = (MatlabEvent) source;
wSource.onNotificationReceived();
}
}
public boolean isAcknowledged() {
return isAcknowledged;
}
public void acknowledge() {
isAcknowledged = true;
}
}
In the MatlabEvent class, I have added a future task which goal is to wait for acknowledgement, the methods now look like this:
public class MatlabEvent {
private Vector<IMatlabListener> data = new Vector<IMatlabListener>();
private Vector<MatlabEventObject> matlabEvents = new Vector<MatlabEventObject>();
public void notifyMatlab(final Object obj, final MatlabAction action) {
final Vector<IMatlabListener> dataCopy;
matlabEvents.clear();
synchronized (this) {
dataCopy = new Vector<IMatlabListener>(data);
}
for (int i = 0; i < dataCopy.size(); i++) {
matlabEvents.add(new MatlabEventObject(this, obj, action));
((IMatlabListener) dataCopy.elementAt(i)).testEvent(matlabEvents.get(i));
}
}
public void onNotificationReceived() {
ExecutorService service = Executors.newSingleThreadExecutor();
long timeout = 15;
System.out.println("Executing runnable.");
Runnable r = new Runnable() {
#Override
public void run() {
waitForAcknowledgement(matlabEvents);
}
};
try {
Future<?> task = service.submit(r);
task.get(timeout, TimeUnit.SECONDS);
System.out.println("Notification acknowledged.");
} catch (Exception e) {
e.printStackTrace();
}
}
private void waitForAcknowledgement(final Vector<MatlabEventObject> matlabEvents) {
boolean allEventsAcknowledged = false;
while(!allEventsAcknowledged) {
allEventsAcknowledged = true;
for(MatlabEventObject eventObject : matlabEvents) {
if(!eventObject.isAcknowledged()) {
allEventsAcknowledged = false;
}
break;
}
}
}
}
What happen is that I discover that Matlab actually WAIT for the java code to be completed. So my waitForAcknowledgement method always wait until it timeouts.
In addition, I must say that I have very little knowledge in parallel computing, but I think our java is single thread, so having java waiting for matlab code to complete while matlab is issuing calls to java functions may be an issue. But I can't be sure : ]
If you have any idea on how to solve this issue in a robust way, it will be much much appreciated.
I had an issue where Text to Speech would not speak anything. I realised this was due to the fact that I was attempting to call 'Speak()' before TTS had initialised.
I need to wait until TTS has initialised, so that I can call 'Speak()' successfully. I thought doing something along the lines of this would work:
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
mTTSInitialised = true;
} else {
Log.e("TTS", "Initialisation Failed!");
}
}
...
while(!mTTSInitialised){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
But this fails to initialise at all. Is there a way to do this effectively?
The initialisation of the Text to Speech engine is asynchronous, which is why you realised you have to 'wait' for it to complete, before requesting that it processes an utterance.
Even when it eventually initialises successfully, it can be subsequently killed by the system, or it can of course fail to initialise, so you always need to be ready to handle a request to speak, where the engine isn't prepared.
Add the following helper class
public class PendingTTS {
private String pendingUtterance;
private int pendingQueueType;
public String getPendingUtterance() {
return this.pendingUtterance;
}
public void setPendingUtterance(#NonNull final String pendingUtterance) {
this.pendingUtterance = pendingUtterance;
}
public int getPendingQueueType() {
return this.pendingQueueType;
}
public void setPendingQueueType(final int pendingQueueType) {
this.pendingQueueType = pendingQueueType;
}
}
Assuming you're using an Activity, you need to declare the following variables:
private volatile PendingTTS pendingTTS;
private static final int MAX_INIT_ATTEMPTS = 4;
private volatile int initCount;
and initialise the Text to Speech object in onCreate()
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
In your onInitListener you would check if there is any pending speech:
#Override
public void onInit(final int status) {
switch (status) {
case TextToSpeech.SUCCESS:
initCount = 0;
// Set up tts stuff
tts.setOnUtteranceProgressListener(YOURprogressListener);
if (pendingTTS != null) {
// We have pending speech, process it and check the result
int speechResult = tts.speak(pendingTTS.getPendingUtterance(),pendingTTS.getPendingQueueType(),
// remaining tts variables here)
switch (speechResult){
case TextToSpeech.SUCCESS:
// Result was successful
pendingTTS = null;
break;
case TextToSpeech.ERROR:
// Speech failed
// Check if it has repeatedly failed up to the max attempts
if(initCount < MAX_INIT_ATTEMPTS){
initCount ++;
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
} else {
// Totally broken - let the user know it's not working
}
break;
}
} else {
// there was nothing to process
}
break;
case TextToSpeech.ERROR:
// Check if it has repeatedly failed up to the max attempts
if(initCount < MAX_INIT_ATTEMPTS){
initCount ++;
tts = new TextToSpeech(YOURActivity.this, YOURonInitListener);
} else {
// Totally broken - let the user know it's not working
}
break;
}
I've glued the above together from my code - where the speech and initialisation methods are all separated, but I tried to give you an overview above of everything you need to handle.
Elsewhere in your code, when you make a tts.speak(//stuff here) request, you need to check the result as demonstrated above, to make sure it was successful. Again, in my code, this is separated into one single method. If it does fail, you need to set the PendingTTS parameters prior to attempting to initialise again:
pendingTTS = new PendingTTS();
pendingTTS.setPendingQueueType(// your queue type);
pendingTTS.setPendingUtterance(// your utterance);
It is is successful, make sure pendingTTS is set to null.
The overall design is that if the initialisation failed, it will attempt to initialise again, up to the maximum allowed attempts. If the speech fails, it will attempt to initialise the engine again, firstly setting the PendingTTS parameters.
Hope you managed to follow that.
Hmm..
Not a very good idea.
You can try to add the text to the TTS queue and let it do it's work. This snippet can be inside button click, etc as:
tts.speak(toSpeak, TextToSpeech.QUEUE_ADD, null);
Small tutorial that would help.
I have a problem with the waiting requests functionality in the volley library. The debugging led me to the AbstractQueue class in java.util where an element is being added (according to some values in the method that indicate a successful addition to the queue) and simultaneously - not being added(according to the 0 elements in the queue - that don't change their value). The adding method is synchronized. Bellow you can find a detailed description of the situation and my research so far. I will be really thankful if you have a look at them and share if you have any idea what is happening.
I try to automatically retry requests upon any kind of error ( for example - when there is no connection, or the server name is not correct ).
The error handler of a request adds the request back to the static singleton RequestQueue of my app.
RetriableRequestWraper.java
m_request = new StringRequest(
method,
url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
handleResponse(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
handleError(volleyError);
}
});
public void handleError(VolleyError volleyError)
{
Log.d("Request: ", m_request.toString());
Log.d("handleError: ", volleyError.toString());
if(retriesCount<3)
{
executeRequest();
++retriesCount;
}
else
{
retriesCount = 0;
}
}
public void executeRequest()
{
RequestsManager.getInstance().executeRequest(m_request);
}
public void executeRequest(Request request)
{
Log.d("executeRequest ","m_requestQueue.add(request)");
m_requestQueue.add(request);
}
RequestManager.java
public void executeRequest(Request request)
{
Log.d("executeRequest ","m_requestQueue.add(request)");
m_requestQueue.add(request);
}
This approach doesn't work and when debugging inside the volley library I come to the point where the request could not be added to the mCacheQueue of the RequestQueue class, because the cacheKey of the reuqest is present in the mWaitingRequests Map. So the request is added in the queue in mWaitingRequests map, corresponding to its key. When the previous request is finished - the new one is not added to the queue although these lines are being executed in the RequestQueue class:
synchronized(this.mWaitingRequests) {
String cacheKey1 = request.getCacheKey();
Queue waitingRequests1 = (Queue)this.mWaitingRequests.remove(cacheKey1);
if(waitingRequests1 != null) {
if(VolleyLog.DEBUG) {
VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.", new Object[]{Integer.valueOf(waitingRequests1.size()), cacheKey1});
}
this.mCacheQueue.addAll(waitingRequests1);
}
}
When debugging further this line
this.mCacheQueue.addAll(waitingRequests1);
In the AbstractQueue.java (class in java.util ) the element is being added to the queue, the "modified" value is true, but throughout the hole time the "this" parameter continues to contain 0 elements.
public boolean addAll(Collection<? extends E> c) {
if (c == null)
throw new NullPointerException("c == null");
if (c == this)
throw new IllegalArgumentException("c == this");
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
Inside the offer(E e) method of PriorityBlockingQueue.java the execution of the program stops at line 453.
l452 siftUpUsingComparator(n, e, array, cmp);
l453 size = n+1;
Obviously the returned value is true, but the element is not added. My debugger could not get into the method that adds the element - siftUpUsingComparator(n, e, array, cmp);
I am going to add a timer before retrying my request, and will construct a new one. So I am not really interested in a workaround, I want to understand what and how is happening in this situation. Do you have any idea as to what could be the reason behind this?
The issue is that you try to add the same Request instance once again to the queue it has been added to. This messes up with the queue and the Request itself as it has states. For example if you simply enable markers you'll have a crash. The solution is to either just use the default retry policy or clone the requests.