Gallery应用程序是预装在许多android设备上的最常用的应用程序之一,并且Google Play中提供了几种不同的应用程序来查看设备中存在的媒体文件。在本文中,我们将简单地创建一个Gallery应用程序,在其中我们可以查看存储在设备上的所有照片。除此之外,我们还可以在我们的应用程序中查看单个照片。
我们将在本文中构建什么?
我们将构建一个简单的应用程序,在该应用程序中,我们将简单地以网格格式显示照片列表,并在单击照片时可以查看该照片并可以放大该照片以正确查看它。下面是vide0,我们将在其中看到我们将要构建的内容。
分步实施
步骤1:创建一个新项目
要在Android Studio中创建新项目,请参阅如何在Android Studio中创建/启动新项目。请注意,选择Java作为编程语言。
步骤2:在build.gradle文件中添加依赖项
导航到应用程序> Gradle脚本> build.gradle(:app)并向其添加以下依赖项。我们正在使用Picasso从ImageView中的路径加载图像。
// below dependency for using Picasso image loading library
implementation ‘com.squareup.picasso:picasso:2.71828’
现在同步您的项目,我们将朝着在AndroidManifest.xml文件中添加权限的方向进行。
步骤3:在我们的AndroidManifest.xml文件中添加权限
导航至应用程序> AndroidManifest.xml文件,然后向其添加以下权限。
XML
XML
android:hardwareAccelerated="false"
android:largeHeap="true"
XML
XML
Java
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.squareup.picasso.Picasso;
import java.io.File;
import java.util.ArrayList;
public class RecyclerViewAdapter extends RecyclerView.Adapter {
// creating a variable for our context and array list.
private final Context context;
private final ArrayList imagePathArrayList;
// on below line we have created a constructor.
public RecyclerViewAdapter(Context context, ArrayList imagePathArrayList) {
this.context = context;
this.imagePathArrayList = imagePathArrayList;
}
@NonNull
@Override
public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// Inflate Layout in this method whch we have created.
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout, parent, false);
return new RecyclerViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
// on below line we are getting th file from the
// path which we have stored in our list.
File imgFile = new File(imagePathArrayList.get(position));
// on below line we are checking if tje file exists or not.
if (imgFile.exists()) {
// if the file exists then we are displaying that file in our image view using picasso library.
Picasso.get().load(imgFile).placeholder(R.drawable.ic_launcher_background).into(holder.imageIV);
// on below line we are adding click listener to our item of recycler view.
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// inside on click listner we are creating a new intent
Intent i = new Intent(context, ImageDetailActivity.class);
// on below line we are passing the image path to our new activity.
i.putExtra("imgPath", imagePathArrayList.get(position));
// at last we are starting our activity.
context.startActivity(i);
}
});
}
}
@Override
public int getItemCount() {
// this method returns
// the size of recyclerview
return imagePathArrayList.size();
}
// View Holder Class to handle Recycler View.
public static class RecyclerViewHolder extends RecyclerView.ViewHolder {
// creating variables for our views.
private final ImageView imageIV;
public RecyclerViewHolder(@NonNull View itemView) {
super(itemView);
// initializing our views with their ids.
imageIV = itemView.findViewById(R.id.idIVImage);
}
}
}
Java
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
public class MainActivity extends AppCompatActivity {
// on below line we are creating variables for
// our array list, recycler view and adapter class.
private static final int PERMISSION_REQUEST_CODE = 200;
private ArrayList imagePaths;
private RecyclerView imagesRV;
private RecyclerViewAdapter imageRVAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// we are calling a method to request
// the permissions to read external storage.
requestPermissions();
// creating a new array list and
// initializing our recycler view.
imagePaths = new ArrayList<>();
imagesRV = findViewById(R.id.idRVImages);
// calling a method to
// prepare our recycler view.
prepareRecyclerView();
}
private boolean checkPermission() {
// in this method we are checking if the permissions are granted or not and returning the result.
int result = ContextCompat.checkSelfPermission(getApplicationContext(), READ_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED;
}
private void requestPermissions() {
if (checkPermission()) {
// if the permissions are already granted we are calling
// a method to get all images from our external storage.
Toast.makeText(this, "Permissions granted..", Toast.LENGTH_SHORT).show();
getImagePath();
} else {
// if the permissions are not granted we are
// calling a method to request permissions.
requestPermission();
}
}
private void requestPermission() {
//on below line we are requesting the rea external storage permissions.
ActivityCompat.requestPermissions(this, new String[]{READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
}
private void prepareRecyclerView() {
// in this method we are preparing our recycler view.
// on below line we are initializing our adapter class.
imageRVAdapter = new RecyclerViewAdapter(MainActivity.this, imagePaths);
// on below line we are creating a new grid layout manager.
GridLayoutManager manager = new GridLayoutManager(MainActivity.this, 4);
// on below line we are setting layout
// manager and adapter to our recycler view.
imagesRV.setLayoutManager(manager);
imagesRV.setAdapter(imageRVAdapter);
}
private void getImagePath() {
// in this method we are adding all our image paths
// in our arraylist which we have created.
// on below line we are checking if the device is having an sd card or not.
boolean isSDPresent = android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
if (isSDPresent) {
// if the sd card is present we are creating a new list in
// which we are getting our images data with their ids.
final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID};
// on below line we are creating a new
// string to order our images by string.
final String orderBy = MediaStore.Images.Media._ID;
// this method will stores all the images
// from the gallery in Cursor
Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null, null, orderBy);
// below line is to get total number of images
int count = cursor.getCount();
// on below line we are running a loop to add
// the image file path in our array list.
for (int i = 0; i < count; i++) {
// on below line we are moving our cursor position
cursor.moveToPosition(i);
// on below line we are getting image file path
int dataColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
// after that we are getting the image file path
// and adding that path in our array list.
imagePaths.add(cursor.getString(dataColumnIndex));
}
imageRVAdapter.notifyDataSetChanged();
// after adding the data to our
// array list we are closing our cursor.
cursor.close();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
// this method is called after permissions has been granted.
switch (requestCode) {
// we are checking the permission code.
case PERMISSION_REQUEST_CODE:
// in this case we are checking if the permissions are accepted or not.
if (grantResults.length > 0) {
boolean storageAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
if (storageAccepted) {
// if the permissions are accepted we are displaying a toast message
// and calling a method to get image path.
Toast.makeText(this, "Permissions Granted..", Toast.LENGTH_SHORT).show();
getImagePath();
} else {
// if permissions are denied we are closing the app and displaying the toast message.
Toast.makeText(this, "Permissions denined, Permissions are required to use the app..", Toast.LENGTH_SHORT).show();
}
}
break;
}
}
}
XML
Java
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;
import com.squareup.picasso.Picasso;
import java.io.File;
public class ImageDetailActivity extends AppCompatActivity {
// creating a string variable, image view variable
// and a variable for our scale gesture detector class.
String imgPath;
private ImageView imageView;
private ScaleGestureDetector scaleGestureDetector;
// on below line we are defining our scale factor.
private float mScaleFactor = 1.0f;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_detail);
// on below line getting data which we have passed from our adapter class.
imgPath = getIntent().getStringExtra("imgPath");
// initializing our image view.
imageView = findViewById(R.id.idIVImage);
// on below line we are initializing our scale gesture detector for zoom in and out for our image.
scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
// on below line we are getting our image file from its path.
File imgFile = new File(imgPath);
// if the file exists then we are loading that image in our image view.
if (imgFile.exists()) {
Picasso.get().load(imgFile).placeholder(R.drawable.ic_launcher_background).into(imageView);
}
}
@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
// inside on touch event method we are calling on
// touch event method and pasing our motion event to it.
scaleGestureDetector.onTouchEvent(motionEvent);
return true;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
// on below line we are creating a class for our scale
// listener and extending it with gesture listener.
@Override
public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
// inside on scale method we are setting scale
// for our image in our image view.
mScaleFactor *= scaleGestureDetector.getScaleFactor();
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
// on below line we are setting
// scale x and scale y to our image view.
imageView.setScaleX(mScaleFactor);
imageView.setScaleY(mScaleFactor);
return true;
}
}
}
由于我们一次要从存储中加载所有图像,因此我们必须在AndroidManifest.xml文件中的应用程序标签中添加2个属性。导航到AndroidManifest.xml文件,然后在清单文件的应用程序标记中的以下两行中添加。
XML格式
android:hardwareAccelerated="false"
android:largeHeap="true"
步骤4:使用activity_main.xml文件
导航到应用程序> res>布局> activity_main.xml,然后将以下代码添加到该文件中。以下是activity_main.xml文件的代码。
XML格式
步骤5:创建要在RecyclerView中显示的项目
导航至应用程序> res>布局>右键单击该应用程序>新建>布局资源文件,然后创建一个新的布局资源文件。将该文件命名为card_layout,然后将以下代码添加到其中。在代码中添加了注释,以便更详细地了解。
XML格式
步骤6:创建一个新的活动以显示单个图像
导航到应用程序> Java >应用程序的程序包名称>右键单击它>新建>空活动,并将您的活动命名为ImageDetailActivity并创建一个新活动。我们将使用此活动来显示不同图像列表中的单个图像。
第7步:创建适配器类,以将数据设置到RecyclerView中的每个项目
导航到应用程序> Java >应用程序的程序包名称>右键单击它>新建Java类,并将您的类命名为RecyclerViewAdapter,然后将以下代码添加到其中。在代码中添加了注释,以便更详细地了解。
Java
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.squareup.picasso.Picasso;
import java.io.File;
import java.util.ArrayList;
public class RecyclerViewAdapter extends RecyclerView.Adapter {
// creating a variable for our context and array list.
private final Context context;
private final ArrayList imagePathArrayList;
// on below line we have created a constructor.
public RecyclerViewAdapter(Context context, ArrayList imagePathArrayList) {
this.context = context;
this.imagePathArrayList = imagePathArrayList;
}
@NonNull
@Override
public RecyclerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// Inflate Layout in this method whch we have created.
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout, parent, false);
return new RecyclerViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerViewHolder holder, int position) {
// on below line we are getting th file from the
// path which we have stored in our list.
File imgFile = new File(imagePathArrayList.get(position));
// on below line we are checking if tje file exists or not.
if (imgFile.exists()) {
// if the file exists then we are displaying that file in our image view using picasso library.
Picasso.get().load(imgFile).placeholder(R.drawable.ic_launcher_background).into(holder.imageIV);
// on below line we are adding click listener to our item of recycler view.
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// inside on click listner we are creating a new intent
Intent i = new Intent(context, ImageDetailActivity.class);
// on below line we are passing the image path to our new activity.
i.putExtra("imgPath", imagePathArrayList.get(position));
// at last we are starting our activity.
context.startActivity(i);
}
});
}
}
@Override
public int getItemCount() {
// this method returns
// the size of recyclerview
return imagePathArrayList.size();
}
// View Holder Class to handle Recycler View.
public static class RecyclerViewHolder extends RecyclerView.ViewHolder {
// creating variables for our views.
private final ImageView imageIV;
public RecyclerViewHolder(@NonNull View itemView) {
super(itemView);
// initializing our views with their ids.
imageIV = itemView.findViewById(R.id.idIVImage);
}
}
}
步骤8:使用MainActivity。 Java文件
转到MainActivity。 Java文件并参考以下代码。下面是MainActivity的代码。 Java文件。在代码内部添加了注释,以更详细地了解代码。
Java
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.MediaStore;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
public class MainActivity extends AppCompatActivity {
// on below line we are creating variables for
// our array list, recycler view and adapter class.
private static final int PERMISSION_REQUEST_CODE = 200;
private ArrayList imagePaths;
private RecyclerView imagesRV;
private RecyclerViewAdapter imageRVAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// we are calling a method to request
// the permissions to read external storage.
requestPermissions();
// creating a new array list and
// initializing our recycler view.
imagePaths = new ArrayList<>();
imagesRV = findViewById(R.id.idRVImages);
// calling a method to
// prepare our recycler view.
prepareRecyclerView();
}
private boolean checkPermission() {
// in this method we are checking if the permissions are granted or not and returning the result.
int result = ContextCompat.checkSelfPermission(getApplicationContext(), READ_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED;
}
private void requestPermissions() {
if (checkPermission()) {
// if the permissions are already granted we are calling
// a method to get all images from our external storage.
Toast.makeText(this, "Permissions granted..", Toast.LENGTH_SHORT).show();
getImagePath();
} else {
// if the permissions are not granted we are
// calling a method to request permissions.
requestPermission();
}
}
private void requestPermission() {
//on below line we are requesting the rea external storage permissions.
ActivityCompat.requestPermissions(this, new String[]{READ_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
}
private void prepareRecyclerView() {
// in this method we are preparing our recycler view.
// on below line we are initializing our adapter class.
imageRVAdapter = new RecyclerViewAdapter(MainActivity.this, imagePaths);
// on below line we are creating a new grid layout manager.
GridLayoutManager manager = new GridLayoutManager(MainActivity.this, 4);
// on below line we are setting layout
// manager and adapter to our recycler view.
imagesRV.setLayoutManager(manager);
imagesRV.setAdapter(imageRVAdapter);
}
private void getImagePath() {
// in this method we are adding all our image paths
// in our arraylist which we have created.
// on below line we are checking if the device is having an sd card or not.
boolean isSDPresent = android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
if (isSDPresent) {
// if the sd card is present we are creating a new list in
// which we are getting our images data with their ids.
final String[] columns = {MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID};
// on below line we are creating a new
// string to order our images by string.
final String orderBy = MediaStore.Images.Media._ID;
// this method will stores all the images
// from the gallery in Cursor
Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, columns, null, null, orderBy);
// below line is to get total number of images
int count = cursor.getCount();
// on below line we are running a loop to add
// the image file path in our array list.
for (int i = 0; i < count; i++) {
// on below line we are moving our cursor position
cursor.moveToPosition(i);
// on below line we are getting image file path
int dataColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
// after that we are getting the image file path
// and adding that path in our array list.
imagePaths.add(cursor.getString(dataColumnIndex));
}
imageRVAdapter.notifyDataSetChanged();
// after adding the data to our
// array list we are closing our cursor.
cursor.close();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
// this method is called after permissions has been granted.
switch (requestCode) {
// we are checking the permission code.
case PERMISSION_REQUEST_CODE:
// in this case we are checking if the permissions are accepted or not.
if (grantResults.length > 0) {
boolean storageAccepted = grantResults[0] == PackageManager.PERMISSION_GRANTED;
if (storageAccepted) {
// if the permissions are accepted we are displaying a toast message
// and calling a method to get image path.
Toast.makeText(this, "Permissions Granted..", Toast.LENGTH_SHORT).show();
getImagePath();
} else {
// if permissions are denied we are closing the app and displaying the toast message.
Toast.makeText(this, "Permissions denined, Permissions are required to use the app..", Toast.LENGTH_SHORT).show();
}
}
break;
}
}
}
步骤9:使用activity_image_detail.xml文件。
导航至应用程序> res>布局> activity_image_detail.xml,然后将以下代码添加到该文件中。以下是activity_image_detail.xml文件的代码。
XML格式
步骤10:使用ImageDetailActivity。 Java文件
转到ImageDetailActivity。 Java文件并参考以下代码。下面是ImageDetailActivity的代码。 Java文件。在代码内部添加了注释,以更详细地了解代码。
Java
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.ImageView;
import androidx.appcompat.app.AppCompatActivity;
import com.squareup.picasso.Picasso;
import java.io.File;
public class ImageDetailActivity extends AppCompatActivity {
// creating a string variable, image view variable
// and a variable for our scale gesture detector class.
String imgPath;
private ImageView imageView;
private ScaleGestureDetector scaleGestureDetector;
// on below line we are defining our scale factor.
private float mScaleFactor = 1.0f;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_detail);
// on below line getting data which we have passed from our adapter class.
imgPath = getIntent().getStringExtra("imgPath");
// initializing our image view.
imageView = findViewById(R.id.idIVImage);
// on below line we are initializing our scale gesture detector for zoom in and out for our image.
scaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
// on below line we are getting our image file from its path.
File imgFile = new File(imgPath);
// if the file exists then we are loading that image in our image view.
if (imgFile.exists()) {
Picasso.get().load(imgFile).placeholder(R.drawable.ic_launcher_background).into(imageView);
}
}
@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
// inside on touch event method we are calling on
// touch event method and pasing our motion event to it.
scaleGestureDetector.onTouchEvent(motionEvent);
return true;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
// on below line we are creating a class for our scale
// listener and extending it with gesture listener.
@Override
public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
// inside on scale method we are setting scale
// for our image in our image view.
mScaleFactor *= scaleGestureDetector.getScaleFactor();
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 10.0f));
// on below line we are setting
// scale x and scale y to our image view.
imageView.setScaleX(mScaleFactor);
imageView.setScaleY(mScaleFactor);
return true;
}
}
}
现在运行您的应用程序,并查看该应用程序的输出。
输出:
Note: Make sure to grant read storage permissions.