यहां एक AsyncTask का एक और उदाहरण है जो Fragment
रनटाइम कॉन्फ़िगरेशन परिवर्तन को संभालने के लिए उपयोग करता है (जैसे कि उपयोगकर्ता स्क्रीन को घुमाता है) setRetainInstance(true)
। एक निर्धारित (नियमित रूप से अद्यतन) प्रगति बार भी प्रदर्शित किया जाता है।
उदाहरण आंशिक रूप से आधिकारिक डॉक्स पर आधारित होता है, जो किसी कॉन्फ़िगरेशन चेंज के दौरान ऑब्जेक्ट को रिटेन करता है ।
इस उदाहरण में पृष्ठभूमि थ्रेड की आवश्यकता वाले कार्य को यूआई में इंटरनेट से एक छवि को लोड करना है।
एलेक्स लॉकवुड को यह सही प्रतीत होता है कि जब "रिटेंस्ड फ्रैगमेंट" का उपयोग करके AsyncTasks के साथ रनटाइम कॉन्फ़िगरेशन परिवर्तन को संभालने की बात आती है तो यह सबसे अच्छा अभ्यास है। onRetainNonConfigurationInstance()
Android स्टूडियो में लिंट में पदावनत हो जाता है। आधिकारिक डॉक्स हमें का उपयोग कर बंद चेतावनी दी है android:configChanges
, से विन्यास बदलें अपने आप हैंडलिंग , ...
कॉन्फ़िगरेशन परिवर्तन को स्वयं संभालना वैकल्पिक संसाधनों का उपयोग करना अधिक कठिन बना सकता है, क्योंकि सिस्टम स्वचालित रूप से आपके लिए उन्हें लागू नहीं करता है। इस तकनीक को अंतिम उपाय माना जाना चाहिए जब आपको कॉन्फ़िगरेशन परिवर्तन के कारण पुनरारंभ से बचना चाहिए और अधिकांश अनुप्रयोगों के लिए अनुशंसित नहीं है।
फिर यह मुद्दा है कि क्या किसी को बैकग्राउंड थ्रेड के लिए एक AsyncTask का उपयोग करना चाहिए।
AsyncTask के लिए सरकारी संदर्भ चेतावनी दी है ...
AsyncTasks को लघु संचालन के लिए उपयोग किया जाना चाहिए (कुछ सेकंड सबसे अधिक।) यदि आपको लंबे समय तक चलने वाले थ्रेड रखने की आवश्यकता है, तो यह अत्यधिक अनुशंसा की जाती है कि आप java.util.concurrentacacge द्वारा प्रदान किए गए विभिन्न API का उपयोग करें जैसे कि निष्पादक, थ्रेडपूल एक्ज़ीक्यूटर और FutureTask।
वैकल्पिक रूप से एक सेवा, लोडर (एक CursorLoader या AsyncTaskLoader का उपयोग करके), या अतुल्यकालिक संचालन करने के लिए सामग्री प्रदाता का उपयोग कर सकता है।
मैं पोस्ट के बाकी हिस्सों को तोड़ता हूं:
- प्रक्रिया; तथा
- उपरोक्त प्रक्रिया के लिए सभी कोड।
प्रक्रिया
एक गतिविधि के एक आंतरिक वर्ग के रूप में एक मूल AsyncTask के साथ शुरू करें (यह एक आंतरिक वर्ग होने की आवश्यकता नहीं है लेकिन यह संभवतः होना सुविधाजनक होगा)। इस स्तर पर AsyncTask रनटाइम कॉन्फ़िगरेशन परिवर्तन को हैंडल नहीं करता है।
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");
}
}
एक नेस्टेड क्लास रिटेनफ्रेगमेंट जोड़ें, जो फ्रिंज क्लास को बढ़ाता है और इसमें अपना यूआई नहीं है। इस Fragment के onCreate इवेंट में setRetainInstance (सत्य) जोड़ें। अपना डेटा सेट करने और प्राप्त करने के लिए प्रक्रियाएँ प्रदान करें।
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> {
....
सबसे बाहरी गतिविधि वर्ग के ऑनक्रिएट () में रिटैडफैगमेंट को संभालें: यदि यह पहले से मौजूद है (गतिविधि के पुनः आरंभ होने पर) इसे देखें; यदि यह मौजूद नहीं है तो इसे बनाएं और जोड़ें; फिर, यदि यह पहले से मौजूद है, तो RetainedFragment से डेटा प्राप्त करें और उस डेटा के साथ अपना UI सेट करें।
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());
}
}
UI से AsyncTask आरंभ करें
public void getPicture(View view) {
new LoadImageFromNetworkAsyncTask().execute(
"http://i.imgur.com/SikTbWe.jpg");
}
एक निर्धारित प्रगति पट्टी जोड़ें और कोड करें:
- UI लेआउट में प्रगति पट्टी जोड़ें;
- गतिविधि oncreate () में इसका संदर्भ लें;
- प्रक्रिया के प्रारंभ और अंत में इसे दृश्यमान और अजेय बनाएं;
- OnProgressUpdate में UI की रिपोर्ट करने के लिए प्रगति को परिभाषित करें।
- Vync से AsyncTask 2nd Generic पैरामीटर को एक प्रकार में बदलें जो प्रगति अपडेट (जैसे पूर्णांक) को संभाल सकता है।
- doInBackground () में नियमित बिंदुओं पर publishProgress।
उपरोक्त प्रक्रिया के लिए सभी कोड
गतिविधि लेआउट।
<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>
के साथ गतिविधि: उपवर्गित AsyncTask भीतरी वर्ग; उप-वर्गित रिटैडग्रैगमेंट इनर क्लास जो कि रनटाइम कॉन्फ़िगरेशन परिवर्तन को संभालता है (जैसे जब उपयोगकर्ता स्क्रीन को घुमाता है); और नियमित अंतराल पर अद्यतन करने के लिए एक निर्धारित प्रगति पट्टी। ...
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);
}
}
इस उदाहरण में लाइब्रेरी फ़ंक्शन (स्पष्ट पैकेज उपसर्ग com.example.standardapplibrary.android.Network के साथ संदर्भित है) जो वास्तविक काम करता है ...
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;
}
AndroidManifest.xml के लिए आपके बैकग्राउंड टास्क के लिए किसी भी अनुमति को जोड़ना होगा ...
<manifest>
...
<uses-permission android:name="android.permission.INTERNET" />
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>