7

我有一个带有edittexts的表单和一个按钮来调用相机(返回一个放入imageview的位图)......从纵向模式我输入所有edittext文件,然后单击将我转发到的相机按钮相机 - 在相机中,我在返回到活动 1 后拍照(保持纵向 - 并且所有编辑文本字段都恢复onRestoreInstanceState()) - 活动 1 的最后一个回调方法是onResume()(没关系) - 但问题当我从纵向模式更改为横向模式时出现 - 回调方法如下

dsfa

所以最后一个回调方向变化是onPause(). 我不懂为什么?问题是 onSaveInstanceState 在 onPause 之前被调用 - 所以当我回到纵向模式时,一切都将是空的(edittexts,imageview ..) - 这种奇怪的行为在每次方向更改时都会继续(最后调用 onPause() )。

我确信这个问题与拍摄图像(startInentforResult ....)有关,因为一切(编辑文本字段)在拍摄图像之前在方向改变上都可以正常工作......有时我也可以拍摄图像并且它有效很好,但在大多数情况下不是...

所以我的问题是,是什么“驱动”我的 Activity 到onPause()方法而不是onResume()

谢谢,如果有人知道解决方案,我将不胜感激,因为我已经为此苦苦挣扎了几天并且找不到解决方案。

该项目有很多类,但这是活动代码(需要注意的是,只有当我从相机应用程序拍摄图像时才会出现问题,之后活动生命周期变得疯狂 - 这个活动也是从主活动中调用的,带有'startIntentforResult ()'。我不使用 'android:configChanges="orientation|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.");
        }
    }
}
4

2 回答 2

0

在调用 recreate() 时出现同样的问题,当活动更新后,它会在 onResume 之后获得 onPause。在模拟器上测试,错误存在于 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();
            }
        });
    }
}

我不知道这是否正确,但它有效。

编辑

避免此问题的最佳解决方案,使用 0 delayMillis 在 postDelayed 中调用 recreate

new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        recreate();
    }
}, 0);
于 2018-03-13T00:05:24.197 回答
0

这很正常,奇怪的代码会产生奇怪的行为......

替换这一行:

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

用这条线:

super.onSaveInstanceState(outState);
于 2019-04-09T00:29:32.973 回答