Copyright notice: This article is the blogger’s original article, shall not be reproduced without the permission of the blogger

Android Development from Scratch series

Source: AnliaLee/PhotoFactory, welcome star

If you see any mistakes or have any good suggestions, please leave a comment

At the beginning of the title is not feel that the blogger is the title party, deliberately deceived you come in? To tell you

The PhotoFactory class is packaged with three lines of code to select a photo and get its bitmap or URI path (optionally compressed or not). Now, how do you use PhotoFactory


PhotoFactory profile

There are three steps to using PhotoFactory. First we instantiate a PhotoFactory

PhotoFactory photoFactory = new PhotoFactory(this.this);//(Activity activity,Context context)
Copy the code

Sets how to select a photo

// There are three ways to select photos
photoFactory.FactoryStart().SetStartType(PhotoFactory.TYPE_PHOTO_UNTREATED).Start();// Call the camera to take a picture and return the original HD picture
/*photoFactory.FactoryStart().SetStartType(PhotoFactory.TYPE_PHOTO_AUTO_COMPRESS).Start(); / / call photo camera, camera after returning the system automatically compressed photo photoFactory. FactoryStart () SetStartType (photoFactory. TYPE_PHOTO_FROM_GALLERY). The Start (); // Select an image from the local album */
Copy the code

Gets the photo bitmap or URI

/** * Call this method */ in onActivityResult
photoFactory.FactoryFinish(requestCode,resultCode,data).GetBitmap();
//photoFactory.FactoryFinish(requestCode,resultCode,data).GetUri();
Copy the code

That’s it. Of course, you can also compress your photos, and there are three ways to do that

addScaleCompress(int w, int h)// Zoom to target width and height
addScaleCompress(int scale)// Same scale, scale ratio is original: new = scale:1
addQualityCompress(int targetSize)// mass compression, targetSize is the targetSize
Copy the code

You can choose one or more compression methods to compress the photo, for example

// Select only one compression method
photoFactory.FactoryFinish(requestCode,resultCode,data)
	    .addQualityCompress(128)
	    .GetBitmap();
	    
// Compress progressively in sequence
photoFactory.FactoryFinish(requestCode,resultCode,data)
	    .addQualityCompress(128)
	    .addScaleCompress(5)
	    .addScaleCompress(300.300)
	    .GetBitmap();
Copy the code

Complete sample

PhotoFactory is compatible with Android 7.0 FileProvider to obtain photo URI problems, of course, the specific Provider configuration and Android 6.0 dynamic permission management needs to be completed in the project. Here in order to facilitate you to complete the configuration, I will be a complete process posted for your reference

1. Download the PhotoFactory Library from Github and import it into your project

Address: AnliaLee/PhotoFactory

2. Create provider_paths.xml in the res\ XML directory

<? xml version="1.0" encoding="utf-8"? > <paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="external_files" path="."/>
</paths>
Copy the code

3. Add permissions and configure the Provider in androidmanifest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
	android:icon="@mipmap/ic_launcher". > <provider android:name="android.support.v4.content.FileProvider"
		android:authorities="${applicationId}.provider"
		android:exported="false"
		android:grantUriPermissions="true">
		<meta-data
			android:name="android.support.FILE_PROVIDER_PATHS"
			android:resource="@xml/provider_paths" />
	</provider>
	...
</application>
Copy the code

4. Add permissions and configure the Provider in androidmanifest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
	android:icon="@mipmap/ic_launcher". > <provider android:name="android.support.v4.content.FileProvider"
		android:authorities="${applicationId}.provider"
		android:exported="false"
		android:grantUriPermissions="true">
		<meta-data
			android:name="android.support.FILE_PROVIDER_PATHS"
			android:resource="@xml/provider_paths" />
	</provider>
	...
</application>
Copy the code

5. Manage dynamic permissions and use PhotoFactory in the Activity

public class PhotoTestActivity extends AppCompatActivity {
    private Button btnPhoto;
    private ImageView imgPhoto;
    private PhotoFactory photoFactory;

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

        photoFactory = new PhotoFactory(this.this);
        imgPhoto = (ImageView) findViewById(R.id.img_photo);
        btnPhoto = (Button) findViewById(R.id.btn_photo);
        btnPhoto.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (ContextCompat.checkSelfPermission(PhotoTestActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ! = PackageManager.PERMISSION_GRANTED) {// Apply for write permission
                    ActivityCompat.requestPermissions(PhotoTestActivity.this.new String[]{
                            Manifest.permission.WRITE_EXTERNAL_STORAGE
                    }, 100);
                } else{ photoFactory.FactoryStart() .SetStartType(PhotoFactory.TYPE_PHOTO_UNTREATED) .Start(); }}}); }@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch(requestCode) {
            case 100:
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    photoFactory.FactoryStart()
                            .SetStartType(PhotoFactory.TYPE_PHOTO_UNTREATED)
                            .Start();
                }else{// Do special processing if no permission is obtained
                    Toast.makeText(this."Please grant permission!", Toast.LENGTH_SHORT).show();
                }
                break;
            default:
                break; }}@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if(requestCode == RESULT_CANCELED){
            Toast.makeText(this."Cancel the photo shoot!, Toast.LENGTH_SHORT).show();
        }else {
            if(data == null){
                Toast.makeText(this."Deselect!", Toast.LENGTH_SHORT).show();
                return;
            }
            // Use the photo you selected
            Uri uri = photoFactory.FactoryFinish(requestCode,resultCode,data).GetUri();
            imgPhoto.setImageURI(uri);
        }
        super.onActivityResult(requestCode, resultCode, data); }}Copy the code

PhotoFactory has been introduced to the end, the specific implementation is not complex, interested in understanding how to realize the internal can look up the source code, if you do not understand the place or check the code has any problems welcome to give me a message ~


update

Although the previous code simplified the process of selecting photos, it did not consider the inclusion of the unselection process. The user had to write a lot of code in onActivityResult to handle the unselection, which showed that PhotoFactory was not convenient enough to use, so I added an interface to determine the unselection. Now we can call these new interfaces for fault tolerance

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	// You can still get photos this way, but you need to write the deselect handle yourself
	Uri uri = photoFactory.FactoryFinish(requestCode,resultCode,data).GetUri();
	imgPhoto.setImageURI(uri);

	// Now just call setOnResultListener like this
	photoFactory.FactoryFinish(requestCode,resultCode,data)
				.setOnResultListener(new PhotoFactory.OnResultListener() {
		@Override
		public void TakePhotoCancel(a) {
			Toast.makeText(PhotoTestActivity.this."Cancel the photo", Toast.LENGTH_SHORT).show();
		}

		@Override
		public void GalleryPhotoCancel(a) {
			Toast.makeText(PhotoTestActivity.this."Deselect", Toast.LENGTH_SHORT).show();
		}

		@Override
		public void HasData(PhotoFactory.FinishBuilder resultData) {// The photo was selected correctlyUri uri = resultData.GetUri(); imgPhoto.setImageURI(uri); }});super.onActivityResult(requestCode, resultCode, data);
}
Copy the code

But… That’s more than three lines of code…