Android 将上一个/下一个按钮添加到;细节片段“;(关于主/细节活动)

Android 将上一个/下一个按钮添加到;细节片段“;(关于主/细节活动),android,gridview,android-cursorloader,Android,Gridview,Android Cursorloader,我想在主视图/详细视图中添加“上一个/下一个”功能。主程序加载一个GridView(带有缩略图),单击它时,它通过URI(基本上包含相应的图像ID)启动DetailActivity 我想要的是细节活动/片段能够直接跳转到上一个/下一个图像,而无需在主视图中来回切换。理想情况下,我希望捕捉滑动手势 我读到最好的方法是使用ViewPager,使用FragmentStatePagerAdapter保存子视图。但是,我想了解为什么我的第一次尝试不起作用(如下)。(此外,我希望避免对代码进行重大修改,除非

我想在主视图/详细视图中添加“上一个/下一个”功能。主程序加载一个GridView(带有缩略图),单击它时,它通过URI(基本上包含相应的图像ID)启动DetailActivity

我想要的是细节活动/片段能够直接跳转到上一个/下一个图像,而无需在主视图中来回切换。理想情况下,我希望捕捉滑动手势

我读到最好的方法是使用ViewPager,使用FragmentStatePagerAdapter保存子视图。但是,我想了解为什么我的第一次尝试不起作用(如下)。(此外,我希望避免对代码进行重大修改,除非我必须这样做。)虽然我的尝试起作用,但我在几次滑动后就收到了OutOfMemory错误/崩溃:

10-13 13:11:21.441    4149-4149/com.example.android.galleri.app E/art﹕ Throwing OutOfMemoryError "Failed to allocate a 33177612 byte allocation with 12795712 free bytes and 12MB until OOM"
10-13 13:11:21.455    4149-4149/com.example.android.galleri.app I/art﹕ Clamp target GC heap from 195MB to 192MB
10-13 13:11:21.456    4149-4149/com.example.android.galleri.app I/art﹕ Alloc partial concurrent mark sweep GC freed 6(192B) AllocSpace objects, 0(0B) LOS objects, 6% free, 179MB/192MB, paused 903us total 10.248ms
10-13 13:11:21.474    4149-4149/com.example.android.galleri.app I/art﹕ Clamp target GC heap from 195MB to 192MB
10-13 13:11:21.474    4149-4149/com.example.android.galleri.app I/art﹕ Alloc concurrent mark sweep GC freed 3(96B) AllocSpace objects, 0(0B) LOS objects, 6% free, 179MB/192MB, paused 975us total 18.144ms
10-13 13:11:21.474    4149-4149/com.example.android.galleri.app I/art﹕ Forcing collection of SoftReferences for 31MB allocation
10-13 13:11:21.490    4149-4149/com.example.android.galleri.app I/art﹕ Clamp target GC heap from 195MB to 192MB
10-13 13:11:21.490    4149-4149/com.example.android.galleri.app I/art﹕ Alloc concurrent mark sweep GC freed 3(96B) AllocSpace objects, 0(0B) LOS objects, 6% free, 179MB/192MB, paused 1.060ms total 15.295ms
10-13 13:11:21.490    4149-4149/com.example.android.galleri.app E/art﹕ Throwing OutOfMemoryError "Failed to allocate a 33177612 byte allocation with 12795712 free bytes and 12MB until OOM"
10-13 13:11:21.490    4149-4149/com.example.android.galleri.app D/skia﹕ --- decoder->decode returned false
10-13 13:11:21.491    4149-4149/com.example.android.galleri.app D/AndroidRuntime﹕ Shutting down VM
    --------- beginning of crash
10-13 13:11:21.492    4149-4149/com.example.android.galleri.app E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.example.android.galleri.app, PID: 4149
    java.lang.OutOfMemoryError: Failed to allocate a 33177612 byte allocation with 12795712 free bytes and 12MB until OOM
            at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
            at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
            at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:635)
            at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:611)
            at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:391)
            at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:417)
            at com.example.android.galleri.app.DetailFragment.onLoadFinished(DetailFragment.java:302)
            at com.example.android.galleri.app.DetailFragment.onLoadFinished(DetailFragment.java:43)
            at android.support.v4.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:427)
            at android.support.v4.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:395)
            at android.support.v4.content.Loader.deliverResult(Loader.java:104)
            at android.support.v4.content.CursorLoader.deliverResult(CursorLoader.java:73)
            at android.support.v4.content.CursorLoader.deliverResult(CursorLoader.java:35)
            at android.support.v4.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:223)
            at android.support.v4.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:61)
            at android.support.v4.content.ModernAsyncTask.finish(ModernAsyncTask.java:461)
            at android.support.v4.content.ModernAsyncTask.access$500(ModernAsyncTask.java:47)
            at android.support.v4.content.ModernAsyncTask$InternalHandler.handleMessage(ModernAsyncTask.java:474)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:211)
            at android.app.ActivityThread.main(ActivityThread.java:5389)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1020)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:815)
这是相关的(我希望是)代码。

  • 注意
    public-void-onItemSelected(Uri-contentUri)
    调用来自MainActivity,它将图像正常加载到“DetailFragment”中

  • 此方法(通过回调/接口)从PhotoFragment调用:GridView的
    onClick
    处理程序,在
    onCreate
    方法中创建。这是图像从主到细节的正常加载,工作正常

  • 然后另一种方式:DetailActivity捕获滑动手势,并调用DetailFragment中的
    changeImage
    方法(通过成员对象/引用)

  • DetailFragment的
    changeImage
    方法通过实用程序类(容器对象)获取PhotoFragment中使用的光标。然后,它获取下一行/上一行并用该ID构造一个新的URI,然后用该URI启动(重新启动?)DetailActivity

这些重启似乎会积累内存,直到应用程序崩溃。崩溃(OOM错误)总是发生在DetailFragment的同一行,在我将位图加载到PhotoView的部分:

// OOM crash always occurs HERE (after ~5 swipes)
thumbBitmap = BitmapFactory.decodeFile(thumbData);  
MainActivity.java PhotoFragment.java DetailFragment.java
public类DetailFragment扩展片段实现LoaderManager.LoaderCallbacks{
私有静态最终字符串PHOTOFRAGMENT_TAG=“PFTAG”;
静态最终字符串详细信息\u URI=“URI”;
私有静态最终整数细节加载程序=0;
私有图像视图mPhotoView、mCloseIcon;
私有文本视图mImageSizeView、mImageDateView;
公共字符串mMemTitle,mMemDesc;
//用于共享的数据
私人长图像;
私有ShareActionProvider mShareActionProvider;
私有静态最终字符串[]详细信息\列={
PhotoContract.PhotoEntry.COLUMN\u IMAGE\u ID,
PhotoContract.PhotoEntry.COLUMN\u DISPLAY\u NAME,
PhotoContract.PhotoEntry.COLUMN_数据,
PhotoContract.PhotoEntry.COLUMN_DESC,
PhotoContract.PhotoEntry.COLUMN\u日期,
添加了PhotoContract.PhotoEntry.COLUMN\u DATE\u,
PhotoContract.PhotoEntry.COLUMN_标题,
PhotoContract.PhotoEntry.COLUMN\u尺寸,
光合同.光条目.柱方向,
PhotoContract.PhotoEntry.COLUMN\u高度,
PhotoContract.PhotoEntry.COLUMN\u宽度
};
静态最终int COL_IMAGE_ID=0;
静态最终整数列显示名称=1;
静态最终整数列数据=2;
静态最终整数列描述=3;
静态最终整数列日期=4;
静态最终整数列添加日期=5;
静态最终整数列标题=6;
静态最终整数列大小=7;
静态最终内柱方向=8;
静态最终内柱高度=9;
静态最终内柱宽度=10;
静态最终int COL_THUMB_ID=0;
静态最终整数COL_THUMB_DATA=1;
静态最终int COL_THUMB_IMAGE_ID=2;
私有Uri mUri;
私有布尔noMedia=false;
私有布尔值mTwoPane=false;
公共详细信息片段(){
SetHasOptions菜单(true);//但仅共享按钮
}
创建选项菜单(菜单菜单,菜单充气机){
充气机。充气(右菜单。细节片段,菜单);
MenuItem MenuItem=menu.findItem(R.id.action\u share);
mShareActionProvider=(ShareActionProvider)MenuItemCompat.getActionProvider(menuItem);
if(mFilePath!=null){
mShareActionProvider.setShareContent(createShareForecastingent());
}
}
公共图像视图getPhotoView(){
返回mPhotoView;
}
@凌驾
CreateView上的公共视图(布局、充气机、视图组容器、捆绑包保存状态){
Bundle arguments=getArguments();
if(参数!=null){
mUri=arguments.getParcelable(DetailFragment.DETAIL\u URI);
}
//从URI获取ID
如果(mUri!=null){
mImageID=PhotoContract.PhotoEntry.getImageIdFromUri(mUri);
}
视图根视图=充气机。充气(R.layout.fragment\u详细信息,容器,错误);
mPhotoView=(ImageView)rootView.findviewbyd(R.id.pic_frame);
mImageSizeView=(TextView)rootView.findviewbyd(R.id.imgSize\u TextView);
mImageDateView=(TextView)rootView.findViewById(R.id.date\u TextView);
返回rootView;
}
//用户滑动;转到上一个(方向=-1)或下一个(方向=1)图像:
公共void changeImage(int方向){
Cursor=Utility.getCursor();
长oldId=mImageID;
if(游标==null)
回来
布尔结果;
开关(方向){
案例1:
if(cursor.isFirst())返回;
结果=cursor.moveToPrevious();
打破
案例1:
if(cursor.isLast())返回;
结果=cursor.moveToNext();
打破
违约:
回来
}
Log.v(“gallery”、“DetailFragment.changeImage”(“+directio
public class MainActivity extends ActionBarActivity implements PhotoFragment.Callback  {

    private static final String DETAILFRAGMENT_TAG = "DFTAG";
    private boolean mTwoPane;
    private PhotoFragment mFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (findViewById(R.id.photo_detail_container) != null) {
            mTwoPane = true;

            if (savedInstanceState == null) {
                getSupportFragmentManager().beginTransaction()
                        .replace(R.id.photo_detail_container, new DetailFragment(), DETAILFRAGMENT_TAG)
                        .commit();
            }
        } else {
            mTwoPane = false;
        }

        mFragment = ((PhotoFragment) getSupportFragmentManager()
                .findFragmentById(R.id.fragment_photo));
        mFragment.setTwoPaneUI(mTwoPane);

    }


    @Override
    // this method is called from PhotoFragment (GridView) via a callback interface
    public void onItemSelected(Uri contentUri) {

        if (mTwoPane) {
            Bundle args = new Bundle();
            args.putParcelable(DetailFragment.DETAIL_URI, contentUri);

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

            fragment.setTwoPane(true);

            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.photo_detail_container, fragment, DETAILFRAGMENT_TAG)
                    .commit();
        } else {

            // launch DetailActivity
            Intent intent = new Intent(this, DetailActivity.class)
                    .setData(contentUri);
            startActivity(intent);
        }
    }

}
public class PhotoFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {

    private final static int LOADER_ID = 87;
    private PhotoAdapter mPhotoAdapter;
    private int mPosition;
    private GridView mGridView;
    private TextView mEmptyView;
    private int count_mem = -1;
    private static final String SELECTED_KEY = "POSITION";
    private boolean mTwoPane;
    private boolean DF_hidden = false;

    // these are the data we want from MediaStore
    private final static String[] THUMBNAIL_COLUMNS = {
            //PhotoContract.ThumbEntry.COLUMN_THUMB_ID,
            PhotoContract.ThumbEntry.COLUMN_THUMB_DATA,
            PhotoContract.ThumbEntry.COLUMN_IMAGE_PK,
            PhotoContract.ThumbEntry.COLUMN_TITLE,
            PhotoContract.ThumbEntry.COLUMN_DESC,
            PhotoContract.ThumbEntry.COLUMN_DATE,
            PhotoContract.ThumbEntry.COLUMN_FILENAME,
            PhotoContract.ThumbEntry.COLUMN_DATA,
            PhotoContract.ThumbEntry.COLUMN_IMAGESEQUENCE
    };


    static final int COL_THUMB_DATA = 0;
    static final int COL_IMAGE_ID = 1;
    static final int COL_TITLE = 2;
    static final int COL_DESC = 3;
    static final int COL_DATE = 4;
    static final int COL_FILENAME = 5;
    static final int COL_DATA = 6;
    static final int COL_IMAGESEQUENCE = 7;

    public void setTwoPaneUI(boolean pTwoPane) {
        mTwoPane = pTwoPane;
    }

    // interfaces
    public interface Callback {
        public void onItemSelected(Uri photoUri);
    }
    public interface FragmentCallback {
        public void onTaskDone(int count);
    }


    public PhotoFragment() {
    }

    public int getPosition() {
       return mPosition;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        getLoaderManager().initLoader(LOADER_ID, null, this);
        super.onActivityCreated(savedInstanceState);
    }

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

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    public void restartLoader() {
        getLoaderManager().restartLoader(LOADER_ID, null, this);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        if (mPosition != GridView.INVALID_POSITION) {
            outState.putInt(SELECTED_KEY, mPosition);
        }
        super.onSaveInstanceState(outState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);

        mPhotoAdapter = new PhotoAdapter(getActivity(), null, 0);
        GridView gridView = (GridView) rootView.findViewById(R.id.listview_photo);
        gridView.setAdapter(mPhotoAdapter);

        mEmptyView = (TextView) rootView.findViewById(R.id.list_empty);
        mGridView = gridView;

        // handle user clicking on an image
        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id) {
                Cursor cursor = (Cursor) parent.getItemAtPosition(position);

                if (cursor != null) {
                    Uri baseUri = PhotoContract.PhotoEntry.buildPhotoUriWithId(cursor.getLong(COL_IMAGE_ID));
                    Log.v("gallery", "PhotoFragment.onItemClick() image_id = " + cursor.getLong(COL_IMAGE_ID)
                           + ", baseUri = " + baseUri.toString());

                    // make sure detail fragment is visible
                    if (mTwoPane) showDetailFragment();
                    else Utility.setPosition(position);  // else (single-pane): store position clicked!

                    ((Callback)getActivity()).onItemSelected(baseUri);
                }
                mPosition = position;
            }
        });

        if (savedInstanceState != null && savedInstanceState.containsKey(SELECTED_KEY)) {
            mPosition = savedInstanceState.getInt(SELECTED_KEY);
        }

        return rootView;
    }


    @Override
    public Loader<Cursor> onCreateLoader(int i, Bundle bundle) {

        Uri thumbs_uri = PhotoContract.ThumbEntry.CONTENT_URI;
        return new CursorLoader(getActivity(), thumbs_uri, THUMBNAIL_COLUMNS,
                null,null,  // read everything (all thumbnails)
                null
               );
    }

    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) {
        if (cursor != null) {

            // register observer onto cursor
            cursor.setNotificationUri(getActivity().getContentResolver(), PhotoContract.ThumbEntry.CONTENT_URI);

            mPhotoAdapter.swapCursor(cursor);
            if (mPosition != GridView.INVALID_POSITION) {
                mGridView.setSelection(mPosition);  // scroll into view
            }
        }

        // save (set) cursor in Utility
        Utility.setCursor(cursor);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> cursorLoader) {
        mPhotoAdapter.swapCursor(null);
    }
}
public class DetailActivity extends ActionBarActivity  {

    private static final String DETAILFRAGMENT_TAG = "DFTAG";
    private float x1,x2, y1,y2;
    static final int MIN_DISTANCE = 150;
    private DetailFragment mFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);

        if (savedInstanceState == null) {

            Bundle arguments = new Bundle();
            arguments.putParcelable(DetailFragment.DETAIL_URI, getIntent().getData());

            //DetailFragment fragment = new DetailFragment();
            mFragment = new DetailFragment();
            mFragment.setArguments(arguments);

            getSupportFragmentManager().beginTransaction()
                    .add(R.id.photo_detail_container, mFragment, DETAILFRAGMENT_TAG)
                    .commit();
        }
    }



    // http://stackoverflow.com/questions/6645537/how-to-detect-the-swipe-left-or-right-in-android
    @Override
    public boolean onTouchEvent(MotionEvent event)
    {

        switch(event.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                x1 = event.getX();
                y1 = event.getY();
                break;
            case MotionEvent.ACTION_UP:
                x2 = event.getX();
                y2 = event.getY();

                float deltaX = x2 - x1;
                if (Math.abs(deltaX) > MIN_DISTANCE) {

                    if (x2 > x1)
                        mFragment.changeImage(-1);  // move backwards
                    else
                        mFragment.changeImage(1);  // move forwards
                }
                break;
        }
        return super.onTouchEvent(event);
    }






    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_detail, menu);
        return true;
    }

}
public class DetailFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> {

    private static final String PHOTOFRAGMENT_TAG = "PFTAG";
    static final String DETAIL_URI = "URI";
    private static final int DETAIL_LOADER = 0;
    private ImageView mPhotoView, mCloseIcon;
    private TextView mImageSizeView, mImageDateView;
    public String mMemTitle, mMemDesc;

    // data for sharing
    private Long mImageID;

    private ShareActionProvider mShareActionProvider;

    private static final String[] DETAIL_COLUMNS = {
            PhotoContract.PhotoEntry.COLUMN_IMAGE_ID,
            PhotoContract.PhotoEntry.COLUMN_DISPLAY_NAME,
            PhotoContract.PhotoEntry.COLUMN_DATA,
            PhotoContract.PhotoEntry.COLUMN_DESC,
            PhotoContract.PhotoEntry.COLUMN_DATE_TAKEN,
            PhotoContract.PhotoEntry.COLUMN_DATE_ADDED,
            PhotoContract.PhotoEntry.COLUMN_TITLE,
            PhotoContract.PhotoEntry.COLUMN_SIZE,
            PhotoContract.PhotoEntry.COLUMN_ORIENTATION,
            PhotoContract.PhotoEntry.COLUMN_HEIGHT,
            PhotoContract.PhotoEntry.COLUMN_WIDTH
    };

    static final int COL_IMAGE_ID = 0;
    static final int COL_DISPLAY_NAME = 1;
    static final int COL_DATA = 2;
    static final int COL_DESC = 3;
    static final int COL_DATE_TAKEN = 4;
    static final int COL_DATE_ADDED = 5;
    static final int COL_TITLE = 6;
    static final int COL_SIZE = 7;
    static final int COL_ORIENTATION = 8;
    static final int COL_HEIGHT = 9;
    static final int COL_WIDTH = 10;

    static final int COL_THUMB_ID = 0;
    static final int COL_THUMB_DATA = 1;
    static final int COL_THUMB_IMAGE_ID = 2;

    private Uri mUri;

    private boolean noMedia = false;
    private boolean mTwoPane = false;

    public DetailFragment() {
        setHasOptionsMenu(true); // only share button, though
    }

    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        inflater.inflate(R.menu.detailfragment, menu);
        MenuItem menuItem = menu.findItem(R.id.action_share);
        mShareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(menuItem);

        if (mFilePath != null) {
            mShareActionProvider.setShareIntent(createShareForecastIntent());
        }
    }

    public ImageView getPhotoView() {
        return mPhotoView;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Bundle arguments = getArguments();
        if (arguments != null) {
            mUri = arguments.getParcelable(DetailFragment.DETAIL_URI);
        }
        // get ID from URI
        if (mUri != null) {
            mImageID = PhotoContract.PhotoEntry.getImageIdFromUri(mUri);
        }

        View rootView = inflater.inflate(R.layout.fragment_detail, container, false);

        mPhotoView = (ImageView) rootView.findViewById(R.id.pic_frame);
        mImageSizeView = (TextView) rootView.findViewById(R.id.imgSize_textview);
        mImageDateView = (TextView) rootView.findViewById(R.id.date_textview);

        return rootView;
    }


    // user swipes; go to prev (direction = -1) or next (direction = 1) image:
    public void changeImage(int direction) {

        Cursor cursor = Utility.getCursor();
        Long oldId = mImageID;
        if (cursor == null)
            return;

        boolean result;
        switch (direction) {
            case -1:
                if (cursor.isFirst()) return;
                result = cursor.moveToPrevious();
                break;
            case 1:
                if (cursor.isLast()) return;
                result = cursor.moveToNext();
                break;
            default:
                return;
        }

        Log.v("gallery", "DetailFragment.changeImage(" + direction + "), old id "
                + oldId + " => IMAGE_ID = " + cursor.getLong(PhotoFragment.COL_IMAGE_ID));

        if (result) {
            mUri = PhotoContract.PhotoEntry.buildPhotoUriWithId(cursor.getLong(PhotoFragment.COL_IMAGE_ID));

            Utility.setPosition(cursor.getPosition());  // store position clicked!

            // re-launch DetailActivity
            Intent intent = new Intent(getActivity(), DetailActivity.class)
                    .setData(mUri);
            startActivity(intent);
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {

        if (mUri != null) {
            return new CursorLoader(getActivity(),
                    mUri, // URI passed in
                    DETAIL_COLUMNS, null, null, null);
        } else {
            mUri = PhotoContract.PhotoEntry.CONTENT_URI;  // means, default (first) image

            return new CursorLoader(getActivity(),
                    mUri, // "default URI": show first image...
                    DETAIL_COLUMNS, null, null, null);
        }
    }


    @Override
    public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor data) {

        if (data == null || !data.moveToFirst()) {
            return;
        }

        String thumbData = data.getString(COL_DATA);
        if (thumbData != null) {
            Bitmap thumbBitmap;
            try {
                thumbBitmap = BitmapFactory.decodeFile(thumbData);  // <--- OOM crash always occurs HERE (after ~5 swipes)
                mPhotoView.setImageBitmap(thumbBitmap);
            } catch (Exception e) {
                return;
            }
        }

        String metaDataText = data.getString(COL_WIDTH) + " x " + data.getString(COL_HEIGHT) + ", "
                + Math.round(data.getLong(COL_SIZE) / 1024.0) + "kb";

        mImageSizeView.setText(metaDataText, TextView.BufferType.SPANNABLE);

        mImageDateView.setText(DateFormat.format("d/M-yyyy",
                new Date(data.getLong(COL_DATE_TAKEN))).toString());

        if (mShareActionProvider != null)
            mShareActionProvider.setShareIntent(createShareForecastIntent());
    }

    @Override
    public void onLoaderReset(Loader<Cursor> cursorLoader) {
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        getLoaderManager().initLoader(DETAIL_LOADER, null, this);
        super.onActivityCreated(savedInstanceState);
    }

    public void setTwoPane(boolean b) {
        mTwoPane = b;
    }
}