current position:Home>Android develops photos / albums, selects photos, uploads a single picture on the interface, and the page displays photos

Android develops photos / albums, selects photos, uploads a single picture on the interface, and the page displays photos

2022-07-28 23:03:35Herding time

Project scenario :

1. This project is MVVP Pattern , Use retrofit

2.ActivityA Click on imageView Control to enter CaptureImgActivity in ,CaptureImgActivity Photo taking is supported in / Photo album , Click to take a picture / After album , Need to take photos / The photos after the album are uploaded to the file server through the interface , At the same time, display the picture to activityA On the page ;

3. Because I came back to write this blog after writing the project , If you report red after copying the code , Please don't be upset , Take a closer look at the code , The main implementation code is posted in detail ;

4. Here I bind the corresponding control with databinding form

Basic knowledge you need to understand before development

1.MediaStore This class is android A multimedia database provided by the system ,android Multimedia information can be extracted from here .

2. By implicitly intent Intended to open the corresponding photo taking or album selection function

Intent intent = new Intent(Intent.ACTION_PICK, null);// Open the system album 
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");// Punch system camera 

3.https://blog.csdn.net/juer2017/article/details/102933451 This blog explains A And B in requestcode and resultcode Correspondence in

4. rewrite onActivityResult Method ,onActivityResult Can receive photos / Data returned automatically after album selection (Intent data)

(startActivityForResult,setResult Method )

Specific implementation code :

Before writing code, you need to pay attention to :

1. In the code mView.hideLoading();mView.onError(err); Such code can be commented out without any impact ;
2. Need to add a camera 、 Photo album view and other permissions , Find out the specific authority by yourself …
3.AndroidManifest Need to add provider
4.AndroidManifest Configure permissions in file_paths,file_paths in external-path Medium xxx yes :AndroidManifest in package name ;
5.requestcode resultcode In different activity In the corresponding
6.gradle(:app) Add glid relevant
//Glid Picture loading Library
implementation ‘com.github.bumptech.glide:glide:4.8.0’

1.AndroidManifest Add camera 、 Photo album view and other permissions
AndroidManifest In addition to adding camera album permissions, you also need to add :

<provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true"
            tools:replace="android:authorities">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
</provider>

2.res->xml Configure new in the file file_paths.xml
Be careful :external-path Medium xxx yes :AndroidManifest in package name

<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
    <external-path path="xxx" name="files_root" />
    <external-path path="." name="external_storage_root" />
    <root-path name="root_path" path="."/>
    <external-path  name="camera_photos"  path="." />
</paths>
</resources>

3.Constanst Global :

public static int PICTURE_REQUEST_CODE = 1;
public static int PICTURE_RESULT_CODE = 2;
public static int  CAMERA_REQUEST_CODE= 3;// Gallery 

4.activityA in :

//** Jump to activityB:CaptureImgActivity in 
binding.ivImage.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
    
                    Intent intent = new Intent(context, CaptureImgActivity.class);
                    context.startActivityForResult(intent, PICTURE_REQUEST_CODE);// implicit intent
                    //PICTURE_REQUEST_CODE It's self defined , This field represents PICTURE_REQUEST_CODE The corresponding is CaptureImgActivity Returned data 
//  To return to this interface , Therefore, do not close the interface 
                }
                    
            });


explain :
Why use PICTURE_REQUEST_CODE To identify ?( If you don't understand this explanation , Please skip …)
1. You can read the third point of the above basic knowledge and know onActivityResult It's easy to explain what it's for ,
activityA Medium onActivityResult Will receive many different activity Back to intent data ,
2. You can know which logo it is through your own definition activity The value passed back , In this code , When onActivityResult Medium judgement if (requestCode == PICTURE_REQUEST_CODE && resultCode == RESULT_CANCELED) Just explain intent By CaptureImgActivity This activity Handed over

5.CaptureImgActivity in :xml style
 Please add a picture description

6.CaptureImgActivity Code :

private String imageSavePath;
@Override
    public void initView() {
    
        binding.tvCapture.setOnClickListener(new View.OnClickListener() {
    
            @Override
            public void onClick(View v) {
    
                File photoFile = createImageSaveFile(getApplicationContext());
                // Start the camera program 
                Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");// Punch system camera 
                Uri imageUri = FileProvider.getUriForFile(
                        getApplicationContext(),
                        getPackageName() + ".fileprovider",
                        photoFile);
                intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
                startActivityForResult(intent, PICTURE_REQUEST_CODE);
            }
        });
        
        binding.tvAlbum.setOnClickListener(new View.OnClickListener() {
    
            @Override
            public void onClick(View v) {
    
                if (ContextCompat.checkSelfPermission(CaptureImgActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
    
                    ActivityCompat.requestPermissions(CaptureImgActivity.this,new String[]{
    Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
                }else {
    
                    Intent intent = new Intent(Intent.ACTION_PICK, null);// Open the system album 
                    intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
                    startActivityForResult(intent, 3);
                }
            }
        });
        
        binding.ivBack.setOnClickListener(new View.OnClickListener() {
    
            @Override
            public void onClick(View v) {
    
                Intent intent = new Intent();
                intent.putExtra("image","0");
                setResult(RESULT_CANCELED,intent);
                finish();
                return;
            }
        });
    }

// Taking pictures : Create a file to store the photos taken 
    private File createImageSaveFile(Context ctx) {
    
        File myCaptureFile = null;
        try {
    
            //  Mounted 
            File pic = ctx.getExternalFilesDir(Environment.DIRECTORY_PICTURES + "/save");
            if (!pic.exists()) {
    
                pic.mkdirs();
            }
            
            myCaptureFile = File.createTempFile("utc", ".jpg", pic);
            if (!myCaptureFile.exists()) {
    
                myCaptureFile.createNewFile();
            }
            
            imageSavePath = myCaptureFile.getAbsolutePath();
        } catch (IOException e) {
    
            e.printStackTrace();
        }
        return myCaptureFile;
    }
    
@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PICTURE_REQUEST_CODE && resultCode == RESULT_CANCELED){
    // Turn on the camera and return without taking pictures 
            Intent intent = new Intent();
            intent.putExtra("image","0");
            setResult(Constans.PICTURE_RESULT_CODE,intent);
            finish();
            return;
        }
        if (requestCode == PICTURE_REQUEST_CODE && resultCode == RESULT_OK) {
    // Turn on the camera and take a picture 
            Intent intent = new Intent();
            intent.putExtra("image",imageSavePath);
            setResult(Constans.PICTURE_RESULT_CODE,intent);
            finish();
            return;
        }

        if (requestCode == 3 && resultCode == RESULT_OK) {
    // Open the album and select pictures 
            Uri originalUri = data.getData(); // Get pictures of uri
            //  The second part that starts here , Get the path of the picture :
            String[] proj = {
    MediaStore.Images.Media.DATA};
            //managedQuery stay Android4.4 Then it was abandoned , use getContentResolver().query Instead of ,
            //  But in this project , Use getContentResolver().query Null pointer exception will be reported 
            Cursor cursor = managedQuery(originalUri, proj, null, null, null);
            if (cursor == null){
    
                 cursor = getContentResolver().query(originalUri, proj, null, null, null);
            }
            // According to my personal understanding   This is the index value of the image selected by the user 
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            cursor.moveToFirst();
            // Finally, the image path is obtained according to the index value 
            String path = cursor.getString(column_index);
            Intent intent = new Intent();
            intent.putExtra("image",path);
            setResult(Constans.PICTURE_RESULT_CODE,intent);// The result to be delivered resultcode, intent

            finish();
            return;
        }
        // Open the album but return without selecting photos 
        if (requestCode == 3 && resultCode == RESULT_CANCELED){
    
            Intent intent = new Intent();
            intent.putExtra("image","0");
            setResult(RESULT_CANCELED,intent);
            finish();
            return;
        }

    }
    

7.activityA in :
// Receive the returned data
// When there is no photo taken or no photo album selected, return to A in , Do nothing
// If you take photos or choose photos , Then upload the photos to the file server through the interface

//actionDetailAdapter The scanning result returned after calling the scanning function of shell 
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode == PICTURE_REQUEST_CODE && resultCode == RESULT_CANCELED){
    // Turn on the camera and return without taking pictures   Or return without selecting photos 
            return;
        }
        if (requestCode == PICTURE_REQUEST_CODE && resultCode == -2){
    // Open the photo album without taking photos and return without selecting photos 
            return;
        }

        if (requestCode == PICTURE_REQUEST_CODE && resultCode == RESULT_CANCELED){
    // Open the photo album without taking photos and return without selecting photos 
        }
        // Taking pictures or Album select photos 
        if (requestCode == PICTURE_REQUEST_CODE && resultCode == Constans.PICTURE_RESULT_CODE) {
    // Open the album to return pictures or take photos to return 
            
                String imageLocalPath = data.getStringExtra("image");// Get by CaptureActivity Medium intent The path of the passed image 
                if (imageLocalPath!=null){
    
                    SPUtils.getInstance().save(Constans.PICTURE_LOCAL_PATH,imageLocalPath);// Save the local path of local photos 
                    mPresenter.postImage(imageLocalPath,1);// Upload the image path to the interface to the server 
                }
        } 
    }

8. Upload pictures to the server through the interface
Novice can read this article first :
retrofit2 -Multipart To upload pictures , file , Upload with multiple parameters :
https://blog.csdn.net/qq_36767261/article/details/108886357

APIService Interface :

/** *  Picture upload  * @param file * @param number  Create folder  * * @return */
     // number The parameters depend on the requirements of the interface , If you don't need to , Then you don't need to add this parameter 
     
    @Multipart
    @POST("v1/upload/")// Your own interface 
    // Upload pictures as files 
    // The interface returns the path of the image uploaded to the file server 
    Observable<Response<String>> uploadImage(@Part MultipartBody.Part file, @Part("number") int number);
    // Because the pictures are uploaded in the form of files , adopt  MultipartBody.Part file;

Be careful : Below 9 in , Because everyone's project is different ,9 This item is for reference only !!!!!!! Just write according to the specifications of your own project
Because the address used by the file server is separate , So it needs to be in retrofitClient Write a file server separately in Url Address
9.RetrofitClient in :

public class RetrofitClient {
    
	private APIService apiServiceUploadImg;
	private Retrofit retrofitUploadImg;
	public APIService getUploadImgApi() {
    
        // Initialize a client, Otherwise retrofit Will add one by default 
        if (retrofitUploadImg == null) {
    
            retrofitUploadImg = new Retrofit.Builder()
                    // Set up the Url Address 
                    .baseUrl(baseUrl_uploadimge)// The address of your own file server **
                    // Set up a data parser 
                    .addConverterFactory(CheckGsonConverterFactory.create())
                    // Set up the network request adapter , To support RxJava And RxAndroid
                    .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
// .client(ClientFactory.getInstance().getOkHttpClient())
                    .client(getOkHttpClient())
                    .build();
        }
        // establish ——  Network request interface ——  example 
        if (apiServiceUploadImg == null) {
    
            apiServiceUploadImg = retrofitUploadImg.create(APIService.class);
        }
        return apiServiceUploadImg;
    }
}

10.model layer :
// Because the project is different , there return RetrofitClient.getInstance().getUploadImgApi().uploadImage(partFile,number); It may not be used in your project , For reference only , Just follow the specifications of your own project !!

@Override
    public Observable<Response<String>> uploadImage(String imagePath, int number) {
    
    // The type of interface required is file file type , So you need to convert the returned image path to file The file type is passed to the interface 
        File file = new File(imagePath);
        RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"),file);
        MultipartBody.Part partFile = MultipartBody.Part.createFormData("file",file.getName(),requestBody);
        **return RetrofitClient.getInstance().getUploadImgApi().uploadImage(partFile,number);
    }
    

11.Contract layer :

public interface Contract {
    
    interface IModel {
    
        Observable<Response<String>> uploadImage(String imagePath,int number);
    }
    interface View extends BaseView {
    
    }
    interface Presenter {
    
    }

12.presenter layer :

private CheckDetailContract_CHUJIAN.IModel model;

	/** *  Upload pictures  *  Convert the local image path into a file and upload it to the file server , The file server will return the path of the uploaded image  * **number: The back-end interface requires delivery number, Customize how to upload pictures to the file server number Under the folder ** * ** You may not add this parameter during the development process ** *  direct public void postImage(String imageLocalPath) */
    public void postImage(String imageLocalPath, int number) {
    
        model.uploadImage(imageLocalPath, number)
                .subscribeOn(Schedulers.io())
// .retryWhen(new RetryWithDelay(3, 2))// Try again when you encounter an error , The first parameter is to retry several times , The second parameter is the retry interval 
                .doOnSubscribe(disposable -> {
    
                    //mView.showLoading();// Show progress bar 
                }).subscribeOn(AndroidSchedulers.mainThread())
                .observeOn(AndroidSchedulers.mainThread())
                .doFinally(() -> {
    
                   // mView.hideLoading();// Hide the progress bar 
                })
                .subscribe(new Observer<Response<String>>(){
    
                    @Override
                    public void onSubscribe(@NonNull Disposable d) {
    
                    }
                    @Override
                    public void onNext(@NonNull Response<String> stringResponse) {
    
                        String imageSeverUrl = "";
                        if (stringResponse.getCode() == 100) {
    
                            imageSeverUrl = stringResponse.getData();// The server image path returned by the server 、
                            notifyPicture(imageSeverUrl );
                        } else {
    
                            String str = "";
                            if (stringResponse.getMsg() == null || stringResponse.getMsg().length() < 1) {
    
                            } else {
    
                                str = stringResponse.getMsg();
                            }
                        }
                    }

                    @Override
                    public void onError(@NonNull Throwable e) {
    
                        mView.hideLoading();
                        if (e instanceof HttpException) {
    
                            ResponseBody body = ((HttpException) e).response().errorBody();
                            try {
    
                                String err = JsonFormatUtils.getErrMsg(body.string());
                                mView.onError(err);
                            } catch (IOException IOe) {
    
                                IOe.printStackTrace();
                            }
                        } else if (e instanceof UnknownHostException) {
    
                        }
                    }

                    @Override
                    public void onComplete() {
    
                    }
                });
    }

After uploading the image, you need to display the network image returned by the server on the page :

ivImage yes imageview Controls to display pictures
Upload the photos taken by the mobile phone to the image server , This picture is equivalent to a network picture , The file server returns the path of this picture , Display the network picture in the corresponding imageview in :

adopt glide Image loading framework

First, you need to add configuration
build.gradle(:app) Add :

//Glid Picture loading Library 
    implementation 'com.github.bumptech.glide:glide:4.8.0'

activityA:

public void notifyPicture(String imageSeverUrl) {
    
	Glide .with(context).load(imageSeverUrl).into(ivImage);
    }
                

copyright notice
author[Herding time],Please bring the original link to reprint, thank you.
https://en.hqmana.com/2022/196/202207130600369519.html