事例场景: 在公司开发的产品中 有开启相机的功能 开启系统相机后 把拍下的照片保存 并且预览 然后拿到这个照片地址 返回 发布前已经测试 这个模块没有问题 后来在一款三星的机型上面 测试出来启动相机 后 拍照点击保存 不会再出现 我自己实现的 预览的界面 后来分析 是个别机型 ROM 太少 把拍照调用系统相机后 系统相机在前台 后台进程在资源不足的情况下 被系统回收了 导致这个BUG的出现 先贴一下 我没有解决BUG之前的代码 和 布局文件 如下:
public class TakingPicturesActivity extends FragmentActivity implements View.OnClickListener { private static final int START_CAMERA = 0x1; private final static int REQUEST_CAMERA = 0x2; private static final String ACTION_CAMERA = "android.media.action.IMAGE_CAPTURE"; private Button mButtonCancel; private Button mButtonSend; private Uri mSavedPicUri; private FragmentManager fm; private FragmentTransaction ft; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case START_CAMERA:
//开启系统相机 startCamera(); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.rc_ac_camera); mButtonCancel = (Button) findViewById(R.id.rc_back); mButtonSend = (Button) findViewById(R.id.rc_send); Message msg = Message.obtain(); msg.what = START_CAMERA; mHandler.sendMessage(msg); mButtonCancel.setOnClickListener(this); mButtonSend.setOnClickListener(this); } @Override public void onClick(View v) { if (v.getId() == R.id.rc_send) { if (mSavedPicUri != null) { Intent data = new Intent(); data.setData(mSavedPicUri); setResult(RESULT_OK, data); } finish(); } else if (v.getId() == R.id.rc_back) { finish(); } }
//调用系统相机拍照并且保存 private void startCamera() { Intent intent = new Intent(ACTION_CAMERA); File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); String name = System.currentTimeMillis() + ".jpg"; File file = new File(path, name); mSavedPicUri = Uri.fromFile(file); RLog.d(this, "startCamera", "output pic uri =" + mSavedPicUri); intent.putExtra(MediaStore.EXTRA_OUTPUT, mSavedPicUri); startActivityForResult(intent, REQUEST_CAMERA); } @Override public void onActivityResult(int requestCode, int resultCode, final Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQUEST_CAMERA:
//用户对拍照完以后执行的操作 if (resultCode == RESULT_CANCELED) {//用户选择取消保存 finish(); Log.e("TakingPicturesActivity","RESULT_CANCELED"); } if (mSavedPicUri != null && resultCode == Activity.RESULT_OK) {//用户选择发送 new Handler().postDelayed(new Runnable() { @Override public void run() { showImage(mSavedPicUri); Log.e("TakingPicturesActivity","RESULT_OK"); } }, 10); } break; } } private final void showImage(Uri uri) { if (uri != null) {
//拿到uri 用桢布局展示 图片 fm = getSupportFragmentManager(); ft = fm.beginTransaction();
//这里的 fragment 就是用来展示 bitmap的 PictureFragment mPhotoFragment = new PictureFragment(this, uri); ft.replace(R.id.rc_frame, mPhotoFragment); ft.commit(); }else{ finish(); } } }
布局文件的代码:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@id/rc_frame" android:layout_width="match_parent" android:layout_height="0dip" android:layout_weight="1" android:background="#000" android:orientation="vertical" > </FrameLayout> <FrameLayout android:layout_width="match_parent" android:layout_height="48dp" android:layout_gravity="bottom" android:background="#c000"> <Button android:id="@id/rc_back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="8dp" android:background="@null" android:gravity="center" android:text="取消" android:textColor="#fff" android:textSize="14sp" /> <Button android:id="@id/rc_send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginLeft="50dp" android:background="@null" android:gravity="center" android:text="发送" android:textColor="#fff" android:textSize="14sp" android:layout_gravity="right|center_vertical" /> </FrameLayout> </LinearLayout>
问题的原因已经分析清楚 但是怎么解决这个问题呢 ? XXX主程帮忙分析 让我用onSaveInstanceState与onRestoreInstanceState来解决这个问题 这两个生命周期的方法比较冷门 虽然知道 但是根本没有正真的在实际应用过 我随即去网上看了几篇相关的博文 但是感觉将概念性的居多 看了半天还是没有特别明白 这边感谢Jenny姐 帮我对 onSaveInstanceState与onRestoreInstanceState的调试和分析 从中学到很多 下面说下具体解决步骤
@Override protected void onRestoreInstanceState(Bundle savedInstanceState) { mSavedPicUri = Uri.parse(savedInstanceState.getString("photo_uri")); super.onRestoreInstanceState(savedInstanceState); //还原 Log.e("TakingPicturesActivity","onRestoreInstanceState"); } @Override public void onSaveInstanceState(Bundle outState) { outState.putString("photo_uri",mSavedPicUri.toString()); super.onSaveInstanceState(outState); //保存 Log.e("TakingPicturesActivity","onSaveInstanceState"); }
if(savedInstanceState == null) { Message msg = Message.obtain(); msg.what = START_CAMERA; mHandler.sendMessage(msg); }
public class TakingPicturesActivity extends FragmentActivity implements View.OnClickListener { private static final int START_CAMERA = 0x1; private final static int REQUEST_CAMERA = 0x2; private static final String ACTION_CAMERA = "android.media.action.IMAGE_CAPTURE"; private Button mButtonCancel; private Button mButtonSend; private Uri mSavedPicUri; private FragmentManager fm; private FragmentTransaction ft; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case START_CAMERA: startCamera(); break; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.rc_ac_camera); mButtonCancel = (Button) findViewById(R.id.rc_back); mButtonSend = (Button) findViewById(R.id.rc_send); if(savedInstanceState == null) { Message msg = Message.obtain(); msg.what = START_CAMERA; mHandler.sendMessage(msg); } mButtonCancel.setOnClickListener(this); mButtonSend.setOnClickListener(this); } @Override public void onClick(View v) { if (v.getId() == R.id.rc_send) { if (mSavedPicUri != null) { Intent data = new Intent(); data.setData(mSavedPicUri); setResult(RESULT_OK, data); } finish(); } else if (v.getId() == R.id.rc_back) { finish(); } } private void startCamera() { Intent intent = new Intent(ACTION_CAMERA); File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES); String name = System.currentTimeMillis() + ".jpg"; File file = new File(path, name); mSavedPicUri = Uri.fromFile(file); RLog.d(this, "startCamera", "output pic uri =" + mSavedPicUri); intent.putExtra(MediaStore.EXTRA_OUTPUT, mSavedPicUri); startActivityForResult(intent, REQUEST_CAMERA); } @Override public void onActivityResult(int requestCode, int resultCode, final Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case REQUEST_CAMERA: if (resultCode == RESULT_CANCELED) { finish(); Log.e("TakingPicturesActivity","RESULT_CANCELED"); } if (mSavedPicUri != null && resultCode == Activity.RESULT_OK) { new Handler().postDelayed(new Runnable() { @Override public void run() { showImage(mSavedPicUri); Log.e("TakingPicturesActivity","RESULT_OK"); } }, 10); } break; } } private final void showImage(Uri uri) { if (uri != null) { fm = getSupportFragmentManager(); ft = fm.beginTransaction(); PictureFragment mPhotoFragment = new PictureFragment(this, uri); ft.replace(R.id.rc_frame, mPhotoFragment); ft.commit(); }else{ finish(); } } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { mSavedPicUri = Uri.parse(savedInstanceState.getString("photo_uri")); super.onRestoreInstanceState(savedInstanceState); //还原 Log.e("TakingPicturesActivity","onRestoreInstanceState"); } @Override public void onSaveInstanceState(Bundle outState) { outState.putString("photo_uri",mSavedPicUri.toString()); super.onSaveInstanceState(outState); //保存 Log.e("TakingPicturesActivity","onSaveInstanceState"); } }如此保存状态以后 在资源不足 被系统回收 顶层的任务栈退出后 恢复之前被回收的activity, 我们只需要保存 carsh 当时为null的值