Странное поведение жизненного цикла активности - почему после onResume() также вызывается onPause()?

У меня есть форма с текстами редактирования и кнопка для вызова камеры с намерением (вернуть растровое изображение, которое помещается в изображение)... В портретном режиме я ввожу весь текст редактирования, а затем нажимаю кнопку камеры, которая перенаправляет меня к камера - в камере я делаю снимок, после чего я возвращаюсь к действию 1 (оставаясь в портретной ориентации - и все поля редактирования восстанавливаются в onRestoreInstanceState()) - и последний метод обратного вызова действия 1 - onResume() (что нормально) - Но проблема возникает, когда я меняю ориентацию с этого портретного на альбомный режим - методы обратного вызова следующие

dsfa

Таким образом, последнее изменение ориентации обратного вызова — onPause(). Я не понимаю почему? Проблема в том, что onSaveInstanceState вызывается до onPause - поэтому, когда я вернусь в портретный режим, все будет пустым (редактирование, просмотр изображений...) - это странное поведение продолжается при каждом изменении ориентации (onPause() вызывается последним).

Я уверен, что эта проблема связана с получением изображения (startInentforResult....), потому что все (поля редактирования текста) отлично работает при изменении ориентации перед съемкой изображения... иногда я также могу сделать изображение, и оно работает хорошо, но в большинстве случаев нет...

Итак, мой вопрос в том, что «подталкивает» мою активность к методу onPause(), а не к onResume()?

Спасибо, я был бы очень признателен, если бы кто-нибудь знал решение, потому что я уже несколько дней борюсь с этим и не могу найти решение.

В проекте много классов, но это код действия (важно отметить, что проблема возникает только тогда, когда я беру изображение из приложения камеры, после чего жизненный цикл действия сходит с ума - также это действие вызывается из основного действия с помощью 'startIntentforResult ()'. Я не использую 'android:configChanges="ориентация|keyboardHidden"', чтобы остановить воссоздание):

public class NewCounterActivity extends Activity {

Button btnCreate;
Button btnCancel;
Button btnTakeImg;
ImageView counterImgView;
CheckBox existsDamage;

EditText inputNameFirst;
EditText inputNameLast;
EditText inputAdresse;
EditText inputCounterID;
EditText inputCounterValue;
EditText inputDescription;
TextView registerErrorMsg;

DatabaseHandler db;

//Data to be submitted
String nameFirst;
String nameLast;
String adresse;
String counterID;
String counterValue;
String countDescript;
String existsDmg;
Bitmap counterBitmap;
Bitmap recievedBitmap;

String longitude;
String latitude;

LocationTracker gps;

// JSON Response node names
private static String KEY_SUCCESS = "success";
private static String KEY_ERROR = "error";
private static String KEY_ERROR_MSG = "error_msg";

//The dimensions of the ImageView
int targetW;
int targetH;



// Some lifecycle callbacks so that the image can survive orientation change
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

    Log.e("onSaveInstanceState", "fadsfass");

    outState.putParcelable("bitmap", counterBitmap);
    outState.putString("fname", inputNameFirst.getText().toString());
    outState.putString("lname", inputNameLast.getText().toString());
    outState.putString("adrese", inputAdresse.getText().toString());
    outState.putString("cID", inputCounterID.getText().toString());
    outState.putString("cValue", inputCounterValue.getText().toString());
    outState.putString("Descript", inputDescription.getText().toString());
    outState.putString("ErrorMsg", registerErrorMsg.getText().toString());

    outState.putBoolean("damageCheck", existsDamage.isChecked());

    ((MyApplicationClass) getApplication()).detach(this);


}

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

    Log.e("onRestoreInstanceState", "fadsfass");

    counterBitmap = savedInstanceState.getParcelable("bitmap");
    counterImgView.setImageBitmap(counterBitmap);

    inputNameFirst.setText(savedInstanceState.getString("fname"));
    inputNameLast.setText(savedInstanceState.getString("lname"));
    inputAdresse.setText(savedInstanceState.getString("adrese"));
    inputCounterID.setText(savedInstanceState.getString("cID"));
    inputCounterValue.setText(savedInstanceState.getString("cValue"));
    inputDescription.setText(savedInstanceState.getString("Descript"));

    registerErrorMsg.setText(savedInstanceState.getString("ErrorMsg"));

    existsDamage.setChecked(savedInstanceState.getBoolean("damageCheck"));
    ((MyApplicationClass) getApplication()).attach(this);
}



@Override
public void onContentChanged() {
    // TODO Auto-generated method stub
    super.onContentChanged();

    Log.e("onContetnChanged", "fadsfass");
}

@Override
protected void onDestroy() {
    // TODO Auto-generated method stub
    super.onDestroy();
    Log.e("onDestroy", "fadsfass");
}

@Override
public void onDetachedFromWindow() {
    // TODO Auto-generated method stub
    super.onDetachedFromWindow();
    Log.e("onDetachedFromWindow", "fadsfass");
}

@Override
protected void onPause() {
    // TODO Auto-generated method stub
    super.onPause();
    Log.e("onPause", "fadsfass");
}

@Override
protected void onRestart() {
    // TODO Auto-generated method stub
    super.onRestart();
    Log.e("onRestart", "fadsfass");
}

@Override
protected void onResume() {
    // TODO Auto-generated method stub
    super.onResume();
    Log.e("onResume", "fadsfass");
}

@Override
protected void onStart() {
    // TODO Auto-generated method stub
    super.onStart();
    Log.e("onStart", "fadsfass");
}

@Override
protected void onStop() {
    // TODO Auto-generated method stub
    super.onStop();
    Log.e("onStop", "fadsfass");
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.newcounteractivity_layout);
    Log.e("onCreate", "mActivity equals NULL");


    inputNameFirst = (EditText) findViewById(R.id.createFirstName);
    inputNameLast = (EditText) findViewById(R.id.createLastName);
    inputAdresse = (EditText) findViewById(R.id.createAdresse);
    inputCounterID = (EditText) findViewById(R.id.createCounterID);
    inputCounterValue = (EditText) findViewById(R.id.createCounterValue);
    inputDescription = (EditText) findViewById(R.id.createDescription);

    registerErrorMsg = (TextView) findViewById(R.id.create_error);

    btnCreate = (Button) findViewById(R.id.btnCreate);
    btnCancel = (Button) findViewById(R.id.btnCancel);
    btnTakeImg = (Button) findViewById(R.id.btnImage);

    counterImgView = (ImageView) findViewById(R.id.counterImgView);

    existsDamage = (CheckBox) findViewById(R.id.createDamageExists);



    //REGISTER BUTTON CLICK EVENTS

    btnCreate.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            //new DoBackgroundTask(NewCounterActivity.this).execute();

            //CounterUser data to submit
             nameFirst = inputNameFirst.getText().toString().trim();
             nameLast = inputNameLast.getText().toString().trim();
             adresse = inputAdresse.getText().toString().trim();
             counterID = inputCounterID.getText().toString().trim();
             counterValue = inputCounterValue.getText().toString().trim();
             countDescript = inputDescription.getText().toString().trim();

             existsDmg = Integer.toString((existsDamage.isChecked()) ? 1 : 0); 

             // create LocationTracker class object
             gps = new LocationTracker(NewCounterActivity.this);

             if(!gps.canGetLocation()){
                 gps.stopUsingGPS();
                 gps.showSettingsAlert();
                 //Ovo se mozda treba i izbaciti
                 gps.getLocation();
             }
             else{
                 processInput();
             }





        }
    }); 


    btnCancel.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            Intent returnIntent = new Intent();
            setResult(RESULT_CANCELED, returnIntent);        
            finish();

        }
    });

    btnTakeImg.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {

            if(isIntentAvailable(NewCounterActivity.this, MediaStore.ACTION_IMAGE_CAPTURE)){
            Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(takePictureIntent,2);
            }

            else {
                Toast.makeText(NewCounterActivity.this, "No Camera Available", Toast.LENGTH_SHORT).show();
            }

        }
    });


}

/************************************************************************************************
 * Methods used in this class
 * */

public void processInput(){

    //Get current Longitude and Latitude
    longitude = Double.toString(gps.getLongitude());
    latitude = Double.toString(gps.getLatitude());

     //Na kraju iskljuci location updatese - ne moze na emulatru jer ja emit coordinate preko DDMS... a kad emit on mora biti ukljucen da bi primio
     //gps.stopUsingGPS();

    Toast.makeText(getApplicationContext(), "Your Location is - \nLat: " + longitude + "\nLong: " + latitude, Toast.LENGTH_LONG).show();

     if (!nameFirst.equals("") && !nameLast.equals("") && !adresse.equals("") && !counterID.equals("") && !counterValue.equals("") 
              && counterBitmap != null ){

         new DoBackgroundTask(NewCounterActivity.this).execute();

        }
     else{
        // Not all fields are filled
        registerErrorMsg.setText("Not all fields are filled");

     }
}


//Method to check whether an app can handle your intent
public boolean isIntentAvailable(Context context, String action) {
    final PackageManager packageManager = context.getPackageManager();
    final Intent intent = new Intent(action);
    List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
    return list.size() > 0;
}

/**************************************************************************************************
 * 
 * When the calling activity, Activity #1, resumes after having called another activity, Activity #2, using startActivityForResult, 
 * the method onActivityResult in Activity #1 is called BEFORE onResume.
 * This is important to know if you are instantiating your SQLite Database objects from within onResume in Activity #1. If so, you will also need to instantiate the object from within onActivityResult, 
 * when returning from Activity #2.
 * 
 * startActivityForResult() is asynchronous. It can feel synchronous to the user since the UI will change and your calling activity will be paused 
 * (your onPause() method will be called).
 */

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // TODO Auto-generated method stub
    super.onActivityResult(requestCode, resultCode, data);
     Log.e("onActivityResult", "fadsfass");

      if (requestCode == 2) {
             if(resultCode == RESULT_OK){   
                 Bundle extras = data.getExtras();
                 recievedBitmap = (Bitmap) extras.get("data");       
             }
             if (resultCode == RESULT_CANCELED) {    
                 Toast.makeText(NewCounterActivity.this, "No Image Taken", Toast.LENGTH_SHORT).show();
             }
          }
}

/**
 * Koristim onWindowFocusChanged jer kad se vratim na Activity 1 onda dodje do potpunog recreate Activitija i getWidth()/height() ne mogu dobiti 
 * ni u jednom od lifecicle methoda - naime ide start onCreate,...onActivityResult(), onResume() - u onactivityResult izvadim bitmap i pohranim ga u receivedBitmap
 * te kad getWidth() postane dostupan system invoke ovu dole methodu. :D
 */
@Override
public void onWindowFocusChanged(boolean hasFocus){
    if(recievedBitmap != null){
    targetW=counterImgView.getWidth();
    targetH=counterImgView.getHeight();
    Log.e("onWindowFocusChanged", "fadsfass" + " " + targetW + " " + targetH);

    // http://stackoverflow.com/questions/4837715/how-to-resize-a-bitmap-in-android
    // http://sunil-android.blogspot.com/2013/03/resize-bitmap-bitmapcreatescaledbitmap.html
    // Scale or resize Bitmap to ImageView dimensions
    counterBitmap = Bitmap.createScaledBitmap(recievedBitmap, targetW, targetH, false);

    /**
     * Canvas: trying to use a recycled bitmap android.graphics - This exception occurs when you try to recycle a bitmap which is already recycled.
     * http://androdevvision.blogspot.com/2011/10/solution-for-out-of-memory-error-and.html
     */
    if(recievedBitmap != null && !recievedBitmap.isRecycled()){
        recievedBitmap.recycle();
        recievedBitmap = null;
    }
    counterImgView.setImageBitmap(counterBitmap);
    }
}

/************************************************************************************************
 * Background AsyncTask to create new counterUser  -  https://github.com/callorico/CustomAsyncTask - najbolje radi 
 * new DoBackgroundTask(NewCounterActivity.this).execute();
 * */



private static class DoBackgroundTask extends CustomAsyncTask<Void, Integer, JSONObject> {

    private static final String TAG = "DoBackgroundTask";

    private ProgressDialog mProgress;
    private int mCurrProgress;

    private NewCounterActivity myActivity = null;

    public DoBackgroundTask(NewCounterActivity activity) {
        super(activity);
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        showProgressDialog();
    }

    @Override
    protected void onActivityDetached() {
        if (mProgress != null) {
            mProgress.dismiss();
            mProgress = null;
        }
    }

    @Override
    protected void onActivityAttached() {
        showProgressDialog();
    }

    private void showProgressDialog() {
        mProgress = new ProgressDialog(mActivity);
        mProgress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
        mProgress.setIndeterminate(true);
        mProgress.setMessage(" Saljem na server...      ");


        mProgress.setCancelable(true);
        mProgress.setOnCancelListener(new OnCancelListener() {
            @Override
            public void onCancel(DialogInterface dialog) {
                cancel(true);
            }
        });


        mProgress.show();
        mProgress.setProgress(mCurrProgress);
    }

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

        //so you need to either pass an instance of the outer class to the inner class method (or its constructor) as a parameter,
        //or create it inside the method.
        JSONObject json = null;

             if(mActivity != null){
             myActivity = (NewCounterActivity) mActivity;

                    //Prepare counterBitmap as String 
                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
                    //Write a compressed version of the bitmap to the specified output stream.
                    myActivity.counterBitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream);
                    byte [] b_array = stream.toByteArray();
                    String bitmapString = Base64.encodeBytes(b_array);

                    //Get workerId from logged worker 
                    Functions workerFunction = new Functions();
                    DatabaseHandler db = new DatabaseHandler(mActivity);
                    String workerID = db.retrieveWorker().get("workerId");

                    if(myActivity != null){
                    //Get JsonObject from Functions.java
                    json = workerFunction.newCounterUser(myActivity.counterID, myActivity.counterValue, myActivity.adresse, myActivity.nameFirst, myActivity.nameLast, bitmapString, myActivity.existsDmg, myActivity.countDescript, workerID, myActivity.longitude, myActivity.latitude);
             }
             }
             return json;
    }

    @Override
    protected void onPostExecute(JSONObject jsonObject) {
        super.onPostExecute(jsonObject);

        if (mActivity != null) {
            mProgress.dismiss();

            try {
                if (jsonObject.getString(KEY_SUCCESS) != null) {
                    myActivity.registerErrorMsg.setText("");
                    String res = jsonObject.getString(KEY_SUCCESS);
                    if(Integer.parseInt(res) == 1){

                        // counterUser successfully registered
                        Toast.makeText(mActivity, "New counterUser is created", Toast.LENGTH_LONG).show();          

                        // Return back to MainActivity
                        Intent returnIntent = new Intent();
                        returnIntent.putExtra("result",jsonObject.toString());
                        mActivity.setResult(RESULT_OK,returnIntent);
                        // Close all views before launching MainActivity
                        returnIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);     
                        mActivity.finish();

                    }else{

                        // Error in registration
                        myActivity.registerErrorMsg.setText("Error occured in registration");
                    }
                }
            } catch (JSONException e) {
                Log.e("Error","NO Json at all");

                e.printStackTrace();
            }


        } else {
            Log.d(TAG, "AsyncTask finished while no Activity was attached.");
        }
    }
}

person ArloGrant    schedule 12.05.2013    source источник
comment
покажи нам свой код в onpause и onresume   -  person deadfish    schedule 12.05.2013
comment
там ничего нет - просто переопределил методы с помощью Log.e(...) для отладки этой проблемы. У меня есть только код в onCreate(), onSaveInstanceState/Restore, onActivityResult(), onWindowFocusChanged(). Использование Android 2.1 (API 7)   -  person ArloGrant    schedule 12.05.2013
comment
ах, лол, проблема в том, что не поддерживается изменение ориентации: D, пожалуйста, используйте этот stackoverflow.com/a/9339319/619673 также, пожалуйста прочитай оп задачу, ты последуешь за мной   -  person deadfish    schedule 13.05.2013
comment
@ 100kg Я не хочу использовать 'android:configChanges=orientation|keyboardHidden' в своей деятельности, потому что я хочу воссоздать активность при изменении ориентации, и у меня также есть методы 'onSave/RestoreInstanceState()'   -  person ArloGrant    schedule 13.05.2013
comment
@StinePike Потому что это происходит только тогда, когда я беру изображение с камеры и нажимаю «ОК» в приложении камеры (когда я нажимаю «Отмена» в приложении камеры, оно просто возвращает меня к этому действию, и все работает нормально) — поэтому я подозреваю, что на «onActivityResult ()» или 'onWindowFocusChanged()' - что-то не так?   -  person ArloGrant    schedule 13.05.2013
comment
Если вы столкнулись с этой проблемой, попробуйте ее на реальном Android-устройстве... в моем примере это произошло в эмуляторе, но когда я протестировал его на Samsung Galaxy I9000 - (версия 2.3.6) - он работал без проблем... Я не могу понять, почему это произошло на моем эмуляторе :/   -  person ArloGrant    schedule 13.05.2013
comment
Любое решение? Я нашел эту проблему в устройстве.   -  person hemanth kumar    schedule 25.11.2014


Ответы (2)


Те же проблемы при вызове recreate(), когда активность была обновлена, она получает onPause после onResume. Протестировано на эмуляторе, ошибка существует на Marshallow и ниже.

Это мое решение

private static boolean isRecreate = false;

private void reCreateActivity() {
    isRecreate = true;
    recreate();
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

    if(isRecreate) {
        isRecreate = false;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                onResume();
            }
        });
    }
}

Я не знаю, правильно ли это, но это работает.

ИЗМЕНИТЬ

Лучшее решение, чтобы избежать этой проблемы, вызовите повторное создание в postDelayed с 0 delayMillis

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        recreate();
    }
}, 0);
person XJIOP    schedule 13.03.2018

Это нормально, что странный код приводит к странному поведению...

замените эту строку:

((MyApplicationClass) getApplication()).detach(this);

с этой строкой:

super.onSaveInstanceState(outState);
person Martin Zeitler    schedule 09.04.2019