를 사용하여 Fragment
(사용자가 화면을 회전 할 때와 같이) 런타임 구성 변경을 처리 하는 AsyncTask의 또 다른 예는 다음과 같습니다 setRetainInstance(true)
. 결정 (정기적으로 업데이트 된) 진행률 표시 줄도 보여줍니다.
이 예는 부분적으로 공식 문서, 구성 변경 중 객체 유지 에 기반합니다 .
이 예제에서 백그라운드 스레드가 필요한 작업은 인터넷에서 UI로 이미지를로드하는 것입니다.
Alex Lockwood는 "Retained Fragment"를 사용하여 AsyncTasks로 런타임 구성 변경을 처리하는 것이 가장 좋습니다. onRetainNonConfigurationInstance()
Lint, Android Studio에서 더 이상 사용되지 않습니다. 공식 문서를 사용하여 우리를 경고 android:configChanges
에서 구성 변경 자신을 취급 , ...
구성 변경을 직접 처리하면 시스템이 자동으로 대체 리소스를 적용하지 않기 때문에 대체 리소스를 사용하기가 훨씬 어려워 질 수 있습니다. 이 기술은 구성 변경으로 인한 재시작을 피해야 할 경우 최후의 수단으로 고려해야하며 대부분의 응용 프로그램에는 권장되지 않습니다.
그런 다음 백그라운드 스레드에 AsyncTask를 사용해야하는지 여부에 대한 문제가 있습니다.
AsyncTask 의 공식 참조는 경고합니다 ...
AsyncTasks는 짧은 작업 (최대 몇 초)에 이상적으로 사용되어야합니다. 스레드를 장기간 계속 실행해야하는 경우 java.util.concurrent pacakge에서 제공하는 다양한 API를 사용하는 것이 좋습니다. Executor, ThreadPoolExecutor 및 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");
}
}
Fragement 클래스를 확장하고 자체 UI가없는 중첩 클래스 RetainedFragment를 추가하십시오. 이 Fragment의 onCreate 이벤트에 setRetainInstance (true)를 추가하십시오. 데이터를 설정하고 얻는 절차를 제공하십시오.
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> {
....
가장 바깥 쪽 Activity 클래스의 onCreate ()에서 RetainedFragment를 처리하십시오. 이미 존재하는 경우 참조하십시오 (활동이 다시 시작되는 경우). 존재하지 않는 경우 작성하여 추가하십시오. 그런 다음 이미 존재하는 경우 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 레이아웃에 진행률 표시 줄을 추가하십시오.
- Activity oncreate ()에서 참조를 얻으십시오.
- 프로세스의 시작과 끝에서 볼 수 있고 보이지 않게하십시오.
- onProgressUpdate에서 UI에보고 할 진행률을 정의하십시오.
- AsyncTask 2nd Generic 매개 변수를 Void에서 진행 업데이트를 처리 할 수있는 유형 (예 : 정수)으로 변경하십시오.
- 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 내부 클래스; 런타임 구성 변경을 처리하는 서브 클래 싱 된 RetainedFragment 내부 클래스 (예 : 사용자가 화면을 회전 할 때); 일정한 간격으로 업데이트되는 확정 진행 막대. ...
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>