java.lang.IllegalStateException? How to get rid of this? - android

I am using a list view. In which i change the content or add contents when scroll. It works fine but if i navigate 2 or three times from that page, it gives an error.
The Error is:
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2131230910, class android.widget.ListView) with Adapter.
#Override
public View getView(final int position, View convertView, ViewGroup arg2)
{
Log.e("vec pos", ""+position);
if(position == vectProductBySearch.size()-1 && scrollState == 0 && vectProductBySearch.size()>8)
{
Log.e("vec pos", "in if()");
if (progDialog != null && progDialog.isShowing())
progDialog.dismiss();
progDialog = ProgressDialog.show(ProducyBySearch.this, "",
"Loading... Please wait..", true);
new Thread(new Runnable()
{
#Override
public void run()
{
SearchByCatagory.startIndex= SearchByCatagory.startIndex+10;
post.getProductBySearch(AppsConstants.email, AppsConstants.password, AppsConstants.AuthenticationToken, SearchByCatagory.CatagoryId, SearchByCatagory.description, SearchByCatagory.brand, SearchByCatagory.rating, AppsConstants.UserNum, SearchByCatagory.startIndex);
runOnUiThread(new Runnable()
{
public void run()
{
deafaultAdapter.refresh(AppsConstants.vectProductBySearch);
if (progDialog != null && progDialog.isShowing())
progDialog.dismiss();
}
});
}
}).start();

Use a handler to force any updates from background threads to occur within the UI thread. UI's in nearly all environments/languages don't support changes from other threads

Make sure you are using the UiThread to modify the content of the list and when the list content changes do not forget to call youradapter.notifyDataSetChanged().

outside from the ui-thread you can do ui-operations using post.
just create a new inline runnable-object and add your code to the run()-method.
its not that beatiful but helps in most cases.
example:
view.post(new Runnable() {
#Override
public void run() {
view.scrollTo(0, 0));
}
});

Related

Only the original thread that created a view hierarchy can touch its views when using Dialog [duplicate]

I've built a simple music player in Android. The view for each song contains a SeekBar, implemented like this:
public class Song extends Activity implements OnClickListener,Runnable {
private SeekBar progress;
private MediaPlayer mp;
// ...
private ServiceConnection onService = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder rawBinder) {
appService = ((MPService.LocalBinder)rawBinder).getService(); // service that handles the MediaPlayer
progress.setVisibility(SeekBar.VISIBLE);
progress.setProgress(0);
mp = appService.getMP();
appService.playSong(title);
progress.setMax(mp.getDuration());
new Thread(Song.this).start();
}
public void onServiceDisconnected(ComponentName classname) {
appService = null;
}
};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.song);
// ...
progress = (SeekBar) findViewById(R.id.progress);
// ...
}
public void run() {
int pos = 0;
int total = mp.getDuration();
while (mp != null && pos<total) {
try {
Thread.sleep(1000);
pos = appService.getSongPosition();
} catch (InterruptedException e) {
return;
} catch (Exception e) {
return;
}
progress.setProgress(pos);
}
}
This works fine. Now I want a timer counting the seconds/minutes of the progress of the song. So I put a TextView in the layout, get it with findViewById() in onCreate(), and put this in run() after progress.setProgress(pos):
String time = String.format("%d:%d",
TimeUnit.MILLISECONDS.toMinutes(pos),
TimeUnit.MILLISECONDS.toSeconds(pos),
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(
pos))
);
currentTime.setText(time); // currentTime = (TextView) findViewById(R.id.current_time);
But that last line gives me the exception:
android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Yet I'm doing basically the same thing here as I'm doing with the SeekBar - creating the view in onCreate, then touching it in run() - and it doesn't give me this complaint.
You have to move the portion of the background task that updates the UI onto the main thread. There is a simple piece of code for this:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Stuff that updates the UI
}
});
Documentation for Activity.runOnUiThread.
Just nest this inside the method that is running in the background, and then copy paste the code that implements any updates in the middle of the block. Include only the smallest amount of code possible, otherwise you start to defeat the purpose of the background thread.
I solved this by putting runOnUiThread( new Runnable(){ .. inside run():
thread = new Thread(){
#Override
public void run() {
try {
synchronized (this) {
wait(5000);
runOnUiThread(new Runnable() {
#Override
public void run() {
dbloadingInfo.setVisibility(View.VISIBLE);
bar.setVisibility(View.INVISIBLE);
loadingText.setVisibility(View.INVISIBLE);
}
});
}
} catch (InterruptedException e) {
e.printStackTrace();
}
Intent mainActivity = new Intent(getApplicationContext(),MainActivity.class);
startActivity(mainActivity);
};
};
thread.start();
My solution to this:
private void setText(final TextView text,final String value){
runOnUiThread(new Runnable() {
#Override
public void run() {
text.setText(value);
}
});
}
Call this method on a background thread.
Kotlin coroutines can make your code more concise and readable like this:
MainScope().launch {
withContext(Dispatchers.Default) {
//TODO("Background processing...")
}
TODO("Update UI here!")
}
Or vice versa:
GlobalScope.launch {
//TODO("Background processing...")
withContext(Dispatchers.Main) {
// TODO("Update UI here!")
}
TODO("Continue background processing...")
}
Usually, any action involving the user interface must be done in the main or UI thread, that is the one in which onCreate() and event handling are executed. One way to be sure of that is using runOnUiThread(), another is using Handlers.
ProgressBar.setProgress() has a mechanism for which it will always execute on the main thread, so that's why it worked.
See Painless Threading.
You can use Handler to Delete View without disturbing the main UI Thread.
Here is example code
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
//do stuff like remove view etc
adapter.remove(selecteditem);
}
});
Kotlin Answer
We have to use UI Thread for the job with true way. We can use UI Thread in Kotlin, such as:
runOnUiThread(Runnable {
//TODO: Your job is here..!
})
I've been in this situation, but I found a solution with the Handler Object.
In my case, I want to update a ProgressDialog with the observer pattern.
My view implements observer and overrides the update method.
So, my main thread create the view and another thread call the update method that update the ProgressDialop and....:
Only the original thread that created a view hierarchy can touch its
views.
It's possible to solve the problem with the Handler Object.
Below, different parts of my code:
public class ViewExecution extends Activity implements Observer{
static final int PROGRESS_DIALOG = 0;
ProgressDialog progressDialog;
int currentNumber;
public void onCreate(Bundle savedInstanceState) {
currentNumber = 0;
final Button launchPolicyButton = ((Button) this.findViewById(R.id.launchButton));
launchPolicyButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
showDialog(PROGRESS_DIALOG);
}
});
}
#Override
protected Dialog onCreateDialog(int id) {
switch(id) {
case PROGRESS_DIALOG:
progressDialog = new ProgressDialog(this);
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog.setMessage("Loading");
progressDialog.setCancelable(true);
return progressDialog;
default:
return null;
}
}
#Override
protected void onPrepareDialog(int id, Dialog dialog) {
switch(id) {
case PROGRESS_DIALOG:
progressDialog.setProgress(0);
}
}
// Define the Handler that receives messages from the thread and update the progress
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
int current = msg.arg1;
progressDialog.setProgress(current);
if (current >= 100){
removeDialog (PROGRESS_DIALOG);
}
}
};
// The method called by the observer (the second thread)
#Override
public void update(Observable obs, Object arg1) {
Message msg = handler.obtainMessage();
msg.arg1 = ++currentPluginNumber;
handler.sendMessage(msg);
}
}
This explanation can be found on this page, and you must read the "Example ProgressDialog with a second thread".
I see that you have accepted #providence's answer. Just in case, you can also use the handler too! First, do the int fields.
private static final int SHOW_LOG = 1;
private static final int HIDE_LOG = 0;
Next, make a handler instance as a field.
//TODO __________[ Handler ]__________
#SuppressLint("HandlerLeak")
protected Handler handler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
// Put code here...
// Set a switch statement to toggle it on or off.
switch(msg.what)
{
case SHOW_LOG:
{
ads.setVisibility(View.VISIBLE);
break;
}
case HIDE_LOG:
{
ads.setVisibility(View.GONE);
break;
}
}
}
};
Make a method.
//TODO __________[ Callbacks ]__________
#Override
public void showHandler(boolean show)
{
handler.sendEmptyMessage(show ? SHOW_LOG : HIDE_LOG);
}
Finally, put this at onCreate() method.
showHandler(true);
Use this code, and no need to runOnUiThread function:
private Handler handler;
private Runnable handlerTask;
void StartTimer(){
handler = new Handler();
handlerTask = new Runnable()
{
#Override
public void run() {
// do something
textView.setText("some text");
handler.postDelayed(handlerTask, 1000);
}
};
handlerTask.run();
}
I had a similar issue, and my solution is ugly, but it works:
void showCode() {
hideRegisterMessage(); // Hides view
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
showRegisterMessage(); // Shows view
}
}, 3000); // After 3 seconds
}
I was facing a similar problem and none of the methods mentioned above worked for me. In the end, this did the trick for me:
Device.BeginInvokeOnMainThread(() =>
{
myMethod();
});
I found this gem here.
I use Handler with Looper.getMainLooper(). It worked fine for me.
Handler handler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
// Any UI task, example
textView.setText("your text");
}
};
handler.sendEmptyMessage(1);
This is explicitly throwing an error. It says whichever thread created a view, only that can touch its views. It is because the created view is inside that thread's space. The view creation (GUI) happens in the UI (main) thread. So, you always use the UI thread to access those methods.
In the above picture, the progress variable is inside the space of the UI thread. So, only the UI thread can access this variable. Here, you're accessing progress via new Thread(), and that's why you got an error.
For a one-liner version of the runOnUiThread() approach, you can use a lambda function, i.e.:
runOnUiThread(() -> doStuff(Object, myValue));
where doStuff() can represents some method used to modify the value of some UI Object (setting text, changing colors, etc.).
I find this to be much neater when trying to update several UI objects without the need for a 6 line Runnable definition at each as mentioned in the most upvoted answer, which is by no means incorrect, it just takes up a lot more space and I find to be less readable.
So this:
runOnUiThread(new Runnable() {
#Override
public void run() {
doStuff(myTextView, "myNewText");
}
});
can become this:
runOnUiThread(() -> doStuff(myTextView, "myNewText"));
where the definition of doStuff lies elsewhere.
Or if you don't need to be so generalizable, and just need to set the text of a TextView object:
runOnUiThread(() -> myTextView.setText("myNewText"));
For anyone using fragment:
(context as Activity).runOnUiThread {
//TODO
}
This happened to my when I called for an UI change from a doInBackground from Asynctask instead of using onPostExecute.
Dealing with the UI in onPostExecute solved my problem.
I was working with a class that did not contain a reference to the context. So it was not possible for me to use runOnUIThread(); I used view.post(); and it was solved.
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
final int currentPosition = mediaPlayer.getCurrentPosition();
audioMessage.seekBar.setProgress(currentPosition / 1000);
audioMessage.tvPlayDuration.post(new Runnable() {
#Override
public void run() {
audioMessage.tvPlayDuration.setText(ChatDateTimeFormatter.getDuration(currentPosition));
}
});
}
}, 0, 1000);
When using AsyncTask Update the UI in onPostExecute method
#Override
protected void onPostExecute(String s) {
// Update UI here
}
This is the stack trace of mentioned exception
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6149)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:843)
at android.view.View.requestLayout(View.java:16474)
at android.view.View.requestLayout(View.java:16474)
at android.view.View.requestLayout(View.java:16474)
at android.view.View.requestLayout(View.java:16474)
at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:352)
at android.view.View.requestLayout(View.java:16474)
at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:352)
at android.view.View.setFlags(View.java:8938)
at android.view.View.setVisibility(View.java:6066)
So if you go and dig then you come to know
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
Where mThread is initialize in constructor like below
mThread = Thread.currentThread();
All I mean to say that when we created particular view we created it on UI Thread and later try to modifying in a Worker Thread.
We can verify it via below code snippet
Thread.currentThread().getName()
when we inflate layout and later where you are getting exception.
If you do not want to use runOnUiThread API, you can in fact implement AsynTask for the operations that takes some seconds to complete. But in that case, also after processing your work in doinBackground(), you need to return the finished view in onPostExecute(). The Android implementation allows only main UI thread to interact with views.
If you simply want to invalidate (call repaint/redraw function) from your non UI Thread, use postInvalidate()
myView.postInvalidate();
This will post an invalidate request on the UI-thread.
For more information : what-does-postinvalidate-do
Well, You can do it like this.
https://developer.android.com/reference/android/view/View#post(java.lang.Runnable)
A simple approach
currentTime.post(new Runnable(){
#Override
public void run() {
currentTime.setText(time);
}
}
it also provides delay
https://developer.android.com/reference/android/view/View#postDelayed(java.lang.Runnable,%20long)
For me the issue was that I was calling onProgressUpdate() explicitly from my code. This shouldn't be done. I called publishProgress() instead and that resolved the error.
In my case,
I have EditText in Adaptor, and it's already in the UI thread. However, when this Activity loads, it's crashes with this error.
My solution is I need to remove <requestFocus /> out from EditText in XML.
For the people struggling in Kotlin, it works like this:
lateinit var runnable: Runnable //global variable
runOnUiThread { //Lambda
runnable = Runnable {
//do something here
runDelayedHandler(5000)
}
}
runnable.run()
//you need to keep the handler outside the runnable body to work in kotlin
fun runDelayedHandler(timeToWait: Long) {
//Keep it running
val handler = Handler()
handler.postDelayed(runnable, timeToWait)
}
If you couldn't find a UIThread you can use this way .
yourcurrentcontext mean, you need to parse Current Context
new Thread(new Runnable() {
public void run() {
while (true) {
(Activity) yourcurrentcontext).runOnUiThread(new Runnable() {
public void run() {
Log.d("Thread Log","I am from UI Thread");
}
});
try {
Thread.sleep(1000);
} catch (Exception ex) {
}
}
}
}).start();
In Kotlin simply put your code in runOnUiThread activity method
runOnUiThread{
// write your code here, for example
val task = Runnable {
Handler().postDelayed({
var smzHtcList = mDb?.smzHtcReferralDao()?.getAll()
tv_showSmzHtcList.text = smzHtcList.toString()
}, 10)
}
mDbWorkerThread.postTask(task)
}
If you are within a fragment, then you also need to get the activity object as runOnUIThread is a method on the activity.
An example in Kotlin with some surrounding context to make it clearer - this example is navigating from a camera fragment to a gallery fragment:
// Setup image capture listener which is triggered after photo has been taken
imageCapture.takePicture(
outputOptions, cameraExecutor, object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}
override fun onImageSaved(output: ImageCapture.OutputFileResults) {
val savedUri = output.savedUri ?: Uri.fromFile(photoFile)
Log.d(TAG, "Photo capture succeeded: $savedUri")
//Do whatever work you do when image is saved
//Now ask navigator to move to new tab - as this
//updates UI do on the UI thread
activity?.runOnUiThread( {
Navigation.findNavController(
requireActivity(), R.id.fragment_container
).navigate(CameraFragmentDirections
.actionCameraToGallery(outputDirectory.absolutePath))
})
Solved : Just put this method in doInBackround Class... and pass the message
public void setProgressText(final String progressText){
Handler handler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
// Any UI task, example
progressDialog.setMessage(progressText);
}
};
handler.sendEmptyMessage(1);
}

All commands of the same method are not being executed

Two things are supposed to happen inside the following method. The ProgressBar is supposed to be set to 100% and a layout is supposed to be visible. But on calling the method, the layout gets visible but the ProgressBar does not change its value.
I must add that this is a file sharing app and the ProgressBar becomes 100% on the client side of the code, the problem is on the server. Although both the codes are the same.
ServerClass_Activity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
mWaveLoadingView.setProgressValue(100);
mWaveLoadingView.setCenterTitle("100%");
meowLayout.setVisibility(View.VISIBLE);
}
});
There is a handler running that updates the ProgressBar for a certain time.
Runnable mStatusChecker = new Runnable() {
#Override
public void run() {
try {
Log.d( "","entered run ");
mWaveLoadingView.setCenterTitle(String.valueOf(progress)+"%");
mWaveLoadingView.setProgressValue(progress);
progress+=1;
if(progress==90 || finished == true)
stopRepeatingTask();
} finally {
if(progress<90 && finished == false)
mHandler.postDelayed(mStatusChecker, mInterval);
}
}
};
The variable finished becomes true when the file is sent successfully.
Any idea why the ProgressBar is not being 100%?

Threading Error

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.

notifyItemRemoved() from non Ui Thread not working in recyclerview

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.

Android ListView, need to call getChildAt(index) but always return null unless wait some times

I am new to Android.
I have to update a ListView with chatAdapter.notifyDataSetChanged();
Everything works as expected, ListView is updated.
Then I need to call ListView getChildAt(index), however it is always null, unless I wait for some times
Here is code snippet below:
chatAdapter.notifyDataSetChanged();
if (requestType == RequestType.FirstRequest){
if (chatMessages.size() != 0) {
//scroll to bottom
chatListView.setSelection(chatMessages.size() - 1);
Log.i(TAG, "" + chatListView.getChildAt(0));
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Log.i(TAG, "" + chatListView.getChildAt(0));
}
}, 3000);
}
}
The first Log always returns null, however, I am able to get child if I wait 3 seconds.
It seemed that after I called chatAdapter.notifyDataSetChanged(), it took some time to inflate those child views.
How do I properly call getChildAt(index) in this case?
chatListView.post(new Runnable(){
#Override
public void run(){
//your code to execute after list redraw
}
});
Runnable passed to post method will be excecuted after all pending operations of ListView (or any other View). in this case - list redrawing

Categories

Resources