草庐IT

android - Activity 生命周期的奇怪行为 - 在 onResume() 之后也调用了 onPause() ...为什么?

coder 2023-12-06 原文

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

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

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

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

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

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

最佳答案

调用 recreate() 时出现同样的问题,当 Activity 已更新时,它会在 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();
            }
        });
    }
}

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

编辑

避免此问题的最佳解决方案是在 postDelayed 中使用 0 delayMillis 调用重新创建

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

关于android - Activity 生命周期的奇怪行为 - 在 onResume() 之后也调用了 onPause() ...为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16507823/

有关android - Activity 生命周期的奇怪行为 - 在 onResume() 之后也调用了 onPause() ...为什么?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  7. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  8. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  9. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  10. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

随机推荐