7

I have a Form with edittexts and a button to call the camera with an intent (return a bitmap that is put into the imageview)...From the portrait mode i enter all edittext filed and then click the camera button which forwards me to the camera - in the camera i take a picture after what I get returned to Activity 1 (staying in portrait orientation - and all editext fields are restore in onRestoreInstanceState()) - and the last callback method of Activity 1 is onResume() (what is ok) - But the problem comes when I make an orientation change from this portrait to landscape mode - the callback methods are following

dsfa

So the last callback orientation change is onPause(). I do not understand why? The problem is that onSaveInstanceState is called prior of onPause - so when I turn back to portrait mode everything will be empty (editexts, imageview..) - this strange behavior continues on every orientation change (the onPause() is called last).

I am sure this problem has to do something with the taking an image (startInentforResult....) because everything (editext fields) works fine on orientation change prior to taking an image...sometimes I can also take an image and it works fine, but in most cases not...

So my question is what is it that "drives" my Activity up to the onPause() method instead up to the onResume()?

Thanks, I would really appreciate if somebody knows the solution because I am struggling with this already a few days and could not find the solution.

The project has many classes but this is the activity code (Important to note is that the problem arises only when I take an image from camera app, after that the activity lifecycle goes crazy - also this activity is called from the main activity with 'startIntentforResult()'. I do not use 'android:configChanges="orientation|keyboardHidden"' to stop the recreatioin ):

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.");
        }
    }
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
ArloGrant
  • 249
  • 5
  • 15
  • show us your code in onpause and onresume – deadfish May 12 '13 at 13:26
  • have nothing there - just overrided the methods with Log.e(...) to debug this issue ..I have only code in onCreate(), onSaveInstanceState/Restore, onActivityResult(),onWindowFocusChanged(). Using Android 2.1 (API 7) – ArloGrant May 12 '13 at 13:40
  • ah lol the problem is with not supporting change orientation :D please use this http://stackoverflow.com/a/9339319/619673 also please read the op problem, you will follow me – deadfish May 12 '13 at 21:17
  • @100kg I do not want to use 'android:configChanges="orientation|keyboardHidden"' in my activity because I want to recreate the activity on orientation change and I have also 'onSave/RestoreInstanceState()' methods – ArloGrant May 13 '13 at 11:23
  • @StinePike Because this hapens only when I take an image from camera and click OK on camera app (when I click cancel on camera app it just returns me to this activity and everything works fine) - so I suspect on 'onActivityResult()' or 'onWindowFocusChanged()' - is there anything wrong? – ArloGrant May 13 '13 at 11:26
  • If you encounter this problem try it on a real android device....in my example this happened in an emulator but when I tested it on a samsung galaxy I9000 - (2.3.6 version) - it worked without problems...I cannot understand why this happened on my emulator :/ – ArloGrant May 13 '13 at 16:29
  • Any Solution? i found this issue in device. – hemanth kumar Nov 25 '14 at 09:00

2 Answers2

0

Same issues on call to recreate(), when activity has been updated it get onPause after onResume. Tested on emulator, bug exists on Marshallow and below.

This is my fix

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();
            }
        });
    }
}

I don't know if that's correct, but it works.

EDIT

Best solution to avoid this issues, call recreate in postDelayed with 0 delayMillis

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        recreate();
    }
}, 0);
XJIOP
  • 89
  • 1
  • 5
  • Had same issue (I call recreate one time in `onResume` and after that I get something like onResume (with recreate();) -> onPause -> onCreate -> onResume ( without recreate) -> onPause. Still don't know why. Anyway your soution quite works, just I see that reload (during which my language is changed) so it works but looks not so good. – KyluAce Aug 26 '21 at 13:03
0

It is only normal, that strange code produces strange behavior ...

replace this line:

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

with this line:

super.onSaveInstanceState(outState);
Martin Zeitler
  • 1
  • 19
  • 155
  • 216