旋转Android设备时保留图像

时间:2014-09-08 04:55:11

标签: android android-activity android-fragments rotation orientation

我正在创建一个应用程序,其中一个活动用于显示带有标题的图像。这些图像使用ViewPager(一页中的每个图像)显示。

创建图像并使用字幕显示它们没有问题。但是,当我旋转设备时,我遇到了问题。在设备旋转时,图像被删除,但字幕是保留的。我想我知道原因(正如下面的代码片段后所解释的那样),但我无法解决它,因此我问这个问题。

首先,这是我的gallery_item.xml文件,用于显示每个图像:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView android:id="@+id/gallery_image"
        android:layout_height="fill_parent"
        android:layout_width="fill_parent"
        android:scaleType="fitCenter"
        android:background="@color/black" />

    <TextView android:id="@+id/gallery_caption"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:gravity="right"



        android:textSize="20sp"


        android:paddingStart="@dimen/activity_horizontal_margin"
        android:paddingEnd="@dimen/activity_horizontal_margin"
        android:paddingBottom="@dimen/activity_vertical_margin"

        android:textColor="@color/white"
        android:background="@color/transparent_black_percent_50" />

</FrameLayout>

然后活动代码GalleryItemPagerActivity.java低于

public class GalleryItemPagerActivity extends Activity {

    private ViewPager mViewPager;

    private NewsItem mNewsItem;
    private int mNewsItemId;

    ImageDownloaderThread<ImageView> mImageDownloaderThread;


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


        mViewPager = new ViewPager(this);
        mViewPager.setId(R.id.galleryItemViewPager);
        setContentView(mViewPager);





        // Create a thread that will be run in the background to download images from the web for each URL
        //
        // IMPORTANT NOTE:
        // We are downloading the image in the activity instead of the fragment because we are use a pager activity
        // ... and pager activities must have the adapter in the activity rather than the fragment, which causes us to download the image here
        // ... if we try to download in the fragment, then we will have a very complicated code that will cause too many memory leaks.
        mImageDownloaderThread = new ImageDownloaderThread<ImageView>(new Handler());

        // Prepare listener to update UI when an image is downloaded
        mImageDownloaderThread.setListener(new ImageDownloaderThread.Listener() {

            // This method is used to update the UI when the image ready
            public void onImageDownloaded(Bitmap image, String url, int pos, int download_image_type) {

                // First, get the fragment by position
                GalleryItemFragment fragment = ((GalleryItemFragmentStatePagerAdapter)mViewPager.getAdapter()).getFragment(pos);

                // If the fragment exists
                if (fragment != null) {

                    // Update the image
                    ImageView imageView = (ImageView) fragment.getView().findViewById(R.id.gallery_image);
                    imageView.setImageBitmap(image);

                }

            }
        });

        // Start the background thread
        mImageDownloaderThread.start();

        // Prepare the looper for the background thread
        mImageDownloaderThread.getLooper();



        mNewsItemId = getIntent().getIntExtra(GalleryItemFragment.EXTRA_NEWS_ITEM_ID, 0);
        mNewsItem = NewsItems.get(this).getNewsItem(mNewsItemId);


        FragmentManager fm = getFragmentManager();
        GalleryItemFragmentStatePagerAdapter adapter = new GalleryItemFragmentStatePagerAdapter(fm);
        mViewPager.setAdapter(adapter);

    }




    // Destroy the background thread when we exit the app, otherwise it will stay forever
    @Override
    public void onDestroy() {
        super.onDestroy();
        mImageDownloaderThread.quit();
    }




    // I am subclassing FragmentStatePagerAdapter so I can add the method getFragment()
    // ... This method allows me to get the displayed fragment by position, and if it does not exist, a null is returned.
    private class GalleryItemFragmentStatePagerAdapter extends FragmentStatePagerAdapter {

        // A map to track current fragments.
        private Map<Integer, GalleryItemFragment> mFragmentReferenceMap = new HashMap<Integer, GalleryItemFragment>();


        // Constructor
        public GalleryItemFragmentStatePagerAdapter(FragmentManager fm) {
            super(fm);

        }


        // Implementation of get count.
        @Override
        public int getCount() {

            // The number of images to download is the number of our fragments
            int count = mNewsItem.getImages().size();
            return count;
        }


        // Fragment to display, and download the main image and author avatar
        @Override
        public Fragment getItem(int pos) {

            // Download this image
            String imageUrl = mNewsItem.getImages().get(pos).getUrl();

            // Initiate a request to download the image at the background thread
            mImageDownloaderThread.queueImage(imageUrl, pos, ImageDownloaderThread.DOWNLOAD_IMAGE_TYPE_MAIN);

            // Get the fragment
            GalleryItemFragment fragment = GalleryItemFragment.newInstance(mNewsItemId, pos);

            // Add the fragment to our map
            mFragmentReferenceMap.put(Integer.valueOf(pos), fragment);



            return fragment;

        }


        // When a fragment is deleted, we have to remove it from the map
        @Override
        public void destroyItem(ViewGroup container, int pos, Object object) {


            mFragmentReferenceMap.remove(Integer.valueOf(pos));

            // Remove the fragment from the map
            mFragmentReferenceMap.remove(Integer.valueOf(pos));
        }


        // Get the fragment by position (returns null if fragment does not exist)
        public GalleryItemFragment getFragment(int key) {
            return mFragmentReferenceMap.get(Integer.valueOf(key));
        }


    }


}

该片段的代码正好在GalleryItemFragment.java

public class GalleryItemFragment extends Fragment {

    public static final String EXTRA_NEWS_ITEM_ID = "com.myproject.android.news_item_id";
    public static final String EXTRA_GALLERY_ITEM_POSITION = "com.myproject.android.gallery_item_position";


    private int mNewsItemId;
    private int mGalleryItemPosition;

    private TextView mCaptionField;


    // This is used to set attach arguments to the fragment
    public static GalleryItemFragment newInstance (int news_item_id, int gallery_item_position) {
        Bundle args = new Bundle();
        args.putInt(EXTRA_NEWS_ITEM_ID, news_item_id);
        args.putInt(EXTRA_GALLERY_ITEM_POSITION, gallery_item_position);

        GalleryItemFragment fragment = new GalleryItemFragment();
        fragment.setArguments(args);

        return fragment;
    }

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

        mNewsItemId = getArguments().getInt(EXTRA_NEWS_ITEM_ID);
        mGalleryItemPosition = getArguments().getInt(EXTRA_GALLERY_ITEM_POSITION);

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {

        // inflate our xml file first
        View v = inflater.inflate(R.layout.gallery_item, parent, false);

        mCaptionField = (TextView)v.findViewById(R.id.gallery_caption);
        mCaptionField.setText(NewsItems.get(getActivity()).getNewsItem(mNewsItemId).getImages().get(mGalleryItemPosition).getCaption());

        return v;
    }

}

现在问题。

如前所述,当我旋转设备时,活动被销毁,但片段被保留(如接受的答案here中所述)。

另外,您注意到我的案例中的图像是在活动而不是片段中下载的(由于使用了寻呼机活动,这要求其适配器位于活动而不是片段中。)

因此,当活动被破坏时,图像消失了(但字幕会被保留,因为它们是保留片段的一部分)。这导致黑色页面没有图像,但只有字幕。

现在,我阅读了不同的解决方案(例如this one),并尝试将以下行添加到AndroidManifest.xml

android:configChanges="orientation|screenSize"

但这并没有多大帮助,因为在旋转设备后左右滑动时图像看起来“不成比例”,因为screenSize属性保留了屏幕尺寸,从而产生了有趣的图像。 / p>

现在,我想我应该尝试onSaveInstanceState(),但我不知道该怎么做。如何保存图像并使用onSaveInstanceState()保留图像?我的活动类中的其他变量(例如mViewPager)如何保存呢?

感谢。

2 个答案:

答案 0 :(得分:1)

请参阅,根据设计,每当设备配置发生变化时,活动或片段都会被破坏,但是如果你想自己处理它们,那么android会为你提供与APIS相同的设施,如

onSaveInstanceState() -- you can save and restore the instance stae
onConfigurationChanged() -- you can handle the configuration changes which you have declared to handle yourself, like in your case "orientation|screenSize"

除此之外,您可以在片段中使用setRetainInstance API在活动被销毁时将对象保存在片段中,您可以阅读它here,但是这个api确实提到不要保留像Bitmaps这样的对象。

现在出现问题,这就是你应该做的。

  1. 不要自己处理任何配置更改,让android为您处理
  2. 通过上面提供的信息,当方向改变而位图时,按住要保留的任何对象。
  3. 现在要有效地处理下载的图像,实现FileChache,在下载图像之前检查图像是否已经下载,并使用相同而不是再次下载,这将确保配置更改时,你不会得到黑点doanloaded image。
  4. 您可以在我的guthub链接中查看。

答案 1 :(得分:0)

您的问题是在onconfigurationchanged上重新加载,在清单文件中给予该活动文件的权限,如下所示:

android:configChanges="orientation|keyboard"