Aşağıda, Fragment
çalışma zamanı yapılandırma değişikliklerini (kullanıcı ekranı döndürdüğü gibi) işlemek için bir kullanan bir AsyncTask örneği verilmiştir setRetainInstance(true)
. Belirleyici (düzenli olarak güncellenen) bir ilerleme çubuğu da gösterilir.
Örnek, kısmen, bir Yapılandırma Değişikliği Sırasında Nesneyi Saklamak için resmi belgelere dayanmaktadır .
Bu örnekte, arka plan iş parçacığı gerektiren iş, yalnızca bir görüntünün internetten kullanıcı arayüzüne yüklenmesidir.
Alex Lockwood, AsyncTasks ile çalışma zamanı yapılandırma değişikliklerini işlemeye gelince "Tutulan Parça" kullanarak en iyi yöntem olduğu doğru görünüyor. onRetainNonConfigurationInstance()
Android Studio'da Lint'te kullanımdan kaldırıldı. Resmi dokümanlar , Yapılandırma Değişikliğini Kendinizi Kullanarak android:configChanges
, bizi uyarıyor ...
Yapılandırma değişikliğini kendiniz halletmek, alternatif kaynakların kullanımını çok daha zor hale getirebilir, çünkü sistem bunları sizin için otomatik olarak uygulamaz. Bu teknik, bir yapılandırma değişikliği nedeniyle yeniden başlatmalardan kaçınmanız gerektiğinde son çare olarak düşünülmelidir ve çoğu uygulama için önerilmez.
Sonra bir arka plan iş parçacığı için hiç bir AsyncTask kullanmak gerekip gerekmediği sorunu var.
AsyncTask için resmi başvuru uyarıyor ...
AsyncTasks ideal olarak kısa işlemler için kullanılmalıdır (en fazla birkaç saniye). İplikleri uzun süre çalışmaya devam etmeniz gerekiyorsa, java.util.concurrent pacakge tarafından sağlanan çeşitli API'ları kullanmanız önemle tavsiye edilir. Yürütücü, ThreadPoolExecutor ve FutureTask.
Alternatif olarak, bir hizmet, yükleyici (bir CursorLoader veya AsyncTaskLoader kullanarak) veya senkronize olmayan işlemleri gerçekleştirmek için içerik sağlayıcısı kullanılabilir.
Gönderinin geri kalanını:
- Prosedür; ve
- Yukarıdaki prosedür için tüm kod.
Prosedür
Bir etkinliğin iç sınıfı olarak temel bir AsyncTask ile başlayın (bir iç sınıf olması gerekmez, ancak muhtemelen uygun olacaktır). Bu aşamada AsyncTask çalışma zamanı yapılandırma değişikliklerini işlemez.
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");
}
}
Fragement sınıfını genişleten ve kendi kullanıcı arayüzüne sahip olmayan bir iç içe sınıf RetainedFragment ekleyin. Bu Parçanın onCreate olayına setRetainInstance (true) öğesini ekleyin. Verilerinizi ayarlamak ve almak için prosedürler sağlayı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> {
....
En dıştaki Activity sınıfının onCreate () yöntemi RetainedFragment öğesini işler: Zaten varsa (Activity yeniden başlatılırsa); yoksa oluşturun ve ekleyin; Ardından, zaten varsa, RetainedFragment'tan veri alın ve kullanıcı arayüzünüzü bu verilerle ayarlayın.
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());
}
}
Kullanıcı arayüzünden AsyncTask'ı başlatın
public void getPicture(View view) {
new LoadImageFromNetworkAsyncTask().execute(
"http://i.imgur.com/SikTbWe.jpg");
}
Belirli bir ilerleme çubuğu ekleyin ve kodlayın:
- Kullanıcı arayüzü düzenine bir ilerleme çubuğu ekleyin;
- Etkinlik oncreate ();
- Sürecin başında ve sonunda görünür ve görünmez hale getirin;
- OnProgressUpdate'de kullanıcı arayüzüne rapor verme ilerlemesini tanımlayın.
- AsyncTask 2nd Generic parametresini Void'den ilerleme güncelleştirmelerini işleyebilecek bir türe değiştirin (örn. Tamsayı).
- doInBackground () içindeki düzenli noktalarda publishProgress.
Yukarıdaki prosedürün tüm kodu
Etkinlik Düzeni.
<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>
Etkinlik: alt sınıf AsyncTask iç sınıfı; çalışma zamanı yapılandırma değişikliklerini işleyen alt sınıf RetainedFragment iç sınıfı (ör. kullanıcı ekranı döndürdüğünde); ve düzenli aralıklarla belirli bir ilerleme çubuğu güncellemesi. ...
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);
}
}
Bu örnekte, gerçek işi yapan kütüphane işlevi (yukarıda açık paket com.example.standardapplibrary.android.Network paket öneki ile başvurulmaktadır) ...
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;
}
Arka plan görevinizin gerektirdiği izinleri AndroidManifest.xml dosyasına ekleyin ...
<manifest>
...
<uses-permission android:name="android.permission.INTERNET" />
Etkinliğinizi AndroidManifest.xml dosyasına ekleyin ...
<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>