Dưới đây là một ví dụ khác về AsyncTask sử dụng Fragment
để xử lý các thay đổi cấu hình thời gian chạy (như khi người dùng xoay màn hình) với setRetainInstance(true)
. Một thanh tiến trình xác định (cập nhật thường xuyên) cũng được thể hiện.
Ví dụ này một phần dựa trên các tài liệu chính thức, Giữ lại một đối tượng trong khi thay đổi cấu hình .
Trong ví dụ này, công việc yêu cầu một luồng nền là việc tải một hình ảnh từ internet vào UI.
Alex Lockwood có vẻ đúng khi nói đến việc xử lý các thay đổi cấu hình thời gian chạy với AsyncT task bằng cách sử dụng "Mảnh vỡ được giữ lại" là cách tốt nhất. onRetainNonConfigurationInstance()
bị phản đối trong Lint, trong Android Studio. Các tài liệu chính thức cảnh báo chúng tôi sử dụng android:configChanges
, từ Xử lý thay đổi cấu hình , ...
Tự xử lý thay đổi cấu hình có thể khiến việc sử dụng các tài nguyên thay thế trở nên khó khăn hơn nhiều, vì hệ thống không tự động áp dụng chúng cho bạn. Kỹ thuật này nên được coi là giải pháp cuối cùng khi bạn phải tránh khởi động lại do thay đổi cấu hình và không được khuyến nghị cho hầu hết các ứng dụng.
Sau đó, có một vấn đề là liệu người ta có nên sử dụng AsyncTask cho chủ đề nền hay không.
Tài liệu tham khảo chính thức cho AsyncTask cảnh báo ...
AsyncT task nên được sử dụng một cách lý tưởng cho các hoạt động ngắn (nhiều nhất là vài giây.) Nếu bạn cần giữ các luồng hoạt động trong thời gian dài, bạn nên sử dụng các API khác nhau được cung cấp bởi java.util.conc hiện nhịp Giám đốc điều hành, ThreadPoolExecutor và FutureTask.
Ngoài ra, người ta có thể sử dụng một dịch vụ, trình tải (sử dụng CoderLoader hoặc AsyncTaskLoader) hoặc nhà cung cấp nội dung để thực hiện các hoạt động không đồng bộ.
Tôi chia phần còn lại của bài viết thành:
- Thủ tục; và
- Tất cả các mã cho các thủ tục trên.
Thủ tục
Bắt đầu với AsyncTask cơ bản như một lớp bên trong của một hoạt động (nó không cần phải là một lớp bên trong nhưng nó có thể sẽ thuận tiện để trở thành). Ở giai đoạn này, AsyncTask không xử lý các thay đổi cấu hình thời gian chạy.
public class ThreadsActivity extends ActionBarActivity {
private ImageView mPictureImageView;
private class LoadImageFromNetworkAsyncTask
extends AsyncTask<String, Void, Bitmap> {
@Override
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
mPictureImageView.setImageBitmap(bitmap);
}
}
/**
* Requires in AndroidManifext.xml
* <uses-permission android:name="android.permission.INTERNET" />
*/
private Bitmap loadImageFromNetwork(String url) {
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream((InputStream)
new URL(url).getContent());
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_threads);
mPictureImageView =
(ImageView) findViewById(R.id.imageView_picture);
}
public void getPicture(View view) {
new LoadImageFromNetworkAsyncTask()
.execute("http://i.imgur.com/SikTbWe.jpg");
}
}
Thêm một lớp RetainedFragment lồng nhau mở rộng lớp Fragement và không có UI riêng. Thêm setRetainInstance (true) vào sự kiện onCreate của Fragment này. Cung cấp các thủ tục để thiết lập và nhận dữ liệu của bạn.
public class ThreadsActivity extends Activity {
private ImageView mPictureImageView;
private RetainedFragment mRetainedFragment = null;
...
public static class RetainedFragment extends Fragment {
private Bitmap mBitmap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// The key to making data survive
// runtime configuration changes.
setRetainInstance(true);
}
public Bitmap getData() {
return this.mBitmap;
}
public void setData(Bitmap bitmapToRetain) {
this.mBitmap = bitmapToRetain;
}
}
private class LoadImageFromNetworkAsyncTask
extends AsyncTask<String, Integer,Bitmap> {
....
Trong lớp Activity ngoài cùng, onCreate () xử lý RetainedFragment: Tham chiếu nó nếu nó đã tồn tại (trong trường hợp Activity đang khởi động lại); tạo và thêm nó nếu nó không tồn tại; Sau đó, nếu nó đã tồn tại, hãy lấy dữ liệu từ RetainedFragment và đặt UI của bạn với dữ liệu đó.
public class ThreadsActivity extends Activity {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_threads);
final String retainedFragmentTag = "RetainedFragmentTag";
mPictureImageView =
(ImageView) findViewById(R.id.imageView_picture);
mLoadingProgressBar =
(ProgressBar) findViewById(R.id.progressBar_loading);
// Find the RetainedFragment on Activity restarts
FragmentManager fm = getFragmentManager();
// The RetainedFragment has no UI so we must
// reference it with a tag.
mRetainedFragment =
(RetainedFragment) fm.findFragmentByTag(retainedFragmentTag);
// if Retained Fragment doesn't exist create and add it.
if (mRetainedFragment == null) {
// Add the fragment
mRetainedFragment = new RetainedFragment();
fm.beginTransaction()
.add(mRetainedFragment, retainedFragmentTag).commit();
// The Retained Fragment exists
} else {
mPictureImageView
.setImageBitmap(mRetainedFragment.getData());
}
}
Bắt đầu AsyncTask từ UI
public void getPicture(View view) {
new LoadImageFromNetworkAsyncTask().execute(
"http://i.imgur.com/SikTbWe.jpg");
}
Thêm và mã một thanh tiến trình xác định:
- Thêm một thanh tiến trình vào bố trí UI;
- Nhận một tham chiếu đến nó trong Activity oncreate ();
- Làm cho nó hiển thị và bất khả xâm phạm khi bắt đầu và kết thúc quá trình;
- Xác định tiến trình để báo cáo cho UI trong onProTHERUpdate.
- Thay đổi tham số Chung thứ 2 của AsyncTask từ Void thành loại có thể xử lý các cập nhật tiến độ (ví dụ: Integer).
- xuất bản Xuất phát tại các điểm thông thường trong doInBackground ().
Tất cả các mã cho thủ tục trên
Bố trí hoạt động.
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.mysecondapp.ThreadsActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin">
<ImageView
android:id="@+id/imageView_picture"
android:layout_width="300dp"
android:layout_height="300dp"
android:background="@android:color/black" />
<Button
android:id="@+id/button_get_picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@id/imageView_picture"
android:onClick="getPicture"
android:text="Get Picture" />
<Button
android:id="@+id/button_clear_picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/button_get_picture"
android:layout_toEndOf="@id/button_get_picture"
android:layout_toRightOf="@id/button_get_picture"
android:onClick="clearPicture"
android:text="Clear Picture" />
<ProgressBar
android:id="@+id/progressBar_loading"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/button_get_picture"
android:progress="0"
android:indeterminateOnly="false"
android:visibility="invisible" />
</RelativeLayout>
</ScrollView>
Hoạt động với: lớp bên trong AsyncTask; lớp bên trong RetainedFragment lớp bên trong xử lý các thay đổi cấu hình thời gian chạy (ví dụ: khi người dùng xoay màn hình); và một thanh tiến trình xác định cập nhật theo định kỳ. ...
public class ThreadsActivity extends Activity {
private ImageView mPictureImageView;
private RetainedFragment mRetainedFragment = null;
private ProgressBar mLoadingProgressBar;
public static class RetainedFragment extends Fragment {
private Bitmap mBitmap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// The key to making data survive runtime configuration changes.
setRetainInstance(true);
}
public Bitmap getData() {
return this.mBitmap;
}
public void setData(Bitmap bitmapToRetain) {
this.mBitmap = bitmapToRetain;
}
}
private class LoadImageFromNetworkAsyncTask extends AsyncTask<String,
Integer, Bitmap> {
@Override
protected Bitmap doInBackground(String... urls) {
// Simulate a burdensome load.
int sleepSeconds = 4;
for (int i = 1; i <= sleepSeconds; i++) {
SystemClock.sleep(1000); // milliseconds
publishProgress(i * 20); // Adjust for a scale to 100
}
return com.example.standardapplibrary.android.Network
.loadImageFromNetwork(
urls[0]);
}
@Override
protected void onProgressUpdate(Integer... progress) {
mLoadingProgressBar.setProgress(progress[0]);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
publishProgress(100);
mRetainedFragment.setData(bitmap);
mPictureImageView.setImageBitmap(bitmap);
mLoadingProgressBar.setVisibility(View.INVISIBLE);
publishProgress(0);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_threads);
final String retainedFragmentTag = "RetainedFragmentTag";
mPictureImageView = (ImageView) findViewById(R.id.imageView_picture);
mLoadingProgressBar = (ProgressBar) findViewById(R.id.progressBar_loading);
// Find the RetainedFragment on Activity restarts
FragmentManager fm = getFragmentManager();
// The RetainedFragment has no UI so we must reference it with a tag.
mRetainedFragment = (RetainedFragment) fm.findFragmentByTag(
retainedFragmentTag);
// if Retained Fragment doesn't exist create and add it.
if (mRetainedFragment == null) {
// Add the fragment
mRetainedFragment = new RetainedFragment();
fm.beginTransaction().add(mRetainedFragment,
retainedFragmentTag).commit();
// The Retained Fragment exists
} else {
mPictureImageView.setImageBitmap(mRetainedFragment.getData());
}
}
public void getPicture(View view) {
mLoadingProgressBar.setVisibility(View.VISIBLE);
new LoadImageFromNetworkAsyncTask().execute(
"http://i.imgur.com/SikTbWe.jpg");
}
public void clearPicture(View view) {
mRetainedFragment.setData(null);
mPictureImageView.setImageBitmap(null);
}
}
Trong ví dụ này, hàm thư viện (được tham chiếu ở trên với tiền tố gói rõ ràng com.example.st Chuẩnappl Library.android.Network) hoạt động thực sự ...
public static Bitmap loadImageFromNetwork(String url) {
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream((InputStream) new URL(url)
.getContent());
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
Thêm bất kỳ quyền nào mà tác vụ nền của bạn yêu cầu vào AndroidManifest.xml ...
<manifest>
...
<uses-permission android:name="android.permission.INTERNET" />
Thêm hoạt động của bạn vào AndroidManifest.xml ...
<manifest>
...
<application>
<activity
android:name=".ThreadsActivity"
android:label="@string/title_activity_threads"
android:parentActivityName=".MainActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.mysecondapp.MainActivity" />
</activity>