Vaadin why not show notification in multiThreads app - java

My problem is that in my app not show notification.
My application does that each time a button is pressed I create new thread and show notification with info that thread is running or waiting (this works fine). Then, if the thread is running, it will randomly sleep for 5-10 seconds and get data from the rest api and a notification should be displayed that the thread is finished (this notification is not displayed).
Fineshed notifications show after i press again button. As you can see in the image.
Image:
constructor view:
public MainView() {
Button ipButton = getIpButton();
setMargin(true);
setHorizontalComponentAlignment(Alignment.START, ipButton);
add(ipButton);
}
button:
private Button getIpButton() {
final UI ui = UI.getCurrent();
final VaadinSession session = VaadinSession.getCurrent();
Button ipButton = new Button("My IP");
AtomicInteger orderIndex = new AtomicInteger();
ipButton.addClickListener(_e -> {
int orderThread = orderIndex.getAndIncrement();
openBeginNotification(orderThread);
executor.submit(() -> {
try {
UI.setCurrent(ui);
VaadinSession.setCurrent(session);
long sleepTime = (long) (Math.random() * (10 - 5) + 5);
System.out.printf("%d: %ds\n", orderThread, sleepTime);
Thread.sleep(sleepTime * 1000);
IpDTO ip = restTemplate.getForObject("http://ip.jsontest.com/", IpDTO.class);
System.out.printf("%d: %s\n", orderThread, ip);
try {
VaadinSession.getCurrent().lock();
getFinishNotification(orderThread).open(); // here not show notification
VaadinSession.getCurrent().unlock();
} catch (Exception e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
});
return ipButton;
}
notification methods:
private void openBeginNotification(int orderThread) {
Notification notification;
if (executor.getActiveCount() == MAX_THREADS) {
// thread is in front
notification = getWaitNotification(orderThread);
} else {
// thread run
notification = getRunNotification(orderThread);
}
notification.open();
}
private Notification getRunNotification(int orderThread) {
return getNotification("Task " + orderThread + ": run", NotificationVariant.LUMO_PRIMARY);
}
private Notification getWaitNotification(int orderThread) {
return getNotification("Task " + orderThread + ": wait", NotificationVariant.LUMO_CONTRAST);
}
private Notification getFinishNotification(int orderThread) {
return getNotification("Task " + orderThread + ": finish", NotificationVariant.LUMO_SUCCESS);
}
private Notification getNotification(String notificationText, NotificationVariant variant) {
Notification notification = new Notification(notificationText, 1000);
notification.addThemeVariants(variant);
return notification;
}

First, you need to enable #Push to make Vaadin open a websocket connection that makes it possible for the server to directly send messages to the browser without waiting for the browser to send a message asking for changes (which happens when you click a button). The #Push annotation should be in different location depending on the Vaadin version you're using, so please refer to documentation to find the right place.
Second, please use UI::access instead of manually doing setCurrent and locking. While I didn't spot anything in your example that would break the happy case, there are still also a whole bunch of edge cases that you'd need to take into account. As an example, you're not cleaning up after setCurrent which might cause memory leaks and you're not unlocking in case something related to the notification throws an exception.

Related

Using incoming data from bluetooth connection for specific objects? C# Windows Form App & Java Android App

first post here. I've tried to look for a question I have but no luck so I figure I ask it myself.
I am working on 2 programs. An Android app in Java and a C# Windows Form App on windows. They are both simply scorekeeping calculators to keep track of the score of 2 players.
The goal of the 2 programs is to use a Bluetooth connection to send data back and forth between each other so that they are "synced". Android app is a client, c# app is a server (32feet library).
Using the Bluetooth Chat example on Android and some code i put together in VS, I managed to get the 2 programs to connect and send and receive data to each other, great!
But now my main goal is that I need to find out a way to take the incoming data coming from the Android app and change the appropriate labels/text on the windows app.
So for example:
on the Windows App, there are 2 Labels: one for Player1, one for Player2 that both say "10".
On the Android App, I have 2 buttons that separately subtract from either Player1 or Player2's score.
On the android app, if I touch the button that subtracts(-) 1 from Player1 it would be 9. I now want that change to apply to Player1's score label on the windows app, where it would also show 9.
I then want the same thing for Player2's score.
This is the best I can describe my goal, and I would like to know if it's possible, and if so, be pointed in the right direction.
Here is some provided code for what I have so far:
C# windows form app:
private void button1_Click(object sender, EventArgs e)
{
if (serverStarted == true)
{
updateUI("Server already started");
return;
}
if (radioButton1.Checked)
{
connectAsClient();
}
else
{
connectAsServer();
}
}
private void connectAsServer()
{
Thread bluetoothServerThread = new Thread(new ThreadStart(ServerConnectThread)); //creates new thread and runs "ServerConnectThread"
bluetoothServerThread.Start();
}
private void connectAsClient()
{
throw new NotImplementedException();
}
Guid mUUID = new Guid("fa87c0d0-afac-11de-8a39-0800200c9a66");
bool serverStarted = false;
public void ServerConnectThread()
{
serverStarted = true;
updateUI("Server started, waiting for client");
BluetoothListener blueListener = new BluetoothListener(mUUID);
blueListener.Start();
BluetoothClient conn = blueListener.AcceptBluetoothClient();
updateUI("Client has connected");
Stream mStream = conn.GetStream();
while (true)
{
try
{
//handle server connection
byte[] received = new byte[1024];
mStream.Read(received, 0, received.Length);
updateUI("Received: " + Encoding.ASCII.GetString(received));
byte[] sent = Encoding.ASCII.GetBytes("hello world");
mStream.Write(sent, 0, sent.Length);
}
catch (IOException exception)
{
updateUI("Client disconnected");
}
}
}
private void updateUI(string message)
{
Func<int> del = delegate ()
{
textBox1.AppendText(message + Environment.NewLine);
return 0;
};
Invoke(del);
}
}
Android App (snippet from the Bluetooth Chat example - i think this is the only relevant part):
/**
* Sends a message.
*
* #param message A string of text to send.
*/
private void sendMessage(String message) {
// Check that we're actually connected before trying anything
if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
return;
}
// Check that there's actually something to send
if (message.length() > 0) {
// Get the message bytes and tell the BluetoothChatService to write
byte[] send = message.getBytes();
mChatService.write(send);
// Reset out string buffer to zero and clear the edit text field
mOutStringBuffer.setLength(0);
mOutEditText.setText(mOutStringBuffer);
}
}
You will want to have to add the clients to alist of streams for reference and also store the scores of each client on a list and then send the data coming from each client to the rest of the clients
so from the server youd have basically something like this
List<Stream> clients=new List<Stream>();
List<String> client_scores=new List<String>();
public void ServerConnectThread()
{
serverStarted = true;
updateUI("Server started, waiting for client");
BluetoothListener blueListener = new BluetoothListener(mUUID);
blueListener.Start();
BluetoothClient conn = blueListener.AcceptBluetoothClient();
updateUI("Client has connected");
Stream mStream = conn.GetStream();
clients.add(mStream);
client_scores.add(new Random().Next()+"");
int index_cnt = clients.IndexOf(mStream);
while (true)
{
try
{
//handle server connection
byte[] received = new byte[1024];
mStream.Read(received, 0, received.Length);
updateUI("Received: " + Encoding.ASCII.GetString(received));
client_scores[client_scores.FindIndex(ind=>ind.Equals(index_cnt))] = Encoding.ASCII.GetString(received);
byte[] sent = Encoding.ASCII.GetBytes("hello world");
mStream.Write(sent, 0, sent.Length);
foreach(Stream str in clients)
{
byte[] my_score = Encoding.ASCII.GetBytes(clients.ToArray()[index_cnt]+"");
str.Write(my_score, 0, my_score.Length);
}
}
catch (IOException exception)
{
updateUI("Client disconnected");
}
}
}
You can then serialize the data being sent in some sort of json so as to send multiple fields of data comfortably for example :
{
"data type": "score",
"source_id": "client_unique_id",
"data": "200"
}
On your displaying side,just get the values of (in our example case source_id and data) and display on a label

The iap.subscribe(Skus[]) mechanism is returning false even when my user is subscribed already (sandbox)

I used the demo app for auto renewing subscriptions to implement autorenewing subscriptions on my app. I am able to log in and subscribe which will bring up the standard ios subscription dialogs. However the next time i Log in i call the iap.isSubscribed() mechanism from Codenameone , the result is always false (Is this because i am in the testflight environment?). When the isSubscribed method returns fault i send the user to the subscribe page which has a button to subscribe, when this button is pressed i get a dialog informing me i am already subscribed.
I have attempted to use the emulator as well as an actual apple iphone6+ neither of which got back the successfully subscribed receipt for the user
#Override
public void initForm() {
theme = UIManager.initFirstTheme("/theme");
//create a new content container
Container content = new Container();
iap = Purchase.getInAppPurchase();
// Pro only feature, uncomment if you have a pro subscription
// Log.bindCrashProtection(true);
// Define a receipt loader
iap.setReceiptStore(createReceiptStore());
/*
The form needs to be split up into 3 parts 1 part for Successful subscriptions
1 part for paymens that have not been sucecssful yet
and 1 part for people who have not subscribed yet
*/
if (!iap.isSubscribed(Skus)) {
EMCDialogFactory.showMessageDialog("Subscription Failed", "Is Subscribed upon login: " + iap.isSubscribed(SKU_1_MONTH));
content = createNonSubscribedHomeScreen();
} else {
EMCDialogFactory.showMessageDialog("Subscription Failed", "Is Subscribed upon login: " + iap.isSubscribed(SKU_1_MONTH));
content = createSuccessfulHomeScreen();
}
setLayout(new BorderLayout());
add(BorderLayout.CENTER, content);
}
/**
* Creates a receipt loader to load receipts from our web service
*
* #return
*/
private ReceiptStore createReceiptStore() {
//fetch all your receipts from the server to be used by the receipt store
listOfReceipts = fetchReceipts();
return new ReceiptStore() {
#Override
public void fetchReceipts(SuccessCallback<Receipt[]> callback) {
List<Receipt> out = new ArrayList<>();
//loop through the receipts
for (Receipt res : listOfReceipts) {
//create a new receipt
Receipt r = new Receipt();
r.setTransactionId(res.getTransactionId());
r.setPurchaseDate(res.getPurchaseDate());
r.setQuantity(1);
r.setSku(res.getSku());
//check cancellation and expiry
if (res.getCancellationDate() != null) {
r.setCancellationDate(res.getCancellationDate());
}
if (res.getExpiryDate() != null) {
r.setExpiryDate(res.getExpiryDate());
}
out.add(r);
}
callback.onSucess(out.toArray(new Receipt[out.size()]));
}
#Override
public void submitReceipt(Receipt r, SuccessCallback<Boolean> callback) {
submitTheReceipt(r, callback);
}
};
}
There is no Error message that shows up it simply returns false that i am not subscribed and it goes back to my subscription page. However if i press my subscribe button again it says that i am already subscribed.

How to use mediaPlayer correctlty?

I'm trying to play music in my app and while the media player is loading I want to allow the user to keep on using the app, but the app gets stuck for few seconds every time I start loading the media player, and when the media player is finished loading, only then the app returns to normal and starts working again, sometimes it's not just freezing, it also shows popup menu from the OS that prompts the user to quit the app.
I couldn't find any solution in Google or YouTube, anyone knows what's wrong with my code?
final Handler handler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
try {
String STREAM_URL = #####; // here i put the URL of the song
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(STREAM_URL);
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
} catch (NullPointerException e) {
Log.d(TAG, "run: NullPointerException = " + e.getMessage());
FirebaseCrash.log("Tag = " + TAG + "run: NullPointerException = " + e.getMessage());
}
}
}
};
handler.post(runnable);
Even though you are creating a Handler, the creation of the MediaPlayer still happens on the main UI thread. You should call prepareAsync or use an AsyncTask or some other means to avoid calling prepare on the main thread.
From the documentation for Handler:
When you create a new Handler, it is bound to the thread / message
queue of the thread that is creating it
If you are streaming music from the network, preparing the media for playback is especially going to take a while. One option may be to call prepareAsync instead of calling prepare. In that case, you should set the OnPreparedListener, and in that callback call start.

executeDispatch synchronous?

I'm working on a java Applet which has a document loaded. On this Applet I have a custom "print" button which basically inits the print process of the document. This is the code that is executed after this button is pressed:
PropertyValue[] printProperties = new PropertyValue[1];
printProperties[0] = new PropertyValue();
printProperties[0].Name = "Print";
printProperties[0].Value = new Boolean(true);
xDispatchProvider = (XDispatchProvider)UnoRuntime.queryInterface (XDispatchProvider.class, xFrame);
dispatcher.executeDispatch(xDispatchProvider, ".uno:Print","_self", 0, printProperties);
someOtherProcess();
This code opens the native(?) print dialog which is the expected behaviour, and works so far. The problem is the "someOtherProcess" method. I need to execute this method right after the print dialog is closed either by pressing its "print" button or canceling/closing the print dialog.
Since executeDispatch is async I tried to make it synchronous using the "SynchronMode" in the PropertyValue[] with no success.
I found a way to listen to print events which are fired when the print process starts or when it's cancelled. This is the whole code:
PropertyValue[] printProperties = new PropertyValue[1];
printProperties[0] = new PropertyValue();
printProperties[0].Name = "Print";
printProperties[0].Value = new Boolean(true);
xDispatchProvider = (XDispatchProvider)UnoRuntime.queryInterface (XDispatchProvider.class, xFrame);
dispatcher.executeDispatch(xDispatchProvider, ".uno:Print","_self", 0, printProperties);
XPrintJobBroadcaster xPrintJobBroadcaster = (XPrintJobBroadcaster)UnoRuntime.queryInterface(XPrintJobBroadcaster.class, xComponent);
xPrintJobBroadcaster.addPrintJobListener(new MyPrintJobListener());
class MyPrintJobListener implements XPrintJobListener {
public void printJobEvent(PrintJobEvent printJobEvent) {
AppletLogger.log("printing");
}
public void disposing(com.sun.star.lang.EventObject eventObject) {
AppletLogger.log("disposing");
}
}
The "printJobEvent" is fired when the print process has either started, finished, cancelled and so on, but I can't find a way to know if the print dialog has been cancelled or closed as this doesn't fire any print event.
So my main questions are, is there a way to open a print dialog in a synchronous way so that the programs waits for the print dialog to close?
Is there a way to listen to the close event of the native print dialog window?
Thanks in advance!
Check the State property. If printing is cancelled, it should first show JOB_STARTED (which is 0) and then JOB_ABORTED (which is 3).
class MyPrintJobListener implements XPrintJobListener {
public void printJobEvent(PrintJobEvent printJobEvent) {
AppletLogger.log("print status: " + printJobEvent.State.getValue());
}
public void disposing(com.sun.star.lang.EventObject eventObject) {
AppletLogger.log("disposing");
}
}
Also the dispatcher didn't work for me. Use the API interface instead:
XPrintJobBroadcaster xPrintJobBroadcaster = (XPrintJobBroadcaster)
UnoRuntime.queryInterface(XPrintJobBroadcaster.class, xComponent);
xPrintJobBroadcaster.addPrintJobListener(new MyPrintJobListener());
XPrintable xPrintable =
(XPrintable)UnoRuntime.queryInterface(XPrintable.class, xComponent);
xPrintable.print(printProperties);
try { Thread.sleep(10000); } catch (Exception e) {} // Wait for print job.

ConcurrentModificationException in Android AsyncTask

I have a strange issue, which I'm hoping I can explain well enough. My app has two activities - MainActivity and SearchActivity. I have a button on MainActivity which triggers an upload from the database on the device to a remote database on my web server. If I click the button when I first launch the app, no problem, works fine. If I switch to the SearchActivity, don't do anything, and switch back, then try the button, the app crashes with a ConcurrentModificationException.
I've got an AsyncTask which sends the contents of a local database (already pulled out of the database and sent to the thread through the parameters as an ArrayList). I've spent hours debugging this and still can't work out where it is. Any suggestions would be greatly appreciated.
This is the code triggered on the button press, to request the contents of the database from a separate Databaser thread
Button btnRemoteSync = (Button)findViewById(R.id.btnSync);
btnRemoteSync.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent startUpload = new Intent(getString(R.string.broadcast_search_database));
startUpload.putExtra("type-id",1);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(startUpload);
}
});
This is the code in the BroadcastReceiver which gets each response from the databaser and adds them to an ArrayList of custom ResponseObjects. When the databaser thread sends a bssid value of DONE, the AsyncTask is launched with the ArrayList passed in as a parameter.
#Override
public void onReceive(Context context, Intent intent) {
String bssid = intent.getStringExtra(getString(R.string.data_bssid));
if (bssid.equals("DONE")) {
RemoteDatabaseUploader rdb = new RemoteDatabaseUploader(getApplicationContext());
rdb.execute(databases);
} else {
databases.add(new ResponseObject(getApplicationContext(),
bssid,
intent.getStringExtra(getString(R.string.data_ssid)),
intent.getStringExtra(getString(R.string.data_capabilities)),
intent.getIntExtra(getString(R.string.data_level), 0),
intent.getIntExtra(getString(R.string.data_frequency), 0),
intent.getStringExtra(getString(R.string.data_timestamp)),
intent.getDoubleExtra(getString(R.string.data_latitude), 0),
intent.getDoubleExtra(getString(R.string.data_longitude), 0)));
}
}
Below is the doInBackground code for the AsyncTask
#Override
protected Integer doInBackground(ArrayList<ResponseObject>... params) {
ArrayList<ResponseObject> entries = params[0];
try {
URL url = new URL(insertURL);
for (Iterator<ResponseObject> it = entries.iterator(); it.hasNext();) {
ResponseObject ro = it.next(); // THIS IS WHERE THE EXCEPTION REFERENCES IN THE DEBUG OUTPUT
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("USER-AGENT", "Mozilla/5.0");
urlConnection.setRequestProperty("ACCEPT-LANGUAGE", "en-US,en;0.5");
urlConnection.setDoOutput(true);
String postParams = "bssid=" + ro.BSSID
+ "&ssid=" + ro.SSID
+ "&capabilities=" + ro.CAPABILITIES
+ "&level=" + String.valueOf(ro.LEVEL)
+ "&frequency=" + String.valueOf(ro.FREQUENCY)
+ "&timestamp=" + ro.TIMESTAMP
+ "&lat=" + String.valueOf(ro.LAT)
+ "&long=" + String.valueOf(ro.LON);
DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
wr.writeBytes(postParams);
wr.flush();
wr.close();
Log.d("RemoteDatabase : ", "Post sent " + ro.BSSID + " || " + String.valueOf(urlConnection.getResponseCode()));
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
entries.clear();
return null;
}
EDIT -- I appear to have traced the issue down to another section of code, where a broadcast is sent on clicking the button. The button definitely only sends once (been checking using Log.d) but the received in the databaser is receiving it twice. Trying to fix this now.
It's been a while but realised I forgot to add how I solved this, just in case it is a help to anyone else.
I found the issue here was actually that some Android devices send multiple copies of a broadcast. I was using an HTC handset for testing and apparently for some reason they send 2 copies of all broadcasts. The way my code was working I was spawning a thread off a broadcast, which was resulting in 2 identical threads operating on the same data. When these completed they were each sending their "Done" broadcast, which was resulting in 4 of them being received by the main thread. Complete mess.
I ended up having to add a unique ID token to each broadcast and record the values at the receiving end, so if the same ID was received twice no action would be taken the second time.
Please insert a progress bar in your onPreExecute() method of async task and dismiss it in onPostExecute().I thing it is taking too much time to complete the async task,and you are tapping the button again prior to the completion of the async task.

Categories