0

我已经实现了一个自定义画廊,让用户可以实时选择许多图像,并将它们传递给一个新活动,在该活动中,为每个传递的图像实用地创建 ImageViews。用户可以自由添加多次图像。我注意到的是,如果用户每次都选择尚未选择的新图像,则一切正常。但是,如果用户选择了已经传递给下一个活动的图像,则应用程序崩溃并且我收到 java.lang.StringIndexOutOfBounds 错误。我需要了解导致此问题的原因。现在我添加我的代码,但如果您需要更好地理解,我可以编辑或添加更多。

自定义画廊:

public void onResume(){
    super.onResume();
    Intent previousIntent= getIntent(); //create a new intent for retrieve the photos path from the PhotoManagement activity (this need to be done for not lost the already selected images)
    Bundle customGalleryIntentBundle = getIntent().getExtras();
    if( customGalleryIntentBundle != null ){
        photosPath = (String) customGalleryIntentBundle.get("Selected Images"); //get the selected images from the previous activity
        photosPath = photosPath.replace("null", "");
        Log.i("CUSTOM GALLERY PHOTOS PATH",""+photosPath);
    }

    final String[] columns = { MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID };
    final String orderBy = MediaStore.Images.Media._ID;
    Cursor imagecursor = managedQuery( //create the cursor for navigate inside the database device and retrieve informations about the media contents like photo, video ecc...
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null,
            null, orderBy);
    int image_column_index = imagecursor.getColumnIndex(MediaStore.Images.Media._ID); //get the current column index
    this.count = imagecursor.getCount(); //count the external content uri of the cursor
    this.thumbnails = new Bitmap[this.count]; //create an array of bitmap using the size retrieved from the count variable
    this.arrPath = new String[this.count]; //create the array that contains the list of the path of the media (photos in this case)
    this.thumbnailsselection = new boolean[this.count]; //initialize the array of boolean to save informations about the selection of the thumbnails
    for (int i = 0; i < this.count; i++) {
        imagecursor.moveToPosition(i); //let's start from the first position and move one by one until the end
        int id = imagecursor.getInt(image_column_index);
        int dataColumnIndex = imagecursor.getColumnIndex(MediaStore.Images.Media.DATA);
        thumbnails[i] = MediaStore.Images.Thumbnails.getThumbnail( //take the thumbnails of the images and store it inside the array using the MICRO format for avoid high memory usage
                getApplicationContext().getContentResolver(), id,
                MediaStore.Images.Thumbnails.MICRO_KIND, null);
        arrPath[i]= imagecursor.getString(dataColumnIndex);
    }
    GridView imagegrid = (GridView) findViewById(R.id.PhoneImageGrid); //assign the GridView to the equivalent element in the xml file
    imageAdapter = new ImageAdapter(); //create a new imageAdapter. It is used how source for all the items in the gridView
    imagegrid.setAdapter(imageAdapter);
    imagecursor.close(); //close the image cursor when we arrive to the end of the columns to analize

    final Button selectBtn = (Button) findViewById(R.id.selectBtn); //assign the button to the equivalent in the xml layout
    selectBtn.setOnClickListener(new OnClickListener() { //create a listener for reveal when it is pressed

        public void onClick(View v) {
            // TODO Auto-generated method stub
            final int len = thumbnailsselection.length;
            int cnt = 0; //initialize a count for check the number of selected photos
            String selectImages = "";
            for (int i =0; i<len; i++)
            {
                if (thumbnailsselection[i]){
                    cnt++;
                    selectImages = selectImages + arrPath[i] + "|"; //store the correct path of the images in the variable (we can use this string for find the images path in others activity)         
                    Log.i("CUSTOM GALLERY SELECT IMAGES",""+selectImages);
                }
            }
            //if no one image is selected show a message to the user
            if (cnt == 0){
                Toast.makeText(getApplicationContext(),
                        "Please select at least one image",
                        Toast.LENGTH_LONG).show();
            } else {
                //If at least one image is selected we create a new activity where the images are displayed and the user can manage them
                Intent photoManagementIntent = new Intent(
                        getApplicationContext(),
                        PhotoManagement.class //select the class for the next activity
                        );
                photoManagementIntent.putExtra("Selected Images",""+selectImages+photosPath); //add an extra parameter that contains the path of the selected images. In this mode we can read it in the next activity
                startActivity(photoManagementIntent); //start the new activity
            }
        }
    });
}

这是我实用地创建 ImageViews 以显示从自定义画廊传递的图像的类:

protected void onResume(){
    super.onResume();
        Intent previousIntent= getIntent(); //create a new intent for retrieve informations from the previous activity
        Bundle photoManagementIntentBundle = getIntent().getExtras();
        if(photoManagementIntentBundle != null) //if the new intent is different from null
        {
            photosPath = (String) photoManagementIntentBundle.get("Selected Images"); //get the "selected images" string created in the previous activity
            photosPath = photosPath.replace("null", "");
            final String photosPathCopy = photosPath;
            int count = photosPath.length() - photosPath.replace("|", "").length(); //count contains the number of images selected

            //SCROLL VIEW
            ScrollView scrollView = new ScrollView(this); //create a new scrollView
            scrollView.setBackground(getResources().getDrawable(R.drawable.background)); //give the background gradient
            scrollView.setLayoutParams(new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT, //set the main params about the dynamic size of the scrollView
                                                         ScrollView.LayoutParams.MATCH_PARENT));
            scrollView.setPadding(0, 20, 0, 0);

            //LINEAR LAYOUT
            LinearLayout linearLayout = new LinearLayout(this); //create a new linearLayout
            linearLayout.setOrientation(LinearLayout.VERTICAL); //set the layout orientation
            linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT));

            for(int i=0; i<count; i++) {
                int indexOf = photosPath.indexOf('|'); //take the number of characters from | char
                String correctPath = photosPath.substring(0, indexOf); //this take the correct path of the photo
                photosPath = photosPath.replace(correctPath+"|", ""); //replace the old path with nothing. In this mode at every loop we have a new path until the end.
                Log.i("PHOTO MANAGEMENT PHOTOS PATH INSIDE LOOP",""+photosPath);
                //RELATIVE LAYOUT
                RelativeLayout relativeLayout = new RelativeLayout(this); //create a new relative layout
                relativeLayout.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, //set main params about the width and height
                        RelativeLayout.LayoutParams.FILL_PARENT));
                relativeLayout.setBackgroundColor(getResources().getColor(R.color.grayColor)); //set background color
                LinearLayout.LayoutParams relativeParams = new LinearLayout.LayoutParams(
                        new LinearLayout.LayoutParams(
                                LinearLayout.LayoutParams.MATCH_PARENT,
                                LinearLayout.LayoutParams.WRAP_CONTENT));
                relativeParams.setMargins(20, 20, 20, 0);
                relativeLayout.setLayoutParams(relativeParams); //set declared params about layout to the relativeLayout
                relativeLayout.requestLayout();
                relativeLayout.setOnClickListener(new View.OnClickListener(){ //create a listener about the layout. When a user press a point inside the relative layout a new activity should be created
                     @Override
                     public void onClick(View v){
                         Intent photoDetailsActivity = new Intent(
                                getApplicationContext(),
                                PhotoDetails.class //assign the class for create a new intent
                            );
                        photoDetailsActivity.putExtra("Selected Images",""+photosPathCopy);
                        startActivity(photoDetailsActivity); //let's start the new activity
                     }
                 });

                //IMAGE VIEW
                ImageView selectedPhoto = new ImageView(this); //create a new imageView
                selectedPhoto.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT)); //set width and height params about the selected photo zone
                try {
                    File standardImage = new  File(correctPath); //create a new file with the original path of the images
                    BitmapFactory.Options o = new BitmapFactory.Options(); //Enable the Bitmap factory options
                    o.inJustDecodeBounds = true; //allow the caller to query the bitmap without having to allocate the memory for its pixels
                    BitmapFactory.decodeStream(new FileInputStream(standardImage),null,o); //decode the image using the bitmap factory options

                    final int REQUIRED_SIZE=70; //The new size we want to scale to (save big quantity of memory)
                    int scale=1; //we need to find the correct scale value. It should be the power of 2.
                    while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
                        scale*=2;
                    BitmapFactory.Options o2 = new BitmapFactory.Options();  
                    o2.inSampleSize=scale; //decode with inSampleSize
                    selectedPhoto.setImageBitmap(BitmapFactory.decodeStream(new FileInputStream(standardImage), null, o2)); //assign the scaled image to the gridView
                } catch (FileNotFoundException e) {
                    Log.i("Error","File not found");
                }
                selectedPhoto.getLayoutParams().height = 90; //use a fixed size for each thumnail
                selectedPhoto.getLayoutParams().width = 90;

                //TEXT VIEWS
                TextView numberCopies = new TextView(this); //create new TextView
                numberCopies.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
                numberCopies.setGravity(Gravity.CENTER); //set position to the center in confront to the parent
                numberCopies.setPadding(25, 25, 25, 25);
                numberCopies.setTextColor(getResources().getColor(R.color.blackColor));
                numberCopies.setText("2 copies "); //this need to be dynamic
                RelativeLayout.LayoutParams layoutParamsNumberCopies = (RelativeLayout.LayoutParams) numberCopies.getLayoutParams();
                layoutParamsNumberCopies.addRule(RelativeLayout.CENTER_HORIZONTAL); //add a rule to the layout params. We put his position at the horizontal center of the relative layout
                numberCopies.setLayoutParams(layoutParamsNumberCopies); //set the layout rules to the textView

                TextView priceCopies = new TextView(this);
                priceCopies.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT));
                priceCopies.setGravity(Gravity.CENTER);
                numberCopies.setPadding(25, 25, 25, 25);
                priceCopies.setTextColor(getResources().getColor(R.color.redColor));

                RelativeLayout.LayoutParams layoutParamsPriceCopies = (RelativeLayout.LayoutParams) priceCopies.getLayoutParams();
                layoutParamsPriceCopies.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
                layoutParamsPriceCopies.addRule(RelativeLayout.CENTER_VERTICAL);
                priceCopies.setLayoutParams(layoutParamsPriceCopies);

                relativeLayout.addView(selectedPhoto);
                relativeLayout.addView(numberCopies);
                relativeLayout.addView(priceCopies);
                linearLayout.addView(relativeLayout);
            }               
            scrollView.addView(linearLayout);
            setContentView(scrollView);
            linearLayout.addView(relativeLayoutOpenButton); //add the button to the view
        }
}

这是我尝试添加已添加到下一个活动的图像时收到的错误:

10-04 09:15:20.019: E/AndroidRuntime(1715): FATAL EXCEPTION: main
10-04 09:15:20.019: E/AndroidRuntime(1715): java.lang.RuntimeException: Unable to resume activity {com.example.dilandprints2/com.example.dilandprints2.PhotoManagement}: java.lang.StringIndexOutOfBoundsException: length=0; regionStart=0; regionLength=-1
10-04 09:15:20.019: E/AndroidRuntime(1715):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2742)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2771)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2235)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at android.app.ActivityThread.access$600(ActivityThread.java:141)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at android.os.Handler.dispatchMessage(Handler.java:99)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at android.os.Looper.loop(Looper.java:137)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at android.app.ActivityThread.main(ActivityThread.java:5041)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at java.lang.reflect.Method.invokeNative(Native Method)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at java.lang.reflect.Method.invoke(Method.java:511)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at dalvik.system.NativeStart.main(Native Method)
10-04 09:15:20.019: E/AndroidRuntime(1715): Caused by: java.lang.StringIndexOutOfBoundsException: length=0; regionStart=0; regionLength=-1
10-04 09:15:20.019: E/AndroidRuntime(1715):     at java.lang.String.startEndAndLength(String.java:583)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at java.lang.String.substring(String.java:1464)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at com.example.dilandprints2.PhotoManagement.onResume(PhotoManagement.java:93)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1185)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at android.app.Activity.performResume(Activity.java:5182)
10-04 09:15:20.019: E/AndroidRuntime(1715):     at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2732)
10-04 09:15:20.019: E/AndroidRuntime(1715):     ... 12 more

请问有什么想法或建议吗?

4

2 回答 2

3

这条线

int indexOf = photosPath.indexOf('|');

正在返回-1|在 上找不到字符photosPath),因此您正在调用

photosPath.substring(0, -1);

抛出IndexOutOfBoundsException. 您正在使用 进行很多操作photosPath,请逐步跟踪跟踪以检查它是否获得了您期望的初始值,以及何时丢失它。

于 2013-10-04T09:56:07.897 回答
0

试试这个,改变这一行:

 photosPath = (String) customGalleryIntentBundle.get("Selected Images"); 

对此:

 photosPath = (String) customGalleryIntentBundle.getString("Selected_Images"); 

为此做同样的事情:

 photosPath = (String) photoManagementIntentBundle.get("Selected Images");

对此:

 photosPath = (String) photoManagementIntentBundle.getString("Selected_Images");

您拥有此密钥的每个地方:"Selected Images"您必须将其更改为"Selected_Images",还必须获取 String 而不仅仅是常规获取。

于 2013-10-04T09:50:46.490 回答