code

백그라운드 작업, 진행 상황 대화, 방향 변경 - 100% 작동하는 솔루션이 있습니까?

starcafe 2023. 8. 26. 12:01
반응형

백그라운드 작업, 진행 상황 대화, 방향 변경 - 100% 작동하는 솔루션이 있습니까?

스레드로 는 인터넷에서 데이터를 사용합니다.)AsyncTask다운로드하는 동안 진행률 대화 상자를 표시합니다.방향이 변경되고 활동이 다시 시작된 다음 비동기 작업이 완료됩니다. 진행 대화 상자를 닫고 새 활동을 시작합니다.그러나 dismissDialog를 호출하면 예외가 발생할 수 있습니다(아마도 활동이 파괴되어 새 활동이 아직 시작되지 않았기 때문일 수 있습니다).

이러한 문제(사용자가 방향을 바꾸더라도 작동하는 백그라운드 스레드에서 UI 업데이트)를 처리하는 가장 좋은 방법은 무엇입니까?구글의 누군가가 "공식적인 해결책"을 제공했습니까?

1단계: 고객의 요구사항 충족AsyncTask a static내부(비정적 중첩) 클래스가 아닌 중첩 클래스 또는 완전히 별도의 클래스입니다.

2단계: 다음 단계를 수행합니다.AsyncTask을다잡을 Activity데이터 멤버를 통해, 생성자 및 설정자를 통해 설정됩니다.

할 때: 3단계를 합니다.AsyncTask합니다.Activity생성자에게.

: 3단계onRetainNonConfigurationInstance()돌려주다, 돌려주다, 돌려주다, 돌려주다, 돌려주다, 돌려주다,AsyncTask원래의 활동에서 분리한 후에.

: 입계onCreate(),한다면getLastNonConfigurationInstance()아닙니다null당신에게 던져주세요AsyncTask클래스를 지정하고 세터에게 전화하여 새 활동을 작업과 연결합니다.

6단계의 .doInBackground().

위의 조리법을 따르면 모든 것이 효과가 있을 것입니다.onProgressUpdate()그리고.onPostExecute() 사에일중다니단됩의 시작 됩니다.onRetainNonConfigurationInstance()그리고 그 후의 끝.onCreate().

여기 기술을 시연하는 샘플 프로젝트가 있습니다.

또 다른 접근 방식은 다음과 같은 것입니다.AsyncTask그리고 당신의 일을 다른 곳으로 옮깁니다.IntentService이 기능은 수행해야 할 작업이 길 수 있으며 사용자가 활동 측면에서 수행하는 작업(예: 대용량 파일 다운로드)에 관계없이 계속 수행해야 하는 경우에 특히 유용합니다.대로 방송하시면 .Intent진행 전면에 ), 또는 작업 인 작업에 응답하도록 .Notification작업이 완료되었는지 사용자에게 알립니다.여기 이 패턴에 대한 자세한 내용이 있는 블로그 게시물이 있습니다.

수락된 답변은 매우 도움이 되었지만 진행 상황 대화 상자가 없습니다.

독자 여러분께 다행스럽게도 진행 대화상자가 있는 매우 포괄적이고 작동하는 비동기 작업의 예제를 만들었습니다!

  1. 회전이 작동하고 대화 상자가 유지됩니다.
  2. 이 동작을 수행하려면 뒤로 버튼을 눌러 작업 및 대화 상자를 취소할 수 있습니다.
  3. 조각을 사용합니다.
  4. 장치가 회전할 때 활동 아래에 있는 조각의 레이아웃이 올바르게 변경됩니다.

매니페스트 파일을 편집하지 않고 이 딜레마에 대한 해결책을 찾기 위해 일주일 동안 고심했습니다.이 솔루션에 대한 가정은 다음과 같습니다.

  1. 진행률 대화 상자를 항상 사용해야 합니다.
  2. 한 번에 하나의 작업만 수행됩니다.
  3. 전화기가 회전하고 진행 대화 상자가 자동으로 해제될 때 작업을 계속해야 합니다.

실행

이 게시물 하단에 있는 두 개의 파일을 작업영역에 복사해야 합니다.다음 사항을 확인하십시오.

  1. 너의 모든 것Activity는 s를 확장해야 .BaseActivity

  2. onCreate(),super.onCreate()의 용가액 하야는구초성후로 .ASyncTask 한또, 의재를 합니다.getContentViewId()양식 레이아웃 ID를 제공합니다.

  3. 재정의onCreateDialog() 활동에 의해 관리되는 대화상자를 만드는 과 같습니다.

  4. 비동기 작업을 만드는 샘플 정적 내부 클래스는 아래 코드를 참조하십시오.결과를 mResult에 저장하여 나중에 액세스할 수 있습니다.


final static class MyTask extends SuperAsyncTask<Void, Void, Void> {

    public OpenDatabaseTask(BaseActivity activity) {
        super(activity, MY_DIALOG_ID); // change your dialog ID here...
                                       // and your dialog will be managed automatically!
    }

    @Override
    protected Void doInBackground(Void... params) {

        // your task code

        return null;
    }

    @Override
    public boolean onAfterExecute() {
        // your after execute code
    }
}

마지막으로, 새로운 작업을 시작합니다.

mCurrentTask = new MyTask(this);
((MyTask) mCurrentTask).execute();

바로 그거야!저는 이 강력한 솔루션이 누군가에게 도움이 되기를 바랍니다.

BaseActivity.java(직접 가져오기 구성)

protected abstract int getContentViewId();

public abstract class BaseActivity extends Activity {
    protected SuperAsyncTask<?, ?, ?> mCurrentTask;
    public HashMap<Integer, Boolean> mDialogMap = new HashMap<Integer, Boolean>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(getContentViewId());

        mCurrentTask = (SuperAsyncTask<?, ?, ?>) getLastNonConfigurationInstance();
        if (mCurrentTask != null) {
            mCurrentTask.attach(this);
            if (mDialogMap.get((Integer) mCurrentTask.dialogId) != null
                && mDialogMap.get((Integer) mCurrentTask.dialogId)) {
        mCurrentTask.postExecution();
            }
        }
    }

    @Override
    protected void onPrepareDialog(int id, Dialog dialog) {
    super.onPrepareDialog(id, dialog);

        mDialogMap.put(id, true);
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        if (mCurrentTask != null) {
            mCurrentTask.detach();

            if (mDialogMap.get((Integer) mCurrentTask.dialogId) != null
                && mDialogMap.get((Integer) mCurrentTask.dialogId)) {
                return mCurrentTask;
            }
        }

        return super.onRetainNonConfigurationInstance();
    }

    public void cleanupTask() {
        if (mCurrentTask != null) {
            mCurrentTask = null;
            System.gc();
        }
    }
}

SuperAsyncTask.java

public abstract class SuperAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
    protected BaseActivity mActivity = null;
    protected Result mResult;
    public int dialogId = -1;

    protected abstract void onAfterExecute();

    public SuperAsyncTask(BaseActivity activity, int dialogId) {
        super();
        this.dialogId = dialogId;
        attach(activity);
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        mActivity.showDialog(dialogId); // go polymorphism!
    }    

    protected void onPostExecute(Result result) {
        super.onPostExecute(result);
        mResult = result;

        if (mActivity != null &&
                mActivity.mDialogMap.get((Integer) dialogId) != null
                && mActivity.mDialogMap.get((Integer) dialogId)) {
            postExecution();
        }
    };

    public void attach(BaseActivity activity) {
        this.mActivity = activity;
    }

    public void detach() {
        this.mActivity = null;
    }

    public synchronized boolean postExecution() {
        Boolean dialogExists = mActivity.mDialogMap.get((Integer) dialogId);
        if (dialogExists != null || dialogExists) {
            onAfterExecute();
            cleanUp();
    }

    public boolean cleanUp() {
        mActivity.removeDialog(dialogId);
        mActivity.mDialogMap.remove((Integer) dialogId);
        mActivity.cleanupTask();
        detach();
        return true;
    }
}

구글의 누군가가 "공식적인 해결책"을 제공했습니까?

네.

솔루션은 단순한 코드라기보다는 애플리케이션 아키텍처 제안에 가깝습니다.

그들은 애플리케이션 상태에 관계없이 애플리케이션이 서버와 동기화되어 작동할 수 있는 3가지 디자인 패턴을 제안했습니다(사용자가 애플리케이션을 완료하고, 화면을 변경하고, 앱이 종료되고, 백그라운드 데이터 작업이 중단될 수 있는 다른 모든 가능한 상태에서도 작동합니다. 이를 포함합니다.)

이 제안은 Virgil Dobjanschi의 Google I/O 2010 중 Android REST 클라이언트 애플리케이션 연설에서 설명합니다.그것은 1시간이지만, 매우 볼만한 가치가 있습니다.

의 기초는 을 추상화하는 것입니다.Service어느 누구와도 독립적으로 작동합니다.Activity에는 데이터베이스,ContentResolver그리고.Cursor에서는 가져온 원격 데이터로 로컬 데이터베이스를 업데이트한 후 추가 논리 없이 UI를 업데이트하는 데 편리한 즉시 사용 가능한 관찰자 패턴을 제공합니다.다른 모든 애프터 오퍼레이션 코드는 콜백을 통해 실행됩니다.Service(사용합니다.ResultReceiver하위 클래스).

어쨌든, 제 설명은 사실 꽤 모호해요, 당신은 연설을 꼭 봐야 해요.

Mark(CommonWare)의 답변은 방향 변경에 실제로 효과가 있지만, 전화 통화의 경우처럼 활동이 직접 삭제되면 실패합니다.

응용프로그램 개체를 사용하여 동기화 작업을 참조하여 방향 변경 및 드물게 파괴된 활동 이벤트를 처리할 수 있습니다.

문제와 해결책에 대한 훌륭한 설명이 여기에 있습니다.

이것을 알아낸 라이언에게 전적으로 공로가 있습니다.

4년 후 Google은 Activity on Create에서 setRetainInstance(true)를 호출하여 문제를 해결했습니다.장치를 회전하는 동안 활동 인스턴스가 보존됩니다.저는 또한 구형 안드로이드를 위한 간단한 솔루션을 가지고 있습니다.

활동 처리기를 사용하여 모든 활동 수행을 호출해야 합니다.따라서 스레드에 있는 경우 활동의 처리기를 사용하여 실행 및 게시할 수 있는 실행을 만들어야 합니다.그렇지 않으면 치명적인 예외가 발생하여 앱이 충돌할 수 있습니다.

이것이 제 해결책입니다: https://github.com/Gotchamoh/Android-AsyncTask-ProgressDialog

기본적으로 단계는 다음과 같습니다.

  1. 사용합니다onSaveInstanceState작업이 계속 처리 중인 경우 저장합니다.
  2. onCreate작업이 저장된 경우 작업을 받습니다.
  3. onPause저는 그것을 버립니다.ProgressDialog보여진다면요.
  4. onResume나는 보여줍니다.ProgressDialog작업이 아직 처리 중인 경우.

언급URL : https://stackoverflow.com/questions/3821423/background-task-progress-dialog-orientation-change-is-there-any-100-working

반응형