Printing the output from a Bufferedreader to a TextView - java

i am currently programming an app that manly works as a console for receiving and sending messages to my socket server.
I want to output the messages that the server sent me to a textview.
My problem is that i am getting the following exception when changing the textview
W/System.err: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
My code:
public class SocketListener implements Runnable {
public static BufferedReader r;
public void run() {
try {
MainActivity.ausgabe.setText("Reading socket");
String message;
Boolean run = true;
while (run) {
if(r != null) {
MainActivity.ausgabe.setText("Reading line");
message = r.readLine();
MainActivity.ausgabe.setText("Line read");
if(message != null){
MainActivity.ausgabe.setText(message);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
As far as i have tested, the problem is in this line:
message = r.readLine();
because changing the textview before this line works perfekt, but after this line doesnt work (It prints the "reading line" but runs into the error when printing "line read")
I hope you can help me cause i couldnt find anything on the internet
Undead

When implementing interaction between Thread and Activity you should use Handler (info) or runOnUiThread (info).
I think the error throw is somehow delayed (because of multithreading) so you are seeing it after the view has actually changed. Probably there is another thread that checks for correct view manipulation and throws this error when discovers validation (I was unable to find exact info in Android docs).

Related

JDA Discord Bot - [ErrorResponseException] 10008: Unknown Message

despite being new to JDA I havent had any big problems till now, maybe I am just missing something crucial. To quickly explain what following code SHOULD do:
Whenever the bot gets started, the onGuildReady event creates an Object containing a loop which sends a single message to a specified channel and after 1 minute edits said message.
#Override
public void onGuildReady(GuildReadyEvent event) {
System.out.println("ON GUILD READY: " + event.getGuild());
new AutoController(event, channelid);
}
Now with my understanding, the guildReady event should enable me to send messages to specified channels in every guild my bot is connected to AND edit them or do stuff with them.
String messageId = null;
String channelId;
public AutoController(GuildReadyEvent event, String channelId){
this.event = event;
start();
}
#Override
public void run(){
try {
while (true) {
sleep((long) timer);
if(messageId == null){
event.getGuild().getTextChannelById(channelId).sendMessage("A").queue();
this.messageId = event.getGuild().getTextChannelById(channelId).getLatestMessageId();
}else{
event.getGuild().getTextChannelById(channelId).editMessageById(messageId,"B").queue();
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
Sending a message whenever the bot goes online works, but as soon as it gets in the 2nd loop where the edit should happen, it throws me an ErrorResponseException saying the message is unkknown.
[ForkJoinPool.commonPool-worker-1] ERROR RestAction - RestAction queue returned failure: [ErrorResponseException] 10008: Unknown Message net.dv8tion.jda.api.exceptions.ContextException at net.dv8tion.jda.api.exceptions.ContextException.here(ContextException.java:54) at net.dv8tion.jda.api.requests.Request.<init>(Request.java:73) at net.dv8tion.jda.internal.requests.RestActionImpl.queue(RestActionImpl.java:200) at net.dv8tion.jda.api.requests.RestAction.queue(RestAction.java:572) at net.dv8tion.jda.api.requests.RestAction.queue(RestAction.java:538) at org.gsbunker.controller.AutoController.run(AutoController.java:45)
I really dont understand why the message is unknown, ive already checked that the messageid and channelid are not null when passed - still getting the same error. the code is slightly simplified for understanding purposes, if questions occur feel free to ask. pleeeeeeeaase help me and my brain <3
Sitting back and relaxing your brain sometimes really is the best solution!
Putting the thread to sleep after queuing made sure that the message is online and ready for retrieval when executing the editMessage method
if(messageId == null){
event.getGuild().getTextChannelById(channelId).sendMessage("A").queue();
sleep(3000);
this.messageId = event.getGuild().getTextChannelById(channelId).getLatestMessageId();
}else{
event.getGuild().getTextChannelById(channelId).editMessageById(messageId,"B").queue();
}
after reviewing the documentation again, if found that the complete() method would be even better suited for a use case like this.
if(messageId == null){
event.getGuild().getTextChannelById(channelId).sendMessage("A").complete();
this.messageId = event.getGuild().getTextChannelById(channelId).getLatestMessageId();
}else{
event.getGuild().getTextChannelById(channelId).editMessageById(messageId,"B").queue();
}
yeeaahh not that big of a problem if you clear your head and stop forgetting java basics, happy coding :D

Jsoup not connecting to webpage in Android Studio

I am working on a project right now where I use jsoup in a class with the function retrieveMedia in order to return an ArrayList filled with data from the webpage. I run it in a thread since you shouldn't be connecting to URLs from the main thread. I run it and join it. However, it doesn't work (I tested the same code in Eclipse separate from Android Studio and it worked fine). It seems that no matter what I do I can't get jsoup to connect to the webpage. Below is my class MediaRetriever.
public class MediaRetreiever {
public ArrayList<Media> retrieveMedia() {
ArrayList<Media> mediaOutput = new ArrayList<Media>(); //Store each scraped post
Thread downloadThread = new Thread(new Runnable() {
public void run() {
Document doc = null;
try {
doc = Jsoup.connect(<Website Im connecting to>).timeout(20000).get();
} catch (IOException e) {
System.out.println("Failed to connect to webpage.");
mediaOutput.add(new Media("Failed to connect", "oops", "", "oh well"));
return;
}
Elements mediaFeed = doc.getElementById("main").getElementsByClass("node");
for (Element e : mediaFeed) {
String title, author, imageUrl, content;
title=e.getElementsByClass("title").text().trim();
author=e.getElementsByClass("content").tagName("p").select("em").text().trim();
content=e.getElementsByClass("content").text().replace(author,"").trim();
Media media = new Media(title, author, "", content);
mediaOutput.add(media);
}
}
});
downloadThread.start();
try {
downloadThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
return mediaOutput;
}
}
Running this class's method from another class and it doesn't ever connect. Any ideas?
Since you say that the problem persists only in Android, it looks like that you should add the user agent string to your request - first get the user agent string of a browser that displays correctly the site, and then add it to the request:
doc = Jsoup.connect(<Website Im connecting to>)
.userAgent("your-user-agent-string")
.timeout(20000).get();
And as a sidenote - if you are catching exception, don't print your own error message - print the original message, it may be very useful.

Why does getNdefMessage() returns null even though debugger shows ndef object has a message payload that is supposedly correctly formatted?

I am trying to continuously poll an NFC tag using an android phone (OnePlus 6T if it's relevant). When my tag is only powered by NFC, I get null values even though the debugger shows the payload being not null and supposedly correctly formatted (screenshot below).
Debugger output when getNdefMessage returns null
Debugger output when the returned value is not null
The code I am using to poll the tag, based on Continuously detect an NFC tag on Android and Is it possible to read an NFC tag from a card without using an intent?
protected void onResume() {
super.onResume();
if (nfcAdapter != null) {
if (!nfcAdapter.isEnabled()) {
Intent intent = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
startActivity(intent);
}
Bundle options = new Bundle();
options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 250);
nfcAdapter.enableReaderMode(this, new NfcAdapter.ReaderCallback() {
#Override
public void onTagDiscovered(Tag tag) {
Log.d("Tag", "New tag detected, attempting connect");
readMessage(tag);
tagInRange = true;
}
},
NfcAdapter.FLAG_READER_NFC_A
| NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS, options);
}
}
Read message function, msg variable is a private volatile NdefMessage:
private void readMessage(Tag tag) {
Log.d("Tag", "Starting thread");
new Thread(() -> {
try {
Thread.sleep(1800);
} catch (InterruptedException e) {
e.printStackTrace();
}
final Ndef ndef = Ndef.get(tag);
Log.d("Tag", "New tag detected, attempting connect");
while (tagInRange) {
try {
ndef.connect();
msg = ndef.getNdefMessage();
Log.d("Tag", "Running on UI thread");
if (msg == null) {
Log.d("Tag", String.valueOf(ndef));
continue;
}
runOnUiThread(() -> {
parseMessage(msg);
dataElapsedTime += 0.2;
});
} catch (IOException | FormatException e) {
e.printStackTrace();
tagInRange = false;
System.out.println("Tag Connection Lost");
}
finally {
try {
ndef.close();
Log.d("tag", "Tag connection closed successfully");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
Does the getNdefMessage function use some sort of lazy loading? Or is this the result of multiple threads being spawned and some strange race condition occurring?
Update 2
Looking at the source of the ndef object the mNdefMsg you highlighted is the cached Ndef message that the System Reads before passing you the Tag object
As you seem have a custom behaving tag and may be this tag won't allow you to read the same data twice without going through a disconnect/connect mechanism.
Based on you debug data I would use ndef.getCachedNdefMessage() to read this data you are highlighting but this might not get you want you want.
Some Background, when the Android NFC service detects a Tag normally it tries to read and Ndef message from it as it might need to parse the Ndef message itself.
When you call ndef.getNdefMessage() it actually re-reads the data directly from the Tag and ignores what the System NFC service has previous read.
I would try enabling FLAG_READER_SKIP_NDEF_CHECK to stop the system reading the Ndef Message and using up you one chance to read the custom Tag .
So try add that flag e.g.
nfcAdapter.enableReaderMode(this, new NfcAdapter.ReaderCallback() {
#Override
public void onTagDiscovered(Tag tag) {
Log.d("Tag", "New tag detected, attempting connect");
readMessage(tag);
tagInRange = true;
}
},
NfcAdapter.FLAG_READER_NFC_A
| NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK
| NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS, options);
Original
I think the problem is your ndef.close() is in the wrong place.
You should not close the tag unless you never want to communicate with it again.
At the moment on the first iteration of the while loop, it does the try block with the ndef.connect(); and the finally is always executed after the code in the preceding try block.
Really you should only ndef.close() outside the while block.
Adjusted code (You should also catch the TagLostException from getNdefMessage )
private void readMessage(Tag tag) {
Log.d("Tag", "Starting thread");
new Thread(() -> {
try {
Thread.sleep(1800);
} catch (InterruptedException e) {
e.printStackTrace();
}
final Ndef ndef = Ndef.get(tag);
Log.d("Tag", "New tag detected, attempting connect");
try {
ndef.connect();
} catch (IOException e) {
e.printStackTrace();
tagInRange = false;
System.out.println("Failed to Connect");
}
while (tagInRange) {
try {
msg = ndef.getNdefMessage();
Log.d("Tag", "Running on UI thread");
if (msg == null) {
Log.d("Tag", String.valueOf(ndef));
continue;
}
runOnUiThread(() -> {
parseMessage(msg);
dataElapsedTime += 0.2;
});
} catch (TagLostException | IOException | FormatException e) {
e.printStackTrace();
tagInRange = false;
System.out.println("Tag Connection Lost");
}
}
// End of while loop try close just on the safe side
try {
ndef.close();
Log.d("tag", "Tag connection closed successfully");
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
Note you might think the raw tag debug output still has an Ndef Message in it, but as you have not disabled FLAG_READER_SKIP_NDEF_CHECK then this is probably the cached data for ndef.getCachedNdefMessage()
If you look at the docs for ndef.getCachedNdefMessage you will see that it says that it causes no RF activity as this just returns the NDEF message that the System NFC read when it first detected the Tag and passed to you in the Tag Object.
Where as getNdefMessage cause I/O (RF) activity and reads the current Ndef message at time of calling (which might be different to the one the system read previously)
Update
I seem to remember you cannot call connect() multiple times and and the docs say "Only one TagTechnology object can be connected to a Tag at a time. " even though it is the same Tag tech it is probably not the same instance, so in the example I've moved connect out of the while loop.
This issue was finally resolved by understanding the following things:
The mNdefmessage variable in the ndef object corresponds to the cached message and would remain unchanged as long as the same tag instance is connected. I was reading the object wrong and presuming that that is the message I want. Thanks to Andrew for pointing this out!
The null I was receiving was not a result of where the connect/close were called and the android code needed minimal changes from what was initially posted. In the documentation for the function getNdefMessage(), it says, function may return null if tag is initialised stage. This turned out to be the real issue, which was only spotted when I set my tag (NHS3152) to blink an LED when starting up and noticed it was restarting several times after taking a set of readings from a connected resistor which shouldn't be happening (this also led to a lot of tag lost/null object exceptions).
Since the documentation on this is scanty, the reason the tag was restarting/reset turned out to be its inability to handle voltages over a certain threshold on its output pins when powered by the NFC field only and connected to a load. This led to the strange scenario of everything working just fine when the tag was being read while connected to a debugging board (LPCLink2) or being powered by the NFC but not connected to a load. This was finally addressed by changing the output voltage on the DAC pin.

Why can't I send image through socket in Java?

I found a quite strange thing when I try to send a picture from client side to server side through socket using Java. Here is my code in client side of Class ImgSender which extends Thread class:
public class ImgSender extends Thread
{
Socket img_s;
BoolFlag imageready,dataready;
ImgBoundingBox image;
ByteArrayOutputStream byteArrayOutputStream;;
public ImgSender(Socket s,BoolFlag dataready,BoolFlag imageready,ImgBoundingBox image)
{
this.img_s=s;
this.imageready=imageready;
this.image=image;
this.dataready=dataready;
}
public void run()
{
boolean running=true;
while(running)
{
// System.out.println("Img sender running");
if(imageready.getFlag())
{ System.out.println("trying to send img");
try
{
OutputStream outputStream = img_s.getOutputStream();
ImageIO.write(image.getImg(), "jpg", outputStream);
System.out.println("Send image"+System.currentTimeMillis());
outputStream.flush();
outputStream.close();
imageready.setFlag(false);
}
catch(Exception e)
{
System.out.println("image client send failed");
imageready.setFlag(false);
}
}
}
}
What is strange is that as I comment out the first statement:
System.out.println("Img sender running");
The image won't be sent to the server and "trying to send img" won't be printed out. If I don't comment it out, or , I do some other stuff like sleep() before the if statement, the picture could be sent to the server and "trying to send img" is printed. Moreover, if I debug the programme by putting a break point at:
if(imageready.getFlag())
Then execute it step by step, it would pass the if statement and send it image successfully.
In terms of the server side, here is the code for the Class ImgManager:
private class ImgManager extends Thread
{
Socket img_s;
boolean working=true;
public ImgManager(Socket s)
{
this.img_s=s;
}
public void run()
{
while(working)
{
try
{
InputStream inputStream = img_s.getInputStream();
System.out.println("Reading: " + System.currentTimeMillis());
BufferedImage image = ImageIO.read(ImageIO.createImageInputStream(inputStream));
System.out.println("Received " + image.getHeight() + "x" + image.getWidth() + ": " + System.currentTimeMillis());
ImageIO.write(image, "jpg", new File("img.jpg"));
}
catch(Exception e )
{
working=false;
System.out.println("stopped working socket");
}
}
}
public void end()
{
try
{
working=false;
img_s.close();
}
catch(Exception e)
{
System.out.println("connection close failed");
}
}
}
}
}
When it receive the image, it would print out the size of the picture so that we know if it can get the image.
I tried these two programmes on different machines(mac and pc windows7) and different software(blueJ,eclipse or even launch it with command line). The problem shows no matter in which environment.
Here is the link to my code of the whole project storing in google drive:
Server:https://drive.google.com/file/d/0B6w_5_wGgS14UnZCbXJKUGdvSFE/view?usp=sharing
Client:https://drive.google.com/file/d/0B6w_5_wGgS14aUlmcG4yQWVnemM/view?usp=sharing
I think it's better to download the source code and look inside it, it's hard to describe everything in here. Sincerely looking for your help!
The behaviour you described: It works sometimes and sometimes not, depending on the delay or the machine where it is executed usually points to a race condition (What is a race condition?).
BoolFlag is used here to indicate when the processing starts, so it is probably accessed (setValue and getValue or similar) by different threads. If we have a statement like:
// b is a BoolFlag
if (b.getValue()) { // (1)
b.setValue(false); // (2)
}
Then it is possible that two threads succeed the test at (1) before (2) was executed. So to make the code thread-safe those two operations have to be executed in one step, they have to be atomic. Java provides java.util.concurrent.atomic.* classes for this, e.g. AtomicBoolean which have a function compareAndSet(expectedValue, newValue) which will only return true if the operation succeeded. Of course you could also write it yourself by using synchronized as you mentioned, adding a public synchronized boolean compareAndSet(...) to the BoolFlag implementation.
And before I tell any lies, this seems also worth reading Volatile boolean vs AtomicBoolean

Console Commands Minecraft Server Start/Stop Through Java GUI

I can't for the life of me figure out how to start a nd stop a server for the game Minecraft using two buttons in Java.
So far I have this mess..
try
{
ProcessBuilder processBuilder = new ProcessBuilder("/Users/UserName/Desktop/servers/test/launch.sh");
Process server;
if (event.getSource() == start_Btn)
{
server = processBuilder.start();
//OutputStream out = server.getOutputStream();
start_Btn.setText("Started");
}
else if (event.getSource() == stop_Btn)
{
OutputStream out = server.getOutputStream();
server.getOutputStream().write(new String("stop").getBytes("utf-8"));
stop_Btn.setText("Stoped");
start_Btn.setText("Start");
}
}
catch (IOException exception)
{
}
catch (InterruptedException exception)
{
}
I have been scouring the internet for the entire day today and I've decided to finally bring it to you guys.
I want to be able to start the server by pressing a "Start" button, then stop it with a "Stop" button I have a GUI set up and I know how to set up button events. I can get the server to start with the start button easily, it is just the stopping feature I can't seem to manage.
Note: To stop the server you must enter in "stop" in the command line where the server was initiated.
Thank you very much for your help, I greatly appreciate it.
Seeing as though there never was an answer that solved my question, and seeing as though I figured it out on my own I figured I'd post it for everyone else happening on the question.
I use a couple classes to accomplish this goal, two to be exact.. One to be the thread that houses the server and the other to send commands to the server.
First things first, the code to start and house the server stream.
The first class here is where the magic happens
public class Sender{
ConsoleWriter cWriter = new ConsoleWriter();
public void execute(){
this.ui = ui;
try{
ProcessBuilder pb = new ProcessBuilder(path_to_server+"launch.bat");
Process process = pb.start();
StreamGobbler sgError = new StreamGobbler(process.getErrorStream());
new Thread( sgError ).start();
writer = new PrintWriter( process.getOutputStream() );
} catch ( IOException e ){
e.printStackTrace();
}
}
private class StreamGobbler implements Runnable
{
private InputStream is;
public StreamGobbler( InputStream is ){
this.is = is;
}
#Override
public void run() {
try {
InputStreamReader isr = new InputStreamReader( is );
BufferedReader br = new BufferedReader( isr );
String line = null;
while ( ( line = br.readLine() ) != null ){
cWriter.writer(line, ui);
}
} catch ( IOException e ){
e.printStackTrace();
}
}
}
}
How does this work you ask? Let's take it from the top.
ConsoleWriter
This is the class I wrote to write the stream from Minecraft's server console to my own GUI, the code for this isn't important so I'll leave it out. You can write that part.
execute()
This method builds the process for the server using Java's ProcessBuilder then starting the process. More importantly, we have the StreamGobbler.. This gives us access to and 'gobbles up' the input stream from the server. Basically it receives all the output the console from the server. For some reason, not sure why, the Minecraft server likes the ErrorStream so I've bound it to that. Then I create a new Thread for the gobbler and that's that. Last thing in this method is the...
PrinterWriter
This binds to the Server as an output which let's me send commands to the server like for stopping it or really any other server command available.
StreamGobbler class
Now, onto the Gobbler its self. Not too much here. Basically just taking the inputStream we sent from the execute method sending it to a reader, then buffering it and finally reading it to my console writer.
The second Class is quite simple!
public class WriteCommand
{
public void send(String command)
{
txtA.append("Command:>>"+ command + "\n");
writer.write(command);
writer.write("\n");
writer.flush();
}
}
All this is doing is writing the command and hitting 'enter' then flushing it to be ready to send the next! txtA.append is for adding the command that was sent to my own console output simply a visual item.
And there you go! Hopefully this will help someone else out.
If you'd like to see this code in action you can see it as part of the app I've used it in.
Here is a link: Minecraft Server Utility(BETA)1.3.6
I was working on this same task today. I am a novice at java but I think I found what you may be missing.
I more or less followed your lead but in the stop command use the slash "/stop"
also it seems that I needed to close the outputstream in order for the action to complete.
private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
try {
oS.write(new String("/stop").getBytes("utf-8"));
oS.close();
} catch (IOException e) {
e.printStackTrace();
}
}
I hope that this helps you.

Categories