简易Gallery
简易Gallery
最近做了一个活动壁纸的需求,涉及到图片文件这块,发现图片如果想在系统的图库里展示需要主动通知发送一个广播,于是我就想着做一个能显示所有图片的Gallery。
1.判断读取sd卡权限。
protected boolean applypermission() {
//检查是否已经给了权限
int checkpermission = ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.READ_EXTERNAL_STORAGE);
if (checkpermission != PackageManager.PERMISSION_GRANTED) {//没有给权限
//参数分别是当前活动,权限字符串数组,requestcode
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
} else {
return true;
}
return false;
}
这里如果没有权限,就申请;再看返回,
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
//grantResults数组与权限字符串数组对应,里面存放权限申请结果
permissionsResult(grantResults[0] == PackageManager.PERMISSION_GRANTED);
}
protected void permissionsResult(boolean result) {
}
2.主界面的相册列表
这是Activity,读取sd卡 /storage/emulated/0/下面的目录,并找出该目录下所有图片的数量,如果数量为0,则不显示该目录
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.widget.Toast;
import com.gallery.base.BaseActivity;
import com.gallery.bean.FileCountBean;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MainActivity extends BaseActivity {
private RecyclerView mRecyclerView;
private FileListAdapter mAdapter;
private List<FileCountBean> mData = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (applypermission()) {
getFileList();
}
mRecyclerView = (RecyclerView) findViewById(R.id.file_list);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new FileListAdapter(this, mData);
mRecyclerView.setAdapter(mAdapter);
}
@Override
protected void permissionsResult(boolean result) {
if (result) {
getFileList();
} else {
showDialog();
}
}
protected void showDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("没有读取sd卡的权限,可以到设置中打开");
builder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
builder.show();
}
private List<FileCountBean> getFileList() {
List<File> fileList = new ArrayList<>();
List<FileCountBean> beans = new ArrayList<>();
String filePath = Environment.getExternalStorageDirectory().toString() + File.separator;
File fileAll = new File(filePath);
if (fileAll.isDirectory()) {
File[] files = fileAll.listFiles();
for (File file : files) {
Log.d(TAG, "file = " + file.getPath());
}
fileList = Arrays.asList(files);
}
for (final File file : fileList) {
new Thread() {
@Override
public void run() {
super.run();
int count = getCount(file.getPath());
if (count != 0) {
mData.add(new FileCountBean(file.getPath(), file.getName(), count));
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
}
}
}.start();
}
return beans;
}
private int getCount(String path) {
return getGallery(new File(path)).size();
}
}
适配器:
import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.gallery.bean.FileCountBean;
import java.util.List;
public class FileListAdapter extends RecyclerView.Adapter<FileListAdapter.ViewHolder> {
private List<FileCountBean> mData;
private Context mContext;
public FileListAdapter(Context context, List<FileCountBean> files) {
mData = files;
mContext = context;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.file_list_item, null);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
holder.fileName.setText(mData.get(position).getName());
holder.count.setText(mData.get(position).getCount() + "");
holder.file_path.setText(mData.get(position).getPath());
holder.fileItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mContext, ThreadShowActivity.class);
intent.putExtra("path", mData.get(position).getPath());
mContext.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return mData.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView fileName, file_path;
TextView count;
View fileItem;
public ViewHolder(View itemView) {
super(itemView);
fileName = itemView.findViewById(R.id.file_item_tv);
count = itemView.findViewById(R.id.file_item_tv_count);
fileItem = itemView.findViewById(R.id.file_item);
file_path = itemView.findViewById(R.id.file_path);
}
}
}
3.某一个相册的具体图片的列表:
这里主要用到的就是递归,将某一相册中所有的图片找出来
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import com.gallery.base.BaseActivity;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class ThreadShowActivity extends BaseActivity {
private static final String TAG = "MainActivityTAG";
public static final int GALLERY_COLUM = 2;
private RecyclerView mRecyclerView;
private ThreadShowAdapter mAdapter;
private List<PicBean> mData = new ArrayList<>();
private TextView gallery_count, gallery_empty;
private Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0) {
gallery_empty.setText("no data");
} else {
gallery_empty.setVisibility(View.GONE);
mAdapter.notifyDataSetChanged();
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
if (!applypermission()) {
finish();
return;
}
getData();
mRecyclerView = (RecyclerView) findViewById(R.id.gallery_grid);
mRecyclerView.setLayoutManager(new GridLayoutManager(this, GALLERY_COLUM));
mAdapter = new ThreadShowAdapter(this, mData, new ThreadShowAdapter.OnPositionCallback() {
@Override
public void onPosition(int position) {
gallery_count.setText(position + mData.get(position).getPath());
}
});
mRecyclerView.setAdapter(mAdapter);
gallery_count = (TextView) findViewById(R.id.gallery_count);
gallery_empty = (TextView) findViewById(R.id.gallery_empty);
}
private void getData() {
new Thread() {
@Override
public void run() {
super.run();
String path = getIntent().getStringExtra("path");
mData.addAll(getPicBeans(getGallery(new File(path))));
if (mData.size() == 0) {
mHandler.sendEmptyMessage(0);
} else {
mHandler.sendEmptyMessage(1);
}
}
}.start();
}
private List<PicBean> getPicBeans(List<String> paths) {
List<PicBean> beans = new ArrayList<>();
for (String path : paths) {
if (isCorrect(path)) {
PicBean bean = new PicBean(path);
beans.add(bean);
}
}
return beans;
}
private boolean isCorrect(String path) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
int h = options.outHeight;
int w = options.outWidth;
return true;
}
}
适配器:
a.这里因为涉及到图片的列表展示,所以用缓存来处理;
b.在子线程中加载图片,因为图片很多所以为了避免不必要的线程开销,使用了线程池,因为在实际展示的时候,我自己的手机大概看到了7000张图片的时候,内存溢出了。
c.用到了BitmapFactory.Options,因为我们这一步是列表展示,所以要对图片的大小进行处理,所以先利用这个options加载出bitmap的宽高,然后再加载图片具体的内容
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadShowAdapter extends RecyclerView.Adapter<ThreadShowAdapter.ViewHolder> {
private final int mScreenWidth;
private final ExecutorService mExecutorService;
private Thread mWorkThread;
private Context mContext;
private List<PicBean> mData;
private int mLastPosition;
private LruCache<String, Bitmap> mMemoryCache;
public ThreadShowAdapter(Context context, List<PicBean> data, OnPositionCallback callback) {
mOnPositionCallback = callback;
mContext = context;
mData = data;
long maxMemory = Runtime.getRuntime().maxMemory();
mMemoryCache = new LruCache<String, Bitmap>((int) maxMemory) {
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
};
DisplayMetrics dm2 = context.getResources().getDisplayMetrics();
mScreenWidth = dm2.widthPixels;
mExecutorService = Executors.newFixedThreadPool(5);
}
public List<PicBean> getData() {
return mData;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.gallery_item, null);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
if (mOnPositionCallback != null) {
mOnPositionCallback.onPosition(position);
}
PicBean bean = mData.get(position);
getBitmap(holder.iv, bean.getPath());
holder.position.setText(position + "");
holder.iv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mContext, GalleryDetailsActivity.class);
intent.putExtra("path", mData.get(position).getPath());
mContext.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return mData.size();
}
private void getBitmap(final HeightImageView iv, final String path) {
Bitmap b = mMemoryCache.get(path);
if (b != null) {
iv.setBitmap(b);
return;
}
mWorkThread = new Thread() {
@Override
public void run() {
super.run();
Bitmap bitmap = getBitmapReal(path);
iv.setBitmap(bitmap);
mMemoryCache.put(path, bitmap);
}
};
mExecutorService.submit(mWorkThread);
}
private Bitmap getBitmapReal(String path) {
Bitmap bitmap = null;
if (bitmap != null) {
return bitmap;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
bitmap = BitmapFactory.decodeFile(path, options);
options.inJustDecodeBounds = false;
options.inSampleSize = getScale(options.outWidth, options.outHeight);
bitmap = BitmapFactory.decodeFile(path, options);
return bitmap;
}
private int getScale(int w, int h) {
int base = mScreenWidth / ThreadShowActivity.GALLERY_COLUM;
int wSize = w / base;
int hSize = h / base;
return Math.min(wSize, hSize);
}
class ViewHolder extends RecyclerView.ViewHolder {
HeightImageView iv;
TextView position;
public ViewHolder(View itemView) {
super(itemView);
iv = itemView.findViewById(R.id.gallery_item_iv);
position = itemView.findViewById(R.id.gallery_item_position);
}
}
public interface OnPositionCallback {
void onPosition(int position);
}
private OnPositionCallback mOnPositionCallback;
}
4.某一图片的单独详情展示:
这里没有做很多处理,仅仅是大概的一个展示,放大缩小做的都不够好,还有如果有很大的图片,可能会报错
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
public class GalleryDetailsActivity extends Activity {
public static final int GALLERY_COLUM = 2;
private MyZoomImageView gallery_details;
private TextView details_info;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery_details);
gallery_details = findViewById(R.id.gallery_details);
details_info = findViewById(R.id.details_info);
String path = getIntent().getStringExtra("path");
if (TextUtils.isEmpty(path)) {
finish();
return;
}
Bitmap bitmap = getBitmapReal(path);
if (bitmap == null) {
finish();
return;
}
gallery_details.setImageBitmap(bitmap);
}
private Bitmap getBitmapReal(String path) {
Bitmap bitmap = null;
if (bitmap != null) {
return bitmap;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
bitmap = BitmapFactory.decodeFile(path, options);
options.inJustDecodeBounds = false;
options.inSampleSize = getScale(options.outWidth, options.outHeight);
bitmap = BitmapFactory.decodeFile(path, options);
return bitmap;
}
private int getScale(int w, int h) {
DisplayMetrics dm2 = getResources().getDisplayMetrics();
int base = dm2.widthPixels;
int wSize = w / base;
int hSize = h / base;
details_info.setText(w + "," + h + "," + base);
int scale = 1;
if (h / w > 10 || w / h > 10) {
scale = 2;
}
return Math.min(wSize, hSize) * scale;
}
}
最后吐槽一下,我自己手机里面共有17000+的图片,其中相册能看到的大概1000+,其余的:
酷狗音乐 1000,
Android 7000+,
腾讯 4700+.
完整的项目我放到github上了,有兴趣可以下载下来看看,https://github.com/sunhaolyg/Gallery