BufferedReader hl = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.lines)));
while(hl.ready()){
showLines.append(hl.readLine()+"\n");
showLines.invalidate();
Thread.sleep(10);
}
That is my code but it is not redrawing when I tell it to. It is supposed to redraw after every line that is added to textview, but it still only redraws at the end? Can someone please help me, I can't figure it out.
That is bacause your invalidate() is in a thread while loop and is being acummulated, so to speak, until the loop ends, and only than it draws...
I had the same problem when using Thread.sleep() within a loop. You can use a post delayed method to draw each line, which in this case is one line per second:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
BufferedReader hl = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.text)));
TextView showLines = (TextView) findViewById(R.id.textView1);
appendLines(hl, showLines);
}
public void appendLines(final BufferedReader br, final TextView tv){
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
try {
if(br.ready()){
try {
tv.append(br.readLine()+"\n");
} catch (IOException e) {
e.printStackTrace();
}
tv.invalidate();
appendLines(br, tv);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}, 1000);
}
That is my code but it is not redrawing when I tell it to.
invalidate() does not happen immediately when you call it. invalidate(), like append() and anything else involving the UI, puts a message on a message queue, that will be processed by the main application thread as soon as you let it. Since you are wasting the user's time in pointless sleep() calls, plus doing flash I/O, in a loop on the main application thread, the main application thread cannot process the messages on the message queue. It will process all of your invalidate() and append() calls after your loop is over and you return control to Android from whatever callback you are in.
It is supposed to redraw after every line that is added to textview
No, it isn't.
but it still only redraws at the end?
Correct.
The simple solution is for you to get rid of the invalidate() and the Thread.sleep(10) and just load the entire file contents into your TextView in one call.
The better solution is for you to read the whole file in via an AsyncTask, then append the text to the TextView in one call in onPostExecute(). If needed, use a ProgressDialog or something to keep the user entertained while this is going on.
Related
I am trying to change the screen of an app during a function is running.
public void StartRecording(View view)
{
start_button.setEnabled(false);
stop_button.setEnabled(true);
recording = true;
while(recording==true)
{
// Here is a code that changes many views on the screen
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
function StartRecording() is called by clicking the start_button in the xml file.
recording is set to false when clicking the stop_button.
The views on the screen should change, wait a second, change again, wait a second and so on.
But what happens is that the function waits until the loop is finished and then shows only the final screen change. What am I doing wrong?
Thanks ahead : )
Edit:
I tried using Handler and it has the same result..
private final Handler mHandler = new Handler(Looper.getMainLooper())
{
public void handleMessage(Message msg)
{
tv.setText((String) msg.obj);
}
};
tv is a textView. Instead of using tv.setText just above the try{} in the code above, I sent a message to mHandler to change the text, and it still changes it only after the whole startRecording function is over.
Now, what am I doing wrong? :/
What am I doing wrong
you are calling sleep wait the UI Thread, that is responsible for drawing your views and handle events. If you want to schedule 10 different redrawing of your views, you can use and Handler and its postDelayed method
I'd like to do setText() on a TextView and make the activity sleep just after.
Here is the code :
tv.setText("myText");
tv.invalidate(); // Doesn't work
pause(1000); // French for sleep
And my function pause :
public void pause(int seconds)
{
synchronized(this)
{
try {
this.wait(seconds);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
The problem is that the TextView doesn't update before sleeping. I tried to call invalidate() on my TextView but it doesn't work.
I have another possible solution : create a new Thread for sleeping the activity, and if the value of my TextView is still the same, reload the Thread, else call my function pause(). But is it possible to get the real value of my TextView in the View ? Because I can get the new text when I do :
tv.setText("myText");
System.out.println(tv.getText());
pause(1000); // French for sleep
Whereas the text doesn't update in the View.
Any idea ?
I would suggest what Jave said.
tv.setText("myText");
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Do something
}
}, 3000); //3000 is time in ms.
If you use the UI thread and make it sleep for too long , you will get the application-not-responding dialog . of course , only when the function ends , you will see the new value , so this is not a good solution . you can use handlers if you wish to use only the UI thread.
If you use a different thread , you will need to set the text of the TextView somehow using the UI thread since it's the only one that is allowed to do so (use handler for this) .
ive been thinking about this for hours and im not closer to an solution!
My thread just stops looping when im fetching a message from an server for some reason, and works perfectly when im not doing it.
This works and prints refreshing every second:
public class ChatRoom extends Activity implements OnClickListener, Runnable {
private Thread t = new Thread(this);
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chatroom);
Button send = (Button) findViewById(R.id.send);
send.setOnClickListener(this);
Intent receiver = getIntent();
String host = receiver.getStringExtra("Host");
int port = receiver.getIntExtra("Port", 4456);
try
{
socket = new Socket(host, port);
this.receive = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
this.send = new PrintWriter(this.socket.getOutputStream(), true);
}
catch(IOException ioe) { System.out.println(ioe); }
t.start();
}
public void run()
{
String message = "";
while(true)
{
try
{
// message = receive.readLine(); BufferedReader
t.sleep(1000);
}
//catch(IOException ioe) { System.out.println(ioe); }
catch (NullPointerException npe) { System.out.println(npe); }
catch (InterruptedException e) { System.out.println(e); }
System.out.println("Refreshing...");
}
}
And when i use my commented code, it actually works and i get a message from the server but it loops just once! Why is that?
Output:
Server Message
Refreshing...
I get no Exception or errors, but i had an error before with some similar code that said that i cant change UI on other threads. So ive been looking at some runOnUiThread but it didnt make it better, and i dont know why it should :(
The method BufferedReader.readLine() blocks until a newline character is received. If there is no newline in your receiver stream it will block forever.
A few things here:
Swap from System.out.println("string"); to Log.d("tagname","string"); then look on DDMS for output lines.
I don't think you're creating a thread properly, and you certainly aren't providing any interface to kill it, which may cause issues when you test it. I would separate the thread into a new file, say NameOfThread:
//File "NameOfThread"
public class NameOfThread extends Thread{
//any fields you want here to mess with e.g.
private String message;
private boolean running;
public NameOfThread(){
message = "";
running = true;
}
#Override
public void run(){
while(running){
//do stuff
}
}
public void setRunning(boolean run){
running = run;
}
}
//When you want to call it
NameOfThread varThread = new NameOfThread();
varThread.start();
//when you want to kill the thread
varThread.setRunning(false);
You may think 'why bother with this whole running variable junk, I don't need it.' but how else will this thread end gracefully? There is another method of killing the thread properly, which is using InterruptedException and your cleanup code goes there, but that's just an alternative.
Try doing this first, then you'll need to sort out the message itself (the method you're using currently isn't great since readLine() will block until a line is received (meaning you'll get "Refreshing..." when you get a new line rather than once per second.
You're surely getting some exceptions thrown, you just can't see them cause you're trying to print them on the standard output, which is missing on Android. Your exception is handled correctly and the code finishes. To properly get the exception information use Logs, or just throw a RuntimeException. Hope this helps.
I can't understand the implementation of a while loop in android.
Whenever I implement a while loop inside the onCreate() bundle, (code shown below)
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
TextView=(TextView)findViewById(R.id.TextView);
while (testByte == 0)
updateAuto();
}
nothing boots up, and the program enters a "hanging" state after a while and I can't understand why. Testbyte is as follows:
byte testByte == 0;
and updateAuto() is supposed to update the code per 1 second and display inside the textView portion. I've been using setText inside updateAuto() as shown below and everything works fine, but once i implement the while loop all i see is a black screen and then an option to force close after a few seconds due to it "not responding".
TextView.setText(updateWords);
I've changed it to a button format (meaning i have to click on the button to update itself for now), but i want it to update itself instead of manually clicking it.
Am i implementing the while loop in a wrong way?
I've also tried calling the while loop in a seperate function but it still gives me the black screen of nothingness.
I've been reading something about a Handler service... what does it do? Can the Handler service update my TextView in a safer or memory efficient way?
Many thanks if anyone would give some pointers on what i should do on this.
Brace yourself. And try to follow closely, this will be invaluable as a dev.
While loops really should only be implemented in a separate Thread. A separate thread is like a second process running in your app. The reason why it force closed is because you ran the loop in the UI thread, making the UI unable to do anything except for going through that loop. You have to place that loop into the second Thread so the UI Thread can be free to run. When threading, you can't update the GUI unless you are in the UI Thread. Here is how it would be done in this case.
First, you create a Runnable, which will contain the code that loops in it's run method. In that Runnable, you will have to make a second Runnable that posts to the UI thread. For example:
TextView myTextView = (TextView) findViewById(R.id.myTextView); //grab your tv
Runnable myRunnable = new Runnable() {
#Override
public void run() {
while (testByte == 0) {
Thread.sleep(1000); // Waits for 1 second (1000 milliseconds)
String updateWords = updateAuto(); // make updateAuto() return a string
myTextView.post(new Runnable() {
#Override
public void run() {
myTextView.setText(updateWords);
});
}
}
};
Next just create your thread using the Runnable and start it.
Thread myThread = new Thread(myRunnable);
myThread.start();
You should now see your app looping with no force closes.
You can create a new Thread for a while loop.
This code will create a new thread to wait for a boolean value to change its state.
private volatile boolean isClickable = false;
new Thread() {
#Override
public void run() {
super.run();
while (!isClickable) {
// boolean is still false, thread is still running
}
// do your stuff here after the loop is finished
}
}.start();
I honestly can't figure it out - I've heard that thread.stop() is not a good thing to use. It also isn't working for me. How to get threads/handlers to stop running?
Threads should be terminated in a "polite" way. You should build in some mechanism for your thread to stop. You can have a volatile boolean parameter that is checked on every loop of your thread (assuming you have loops in there) like so:
while (!threadStop) {
// Do stuff
}
And then you can set the boolean value to false from another thread (make sure you handle all synchronization issues though) and your thread will stop in it's next iteration.
Ok the answer to stop threads have been done. To stop handler you have to use this following method :
removeCallbacksAndMessages from Handler class like this
myHandler.removeCallbacksAndMessages(null);
you can use it like this..
Thread mythread=new Thread();
if(!mythread){
Thread dummy=mythread;
mythread=null;
dummy.interrupt();
}
or
you can use
mythread.setDeamon(true);
The correct way of stopping a handler is:
handler.getLooper().quit();
I usually implement this by sending a quit message to handler which terminates itself.
The correct way of stopping a generic Thread is:
thread.interrupt();
The thread that is being stopped needs to handle the interrupt:
if(isInterrupted())
return;
This can be put in a loop if you wish:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
try {
while(!isInterrupted() && (line = br.readLine()) != null) {
// Do stuff with the line
}
}
catch(IOException e) {
// Handle IOException
}
catch(InterruptedException e) {
// Someone called interrupt on the thread
return;
}