In a Fragment I have this Thread that have to refresh the text of a
TextView. The problem is that after setText() (the text is set in fact if I log TextView.getText() it returns the text changed) the screen the text is always the same. It change only if a add a view to the Fragment's view.
This is the code,
Thread time = new Thread() {
public void run() {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
while(true) {
TextView.setText("some text");
// i tried also to use TextView.invalidate()
}
});
}
};
}
Remove while(true), you are blocking the UI thread with that
Related
I get some error. I really couldn't solve it today :( I get error after set ID data to lblID in FillData() method. It sets ID data properly but lblTitle and lblPrice always returns error like "Only the original thread that created a view hierarchy can touch its views" and program stops running.
Note : This is not my original code. I just minimized it to be more understandable and of course it gives same error like below code. Anyway in FillData() method i get data from wcf service and it returns data properly. i tried runonuithread but it didn't make any sense. Also if i write the code outside of the thread it doesn't fill the controls. Because it's originally gets the data from wcf service.
public class MainActivity extends AppCompatActivity {
LinearLayout lytData;
TextView lblTitle, lblID, lblPrice;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lytData = (TextView)findViewById(R.id.lytNewData);
lblID = (TextView)findViewById(R.id.lblID);
lblTitle = (TextView)findViewById(R.id.lblTitle);
lblPrice = (TextView)findViewById(R.id.lblPrice);
new Thread() {
public void run() {
FillData();
}
}.start();
lytData.setOnTouchListener(new OnCustomTouchListener (context) {
#Override
public void ToLeft() {
new Thread() {
public void run() {
FillData();
}
}.start();
}
#Override
public void ToRight() {
new Thread() {
public void run() {
FillData();
}
}.start();
}
});
}
void FillData() {
lblID.setText("aaa");
lblTitle.setText("aaa");
lblPrice.setText("aaa");
}
The problem is you're trying to update the UI in another thread, but the UI can only be updated in the UI thread. If you're simply updated the UI as your code is showing then you should remove the calls from FillData from the secondary thread, use a secondary thread if you're doing heavy loading inside FillData() otherwise you're better off updating the UI directly in the UI thread:
So instead of doing this:
new Thread() {
public void run() {
FillData();
pd.cancel();
}
}.start();
Just simply call FillData(); outside the new thread.
You can also call runOnUiThread to bring the update to the ui thread:
getActivity().runOnUiThread(new Runnable() {
public void run() {
FillData();
}
});
If your code inside FillData is mixed with heavy load code, then you can bring the runOnUiThread method to inside the FillData and move only the UI update code to runOnUiThread.
If you still want to keep your code the way it is you can "post" changes from your secondary thread like this:
viewElement.post(new Runnable() {
public void run() {
//update UI
}
});
}
viewElement is any UI element that extends from View.
I am trying to remove item from list and notifyItemRemoved() method it is not working it gives array index out of bound exception by removing last item and if I remove item from middle its also remove very next item to it but if put the code outside the thread its working fine
there is my code
Runnable runnable = new Runnable() {
#Override
public void run() {
int progress = 0;
ArrayList<MediaFileObject> selection = localDatabase.getAllMediaObjectsOfID(list.get(selectedAlbum).getId());
for (MediaFileObject obj : selection) {
if (searializeableTasks.isCancelled())
break;
localDatabase.moveMediaObjectToTrash(obj);
progress++;
if (searializeableTasks.isCancelled())
sendProgressToHandle(-101);
else
sendProgressToHandle(progress);
}
if (!searializeableTasks.isCancelled())
localDatabase.deleteAlbum(list.get(selectedAlbum).getId());
Handler handler = new Handler(getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
list.remove(selectedAlbum);
savedAlbumAdapter.notifyItemRemoved(selectedAlbum);
}
});
}
};
searializeableTasks.startTasks(localDatabase.getAllMediaObjectsOfID(list.get(selectedAlbum).getId()).size(), runnable);
but if put all this code inside main thread(Class) its working fine as expected I am putting my code here I want to show my custom progress dialog there for after completion I want to update my RecyclerView can someone please help me. What is wrong in my code? or Why it is not working in separate thread?
Call notify on main thread.
runOnUiThread(new Runnable() {
#Override
public void run() {
savedAlbumAdapter.notifyItemRemoved(selectedAlbum);
}
});
Or
yourrecyclerView.post(new Runnable() {
#Override
public void run() {
savedAlbumAdapter.notifyItemRemoved(selectedAlbum);
}
});
use only
notifyDataSetChanged();
It will work.If you use notifyItemRemoved() after remove() then it would again try to remove next position , so Exception arises.
When called setText(String) from thread (handler) android updated all UI widgets. (e.g. called getView in listview adapters).
handler.post(new Runnable() {
#Override
public void run() {
if (mCurrentTime != null)
mCurrentTime.setText(time);
}
});
(used for showed current audio progress)
How update textview without updated adapters?
I have a countdown timer that onFinished I want to have the screen change colors repeatedly.
I'm trying:
public void onFinish() {
findViewById(R.id.screenid).setTag("BLACK");
_timer2=new Timer();
_timer2.scheduleAtFixedRate(Flashscreen, 0,1700);}
TimerTask Flashscreen = new TimerTask()
{
public void run() {
if ( findViewById(R.id.screenid).getTag()=="BLACK" )
{
findViewById(R.id.screenid).setBackgroundColor(Color.BLUE);
findViewById(R.id.screenid).setTag("BLUE");
return;
}
if (findViewById(R.id.screenid).getTag()=="BLUE")
{
findViewById(R.id.screenid).setBackgroundColor(Color.BLACK);
findViewById(R.id.screenid).setTag("BLACK");
return;
}
}};
But it will only change the color to blue once. What's happening wrong?
Is it checking for object equality and not string content equality?
Try changing
( findViewById(R.id.screenid).getTag()=="BLACK" )
To
(((String)findViewById(R.id.screenid).getTag()).equals("BLACK"))
And likewise for the check for "BLUE"
Basically, '==' checks to see if the reference is the same, as in they are both pointing to the same object. 'equals' actually checks to see if the content of the strings are equal.
Can you try putting both changing of color to run on uithread.
Something like below
runOnUiThread(new Runnable() {
#Override
public void run() {
findViewById(R.id.imageView1).setBackgroundColor(Color.BLACK);
findViewById(R.id.imageView1).setTag("BLACK");
}
});
I want to change the color of a text after every few seconds. I tried generating a random number and using it for setting the color of the text view object in a loop. But the app is not responding. Can anybody help me with this please?
Try running the color-cycling part of your code in a separate thread. For example
Thread thread = new Thread( new Runnable() {
public void run() {
while(true) {
int number = // generate random number ;
runOnUiThread( new Runnable() {
public void run() {
TextView text = // get your TextView ;
text.setTextColor(number);
{
{
try {
Thread.sleep(DELAY);
} catch (InterruptedException e) {}
}
}
}
thread.start();
You will need to run the code that actually changes the TextView via the runOnUiThread because Android does not allow other threads to modify parts of an Activity.
You could use a Handler with .postDelayed() and set it up to have a recursive structure, so each time through it will change the color and then post the next runnable to fire off a few seconds later.