在方向变化Android应用程序丢失数据 [英] Android app losing data during orientation change

查看:202
本文介绍了在方向变化Android应用程序丢失数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有,我已经从一个教程,拍摄的图像与 MediaStore.ACTION_IM​​AGE_CAPTURE 复制的应用程序。我有一些古怪的打算时,我在我的手机上运行的应用程序上。

I've got an app that I've copied from a tutorial that captures an image with MediaStore.ACTION_IMAGE_CAPTURE. I've got some kind of weirdness going on when I run the app on my phone.

相机应​​用程序本身在操作过程中翻转其方向几次,即使我没有移动电话。它简单地进入横向模式返回到教程应用程序之前。因此,本教程的应用程序是翻转回纵向模式后,控制返回到它,并且图像丢失。我尝试了相机的活动的方向设置为横向,并且图像不丢失。

The camera app itself is flipping its orientation a couple times during operation even though I am not moving the phone. It briefly goes into landscape mode before returning to the tutorial app. Consequently, the tutorial app is flipping back to portrait mode after control is returned to it, and the image is lost. I tried setting the camera activity's orientation to landscape, and the image is not lost.

但是该应用的布局是用于纵向模式。或者,如果我认为我的相机横向拍摄时的照片,我可以打开手机后,我的应用程序已经回到专注,而不是失去的图像。

But the layout of the app is intended for portrait mode. Or, if I hold my camera in landscape orientation while capturing the photo, I can turn the phone after my app has returned to focus, and not lose the image.

我做了一些在网络上闲逛。有人在#1提到,在方向的变化引起的额外调用的onCreate 。 之​​所以的onCreate()被称为是因为当你调用在纵向相机的活动,它会改变方向,并摧毁你的previous活动。 我跑在调试模式下的应用程序在的onCreate设置断点,并在 onActivityResult 的方法。这的确是真实的的onCreate 当我把照片在纵向模式下获取调用。调用的顺序是的onCreate,onActivityResult,的onCreate。如果我把照片在横向模式(这是我的相机应用结束了两种方式),的onCreate不会被调用。现在,我有一些想法是怎么回事,我该如何保持这种距离是一个问题?下面是应用程序看起来像现在:

I did some poking around on the web. Someone on Stackoverflow mentioned that the change in orientation caused additional calls to onCreate. "The reason that onCreate() is called is because when you do call the camera activity during the portrait orientation, it will change the orientation and destroy your previous activity." I ran the app in debugging mode with breakpoints set in onCreate and in the onActivityResult methods. It is indeed true that onCreate is getting called when I take the photo in portrait mode. The order of calls is onCreate, onActivityResult, onCreate. If I take the photo in landscape mode (which is where my camera app ends up either way), onCreate does not get called. Now that I have some idea what is going on, how do I keep that from being a problem? Here's what the app looks like now:

package com.example.testapp;

import java.io.IOException;
import java.io.InputStream;

import android.app.Activity;
import android.app.WallpaperManager;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;

public class CameraActivity extends Activity implements View.OnClickListener {

    ImageButton ib;
    Button b;
    ImageView iv;
    Intent i;
    final static int cameraData = 0;
    Bitmap bmp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.photo_activity);
        initialize();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        // TODO Auto-generated method stub
        super.onConfigurationChanged(newConfig);
        setContentView(R.layout.photo_activity);
        initialize();
    }

    private void initialize() {
        iv = (ImageView)findViewById(R.id.imageViewReturnedPicture);
        ib = (ImageButton)findViewById(R.id.imageButtonTakePicture);
        b = (Button)findViewById(R.id.buttonSetWallpaper);
        b.setOnClickListener(this);
        ib.setOnClickListener(this);
    }

    @Override
    public void onClick(View arg0) {
        switch (arg0.getId()) {

        case R.id.buttonSetWallpaper:
            try {
                WallpaperManager wm = WallpaperManager.getInstance(getApplicationContext());
                wm.setBitmap(bmp);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            break;

        case R.id.imageButtonTakePicture:
            i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(i, cameraData);
            break;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        // TODO Auto-generated method stub
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            Bundle extras = data.getExtras();
            bmp = (Bitmap)extras.get("data");
            iv.setImageBitmap(bmp);
        }
    }
}

和这里就是我在清单这项活动:

And here's what I have in the manifest for this activity:


                android:name="com.example.testapp.CameraActivity"
                android:label="Camera Activity"
                android:configChanges="orientation"
                android:screenOrientation="portrait" 

我已经做了相当多的搜索,但许多事情,我觉得缺乏具体的例子。我需要知道什么是code的样子,而不仅是功能使用。

I've done considerable searching, but much of what I find lacks concrete examples. I need to know what the code looks like, not just what feature to use.

我的手机是LG电子的运动。有没有其他人遇到这个问题?怎样才可以解决吗?

My phone is an LG Motion. Has anyone else run into this problem? How can it be fixed?

推荐答案

您将不得不重写<一个href="http://developer.android.com/reference/android/app/Activity.html#onRetainNonConfigurationInstance%28%29">onRetainNonConfigurationInstance并使用<一个href="http://developer.android.com/reference/android/app/Activity.html#getLastNonConfigurationInstance%28%29">getLastNonConfigurationInstance保存/恢复位图。

You'll have to override onRetainNonConfigurationInstance and use getLastNonConfigurationInstance to save/restore the bitmap.

这样的:

// during onCreate(Bundle), after initialise()
bmp = getLastNonConfigurationInstance();
if(bmp!=null){ iv.setImageBitmap(bmp); }
else { /* the image was not taken yet */ }

然后在您的活动ü覆盖:

then on your activity u override:

@Override
public Object onRetainNonConfigurationInstance (){
     return bmp;
}

旋转过程中将保存位图。

That will 'save' the bitmap during rotation.

编辑:

例如,使用建议的onSaveInstanceState,将工作但不可取的,因为它会使用大量的内存和很慢但你需要的其他情形很快:

example using suggested onSaveInstanceState that will work but is not advisable because it will use a lot of memory and be very slow but you'll need for other situations soon:

public class SomethingSomething extends Activity{

    String name="";
    int page=0;

    // This is called when the activity is been created
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

            // if you saved something on outState you can recover them here
            if(savedInstanceState!=null){
                name = savedInstanceState.getString("name");
                page = savedInstanceState.getInt("page");
            }
    }

    // This is called before the activity is destroyed
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);

            outState.putString("name", name);
            outState.putInt("page", page);
    }
}

你可以看到,这个解决方案是不利于你的情况的原因是因为的Andr​​oid包使用上,这是Android的特殊类型的序列化,可以处理原语,字符串和类的实现Parcelable(这些类实际上只包裹的原语)。即使你的位图实现Parcelable,它将采取了很多时间做的每一个字节的副本位图到捆绑,将加倍位图已经大内存的消耗。

as you can see, the reason this solution is not good for your case is because the Android Bundle used on for this is Android special type of serialization that can handle primitives, Strings and Classes that implements Parcelable (those classes really only parcel their primitives). And even thou Bitmaps do implement Parcelable, it will be taking a lot of time to do a copy of every byte on the Bitmap to the bundle and will be doubling the already big memory consumption of a Bitmap.

现在,让我们使用 setRetainInstance (略复制的例子中,你可以找到一个解决方案见<$c$c>\sdk\extras\android\support\samples\Support4Demos\src\com\example\android\supportv4\app\FragmentRetainInstanceSupport.Java.

Now let's see at a solution using the setRetainInstance (slightly copied from the example you can find on \sdk\extras\android\support\samples\Support4Demos\src\com\example\android\supportv4\app\FragmentRetainInstanceSupport.Java.

请务必同时检查的例子,因为它显示了一些其他的花哨的技巧。

Make sure to also check the examples as it shows some other fancy tricks.

// This fragment will be managed by the framework but we won't built a UI for it.
public class FragRetained extends Fragment{
   public static final String TAG = "TAG.FragRetained";
   private Bitmap bitmap;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Tell the framework to try to keep this fragment around
        // during a configuration change.
        setRetainInstance(true);
    }
    public Bitmap getBitmap() { return bitmap; }
    public void setBitmap(Bitmap bmp) { bitmap = bmp; }
}

public class MyActivity extends Activity{

    private FragRetained myFragRetained;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
            // set the content view
            img = (ImageView)findViewById(R.id.byImgV);


            myFragRetained = getFragmentManger.findFragmentByTag(FragRetained.TAG);
            if(myFragRetained == null){
                myFragRetained = new FragRetained ();
            }else{
               Bitmap b = myFragRetained.getBitmap();
               if(b==null){
                  // the user still did not choose the photo
               }else{
                  img.setImageBitmap(b);
               }
            }
    }


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK) {
            Bundle extras = data.getExtras();
            bmp = (Bitmap)extras.get("data");
            iv.setImageBitmap(bmp);
            myFragRetained.setBitmap(bmp);
        }
    }

}

和确保删除行安卓configChanges =定向从您的manifest因为它可能做更多的伤害那么好,关于它的小报价:

and make sure to remove the line android:configChanges="orientation" from your manifest because it's probably doing more harm then good, a small quote about it:

请注意:使用这个属性应该避免只作为   最后一招。请阅读处理运行时更改的更多信息   关于如何妥善处理重新启动由于配置更改。

Note: Using this attribute should be avoided and used only as a last-resort. Please read Handling Runtime Changes for more information about how to properly handle a restart due to a configuration change.

这篇关于在方向变化Android应用程序丢失数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆