I create a thread to update my data and try to do notifyDataSetChanged at my ListView.
private class ReceiverThread extends Thread {
#Override
public void run() {
//up-to-date
mAdapter.notifyDataSetChanged();
}
The error occurs at line:
mAdapter.notifyDataSetChanged();
Error:
12-29 16:44:39.946: E/AndroidRuntime(9026): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
How should I modify it?
Use runOnUiThread() method to execute the UI action from a Non-UI thread.
private class ReceiverThread extends Thread {
#Override
public void run() {
Activity_name.this.runOnUiThread(new Runnable() {
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
}
You can not touch the views of the UI from other thread. For your problem you can use either AsyncTask, runOnUiThread or handler.
All The Best
You cant access UI thread from other thread.You have to use handler to perform this.You can send message to handler inside your run method and update UI (call mAdapter.notifyDataSetChanged()) inside handler.
access the UI thread from other threads
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
my approach whe i use other Threads for work:
private AbsListView _boundedView;
private BasicAdapter _syncAdapter;
/** bind view to adapter */
public void bindViewToSearchAdapter(AbsListView view) {
_boundedView = view;
_boundedView.setAdapter(_syncAdapter);
}
/** update view on UI Thread */
public void updateBoundedView() {
if(_boundedView!=null) {
_boundedView.post(new Runnable() {
#Override
public void run() {
if (_syncAdapter != null) {
_syncAdapter.notifyDataSetChanged();
}
}
});
}
}
btw notifyDatasetChanged() method hooks to DataSetObservable class object of AbsListView which is set first by involving AbsListView.setAdaptert(Adapter) method by setting callback to Adapter.registerDataSetObserver(DataSetObserver);
You can write in this way also.
new Handler().postDelayed(new Runnable() {
public void run() {
test();
}
}, 100);
private void test() {
this.notifyDataSetChanged();
}
just test it.
Related
My fragment is
public class sample extends Fragment implements statusChanger{
void onResume() {
Listener.registerListener(this);
}
void onPause() {
Listener.deRegisterListener(this);
}
#Override
public void onStatusChanged() {
MyTextView.setVisibility(View.VISIBLE);
}
}
My Interface is
public interface StatusChanger {
void onStatusChanged();
}
My callback from another java class is
public void onstatusChanged() {
listener.onStatusChanged();
}
The above is the outline of my code , I could get a call back from the ordinal java class to my fragment , but the textView is not set to visible and i do not get any runtime errors.
Looks like it might be a thread issue. What if you run the onStatusChanged() code on the UI thread?
#Override
public void onStatusChanged() {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
MyTextView.setVisibility(View.VISIBLE);
}
});
}
In normal cases, following code will work:
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
// Update UI here.
}
});
Note: If you have wrap above code with Handler with a delay then it may not work.
I am working on an android application, that fetches image from Internet and show in the user interface. I am using RecyclerView for showing the image. I am planning to download the image using a separate thread. and update RecyclerView via the handler. I dont know wether this concept is correct or not, (I know AsyncTask, but for learning purpose I am trying to implement Handler.)
So I coded for the same as below
private void loadNewsThumbnailImage(ArrayList<DataItem> dataList) {
for (DataItem item : DataList) { //DataItem is the model class
loadThumbnailFromInternet(item);
}
}
private void loadThumbnailFromInternet(final DataItem dataItem) {
Thread imageDowloaderThread = new Thread(new Runnable() {
#Override
public void run() {
Bitmap bitmap = null;
try {
bitmap = getDataItemBitmap(dataItem.getmImageUrl());
dataItem.setmThumbnail(bitmap);
new Handler().post(new Runnable() { // Tried new Handler(Looper.myLopper()) also
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
});
imageDowloaderThread.start();
}
I have executed this code but I am getting error, and application is terminated, I don't know why this is happening . please any one help me to sort it out. and explain what is the problem for the current code.
(Please do not suggest to use AsyncTask (I have tried that and it works fine))
UPDATE
Error getting :java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Your application is getting terminated because you are calling notifyDataSetChanged() from a non UI Thread.
Replace:
new Handler().post(new Runnable() { // Tried new Handler(Looper.myLopper()) also
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
With this:
new Handler(Looper.getMainLooper()).post(new Runnable() { // Tried new Handler(Looper.myLopper()) also
#Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
The thread you defined does not have a Looper, and no message queue,so you can not send message in this thread. AsyncTask has its own Looper which you can find it in its source code. This is handler defined in AsyncTask:
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
#SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
#Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
I have a packet listener that detect when a packet arrived and I need refresh an ArrayAdapter when this happens. The problem is that if I try to access the adapter.notifyDataSetChanged() method, an Exception is thrown:
Exception in packet listener: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
Any ideas?
Assuming you are in an object with access to the application's context:
If you are in an Activity:
runOnUiThread(new Runnable() {
#Override
public void run() {
adapter.notifyDataSetChanged();
}
});
If you are in a Fragment:
Activity act = getActivity();
if (act != null) {
act.runOnUiThread(new Runnable() {
#Override
public void run() {
adapter.notifyDataSetChanged();
}
});
}
Other options exist such as looper/message handler and so on but this is by far the simplest.
I have a fragment that incorporates a ViewPager with custom views and a spinner in a top bar. Every time a change the page in the viewpager, I have to update strings in the spinner from a db. To do this, in the onPageSelected of the viewPager listener I launch a thread that retrieve data from the db and updates via runOnUiThread the spinner's adapter. The problem is that the notifyDataSetChanged() called for the spinner's adapter lags the viewpager: it has to rebuild few views, but it lags it a bit.
#Override
public void onPageSelected(final int pos) {
new Thread(new Runnable() {
#Override
public void run() {
...
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
mSpinnerAdapter.notifyDataSetChanged();
}
});
}
}).start();
}
How to resolve this? It is possible to run code on the main thread with lowest priority?
First, remove the Thread, then try to remove the runOnUiThread.
you should be able to get away with :
#Override
public void onPageSelected(final int pos) {
... // your hidden code
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
mSpinnerAdapter.notifyDataSetChanged();
}
});
}
The new thread stuff isnt needed.
I created a View component for android. The component has its own thread to make background work. I start the thread in the View constructor.
Where should I stop the thread? Is onDetachedFromWindow a correct place to make it?
I would do it the following way provided the Thread has to be active during the time the View has a Surface and uses it for drawing:
public class MyView extends View {
class MyThread extends Thread {
private boolean mActive = true;
public void run() {
while (mActive) {
doThings();
}
}
public void terminate() {
mActive = false;
}
private void doThings() {
// the things your thread should do
}
}
private MyThread mBackgroundOperation = null;
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mBackgroundOperation = new MyThread();
mBackgroundOperation.start();
}
protected void onDetachedFromWindow() {
mBackgroundOperation.terminate();
mBackgroundOperation = null;
super.onDetachedFromWindow();
}
}
If this is not the case (if the Thread's lifecycle is not directly dependant of the use of the View's Surface for drawing) I would think twice about handling it inside the View, and would maybe consider moving it to the Activity that uses this View instead. "Maybe" because this is a difficult thing to determine without knowing what this Thread actually does.
stop() method is deprecated. Check this:
http://developer.android.com/reference/java/lang/Thread.html#stop%28java.lang.Throwable%29
you should get your work done and leave it, Android is smart enough to take care of it..
The best time to stop a view updating is probably when it's no longer visible. Your activity's onStop() method will be called when this happens, and from there you could call a method you write in your custom view to shutdown its update thread.
// Activity.java
public void onStop() {
myThreadedView.shutdown();
... // rest of onStop() here
}
// ThreadedView.java
public void shutdown() {
myViewThread.shutdown();
}
// ViewThread.java
bool stop = false;
public void shutdown() {
stop = true;
}
public void run() {
while (!stop) {
updateView();
}
}