Updating Multiple Textbox Java GUI - java

I have an activity or form in which there is one text box called time here. As suggested by experts from this forum I am using runnable to update the TextBox while receiving the data from wifi.
My doubt is what to do when I want to update multiple TextBox's. Should I use multiple blocks of runnables like
time1.post(new Runnable() {
#Override
public void run() {
time2.setText(s1);
}
});
time2.post(new Runnable() {
#Override
public void run() {
time2.setText(s2);
}
});
time3.post(new Runnable() {
#Override
public void run() {
time3.setText(s2);
}
});
Or some other technique is there to update multiple TextBoxes? My present code is like below.
package com.example.cdttiming;
public class MainActivity extends Activity
{
EditText time;
String s;
Button button;
byte[] buffer = new byte[65535];
InetAddress ia = null;
byte[] bmessage = new byte[1500];
DatagramPacket dp = new DatagramPacket(bmessage, bmessage.length);
MulticastSocket ms = null;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
time = (EditText) findViewById(R.id.et_time);
try
{
WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock multicastLock = wm.createMulticastLock("multicastLock");
multicastLock.setReferenceCounted(true);
multicastLock.acquire();
ia = InetAddress.getByName("226.1.1.1");
try {
ms = new MulticastSocket(4321);
} catch (IOException e) {
e.printStackTrace();
}
try {
ms.joinGroup(ia);
} catch (IOException e) {
e.printStackTrace();
}
ms.setReuseAddress(true);
}
catch (UnknownHostException e) {
time.setText(e.getMessage());
}
catch (IOException e) {
time.setText(e.getMessage());
}
}
public void startProgress(View view) {
Runnable runnable = new Runnable() {
#Override
public void run() {
while(true) {
try {
// String str="This is test string";
ms.receive(dp);
s = new String(dp.getData(),0,dp.getLength());
char retval[] = s.toCharArray();
}
catch (UnknownHostException e) {
time.setText(e.getMessage());
}
catch (IOException e) {
time.setText(e.getMessage());
}
****////// My doubt is here if i have multple strings of data and multiple
/// multiple textboxes to update then what to do ???****
time.post(new Runnable() {
#Override
public void run() {
time.setText(s);
}
});
} // while
}
};
new Thread(runnable).start();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}

Your code is a bit confusing. In one case inside your primary while loop you are capturing the data, assigning it to a String variable s then using the text widget post() function and a Runnable to set the EditText widget to that value. But inside that same while loop you have exception handlers that simply set the same EditText widget directly. Your code also looks like you could potentially lose messages if the while loop resets the value of s before the timer loop has a chance to fire the set text call.
It appears you are trying to create some form of real-time system and need the primary while loop to continually process, and display data as it becomes available. Now you have 3 different consumers (text widgets), but you didn't mention if you also have 3 different sources of messages or is there still only one main processing loop and some form of selector will decide which text widget gets the message?
Were I building something along these lines, I would probably use a messaging system and follow the producer-consumer model. When text was received, I would have the primary processing loop push a simple 2-field message onto a queue that contained a reference to the text widget and a reference to the data string. Because Strings are immutable in Java, once the message object had its own copy of the text, any changes to s would not affect the message.
Then, I would have a second thread running in the background that consumes the message queue. It would pull the message off the queue, construct a post call to the target text widget with the message data, fire it off, then go back to get the next message.
By going this route you separate the data processing thread from the UI update processing and would not need to worry about how many text widgets or other widgets you need updated. If you ever need to add others you only need to worry about the new widgets being known to the code that creates the update messages. The thread doing the widget update doesn't know how many widgets you have, it simply uses the one referenced in the update message object that the message creator said to use.

I suggest you only create one runnable and post it once on main thread like this :
time1.post(new Runnable() {
#Override
public void run() {
time2.setText(s1);
time2.setText(s2);
time3.setText(s3);
}
});
The need to create a runnable and to post it on the main thread handler of a view is only about running a piece of code on the UI thread. No matter where you get the main thread handler reference from.
you could also have created your how handler on main thread :
protected void onCreate(Bundle savedInstanceState)
{
this.uiThrdHandler = new Handler();
}
then post a runnable using it :
this.uiThrdHandler.post(new Runnable(){
...
});
Of course there is no need to create another handler but it's for demonstration purpose.
The Activity object has an utility method for that purpose : runOnUiThread
Using it, it would be :
MainActivity.this.runOnUiThread (new Runnable() {
#Override
public void run() {
time2.setText(s1);
time2.setText(s2);
time3.setText(s3);
}
});
But again, the result is the same.

Related

My handler doesn't instantly get notification when a message sent to it

I use two search thread and a filter thread to search for the file I want.
After the FileFilter found the matched file, the passed-in parameter 'handler' will obtainMessage to notify m_handler in MainActivity to update the UI.
It was fine before they work without thread pool (Excecutor). After I have my threads activated by Executor in Controller.java, my file view UI doesn't instantly update when message sent From FileFilter.
After viewing the log, the hanlder message notifications don't show until the two search threads end, and that cause my UI to get stuck till threads end. It seems that the notifications get stuck because of the try-catch block in Controller.java cuz the executor was waiting for the result of the two seach threads. After leaving the startSearching() function in Controller.java, the notifications to the target m_handler in MainActivity then can be informed to update. That is, UI delayed till the end.
My way I deliver the variable of my handler: MainActivity -> Controller -> FileFilter
How can I solve this problem?
MainActivity Class
public class MainActivity extends Activity {
Handler m_handler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("myLog", "UI handler got informed to update.");
switch (msg.what){
case 1:
File receivedFile = (File) msg.obj;
addFilesToAdapter(receivedFile);
}
}
};
private Controller m_controller = new Controller();
#Override
protected void onCreate(Bundle savedInstanceState) {
m_btn_search.setOnClickListener(new Button.OnClickListener() {
#Override
public void onClick(View view) {
List<String> strListInputText = detectEditTextInputStatus();
m_controller.startSearching(m_handler, strListInputText);
}
});
}
}
Controller Class
public class Controller {
public void startSearching(Handler handler, List<String> strListInputText) {
CallBack forSearchAndFilter = new SharedFiles();
ExecutorService executor = Executors.newCachedThreadPool();
//my 1st search thread
FileSearcher searchCallable = new FileSearcher(forSearchAndFilter);
Future<Boolean> result = executor.submit(searchCallable);
//my 2ed search thread
FileSearcher SecSearchCallable = new FileSearcher(forSearchAndFilter);
Future<Boolean> result2 = executor.submit(SecSearchCallable);
executor.shutdown();
//my filter thread
if (strListInputText != null) { //has input
Runnable filterRunnable = new FileFilter(forSearchAndFilter, handler, strListInputText);
Thread filterThread = new Thread(filterRunnable);
filterThread.start();
}
//this try catch block cause my UI to get stuck
try {
Log.d("myLog", "result: " + result.get());
Log.d("myLog", "result2: " + result2.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
forSearchAndFilter.setFinishedPutFile(true); //inform filter thread that the two search threads have finished
Log.d("myLog", "All thread tasks done");
}
}
FileFilter Class
public class FileFilter implements Runnable {
private Handler m_handler;
public FileFilter(CallBack callBackToTakeFile, Handler handler, List<String> strListinputText) {
this.m_callBackToTakeFile = callBackToTakeFile;
this.m_handler = handler;
}
#Override
public void run() {
if (matchedFile != null) {
m_handler.obtainMessage(1, matchedFile).sendToTarget(); //Send matched file to UI
}
}
}

Google Glass Immersion - OnClick not working inside a separate thread

My problem is pretty simple. I am creating a card based on the result of a HTTP query performed inside a separate thread. The card also has an onclick method and is defined inside a runOnUiThread() located inside the separate thread. However, when the device is tapped, the onclick event isn't fired.
Here is my code:
private void login() {
Runnable r = new Runnable() {
#Override
public void run() {
// irrelevant code
runOnUiThread(new Runnable() {
#Override
public void run() {
setContentView(buildError(code));
}
}
}
Thread t = new Thread(r);
t.start();
}
private View buildError(String code) {
CardBuilder card = new CardBuilder(this, CardBuilder.Layout.ALERT);
card.setIcon(R.drawable.ic_warning_150);
if (code.equals("1"))
card.setText("Incorrect credientals");
else
card.setText("Unexpected error");
card.setFootnote("Tap to try again");
View cView = card.getView();
cView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.i("Event", "Clicked"); // This is what isn't triggering
}
});
cView.setFocusable(true);
cView.setFocusableInTouchMode(true);
return cView;
}
Even though the snippet of code contains an error (can't be compiled, missing ; at the Runnable statement), you were on the right track.
The View simply needs to request the focus in order to be clickable right away. Otherwise you'll have to move the focus manually.
cView.setFocusable(true);
cView.setFocusableInTouchMode(true);
cView.requestFocus();
Reference

Threading and events

I'm really stuck here, I've read a lot on threading on android but I'm unable to find an answer that suits my proyect.
I've got a frontend (Manages GUI) and a backend (Manages the data and stuff). I need to update the GUI as soon as the backend finishes running a thread but I can't figure out how!
Main.java package frontend
public class Main extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread thread = new Thread() {
#Override
public void run() {
Server server = new Server(getApplicationContext());
}
};
thread.start();
Server.java package backend
public static List<String> lista = new ArrayList<String>();
public Server(Context context) {
Revisar archivo = New Revisar();
archivo.DoSomething();
}
After archivo.doSomething finishes I need to update the GUI with the backend data stored in the static list.
Any suggestions?
As you've surmised, you can't update the GUI from a background thread.
Typically, to do what you want, you use the message handling mechanism to pass a message to the GUI thread. Typically, you pass a Runnable which will be executed in the GUI thread. You can also pass a Message if you've subclassed the Handler and added code to deal with messages.
Messages are passed to Handlers. You can either create your own Handler in the GUI thread, or use one of several that already exist. For example, every View object includes a Handler.
Or you can simply use the runOnUiThread() Activity method.
Pattern 1, handler plus runnables:
// Main thread
private Handler handler = new Handler();
...
// Some other thread
handler.post(new Runnable() {
public void run() {
Log.d(TAG, "this is being run in the main thread");
}
});
Pattern 2, handler plus messages:
// Main thread
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
Log.d(TAG, "dealing with message: " + msg.what);
}
};
...
// Some other thread
Message msg = handler.obtainMessage(what);
handler.sendMessage(msg);
Pattern 3, call runOnUiThread():
// Some other thread
runOnUiThread(new Runnable() { // Only available in Activity
public void run() {
// perform action in ui thread
}
});
Pattern 4, pass a Runnable to a View's built-in Handler:
// Some other thread
myView.post(new Runnable() {
public void run() {
// perform action in ui thread, presumably involving this view
}
});

How to *not* use runOnUiThread

As you can see in the title, I'm trying to not use runOnUiThread each time I need it. I'll explain what I mean later, but first, here is my current code (part of):
private void filePaste()
{
final File src = new File(FileClip); //Source file (as a string)
final File dest = new File(myPath.getText()+"/"+src.getName()); //Destination file
final ProgressDialog dlg = new ProgressDialog(AppContext);
final Thread copythread = new Thread(new Runnable() {
public void run() {
if(FileClip==null)
Main.this.runOnUiThread(new Runnable() {
public void run(){
toast(getString(R.string.msg_EmptyClip));
}
});
else
{
if(src.canRead()){
if(!src.isDirectory())
{
try{
BufferedInputStream in = new BufferedInputStream(new FileInputStream(src), 8192);
BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dest));
long pos = 0;
long read = 8192;
byte[] data = new byte[(int)read];
while(pos<src.length()){
int bytes = in.read(data, 0, (int)read);
if(bytes>-1) {
out.write(data,0,bytes);
in.skip(read);
in.mark((int)pos+bytes);
in.reset();
dlg.incrementProgressBy(bytes);
pos+=bytes;
}
}
Main.this.runOnUiThread(new Runnable() {
public void run(){
dlg.dismiss();
}
});
in.close();
out.close();
}catch(final Exception e)
{
Main.this.runOnUiThread(new Runnable() {
public void run(){
alert("filePaste():\n"+e);
}
});
}
if(Moving==true) {
boolean q = src.delete();
if(q==true)
Main.this.runOnUiThread(new Runnable() {
public void run(){
toast(getString(R.string.msg_MoveOK,src.getName()));
}
});
else
Main.this.runOnUiThread(new Runnable() {
public void run(){
toast(getString(R.string.msg_MoveNO,src.getName()),1);
}
});
Moving = false;
}
else {
Main.this.runOnUiThread(new Runnable() {
public void run(){
toast(getString(R.string.msg_CopyOK,src.getName()));
}
});
}
}
}
else
Main.this.runOnUiThread(new Runnable() {
public void run(){
toast(getString(R.string.msg_CopyNO,src.getName()));
}
});
FileClip = null;
Main.this.runOnUiThread(new Runnable() {
public void run(){
getDir(myPath.getText().toString());
}
});
}
}
});
dlg.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dlg.setTitle(Moving?getString(R.string.moving):getString(R.string.copying));
dlg.setMessage(src.getName());
dlg.setCancelable(true);
dlg.setButton(DialogInterface.BUTTON_NEGATIVE, getString(android.R.string.cancel), new DialogInterface.OnClickListener()
{
#Override
public void onClick(DialogInterface dialog, int which) {
dlg.cancel();
}
});
dlg.setOnCancelListener(new DialogInterface.OnCancelListener()
{
#Override
public void onCancel(DialogInterface dialog) {
copythread.interrupt();
if(dest.exists())
dest.delete();
}
});
dlg.setMax((int)src.length());
dlg.show();
copythread.start();
}
What this code does is try to copy a given file (stored as a string in FileClip).
As you can see, the code is quite long, because the excessive use of runOnUiThread. I want to know how to move all of the
Main.this.runOnUiThread(new Thread(new Runnable()
public void run()
{
//Simple stuff for 6 lines
}
));
to a class or something. I was thinking of
public class runAtUI implements Runnable
But I stop at that point, I don't know how to make constructors. I hope you know what I mean with this; something like:
new runAtUI()
{
//This makes less lines IMO, and could be executed
}
*Note: I looked for topics about this but all saying the same, use the runOnUiThread. I know it's ok but for something short (like displaying a toast -using toast() with the same purpose- or an alert -again, but with alert()-) it's pointless.
PS: This is for a simple file manager that I am doing and will not be published on Google Play because of the lack of money, and I don't want to use ads either (breaking the "simplicity" in the name). Yes, I know that there are free and adsless (that word exists?) and better apps but I wanted to learn how to make one n_n;
Any information, idea or guide will be appreciated.
Edit #2: Thank you to all that answered quickly! The samples that you provided will work for now but I'd like it to be more flexible. Like eval("code as string") in javascript (without the code being a string).
I'll consider this question answered but leave it open to let people give some more ideas ;D
Edit #3: Okay, first, sorry for the long time no response. Second, I'm adding links to the current code as it is now, from 123 lines (this one) to 77 lines of code at pastebin. I'm also adding the code for uithread.
About the app: If you want it for testing, see how it is right now or anything, drop me a mail and I'll send it to you ;)
You could create a utility class to encapsulate the steps of creating a runnable to be run by the UI thread and invoke Toast. Here's a simple implementation:
public abstract class ToastUtils {
/**
* Displays a toast message, making sure that the toast is always invoked from the main (ui) thread.
* #param act Calling Activity
* #param text Toast text
* #param duration Toast duration
*/
public static void showToast(final Activity act, final String text, final int duration) {
act.runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(act, text, duration).show();
}
});
}
}
Using this class you would do this to toast wherever necessary:
ToastUtils.showToast(this, "some text", Toast.LENGTH_SHORT);
You can create a Handler in activity:
Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case R.string.cancel:
//show toast
break;
default:
break;
}
}
};
And use it from your thread like:
handler.sendEmptyMessage(R.string.cancel);
From http://developer.android.com/guide/components/processes-and-threads.html:
However, as the complexity of the operation grows, this kind of code
can get complicated and difficult to maintain. To handle more complex
interactions with a worker thread, you might consider using a Handler
in your worker thread, to process messages delivered from the UI
thread. Perhaps the best solution, though, is to extend the AsyncTask
class, which simplifies the execution of worker thread tasks that need
to interact with the UI.
... skipping ahead ...
You can call publishProgress() at anytime in doInBackground() to
execute onProgressUpdate() on the UI thread
It looks to me like this is what you want to do.
With regard to your other question (you should try to ask only one question per topic), copying files in Java is kind of a solved problem. Among threads on SO, I think this one has some pretty good answers: Standard concise way to copy a file in Java?

findViewById(R.id.progressbar) and static hell:

clipProgress resets a progress bar to zero:
public class Whatever extends Activity implements ListenerA, ListenerB {
private Handler mHandler = new Handler();
ProgressBar myProgressBar;
int myProgress = 0;
public void clipProgress() {
myProgressBar = (ProgressBar)findViewById(R.id.progressbar);
myProgressBar.setProgress(myProgress);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
clipProgress();
public void onClick(View view) {
Duration.duration = 0;
startRecording();
new Thread(new Runnable(){
#Override
public void run() {
while(myProgress<100){
try{
myHandle.sendMessage(myHandle.obtainMessage());
Thread.sleep(50);
}catch(Throwable t){
}
}
}
}).start();
}
Handler myHandle = new Handler(){
#Override
public void handleMessage(Message msg) {
myProgress++;
myProgressBar.setProgress(myProgress);
}
};
});
}
I have two different methods, below, where I suppose I could attempt to reset the progress bar to zero. But they both reside in a different class entirely:
#Override protected void onPostExecute(Void result) {
Whatever.clipProgress(); //...which throws all kinds of red lines if I use this statement.
}
and
public void stopThis(){
thing.stop();
try {
Whatever.clipProgress(); //...which throws all kinds of red lines if I use this statement.
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Eclipse wants to apply "static" to various initializations in the Whatever class. But those fixes just leave findViewById(R.id.progressbar) redlined.
I just want to reset the progress bar (which was started from within class 1) from class 2. It's too much to ask for.
UPDATE:
Whatever is the starting point, the Android Activity. Its handler, which I should have included in the above snip, right underneath onCreate is included in the snip below. So more completely, and invoked from a button, is thus:
public void onClick(View view) {
new Thread(new Runnable(){
#Override
public void run() {
while(myProgress<100){
try{
myHandle.sendMessage(myHandle.obtainMessage());
Thread.sleep(87);
}catch(Throwable t){
}
}
}
}).start();
}
Handler myHandle = new Handler(){
#Override
public void handleMessage(Message msg) {
myProgress++;
myProgressBar.setProgress(myProgress);
}
};
Once that button is pressed a listener is produced:
myTask = new Task();
myTask.addTaskListener(this);
myTask.execute(this);
It is inside the Task class:
public class Task extends AsyncTask<Whatever, ArrayList<Float>, Void>{
...
public void addTaskListener(TaskListener rl){
this.rl = rl;
}
...
that those two functions reside, one of which I'm hoping to use to stop the progress bar.
A task is designed elsewhere to shut down at exactly a constant number of seconds, and so I can hardcode 50 into that progress bar value on the sleep(). I just want to be able to shut the bar down back to zero earlier if I stop the task earlier.
Eclipse warns you because you are accessing the clipProgress method in a static way (by calling Whatever.clipProgress()).
Also, you should only assign your progress bar once, so move
myProgressBar = (ProgressBar)findViewById(R.id.progressbar);
into your onCreate method.
You should probably pass the ProgressBar into the other class that needs to update it, and then do something like
myProgressBar.post(new Runnable() {
public void run() {
myProgressBar.setProgress(myProgress);
}
});
this post method updates the ProgressBar on the UI thread, which is the only safe way to do it. Make sure you are only doing any of this if the activity with the ProgressBar is currently active.
You should also question whether you need to update the progress bar in this other class at all. I only see you updating the myProgress variable inside your handler, where you set the progress on the bar immediately after. Could you explain a bit more about the relationship between this other class and the activity with your progress bar?
This has more to do with Java programming and instance / static methods than with Android:
When you call Whatever.clipProgress() you're attempting to make a call to a static method call to clipProgress on the Whatever class, which is why Eclipse wants to add the static modifier.
However, findViewById() is an instance method (read the link above) on Activity, which is presumably some ancestor of your Whatever class. Static methods can't call instance methods statically, so even if you let Eclipse make clipProgress static, you need to call clipProgress on an instance of your activity.
Your other class needs to have a reference to the instance of the class on which you want to call clipProgress(). You should either pass in that reference to the other class, or as another poster noted, pass in a reference to the ProgressBar itself.
Then you can call e.g. mWhatever.clipProgress() or progressBar.setProgress(0).

Categories