I use this void to append TextViews in a log-like process to display it to the user:
static void addlog(Activity innercont, String txt)
{
TextView tadd = new TextView(innercont);
tadd.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
tadd.setText(txt);
Log.i(TAG,"addlog: "+txt);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(tadd);
ScrollView scro = (ScrollView) innercont.findViewById(R.id.ScrollView1);
scro.removeAllViews();
scro.addView(layout);
innercont.setContentView(scro);
}
I know that most of the things are useless, but this is my attempt at the moment.
The problem
At first (MainActivity-onCreate) i add an initialization entry using this void - it works.
Afterwards, i have a function (private class navigata extends WebViewClient) that calls another function (custom void) that has a lot of entries using this function.
None of them become displayed until the function is finished (and that takes a lot of time), what makes the whole log useless (no one needs a log that you can only see after everything is finished).
So my question is: How can i do sth like pausing the function so that the textviews can be added?
Thanks to Michael Butscher, i solved the problem using Threads.
Therefore, i modified the original addlog-function like this:
static void addlog(Activity innercont, String txt)
{
if (innercont.findViewById(255) != null)
{
TextView tadd = (TextView) innercont.findViewById(255);
String atmtxt = (String) tadd.getText();
atmtxt = atmtxt+"\n"+txt;
tadd.setText(atmtxt);
return;
}
TextView tadd = new TextView(innercont);
tadd.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
tadd.setText(txt);
tadd.setId(255);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(tadd);
ScrollView scro = (ScrollView) innercont.findViewById(R.id.ScrollView1);
scro.removeAllViews();
scro.addView(layout);
innercont.setContentView(scro);
}
And had the main work doing in a thread with its own addlog-function, which uses View.post to access the UI without blocking it.
final TextView tadd = (TextView) cont.findViewById(255);
tadd.setText("");
//Log.i(TAG, "get lists" );
new Thread(new Runnable() {
public void addlog2(final Activity cont, final String txt)
{
tadd.post(new Runnable() {
public void run() {
String atmtxt = (String) tadd.getText();
atmtxt = atmtxt+"\n"+txt;
tadd.setText(atmtxt);
}
});
}
public void run() {
addlog2(cont,"log text");
//...
}
}).start();
Related
I'm trying to make a repeating loop to display increasing numbers in a single textview.
The general idea is this
....
int rep = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.Layout);
do { meth(); } while (rep < 11);
}
private void meth() {
final TextView textv = (TextView) findViewById( R.id.tex );
String srep = Integer.toString(rep);
textv.setText(srep);
if(rep <11) { rep = rep +1; }
}
....
The idea is to display the numbers 1 to 10 in the textview textv ONE BY ONE on screen. But when I ran it, it just shows 10. I'm tried to put in a CountDownTimer inside meth() and also inside the do {} loop but it just crashes the program.
Would appreciate if anyone can point me the right way of doing this.
Try this
private class MethTask extends AsyncTask<String, String, String> {
protected String doInBackground(String... urls) {
do { meth(); SystemClock.sleep(1000);
} while (rep < 11);
return "";
}
}
And call from onCreate() like this:
new MethTask().execute("");
First thing you cannot run this code into oncreate otherwise you won't see anything since onCreate is run before the activity is rendered.
So what you should do is first create a CountownTimer, start it in the onStart method this way:
handler.postDelayed(new Runnable() {
startCountDown();
}, 1000);
This way you will be sure the activity is displayed
UPDATE
If you use CountownTimer there is no need to call sleep or other similar methods
Im trying to do this silly "game" where I have a relative layout and classes that extend from View. I create the Views and want to add them onto the Relative layout using a Thread. So far so good. I had it working just fine with little object views scrolling down the relative layout. I then added two more screens for options and only after those screens I wanted to show the Activity with the scrolling views. The problem is that it stop working with the following error:
08-03 20:13:48.140: E/AndroidRuntime(5152): java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
I canĀ“t understand this error...
Here is the sample code for the thread that starts and the function that updates the UI:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
context = this.getApplicationContext();
/*load all bitmaps*/
loadBitmaps();
/*get all the activities components*/
gameCanvasRL = (RelativeLayout)findViewById(R.id.gameCanvasRL);
playerScoreTV = (TextView)findViewById(R.id.playerPoints);
/*GameManager instance*/
manager = GameManager.getInstance();
/*Start Threads*/
startAllThreads();
}
private void startAllThreads() {
refreshCanvasHandler = new Handler();
spawnHandler = new Handler();
refreshCanvasThread = new Thread(new RefreshCanvasTask());
spawnTask = new Thread(new spawnTask());
refreshCanvasThread.start();
spawnTask.start();
}
class RefreshCanvasTask implements Runnable {
#Override
public void run() {
while(true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
refreshCanvasHandler.post(new Runnable() {
#Override
public void run() {
refreshCanvas();
}
});
}
}
}
private void refreshCanvas() {
int germSize;
/*Move all germs*/
manager.moveGerms();
germSize = manager.getGerms().size();
if(gameCanvasRL.getChildCount() > 0)
gameCanvasRL.removeAllViews();
for(int i = 0; i < germSize; i++) {
gameCanvasRL.addView(manager.getGerms().get(i));
}
}
The error means you're trying to add a view that is already added to another view. A view may only have 1 parent, so the second add throws an exception. You need to remove it from the original parent before adding it to the new one.
I have got some problems to understand runOnUiThread(). I want to update the TextView continously but nothing happens. The GUI is still blocked. Could somebody help me?
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
runner();
}
public void runner (){
String[] testFiles = GeneralHelper.getPictureFileList();
TextView text = (TextView) findViewById(R.id.textfeld);
for (int i = 0; i < 2; i++)
{
runOnUiThread(new Runnable() {
public void run() {
text.setText("\n" + GeneralHelper.getPictureFileList()[i]);
}
});
...
// image analysis
}}
The loop has only 2 iterations and it is done so fast that you even can't see changes. You only see result GeneralHelper.getPictureFileList()[1]
And you are inside UiThread so you shouldn't use it. Just:
public void runner (){
String[] testFiles = GeneralHelper.getPictureFileList();
TextView text = (TextView) findViewById(R.id.textfeld);
for (int i = 0; i < 2; i++)
{
text.setText("\n" + GeneralHelper.getPictureFileList()[i]);
}
}
Sounds like you need to create your own timer class where you can include runOnUiThread() to update your TextView. That's what I did on a program I wrote where I needed to display the time counting up every second as soon as the user pressed a button.
my application keeps force closing. But Eclipse shows no error or warnings
package com.example.pkg;
import android.os.Bundle;
import android.widget.TextView;
import android.app.Activity;
public class subActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sub);
Thread r = new Thread(new Runnable(){
public void run()
{ final TextView tv=(TextView)findViewById(R.id.rline1);
String s=(String)tv.getText();
tv.setText(s+"Works !");
}
});
r.start();
}
}
Another Activity calls this Activity. That one has the TextView displayed. All I want to do is to change this string resource called R.string.rline1 that is being displayed on the TextView. Please tell me how to do this if there is another way
First thing, you must need to update GUI stuffs inside UI thread else it will never work. Second thing you know how many times you are creating the instance of your text view and setting it again again, you are inside the thread and you havn't set any flag to stop your thread once you are done. E.g for UI thread :
Runnable update_gui = new Runnable() {
#Override
public void run() {
final TextView tv=(TextView)findViewById(R.id.rline1);
String s=(String)tv.getText();
tv.setText(s+"Works !");
}
};runOnUiThread(update_gui);
You are trying to update your UI (with tv.setText(s+"Works !");) in a thread. You cannot do that. You must update your UI in the main thread. Just delete this useless Thread:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sub);
TextView tv=(TextView)findViewById(R.id.rline1);
String s=(String)tv.getText();
tv.setText(s+"Works !");
}
Note: Eclipse doesn't show errors, you must open your logcat (by default in the DDMS perspective in Eclipse.)
Next time, post your logcat error when you have troubles.
Replace below code
Thread r = new Thread(new Runnable(){
public void run()
{ **final TextView tv=(TextView)findViewById(R.id.rline1);
String s=(String)tv.getText();
tv.setText(s+"Works !");**
}
});
r.start();
with
final TextView tv=(TextView)findViewById(R.id.rline1);
String s=(String)tv.getText();
tv.setText(s+"Works !");
I have an array of drawables, that I would like to change by my own timer to a imageview.
(i tried the other option with xml and setBackgroundResource, but does not work for me as I have hundret of pics and always got memory problem as it looks android assign already the whole memory for all pics at once. (just in this demo i shorted it to 4 images)
Ok, so first i make my array
private static int[] draws = {
R.drawable.frankiearmevor_0001,
R.drawable.frankiearmevor_0002,
R.drawable.frankiearmevor_0003,
R.drawable.frankiearmevor_0002
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imgView = (ImageView) findViewById(R.id.fredi);
// create timer
Timer updateProgressTimer = new Timer();
updateProgressTimer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
myloop();
}
}, 0, 150);
}
int mycounter;
public void myloop()
{
mycounter++;
if (mycounter > 4) mycounter = 1;
imgView.setImageResource(draws[mycounter-1]);
String hallo; hallo = "now: "+mycounter;
Log.d("1",hallo);
}
when I assign only a fixed image: imgView.setImageResource(draws[2]);
it shows that fine and I see also my thread is logged fine, but when I exchange the
fixed resource draws[2] into a dynamic draws[mycounter-1] .. i just get a black screen, no error, nothing.
what to do, so i will show the images :)
thx
chris
EDIT: 22. August:
I tried now with the comment I got, it compiles fine, but somehow there is an error i guess.. it crash:
imgView = (ImageView) findViewById(R.id.fredi);
Timer updateProgressTimer = new Timer();
updateProgressTimer.scheduleAtFixedRate(new TimerTask()
{
#Override
public void run()
{
//myloop();
imgView.post (new Runnable()
{
public void run()
{
mycounter++;
if (mycounter > 10) mycounter = 1;
imgView.setImageResource(draws[1]);
//imgView.invalidate();
String hallo; hallo = "now: "+mycounter;
Log.d("1",hallo);
}
});
}
}, 0, 150);
The ImageView update should happen on the UI Thread...
Refer this answer. The TimerTask runs on a different thread, so you've to use the imgView.post() to update the UI Component.
Are you sure you need to update the Component every 150ms? That's very expensive.
Good Luck.