Reputation: 11608
A brief explanation of what I'm doing: my FragmentActivity
hosts 4 Fragments via a ViewPager
, those are created in my class which extends Fragment
.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = null;
switch (mPage) {
case 1:
view = inflater.inflate(R.layout.frag1,
container, false);
initFrag1(view);
break;
// ....... and so on
}
return view;
}
In the onCreateView()
method I initialize the data depending on the page (Fragment). Each Fragment has quite a complex Layout with a LOT OF TextViews
. That FragmentActivity
gets started when the user clicks a ListItem
in the previous Activity
, and there's a delay of about 0.5-1 sec until the FragmentActivity
starts. My consideration was that the delay is caused by initializing and setting tons of TextViews
, so I tried to do all that stuff in an AsyncTask
:
@Override
protected Void doInBackground(Void... params) {
DecimalFormat df = new DecimalFormat("#0.00");
for (int i = 0; i < FirstTextViewArray.length; i++) {
tmp = (TextView) v.findViewById(FirstTextViewArray[i]);
tmp.setText("test " + String.valueOf(i));
}
for (int i = 0; i < SecondTextViewArray.length; i++) {
tmp = (TextView) v.findViewById(SecondTextViewArray[i]);
tmp.setText(df.format((SomeClass
.getSomeFloatArray(Constants.tmpObject.getSomeInt())[i]));
}
return null;
}
So basically I'm just passing TextViews
as Arrays
and the inflated View
to the AsyncTask
in its constructor, then initialize and set them inside a loop.
It works BUT sometimes (like 1 out of 10) when I swipe between Fragments
the app crashes with an Exception:
CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views
I know what that Exception
means, but the question is: why does it occur accidentally?
2nd question: I guess init and set Views
in the background is not the way to go. How can I then avoid delay at Activity's
start?
Upvotes: 0
Views: 106
Reputation: 313
Only the main thread can work with the views, that's why you get this error. You should use this thread :
getActivity().runOnUiThread(new Runnable() {
public void run() {
//stuff that updates your views
DecimalFormat df = new DecimalFormat("#0.00");
for (int i = 0; i < FirstTextViewArray.length; i++) {
tmp = (TextView) v.findViewById(FirstTextViewArray[i]);
tmp.setText("test " + String.valueOf(i));
}
for (int i = 0; i < SecondTextViewArray.length; i++) {
tmp = (TextView) v.findViewById(SecondTextViewArray[i]);
tmp.setText(df.format((SomeClass.getSomeFloatArray(Constants.tmpObject.getSomeInt())[i]));
}
}
});
So
Upvotes: 0
Reputation: 17820
Use the AsyncTask.onProgressUpdate method to safely update the UI on the UI thread. Here's a rough outline:
new AsyncTask<Void, Object, Void>() {
DecimalFormat df = new DecimalFormat("#0.00");
@Override
protected void onProgressUpdate(Object... values) {
String label = (String) values[0];
int viewId = (Integer) values[1];
TextView tv = (TextView) v.findViewById(viewId);
tv.setText(label);
}
@Override
protected Void doInBackground(Void... params) {
for (int i = 0; i < FirstTextViewArray.length; i++) {
publishProgress("test " + String.valueOf(i), FirstTextViewArray[i]);
}
for (int i = 0; i < SecondTextViewArray.length; i++) {
publishProgress(
df.format((SomeClass.getSomeFloatArray(Constants.tmpObject.getSomeInt())[i])),
SecondTextViewArray[i]);
}
return null;
}
}.execute();
Upvotes: 1