I'm making a chat program with Java, and I'm doing the communication through TCP and serializable objects. The chat can exchange files, too, but when the files are too big (video files) the interface freezes until it completes the file loading and object transmition process. I need to show a message while the file is being loaded. This is my code:
File file = jFileChooser1.getSelectedFile();
String name= fichero.getName();
int size = (int)fichero.length();
byte[] byteArray = new byte[size];
try {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
bis.read(byteArray);
} catch (IOException ex) {
Logger.getLogger(Explorador.class.getName()).log(Level.SEVERE, null, ex);
}
I need to show a message while this line "bis.read(byteArray);" is reading, since I believe that line is the reason the interface freezes.
After the byteArray is loaded I put it on a object and send it through the socket connection.
I also need a video streaming, not live, just to open a video file on the server and send it by pieces to the connected clients and play it. Can anyone give me tutorials or tips? thanks.
That UI freezing indicates that you are blocking Swing's Event Dispatch Thread. You want to perform all time-consuming tasks explicitly in other threads instead. One simpler way is to use SwingWorker.
http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
You can put your code in a Thread and code a method waiting for it to complete.
new Thread(new Runnable() {
#Override
public void run() {
//Code here
}
}).start();
You can perform your tasks in a thread:
new Thread(new Runnable() {
#Override
public void run() {
//Code here
}
}).start();
And use runlater() to update your view.
Related
I'm trying to better understand the behavior of threads in my android app. For some reason, when I use while(true) in one of my worker threads, code within that thread's run method that exists sequentially BEFORE the while(true) loop never executes. To be clear, I'm not sure if the code(toast messages) actually isn't executing or if the way the thread synchronization is handled by the Android OS is causing my Toast messages not to display. This behavior appears to be some sort of blocking but I can't figure out why this happens.
My app uses 3 threads: the UI thread(default/main thread in an Android app), a thread to infinitely read data from the device's USB port during runtime, and a thread to process this data via messages from the USB-read thread. The problem seems to occur in my USBController class. When I comment out my infinite while loop, all of the Toast messages before the start of the loop display just fine. When I don't comment out my while(true), NO TOAST MESSAGES EVER DISPLAY! I'm pretty confused by this, I think i'm misunderstanding something fundamental about thread handling by the Android OS. Even if a while loop were to cause blocking, which i don't think it since it resides in a worker thread, why wouldn't the toast messages that occur before the while loop be triggered? Is this a synchronization issue? Am I misusing Android's Handler-Looper system?
Code below. Note: I've included the relevant portion of the main activity and the entirety of the USBController class. My implementation of this class relies heavily on the USB to Serial library found here mik3y/usb-serial-for-android. I don't think it's necessary, but i've included the class that contains my third thread, SensorDataBuffer, that receives messages from the thread UsbController.
UsbController.java
public class UsbController extends Thread{
...
#Override
public void run() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_DEFAULT); //sets thread to default queing priority
Looper.prepare();
Toast.makeText(mContext.getApplicationContext(), "Hello from UsbController's run method!", Toast.LENGTH_SHORT).show();
// **********************USB otg*******************************
//Obtain permission to use Android device's USB intent
PendingIntent mPermissionIntent;
mPermissionIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_USB_PERMISSION), 0);
// Find all available drivers from attached devices.
ProbeTable customTable = new ProbeTable();
customTable.addProduct(0x03EB, 0x2044, CdcAcmSerialDriver.class);
UsbManager manager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
UsbSerialProber prober = new UsbSerialProber(customTable);
List<UsbSerialDriver> availableDrivers = prober.findAllDrivers(manager);
if (availableDrivers.isEmpty()) {
Toast.makeText(mContext.getApplicationContext(), "No available USB drivers found",Toast.LENGTH_SHORT).show(); // Toast message for debugging
}
else { // open connection to first avail. driver
UsbSerialDriver driver = availableDrivers.get(0);
Toast.makeText(mContext.getApplicationContext(), "Driver found",Toast.LENGTH_SHORT).show(); // Toast message for debugging
UsbDeviceConnection connection = manager.openDevice(driver.getDevice());
Toast.makeText(mContext.getApplicationContext(), "Device Driver Opened",Toast.LENGTH_SHORT).show(); // Toast message for debugging
if (connection == null) { // You probably need to call UsbManager.requestPermission(driver.getDevice(), ..)
Toast.makeText(mContext.getApplicationContext(),"Connection to device not allowed, need permissions",Toast.LENGTH_LONG).show();
manager.requestPermission(driver.getDevice(),mPermissionIntent); //conn test
if (manager.hasPermission(driver.getDevice())==true){
Toast.makeText(mContext.getApplicationContext(),"Permissions granted",Toast.LENGTH_SHORT).show();
}
}
else { // Read some data! Most have just one port (port 0).
List<UsbSerialPort> myPortList = driver.getPorts();
UsbSerialPort port = myPortList.get(0);
Toast.makeText(mContext.getApplicationContext(),"USB OTG Connection Established",Toast.LENGTH_SHORT).show();
try {
port.open(connection);
port.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE); // sets baud rate,databits, stopbits, & parity
port.setDTR(true); //necessary to make Arduino Micro begin running it's program
Toast.makeText(mContext.getApplicationContext(),"port opened, parameters set, DTR set",Toast.LENGTH_SHORT).show();
byte buffer[] = new byte[16];
String incompPacket = "";
Toast.makeText(mContext.getApplicationContext(), "hi again!"), Toast.LENGTH_LONG).show();
while (true){ //continuous loop to read data
numBytesRead = port.read(buffer, 100);
arduinoData = new String(buffer, "US-ASCII");
String raw = arduinoData.substring(0, numBytesRead);
if (numBytesRead > 0) {
...
}
}
} catch (IOException e) {
Toast.makeText(mContext, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
Looper.loop();
}
}
MainActivity.java
...
#Override
protected void onCreate(Bundle savedInstanceState) {
//Multi-threading
//Create thread to handle incoming data from USB Controller thread
SensorDataBuffer pressureDataBuffer = new SensorDataBuffer(MainActivity.this);
Thread bufferThread = new Thread(pressureDataBuffer);
bufferThread.start();
//Create USB Serial Worker thread which will continuously receive data
UsbController serialDataLink = new UsbController(PlayFrets.this);
Thread sensorMonitorThread = new Thread(serialDataLink);
sensorMonitorThread.start();
//Toast.makeText(this, "USB Controller thread started", Toast.LENGTH_SHORT).show();
//Build GUI
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE); //Removes action bar from display
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //Removes status bar from display
//Create AsyncTask to load the note files. A splash screen will be displayed while task is executing
new AsyncTask_NoteFileLoader(this).execute();
}
...
SensorDataBuffer.java
public class SensorDataBuffer extends Thread{
//Handler subclass which accepts messages one by one in
//the main activitiy's FIFO message que called a "Looper"
//The worker thread, sensorMonitor, runs UsbController in parallel
//with the UI thread and continuously formats and sends pressure sensor
//values read from the microcontroller to the Handler which updates the
//corresponding pressure state logic variables in the UI thread.
public void run(){
android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO); //TODO:priority was previously more favorable, test this to ensure UI doesn't lag
Looper.prepare(); //create MessageQue to receive messages from USB Controller thread
UsbController.setHandler(bufferHandler);
bufferHandler = new Handler(Looper.myLooper()) {
//do stuff
};
Looper.loop();
}
}
How about using HandlerThreads, Handlers and Runnables instead? Makes your code a lot cleaner and easier to maintain.
In your onCreate() just create a couple of them:
HandlerThread usbThread = new HandlerThread("USBController");
usbThread.start();
usbHandler = new Handler(usbThread.getLooper());
HandlerThread sensorThread = new HandlerThread("SensorDataBuffer");
sensorThread.start();
sensorHandler = new Handler(sensorThread.getLooper());
Then you create your Runnables and post them to the Handlers
usbHandler.post(new Runnable(){
run(){
//....
numBytesRead = port.read(buffer, 100);
if (numBytesRead > 0) {
sensorHandler.post(new Runnable(){run(){//doSomething}});
}
//....
if(isStillRunning)
usbHandler.post(this);
}
});
You can let the runnable post itself and it will run forever. From within you can post runnables to other handlers (like the Main Thread Handler) to show your Toasts.
I have a file open and write situation that crashes with EOFException once in about 20-30 times, because the file is unavailable because some other process is writing to it.
Can I catch this exception, then somehow wait for the file write operation synchronously to end, so I can recurse the method?
File productJSON = getFileStreamPath("product" + "_" + getId() + ".json");
if (!productJSON.exists()) {
productJSON = getFileStreamPath("product" + ".json");
}
InputStream jsonStringsFileInputStream;
try {
jsonStringsFileInputStream = new FileInputStream(productJSON);
HashMap<String, Map> that = new JSONToProductParser().convertThisToThat(jsonStringsFileInputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
You can check the file for write access before opening it.This is done with the canWrite() method.
Oracle Docs - File # canWrite
Also check out this solved question. It deals with the synchronized attribute.
Solved Question - Synchronized
You can use a handler to introduce delays in your code.
final Handler handler=new Handler();
handler.postdelayed(new Runnable(){
#override
public void run(){
//Do something after 5 seconds....your code here
}
},5000);
write your code within the run method
I have an app in which the user may need to download up to 760 files, totaling around 350MB. It is not possible to zip these files, they must be downloaded as loose files!
I'm currently using Android Asynchronous Http Client to download individual files, and AsyncTask to run the entire process.
Here's an example of a DownloadThread object which handles downloading hundreds of files in the background:
public class DownloadThread extends AsyncTask<String,String,String> {
ArrayList<String> list;
AsyncHttpClient client;
String[] allowedContentTypes = new String[] { "audio/mpeg" };
BufferedOutputStream bos;
FileOutputStream fos;
#Override
protected String doInBackground(String... params) {
DownloadTask task;
for (String file : list) {
//the "list" variable has already been populated with hundreds of strings
task = new DownloadTask(file);
task.execute("");
while (!task.isdone)
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
class DownloadTask extends AsyncTask<String, String, String> {
String character, filename;
boolean isdone = false;
public DownloadTask(String file) {
//file = something like "Whale/sadwhale.mp3"
character = file.split("/")[0];
filename = file.split("/")[1];
}
#Override
protected void onPreExecute() {
}
#Override
protected void onPostExecute(String result) {
if (!result.equals("Error")) {
//Do something on success
}
isdone = true;
}
#Override
protected String doInBackground(String... str) {
client = new AsyncHttpClient();
client.get("http://some-site.com/sounds/" + character + "/"
+ filename, new BinaryHttpResponseHandler(
allowedContentTypes) {
#Override
public void onSuccess(byte[] fileData) {
try {
// Make file/folder and create stream
File folder = new File(Environment
.getExternalStorageDirectory()
+ CharSelect.directory + character);
folder.mkdirs();
File dest = new File(folder, filename);
fos = new FileOutputStream(dest);
bos = new BufferedOutputStream(fos);
// Transfer data to file
bos.write(fileData);
bos.flush();
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
return "Success";
}
}
}
DownloadThread runs in the background, and also calls hundreds of it's own AsyncTasks. It waits until the task is done downloading, then continues the for loop for each download.
This works, kinda. Some downloads appear to not finish properly or not start at all. Out of a list of 760 downloads, an average of 100 downloads complete properly, and I have to restart the process to download another additional 100 downloads until that one fails as well. I have a feeling this is due to timing issues, as the Thread.sleep(10) line seems a little "hackish".
Surely, calling hundreds of AsyncTasks from another AsyncTask is not the most efficient way to do this. How can I alter this code or implement a 3rd party solution to fit this task?
Try out DownloadManager API. This should be what you need.
Here is the thing you need to keep in mind:
Computers have limited resources; network bandwidth, CPU, memory, disk, etc
The time it takes to download 1 file at a time vs. 760 files simultaneous can never logically take any longer than simultaneous download.
However, by spawning a whole lot of background tasks/threads you are incurring a lot of thread thrashing/overhead as each one needs to be context switched in and out. CPU bandwidth will be consumed in the switching instead of actually moving data in and off of the network interface. In addition, each thread will consume it's own memory and potentially need creating if not part of a pool.
Basically the reason your app isn't working reliably/at all is almost certainly because it's running out of CPU/DISK-IO/memory resources well before it finishes the downloads or fully utilizes the network.
Solution: find a library to do this or make use of the Executor suite of classes and use a limited pool of threads (then only download a few at a time).
Here is some good evidence in the wild that what you're trying to do is not advised:
Google play updates are all serialized
Amazon MP3 file downloader is totally serialized
default scp client in Linux is serialized file transfer
Windows update downloads serially
Getting the picture? Spewing all those threads is a recipe for problems in return for perceived speed improvement.
I am writing an application that displays webcam connected to my computer.
I will just write code here since the code is very simple.
public static void main(String[] args) {
JFrameImageDisplayer _window = new JFrameImageDisplayer();
//webcamGrabber _wg = new webcamGrabber();
//commented out because I am having trouble with this class.
}
JFrameImageDisplayer opens a frame, pretty much that's all it does.
When I run this code, I open a simple application with a JLabel in the frame. If I close the application, then the whole process terminates( and the process at the Windows Task Manager Process tab processes as well).
However once I create _wg, the process at the Task Manager does not terminate even after I close the application ending up just burning processing power until I manually go to process bar to end it.
Below is the construction code for the webcamGrabber.
{
OpenCVFrameGrabber _grab = new OpenCVFrameGrabber(0);
try{
_grab.start();
} catch (Exception e){
e.printStackTrace();
}
}
Well I was not so sure what do. So I manually released the resources.
protected void processWindowEvent(WindowEvent e){
if(e.getID() == WindowEvent.WINDOW_CLOSING) {
try{_wg._grab.release();}
catch(Exception ee){}
}
super.processWindowEvent(e);
}
Not the prettiest way to do it, but it works.
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.