Android ViewPager: воссоздать отдельный фрагмент - PullRequest
1 голос
/ 03 июня 2019

Я использую ViewPager с двумя фрагментами: PhotoFragment и GalleryFragment.
Если я проведу пальцем ко второму фрагменту (GalleryFragment), я всегда захочу воссоздать этот фрагмент.
Но когда я проведу пальцем назад к первому фрагменту (Фотофрагмент), я хочу, чтобы это вытащили из памяти.

Я пытался реализовать решение по этому вопросу Обновлять ViewPager динамически?

Я использую notifyDataSetChanged() и переопределил getItemPosition() для возврата POSITION_NONE при перелистывании ко второму фрагменту.
А при перелистывании ко второму фрагменту это воссоздается правильно.Но когда я провожу назад к первому фрагменту, я замечаю, что это также было воссоздано.

Я полагаю, возвращение POSITION_NONE приведет к удалению и воссозданию всех фрагментов в адаптере.Я начинающий Android-разработчик и не знаю, как мне просто воссоздать только второй фрагмент.

MainActivity с ViewPager:

public class MainActivity extends AppCompatActivity {

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

        final ViewPager viewPager = findViewById(R.id.viewpager);
        ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
        viewPager.setAdapter(adapter);

        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int i, float v, int i1) {
            }

            @Override
            public void onPageSelected(int i) {
                if (i == 1) {
                    viewPager.getAdapter().notifyDataSetChanged();
                }
            }

            @Override
            public void onPageScrollStateChanged(int i) {
            }
        });

        TabLayout tabLayout = findViewById(R.id.tabs);
        tabLayout.setupWithViewPager(viewPager);
    }
}

Адаптер:

public class ViewPagerAdapter extends FragmentStatePagerAdapter {

    public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public int getCount() {
        return 2;
    }

    @Override
    public Fragment getItem(int i) {
        switch (i) {
            case 0:
                return new PhotoFragment();
            case 1:
                return new GalleryFragment();
            default:
                return null;
        }
    }

    @Nullable
    @Override
    public CharSequence getPageTitle(int position) {
        switch (position) {
            case 0:
                return "Photo";
            case 1:
                return "Gallery";
            default:
                return null;
        }
    }

    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }
}

Фотофрагмент:

public class PhotoFragment extends Fragment {

    private static final int CAMERA_REQUEST_CODE = 0;
    private static final int GALLERY_REQUEST_CODE = 1;
    private ImageView mCapturedImageView;
    private String mCacheFileLocation;
    private File mCacheFolder;
    private File mGalleryFolder;
    private String mImageFileLocation;
    private TextView mMonthText;
    private FrameLayout stickerFrameLayout;
    private static final String TAG = "PhotoFragment";

    public PhotoFragment() {
        // Required empty public constructor
    }

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

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

        mMonthText = rootView.findViewById(R.id.monthText);
        mCapturedImageView = rootView.findViewById(R.id.capturedImageView);
        ImageButton mCameraButton = rootView.findViewById(R.id.cameraButton);
        ImageButton mSaveButton = rootView.findViewById(R.id.saveButton);
        stickerFrameLayout = rootView.findViewById(R.id.stickerFrameLayout);
        ImageButton mRainbowButton = rootView.findViewById(R.id.buttonRainbow);
        ImageButton mDancerButton = rootView.findViewById(R.id.buttonDancer);
        ImageButton mGlassesButton = rootView.findViewById(R.id.buttonGlasses);
        ImageButton mHeartButton = rootView.findViewById(R.id.buttonHeart);
        ImageButton mCrownButton = rootView.findViewById(R.id.buttonCrown);
        ImageButton mJorisButton = rootView.findViewById(R.id.buttonJoris);

        mMonthText.setVisibility(View.INVISIBLE);
        createImageFolders();

        View.OnClickListener stickerListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                addSticker(v.getId());
            }
        };
        mRainbowButton.setOnClickListener(stickerListener);
        mDancerButton.setOnClickListener(stickerListener);
        mGlassesButton.setOnClickListener(stickerListener);
        mHeartButton.setOnClickListener(stickerListener);
        mCrownButton.setOnClickListener(stickerListener);
        mJorisButton.setOnClickListener(stickerListener);

        mCameraButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showPictureDialog();
            }
        });

        mSaveButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                saveImage();
            }
        });

        return rootView;
    }

    private void showPictureDialog() {
        AlertDialog.Builder pictureDialog = new AlertDialog.Builder(getActivity());
        pictureDialog.setTitle("Select Action");
        String[] pictureDialogItems = {"Select photo from device", "Capture photo with camera"};
        pictureDialog.setItems(pictureDialogItems, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                switch (which) {
                    case 0:
                        pickImage();
                        break;
                    case 1:
                        takePhoto();
                        break;
                }
            }
        });
        pictureDialog.show();
    }

    private void pickImage() {
        Intent pickImageIntent = new Intent(Intent.ACTION_PICK);
        pickImageIntent.setType("image/*");
        String[] mimeTypes = {"image/jpeg", "image/png"};
        pickImageIntent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
        pickImageIntent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
        startActivityForResult(pickImageIntent, GALLERY_REQUEST_CODE);
        mMonthText.setVisibility(View.INVISIBLE);
    }

    private void takePhoto() {
        Intent callCameraApplicationIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
        if (callCameraApplicationIntent.resolveActivity(getActivity().getPackageManager()) != null) {
            File file = null;
            try {
                file = createCacheFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (file != null) {
                Uri photoURI = FileProvider.getUriForFile(getActivity(), "com.jorisvanlaar.employeeofthemonth.fileprovider", file);
                callCameraApplicationIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
                startActivityForResult(callCameraApplicationIntent, CAMERA_REQUEST_CODE);
                mMonthText.setVisibility(View.INVISIBLE);
            }
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == getActivity().RESULT_OK) {
            switch (requestCode) {
                case GALLERY_REQUEST_CODE:
                    Bitmap bitmap = null;
                    if (data.getData() != null) {
                        try {
                            bitmap = BitmapFactory.decodeStream(getActivity().getContentResolver().openInputStream(data.getData()));
                        } catch (FileNotFoundException e) {
                            e.printStackTrace();
                        }
                    }
                    try {
                        writeBitmapToFile(bitmap, createCacheFile());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    rotateImage(reduceImageSize());
                    break;

                case CAMERA_REQUEST_CODE:
                    rotateImage(reduceImageSize());
                    break;
            }
        }
    }

    private void createImageFolders() {
        File storageDirectory = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES);
        mCacheFolder = new File(storageDirectory, "cached files");
        if (!mCacheFolder.exists()) {
            mCacheFolder.mkdirs();
        }
        mGalleryFolder = new File(storageDirectory, "Image Gallery");
        if (!mGalleryFolder.exists()) {
            mGalleryFolder.mkdirs();
        }
    }

    @SuppressLint("SimpleDateFormat")
    private File createCacheFile() throws IOException {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String cacheFileName = "IMG_" + timeStamp + "_";
        File image = File.createTempFile(cacheFileName, ".jpg", mCacheFolder);
        mCacheFileLocation = image.getAbsolutePath();
        return image;
    }

    @SuppressLint("SimpleDateFormat")
    private File createImageFile() {
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "EMPL_" + timeStamp + "_.jpg";
        File image = new File(mGalleryFolder, imageFileName);
        mImageFileLocation = image.getAbsolutePath();
        return image;
    }

    private void writeBitmapToFile(Bitmap bitmap, File destination) {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(destination);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
        } catch (Exception ex) {
            Log.i(TAG, "Error writing bitmap to file");
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    private Bitmap reduceImageSize() {
        int targetImageViewWidth = mCapturedImageView.getWidth();
        int targetImageViewHeight = mCapturedImageView.getHeight();

        BitmapFactory.Options bmOptions = new BitmapFactory.Options();
        bmOptions.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(mCacheFileLocation, bmOptions);
        int cameraImageWidth = bmOptions.outWidth;
        int cameraImageHeight = bmOptions.outHeight;

        int scaleFactor = Math.min(cameraImageWidth / targetImageViewWidth, cameraImageHeight / targetImageViewHeight);

        bmOptions.inJustDecodeBounds = false;
        bmOptions.inSampleSize = scaleFactor;

        Bitmap photoReducedSizeBitmap = BitmapFactory.decodeFile(mCacheFileLocation, bmOptions);
        return photoReducedSizeBitmap;
    }

    private void rotateImage(Bitmap bitmap) {
        ExifInterface exifInterface = null;
        try {
            exifInterface = new ExifInterface(mCacheFileLocation);
        } catch (IOException e) {
            e.printStackTrace();
        }
        int orientation = 0;
        if (exifInterface != null) {
            orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
        }
        Matrix matrix = new Matrix();
        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                matrix.setRotate(90);
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                matrix.setRotate(180);
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                matrix.setRotate(270);
                break;
            default:
        }
        Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        mCapturedImageView.setImageBitmap(rotatedBitmap);
    }

    @SuppressLint("SetTextI18n")
    private void saveImage() {
        Calendar calendar = Calendar.getInstance();
        int currentMonth = calendar.get(Calendar.MONTH);
        MonthCollection monthCollection = new MonthCollection();
        mMonthText.setText("Employee of " + monthCollection.getMonth(currentMonth));
        mMonthText.setVisibility(View.VISIBLE);

        Bitmap bitmap = Bitmap.createBitmap(stickerFrameLayout.getWidth(), stickerFrameLayout.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        stickerFrameLayout.draw(canvas);

        writeBitmapToFile(bitmap, createImageFile());
        Toast.makeText(getActivity(), "Image saved!", Toast.LENGTH_SHORT).show();
    }

    private void addSticker(int id) {
        StickerImageView sticker = new StickerImageView(getActivity());
        switch (id) {
            case R.id.buttonRainbow:
                sticker.setImageDrawable(getResources().getDrawable(R.drawable.sticker_rainbow));
                break;
            case R.id.buttonDancer:
                sticker.setImageDrawable(getResources().getDrawable(R.drawable.sticker_dancer));
                break;
            case R.id.buttonGlasses:
                sticker.setImageDrawable(getResources().getDrawable(R.drawable.sticker_sunglasses));
                break;
            case R.id.buttonHeart:
                sticker.setImageDrawable(getResources().getDrawable(R.drawable.sticker_heart));
                break;
            case R.id.buttonCrown:
                sticker.setImageDrawable(getResources().getDrawable(R.drawable.sticker_crown));
                break;
            case R.id.buttonJoris:
                sticker.setImageDrawable(getResources().getDrawable(R.drawable.sticker_joris));
                break;
            default:
                throw new RuntimeException("Unknown button ID");
        }
        stickerFrameLayout.addView(sticker);
    }
}

ГалереяФрагмент:

public class GalleryFragment extends Fragment {

    private RecyclerView mRecyclerView;
    private File mGalleryFolder;
    private static int mColumnCount = 3;
    private static int mImageWidth;
    private static int mImageHeight;

    public GalleryFragment() {
        // Required empty public constructor
    }

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

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

        mRecyclerView = rootView.findViewById(R.id.galleryRecyclerView);
        mGalleryFolder = getActivity().getExternalFilesDir(Environment.DIRECTORY_PICTURES + "/Image Gallery");

        DisplayMetrics displayMetrics = new DisplayMetrics();
        getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        mImageWidth = displayMetrics.widthPixels / mColumnCount;
        mImageHeight = mImageWidth * 4 / 3;

        GridLayoutManager layoutManager = new GridLayoutManager(getActivity(), mColumnCount);
        mRecyclerView.setLayoutManager(layoutManager);

        File[] sortedGalleryFolder = sortFilesToLatest(mGalleryFolder);
        RecyclerView.Adapter imageAdapter = new ImageAdapter(sortedGalleryFolder, mImageWidth, mImageHeight);
        mRecyclerView.setAdapter(imageAdapter);

        return rootView;
    }

    private File[] sortFilesToLatest(File imageDirectory) {
        File[] files = imageDirectory.listFiles();
        Arrays.sort(files, new Comparator<File>() {                                     
            @Override
            public int compare(File o1, File o2) {
                return Long.valueOf(o2.lastModified()).compareTo(o1.lastModified());
            }                                                                           
        });
        return files;
    }
}

Ответы [ 3 ]

1 голос
/ 04 июня 2019

Первый фрагмент воссоздается, потому что когда вы вызываете notifyDataSetChanged(), он влияет на оба фрагмента, а не только на i == 1 фрагмент

Решение, основанное на вашем текущем состоянии, это

@Override
public int getItemPosition(@NonNull Object object) {
    if (object instanceof PhotoFragment) {
        return POSITION_UNCHANGED;
    }
    return POSITION_NONE;
}

Однако это не оптимально, поскольку прокрутка медленная, вы можете попытаться использовать дочерний фрагмент, чтобы достичь того, что вы хотите

0 голосов
/ 04 июня 2019

Использование viewpager.setOffscreenPageLimit(1);

Это установит количество страниц, которые должны быть сохранены на стороне текущей страницы в иерархии представления в состоянии ожидания. Страницы, превышающие этот предел, будут воссозданы из адаптера при необходимости.

0 голосов
/ 03 июня 2019

Вы можете сохранить свой первый фрагмент в переменной, повторно использовать его и каждый раз создавать второй. Что-то вроде:

@Override
public Fragment getItem(int i) {
    switch (i) {
        case 0:
            if(photoFragment == null) {
               photoFragment = new PhotoFragment();
            }
            return photoFragment;
        case 1:
            return new GalleryFragment();
        default:
            return null;
    }
}
...