I have a problem. I need to go from one activity to anoth开发者_如何转开发er. My second activity has a big xml layout, with a lot of elements (I'm speaking about four hundred aprox.), then it takes a few seconds (too much) to show this second Activity.
How can I show a Progress dialog between two activities?
I'm trying to use a background task to do this.
I have this method in my Activity A:
private void goToYear() {
Intent intent = new Intent();
intent.setClass (getBaseContext(), YearActivity.class);
startActivity( intent);
}
And in my Activity B:
public class YearActivity extends Activity {
private String TAG = "YearActivity ::";
private ProgressDialog pd = null;
@Override
public void onCreate( Bundle savedInstanceState) {
super.onCreate( savedInstanceState);
// Show the ProgressDialog on this thread
this.pd = ProgressDialog.show(this, "Working...", "Calculating the screen...", true, false);
// Start a new thread that will download all the data
new MakeYearTask().execute();
}
private void initCalendar () {
this.setContentView( R.layout.calendar_year);
...
...
initialize values
...
...
}
private class MakeYearTask extends AsyncTask<String, Void, Object> {
protected Void doInBackground(String... args) {
Log.i("YearActivity::MakeYearTask", "MakeYearTask Background thread starting");
YearActivity.this.initCalendar();
}
protected void onPostExecute(Object result) {
if (YearActivity.this.pd != null) {
YearActivity.this.pd.dismiss();
}
}
}
}
You can see that I make the setContentView
out of the onCreate
method.
This doesn't work. It gives me one exception, like this:
12-09 19:49:17.729: ERROR/AndroidRuntime(218): java.lang.RuntimeException: An error occured while executing doInBackground()
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at android.os.AsyncTask$3.done(AsyncTask.java:200)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:234)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:258)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at java.util.concurrent.FutureTask.run(FutureTask.java:122)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:648)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:673)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at java.lang.Thread.run(Thread.java:1060)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): Caused by: android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at android.view.ViewRoot.checkThread(ViewRoot.java:2629)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at android.view.ViewRoot.requestLayout(ViewRoot.java:545)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at android.view.View.requestLayout(View.java:7657)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at android.view.ViewGroup.addView(ViewGroup.java:1749)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at android.view.ViewGroup.addView(ViewGroup.java:1731)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at com.android.internal.policy.impl.PhoneWindow.generateLayout(PhoneWindow.java:2186)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at com.android.internal.policy.impl.PhoneWindow.installDecor(PhoneWindow.java:2239)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:309)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at android.app.Activity.setContentView(Activity.java:1620)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at es.jota.app.YearActivity.initCalendar(YearActivity.java:42)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at es.jota.app.YearActivity.access$0(YearActivity.java:41)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at es.jota.app.YearActivity.initCalendar$MakeYearTask.doInBackground(YearActivity.java:120)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at es.jota.app.YearActivity.initCalendar$MakeYearTask.doInBackground(YearActivity.java:1)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at android.os.AsyncTask$2.call(AsyncTask.java:185)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:256)
12-09 19:49:17.729: ERROR/AndroidRuntime(218): ... 4 more
This is poor design to start with. If you have such a large amount of data to present to the user which would presumably be scrolled through, you should instead use an AdapterView
subclass, such as a ListView
or GridView
. An XML layout with almost 400 elements is incredibly large.
I understand what you're trying to do (you're attempting to perform the lengthy building of the massive View
hierarchy on a separate Thread
using an AsyncTask
, but what you've found is that it's blown up on you for trying to touch the View
hierarchy on a non-UI Thread
).
Even if you did manage to implement some kind of progress bar in the foreground while the hierarchy is being built, I'm not sure if the system would provide the means to call back progress information while it inflates the View
hierarchy (but I may be wrong).
AdapterView
s were created to solve exactly this kind of problem. With an AdapterView
, typically only a screen's worth of Views
exist in memory at any time. For example, you could have a table with a thousand rows, but with only seven rows fitting onto the screen at once, only eight row View
s might exist in memory at once. Furthermore, the adapter should also recycle the View
s, further optimising performance.
This may not be the best solution but what you can do is extend the basic Theme used in android and set the window background to an image that indicates the activity is loading. Then set that theme to Activity B. Now while Activity B is loading it will show your drawable instead of the black window. You may even be able to get creative with an animation-list and get some kind of indeterminate loading effect.
Have you tried doing new MakeYearTask().execute();
in onResume() instead?
While not elegant you could fire a delayed thread post in on create to wait for a couple of millis.
Edit:
I just this error:
(Caused by: android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views)
are you modifying the UI from the AsyncTask?
You should just build the data in doInBackground()
, but update the ui in onPostExecute()
.
Your formatting is a little off, but if I understand correctly, you are calling initCalendar()
in your AsyncTask
's doInBackground()
. You are not allowed to do that with AsyncTask
s.
Use doInBackground()
for long-running operations such as HTTP calls, DB accesses, etc. Once you have the stuff you need, call initCalendar()
from onPostExecute()
.
精彩评论