In my application i should used socket.io and i want when receive my event update UI elements!
I write below codes and i receive my events show me logs, but not update any UI!
I want when receive event, check this winner is user or not and then update my UI.
In logCat show me my logs but not update any UI elements!
My codes:
public void onsocketFinishRecieve(final JSONObject ob) {
try {
((BaseActivity) context).runOnUiThread(() -> {
try {
cancelTimer();
final FinishResponse finishResponse = new Gson().fromJson(ob.toString(), FinishResponse.class);
if (finishResponse.getRes().getWinnerName().equals("not user") || finishResponse.getRes().getWinnerName().equals("not winner")) {
winnerNameWhenFinished = "Not winner";
} else {
winnerNameWhenFinished = finishResponse.getRes().getWinnerName();
}
if (detail.getId() != null) {
if (detail.getId() == finishResponse.getRes().getId()) {
//Set new winner layouts
//Register in auction
if (Constants.profileResponse != null) {
if (Constants.profileResponse.getRes() != null) {
if (Constants.profileResponse.getRes().getUser() != null) {
//Winner
if (Constants.profileResponse.getRes().getUser().getId().equals(finishResponse.getRes().getUserId())) {
Log.e("FinishedSocket", "1");
detailPage_bottomWinnerRateTxt.setVisibility(View.GONE);
detailPage_bottomWinnerBuyTxt.setText("Show basket");
detailPage_bottomWinnerBuyTxt.setOnClickListener(v -> {
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("OPEN_CART_IN_MAIN", "true");
startActivity(intent);
});
} else {
Log.e("FinishedSocket", "2");
//Loser
detailPage_bottomWinnerBuyTxt.setText("Awesome offers");
}
}
}
}
}
}
} catch (Exception e) {
Log.e("DetailResErr", e.getMessage());
}
});
} catch (Exception e) {
Log.e("DetailResErr", e.getMessage());
}
}
Logcat message :
2020-03-08 13:37:37.399 E/FinishedSocket: 2
In logcat show me above message , why not run this line : detailPage_bottomWinnerBuyTxt.setText("Awesome offers"); ??
How can i fix it?
try to run this on Mainthread like this.
someActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
//Your code to run in GUI thread here
detailPage_bottomWinnerBuyTxt.setText("Awesome offers");
}
});
Sockets work on IOThread while other side UI Work on separate Thread called UI thread. So, update the UI element on UI Thread.
Use Annotation :
#UiThread
public abstract void setText(#NonNull String text) { ... }
For know about more annotation, Check the following blog:
https://medium.com/#gurwindersingh_37022/android-annotations-30b4a2850d0
Related
I want to send value from string (distance to obstacle) to my TextView in main activity.
I tried to use Handler, but still not working (crash) or receive nothing.
A part code which receive data from HC-05 (screen where you see in debug value assignet to variable)
enter image description here
#Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while(true){
try {
bytes = inputStream.read(buffer);
final String comingMsg = new String(buffer,0,bytes);
Log.d(TAG,"InputStream: " + comingMsg);
/*mHandler2.post(new Runnable() {
#Override
public void run() {
Message message = new Message();
message.obj = comingMsg;
mHandler2.sendMessage(message);
}
});*/
}catch (IOException e){
Log.e(TAG,"Write: Error reading input." + e.getMessage());
active=false;
break;
}
}
}
Here It's parts of code from MainActivity where I tried put something to get values from service.
[I add, that for this moment i want to see something values from bluetooth in textView. Later I want to create parse string and send custom text to custom TextView - example: FL: (Front Left)- to one textView, FR: (Front Right) - to second textView]
There is method implementThreads(), because I wanted to do 6 Threads to 6 TextView which every time is refreshing value from string in Services (there I tried get value from Bluetooth Service)
Log.d(TAG,"Check intent - result");
if(getIntent().getIntExtra("result",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded device");
myBluetoothService = new MyBluetoothService(getApplicationContext());
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service");
checkIfActive();
}
Log.d(TAG,"Check intent - connect_to_paired");
if(getIntent().getIntExtra("connect_to_paired",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded_paired_device");
myBluetoothService = new MyBluetoothService(getApplicationContext());
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service");
checkIfActive();
}
}
#Override
public void onStart(){
super.onStart();
myBluetoothService = new MyBluetoothService(getApplicationContext());
}
public void checkIfActive(){
Log.d(TAG,"CheckIfActive: Started");
if(myBluetoothService.active){
Log.d(TAG,"CheckIfActive: Running method implementThreads()");
implementThreads();
}
}
public void implementThreads(){
Log.d(TAG,"ImplementThreads: Started");
Thread thread = new Thread(){
#Override
public void run() {
try{
sleep(100);
}catch (InterruptedException e){
e.printStackTrace();
}
}
};
thread.start();
}
public void startConnection(BluetoothDevice device,UUID uuid){
Log.d(TAG,"StartConnection: Initializing connection");
myBluetoothService.startClient(device,uuid);
}
Thanks all for help, because It's very important for me !
Use this to interect with UI Thread for operations like updating textviews etc.
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
//YOUR CODE HERE
Message message = new Message();
message.obj = comingMsg;
mHandler2.sendMessage(message);
}
});
I'm running an AsyncTask on my TakePic class. In doInBackground function I'm using Camera.takePicture function. Now everything is fine at this point; I'm taking the picture and saving the file to /sdcard/%d.jpg that location.
public class TakePic extends AsyncTask<CameraPreview, String, Integer> {
#Override
protected Integer doInBackground(final CameraPreview... params) {
params[0].camera.takePicture(null,null,new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.e("picture_saved", "Picture has been saved succesfully: " + data.length);
camera.release();
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.e("file_not_found: ","couldn't save the file "+e.getMessage());
} catch (IOException e) {
e.printStackTrace();
Log.e("IOexception: ","couldn't save the file "+e.getMessage());
}
}
});
Log.e("doinback_compt:" ,"done");
return 0;
}
#Override
protected void onPostExecute(Integer integer) {
}
}
But after I execute this AsyncTask on my main class it doesn't finish. I need to execute another function and I have to wait until this AsyncTask finishes. So after I execute the AsyncTask I'm using a while loop to check the status of the task but the status never changes.
TakePic backCam=new TakePic();
backCam.execute(cameraPreview_front);
while (backCam.getStatus()!= AsyncTask.Status.FINISHED){
*waiting for async task to finish*
}
It stuck at the while loop and my logcat show that doInBackground running normal, and the file is saving to that location.
10-10 18:06:14.497 15975-15975/com.urun.camera_test E/clicked_capture:: ok
10-10 18:06:14.633 15975-16452/com.urun.camera_test E/doinback_compt:: done
So what am I need to do? Thanks in advance.
This is being handled in an odd way. First CameraPreview.camera.takePicture() will run in the background itself, that is why you pass it the Camera.PictureCallback in the constructor. You are simply stacking threads there. Try this in the main thread
[yourCameraPreview].camera.takePicture(null,null,new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
camera.release();
// Read below
}
}
Now we can just wait for the picture callback. Once we get data back, we can call an AsyncTask to store it in the file, and apply our own callback to wait for it's response. We can utilize a static inner class to make this all work.
private static class ImageSaver extends AsyncTask<Byte, Void, Exception>{
public interface ImageSavedListener{
void onImageSaved(Exception e);
}
private ImageSavedListener mCallback;
public ImageSaver(ImageSavedListener callback){
mCallback = callback;
}
#Override
protected void doInBackground(Byte... data){
if(data == null || data.length == 0)
return new Exception("Data returned from camera is invalid");
try {
FileOutputStream outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.d("picture_saved", "Picture has been saved succesfully: " + data.length);
} catch (FileNotFoundException e) {
Log.e("file_not_found: ","couldn't save the file "+e.getMessage());
return e;
} catch (IOException e) {
Log.e("IOexception: ","couldn't save the file "+e.getMessage());
return e;
}
return null;
}
#Override
protected void onPostExecute(Exception e){
if(mCallback != null)
mCallback.onImageSaved(e);
}
}
Then call it like this (in the section stated Read below above)
new ImageSaver(new ImageSavedListener(){
#Override
public void onImageSaved(Exception e){
if(e == null){
// do what you want
}
else
e.printStackTrace();
}
}).execute(data);
This will take the picture in the background, wait for the response, save the response to a file in the background, wait for the response, and then do what you want based on the exception returned after saving.
If you need to do some code after AsyncTask execution, I can suggest one solution.
Wrap your *waiting for async task to finish* code in Runnable and send it as a param to Async task ( but this is not the best solution, just fast one )
new AsyncTask<Object, Void, Runnable>() {
#Override
protected Runnable doInBackground(Object... runnables) {
CameraPreview cp = (CameraPreview) runnables[0];
Runnable callback = (Runnable) runnables[1];
/**your main logic*/
return callback;
}
#Override
protected void onPostExecute(Runnable aVoid) {
super.onPostExecute(aVoid);
if (aVoid != null)
aVoid.run();
}
}.execute( cameraPreview , new Runnable() {
#Override
public void run() {
/**code to run();**/
}
});
Possible problem with your current code is :
You are not executing super.onPostExecute(integer);
Try change code to
#Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
}
As pointed out before, does not make sense blocking your main thread waiting do certain event. However, if you still want to get a something from your AsyncTask, I would advise you to use FutureTask
As I can see in your code, the AsyncTask is finishing correctly.
The problem is that you are taking the picture inside the AsyncTask. So while the Camera.PictureCallback is waiting for the picture the task ends immediately after call the "takePicture" method.
What I should do is something like this (this is only an approach):
public class TakePic {
public interface MyTakePicListener{
void onPictureTaken();
void onPictureError();
}
private MyTakePicListener myListener;
public void takePicture(CameraPreview cameraPreview) {
cameraPreview.camera.takePicture(null, null, new Camera.PictureCallback() {
#Override
public void onPictureTaken(final byte[] data, final Camera camera) {
new Thread(new Runnable() {
#Override
public void run() {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.e("picture_saved", "Picture has been saved succesfully: " + data.length);
camera.release();
HERE you should call a listener to continue with your success code
myListener.onPictureTaken();
} catch (FileNotFoundException e) {
e.printStackTrace();
Log.e("file_not_found: ", "couldn't save the file " + e.getMessage());
HERE you should call a listener to continue with your error code
myListener.onPictureError();
} catch (IOException e) {
e.printStackTrace();
Log.e("IOexception: ", "couldn't save the file " + e.getMessage());
HERE you should call a listener to continue with your error code
myListener.onPictureError();
}
Log.e("doinback_compt:", "done");
}
}).start();
}
});
}
}
Please, let me know if this could help you.
I have the code below (app live, and I got a crash reported at the line with mService.consumePurchase):
Thread trd = new Thread(new Runnable()
{
#Override
public void run()
{
try
{
int response = mService.consumePurchase(3, getPackageName(), sku.mToken);
if (response == 0)
{
System.out.println("onActivityResult consume ok");
purchasesOK.add(sku.mSku);
}
else
{
System.out.println("onActivityResult consume failed");
purchasesFail.add(sku.mSku);
runOnUiThread(new Runnable()
{
public void run()
{
alert("Store Problems!", "There were problems consuming the product, please use RESTORE button.");
}
});
}
} catch (RemoteException e) {
purchasesFail.add(sku.mSku);
System.out.println("onActivityResult consume crashed");
runOnUiThread(new Runnable()
{
public void run()
{
alert("Store Problems!", "There were problems consuming the product, please use RESTORE button.");
}
});
}
}
});
trd.start();
here is the crash report:
java.lang.NullPointerException at
com.XXXXX.GGActivity.j_ItemPurchase(GGActivity.java:1309) at
com.XXXXX.GGLib.step(Native Method) at
com.XXXXX.GGView$Renderer.onDrawFrame(GGView.java:436) at
android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1523)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
I thought that try/catch will show the popup error in any case of exception. Any ideas what might caused it ? Or how can I avoid it?
Thanks,
/C.
Add this:
catch(NullPointerException e){
purchasesFail.add(sku.mSku);
System.out.println("onActivityResult consume crashed");
runOnUiThread(new Runnable(){
public void run(){
alert("Store Problems!", "There were problems consuming the product, please use RESTORE button.");
}
});
}
in order to show the popup message
I'm trying to create a new android application that is comprised of multiple mini-games. The launcher activity extends BaseGameActivity and has a sign-in button and a ListView containing all the possible games that can be played.
Inside of a mini-game activity (also extends BaseGameActivity), how can I get it to create a notification which will launch a specific Activity? Currently, when I call invitePlayersToGame, the invitation that gets sent is for the full application (Mini-Games) and not the individual game (specific dice game).
public void invitePlayersToGame(View pView) {
Intent intent = Games.RealTimeMultiplayer.getSelectOpponentsIntent(getApiClient(), 1, 1);
intent.putExtra("gameName", "Patman Yahtzee");
startActivityForResult(intent, RC_SELECT_PLAYERS);
}
Is there a way to get the notification to generate with a specific message? Is there a way to get notification to open directly to the mini-game activity without going to the main launcher activity first?
Any help is appreciated. Thanks!
You can send sendReliableMessage for method handshaking.
First enter a room (quickgame or send invite).
public void openInvitationIntent() {
// launch the player selection screen
// minimum: 1 other player; maximum: 1 other players
Intent intent = Games.RealTimeMultiplayer.getSelectOpponentsIntent(mGoogleApiClient, 1, 1);
startActivityForResult(intent, RC_SELECT_PLAYERS);
}
onConnected:
#Override
public void onConnected(Bundle connectionHint) {
// QuickGame
if (mGameMode == 1) {
Log.d(TAG, "onConnected() called. Sign in successful!");
Log.d(TAG, "Sign-in succeeded.");
startQuickGame();
// register listener so we are notified if we receive an invitation to play
// while we are in the game
if (connectionHint != null) {
Log.d(TAG, "onConnected: connection hint provided. Checking for invite.");
Invitation inv = connectionHint.getParcelable(Multiplayer.EXTRA_INVITATION);
if (inv != null && inv.getInvitationId() != null) {
// retrieve and cache the invitation ID
Log.d(TAG, "onConnected: connection hint has a room invite!");
acceptInviteToRoom(inv.getInvitationId());
return;
}
}
}
// Send request
else if (mGameMode == 0) {
// request code for the "select players" UI
// can be any number as long as it's unique
invitationInbox();
}
// request accepted
else {
mIncomingInvitationId = getIntent().getExtras().getString(AppConstants.RC_INVITATION_ID);
RoomConfig.Builder roomConfigBuilder = makeBasicRoomConfigBuilder();
roomConfigBuilder.setInvitationIdToAccept(mIncomingInvitationId);
Games.RealTimeMultiplayer.join(mGoogleApiClient, roomConfigBuilder.build());
// prevent screen from sleeping during handshake
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
After this, you can send model class (includes what you need).
private void broadcastMessage(ModelGameRecievedMessage broadcastedMessage, boolean isFinal) {
try {
if ( mParticipants != null && broadcastedMessage != null) {
byte[] bytes = Utils.serialize(broadcastedMessage);
// Send to every other participant.
for (Participant p : mParticipants) {
if (p.getParticipantId().equals(mMyId)) {
continue;
}
if (p.getStatus() != Participant.STATUS_JOINED) {
continue;
}
if (mRoomId != null) {
if (isFinal) {
// final score notification must be sent via reliable broadcastedMessage
Games.RealTimeMultiplayer.sendReliableMessage(mGoogleApiClient, null, bytes,
mRoomId, p.getParticipantId());
} else {
// it's an interim score notification, so we can use unreliable
Games.RealTimeMultiplayer.sendUnreliableMessage(mGoogleApiClient, bytes,
mRoomId, p.getParticipantId());
}
}
}
Logy.l("broadcastedMessage.getMessageTypeId(); " + broadcastedMessage.getMessageTypeId());
Logy.l("broadcastedMessage.getMessage(); " + broadcastedMessage.getMessage());
}
} catch (IOException e) {
e.printStackTrace();
}
}
finally you can reach the data on other devices:
#Override
public void onRealTimeMessageReceived(RealTimeMessage rtm) {
byte[] bufy = rtm.getMessageData();
ModelGameRecievedMessage recievedMessage = null;
try {
recievedMessage = (ModelGameRecievedMessage) Utils.deserialize(bufy);
Logy.l("recievedMessage.getMessageTypeId(); " + recievedMessage.getMessageTypeId());
Logy.l("recievedMessage.getMessage(); " + recievedMessage.getMessage());
} catch (Exception e) {
Logy.e("Exception onRealTimeMessageReceived deserialize: " + e);
}
switch (recievedMessage.getMessageTypeId()) {
case AppConstants.RC_MULTI_START_TIMEMILIS_MULTIPLAYER:
....
Similar or the same Question has been answered here
I am creating an Android App, which sends a broadcast message to the network and prepares a list of devices responding back.
Now What I did:
I created an Activity Class DeviceManagerWindow.java which calls a thread Sender.java.
Sender.java is responsible for sending the broadcast message.
Then the DeviceManagerWindow.java calls another thread which is responsible for listening to the devices responding back. The devices responding back will be listed in the Activity as soon as the device responds back. For that I have a TableLayout named deviceList.
What code I have written:
DeviceManagerWindow.java This method is called when a button for search is pressed
public void searchDevice(View v) throws IOException, InterruptedException
{
//Log.v("TableLayout:",view.toString());
sendMulticastFlyport = new Thread(new FlyportSender(MAC));
sendMulticastFlyport.start();
new Thread()
{
public void run()
{
MulticastSocket socketComputer=null;
try
{
socketComputer = new MulticastSocket(WifiConstants.COMPUTER_RECV_PORT);
socketComputer.joinGroup(InetAddress.getByName(WifiConstants.COMPUTER_NETWORK_ADDR));
socketComputer.setSoTimeout(1*60*1000);
byte[] inBufComputer = new byte[1024];
DatagramPacket inPacketComputer = new DatagramPacket(inBufComputer, inBufComputer.length);
while(true)
{
System.out.println("Listening...");
socketComputer.receive(inPacketComputer);
System.out.println("Received");
String msg = new String(inBufComputer, 0, inPacketComputer.getLength());
DeviceInformation device = new DeviceInformation(1, msg, inPacketComputer.getAddress().toString());
addDevice(device, false, 1);
Log.v("Received:","Received Computer From :" + inPacketComputer.getAddress() + " Msg : " + msg);
//System.out.write(inPacket.getData(),0,inPacket.getLength());
System.out.println();
Thread.sleep(2000);
}
}
catch(Exception e)
{
Log.v("Exception:","During Receiving Computer: "+e.toString());
try
{
addDevice(null, true, 1);
}
catch (IOException e1)
{
Log.v("Exception:", "Computer End Error: " +e1);
}
}
finally
{
socketComputer.close();
}
}
}.start();
The following code creates a list:
public void addDevice(DeviceInformation device, boolean bool, int type) throws IOException
{
TableLayout tb = (TableLayout) findViewById(R.id.DeviceList);
Log.v("addDevice","Called");
if(bool)
{
LayoutParams layout = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
TableRow tr = new TableRow(getApplicationContext());
TextView tv = new TextView(getApplicationContext());
System.out.println(tb);
tv.setLayoutParams(layout);
tr.setLayoutParams(layout);
String message;
Log.v("addDevice","Device Timeout");
switch(type)
{
case 1:
computerEnd=true;
break;
case 2:
raspberryEnd=true;
break;
case 3:
flyportEnd=true;
break;
}
if(computerEnd && raspberryEnd && flyportEnd)
{
if(rowCounter>0)
{
message = "No More Devices";
}
else
{
message = "No Devices Found";
}
tv.setText(message);
tv.setTextColor(Color.WHITE);
if(rowCounter%2==0)
{
tr.setBackgroundColor(Color.DKGRAY);
}
else
{
tr.setBackgroundColor(Color.GRAY);
}
tv.setVisibility(1);
tr.addView(tv);
tb.addView(tr);
}
}
else
{
LayoutParams layout = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
TableRow tr = new TableRow(getApplicationContext());
TextView tv = new TextView(getApplicationContext());
tv.setLayoutParams(layout);
tr.setLayoutParams(layout);
Log.v("addDevice","Received");
String textToDisplay = device.getDeviceTypeString()+"\n"+device.getIPAddress(); //Write the text to display
tv.setText(textToDisplay);
tv.setTextColor(Color.WHITE);
Drawable img;
if(device.getDeviceType()==1)
{
img = getApplicationContext().getResources().getDrawable(R.drawable.pc);
}
else if(device.getDeviceType()==2)
{
img = getApplicationContext().getResources().getDrawable(R.drawable.raspberry);
}
else
{
img = getApplicationContext().getResources().getDrawable(R.drawable.flyport);
}
img.setBounds(0,0,70,45);
tv.setCompoundDrawables(null, null, img, null);
tv.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
}
});
if(rowCounter%2==0)
{
tr.setBackgroundColor(Color.DKGRAY);
}
else
{
tr.setBackgroundColor(Color.GRAY);
}
rowCounter++;
Log.v("Result","Device Added");
}
}
Now it is showing me an error in the logCat as:
05-11 22:01:10.165: E/AndroidRuntime(13873): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
What I have figured out from this is only the UIThread is allowed to access the Views that is created.
Previously I had tried:
new Thread()
{
public void run()
{
runOnUiThread(){
MulticastSocket socketComputer=null;
try
{
....
....
....
}
}
And that time I received an error:
Main thread cannot access Network
Before that I had tried to use synchronized methods which was called from the Receiving.java Thread File. but It also gave an error of not creating the list.
I have tried all possible ways.
Now what whould I do.?
You figured it out right. Now you can learn to either use a Handler to pass information to the UI thread (see http://www.techotopia.com/index.php/A_Basic_Overview_of_Android_Threads_and_Thread_handlers) or AsyncTask (see http://developer.android.com/reference/android/os/AsyncTask.html).
I personally prefer AsyncTask. You can paste the code which performs the search into the doInBackground() method (not need to use a separate thread, doInBackground() already does that for you) and paste the UI-related code (the list creation code) into the onPostExecute() method. Search for further examples of AsyncTask if it is not sufficiently clear how it works from the link.
EDIT: If you intend your device search code to run indefinitely, then you have to resort to Handler, as AsyncTask expects the doInBackground() method to finish before running onPostExecute(). See which option better suits your needs.