在做项目时常常会遇到选择本地图片的需求。曾经都是懒得写直接调用系统方法来选择图片。可是这样并不能实现多选效果。近期又遇到了,所以还是写一个demo好了。以后也方便使用。还是首先来看看效果

显示的图片使用RecyclerView实现的,利用Glide来载入;以下弹出的图片目录效果是採用PopupWindow实现,这里比採用PopupWindow更方便,弹出显示的左边图片是这个目录里的第一张图片;选中的图片能够进行预览,使用网上一个大神写的来实现的;至于图片的获取是用ContentProvider。

看看主界面的布局文件。上面一栏是一个返回button和一个跳转预览界面的button。依据是否有选中的图片来设置它的点击和显示状态。中间就是一个用于显示图片的RecyclerView,左下角是显示目录的名字可点击切换。右下角就是确定button。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.cdxsc.imageselect_y.ImageSelecteActivity"> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@android:color/white"> <ImageButton
android:id="@+id/ib_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:background="@mipmap/action_bar_back_normal" /> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:layout_toRightOf="@id/ib_back"
android:text="选择图片"
android:textColor="#000"
android:textSize="16sp" /> <TextView
android:id="@+id/tv_preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:enabled="false"
android:text="预览"
android:textColor="#BEBFBF"
android:textSize="16sp" />
</RelativeLayout> <View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#eeeeee" /> <android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"></android.support.v7.widget.RecyclerView> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="50dp"> <TextView
android:id="@+id/tv_allPic"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:clickable="true"
android:gravity="center_vertical"
android:text="全部图片"
android:textColor="@android:color/black"
android:textSize="16sp" /> <Button
android:id="@+id/bt_confirm"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:background="@drawable/shape_disable"
android:enabled="false"
android:text="确定"
android:textColor="#676767"
android:textSize="16sp" />
</RelativeLayout>
</LinearLayout>

好了。如今看主界面的代码

public class ImageSelecteActivity extends AppCompatActivity {

    private static final String TAG = "lzy";
@BindView(R.id.ib_back)
ImageButton mButtonBack;
@BindView(R.id.tv_preview)
TextView mTextViewPreview;
@BindView(R.id.rv)
RecyclerView mRecyclerView;
@BindView(R.id.tv_allPic)
TextView mTextViewAllPic;
@BindView(R.id.bt_confirm)
Button mButtonConfirm;
private GalleryPopupWindow mPopupWindow;
//存储每一个目录下的图片路径,key是文件名称
private Map<String, List<String>> mGroupMap = new HashMap<>();
private List<ImageBean> list = new ArrayList<>();
//当前目录显示的图片路径
private List<String> listPath = new ArrayList<>();
//所选择的图片路径集合
private ArrayList<String> listSelectedPath = new ArrayList<>(); private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//扫描完毕后
getGalleryList();
listPath.clear();
listPath.addAll(mGroupMap.get("全部图片"));
adapter.update(listPath);
if (mPopupWindow != null)
mPopupWindow.notifyDataChanged();
}
};
private ImageSelectAdapter adapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_selecte);
ButterKnife.bind(this);
init();
} private void init() {
getImages();
mRecyclerView.setLayoutManager(new GridLayoutManager(ImageSelecteActivity.this, 3));
adapter = new ImageSelectAdapter(this, listPath);
mRecyclerView.setAdapter(adapter);
adapter.setOnCheckedChangedListener(onCheckedChangedListener);
} @OnClick({R.id.ib_back, R.id.tv_preview, R.id.tv_allPic, R.id.bt_confirm})
public void onClick(View view) {
switch (view.getId()) {
case R.id.ib_back:
finish();
break;
case R.id.tv_preview://跳转预览界面
Intent intent = new Intent(ImageSelecteActivity.this, ImagePreviewActivity.class);
//把选中的图片集合传入预览界面
intent.putStringArrayListExtra("pic", listSelectedPath);
startActivity(intent);
break;
case R.id.tv_allPic://选择图片目录
if (mPopupWindow == null) {
//把目录列表的集合传入显示
mPopupWindow = new GalleryPopupWindow(this, list);
mPopupWindow.setOnItemClickListener(new GalleryPopupWindow.OnItemClickListener() {
@Override
public void onItemClick(String fileName) {
//切换了目录。清除之前的选择的信息
setButtonDisable();
listPath.clear();
listSelectedPath.clear();
//把当前选择的目录内图片的路径放入listPath,更新界面
listPath.addAll(mGroupMap.get(fileName));
adapter.update(listPath);
mTextViewAllPic.setText(fileName);
}
});
}
mPopupWindow.showAtLocation(mRecyclerView, Gravity.BOTTOM, 0, dp2px(50, ImageSelecteActivity.this));
break;
case R.id.bt_confirm://确定
for (int i = 0; i < listSelectedPath.size(); i++) {
//这里可通过Glide把它转为Bitmap
Glide.with(this).load("file://" + listSelectedPath.get(i)).asBitmap().into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
Log.i(TAG, "onResourceReady: " + resource);
}
});
}
break;
}
} /**
* dp转px
*/
public static int dp2px(int dp, Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
context.getResources().getDisplayMetrics());
} //选择图片变化的监听
private ImageSelectAdapter.OnCheckedChangedListener onCheckedChangedListener = new ImageSelectAdapter.OnCheckedChangedListener() {
@Override
public void onChanged(boolean isChecked, String path, CheckBox cb, int position) {
if (isChecked) {//选中
if (listSelectedPath.size() == 9) {
Toast.makeText(ImageSelecteActivity.this, "最多选择9张图片", Toast.LENGTH_SHORT).show();
//把点击变为checked的图片变为没有checked
cb.setChecked(false);
adapter.setCheckedBoxFalse(position);
return;
}
//选中的图片路径加入集合
listSelectedPath.add(path); } else {//取消选中
//从集合中移除
if (listSelectedPath.contains(path))
listSelectedPath.remove(path);
}
//假设没有选中的button不可点击
if (listSelectedPath.size() == 0) {
setButtonDisable();
} else {
setButtonEnable();
}
}
}; //选中图片时的button状态
private void setButtonEnable() {
mButtonConfirm.setBackgroundResource(R.drawable.selector_bt);
mButtonConfirm.setTextColor(Color.parseColor("#ffffff"));
mButtonConfirm.setEnabled(true);
mTextViewPreview.setEnabled(true);
mTextViewPreview.setTextColor(getResources().getColor(R.color.colorAccent));
mButtonConfirm.setText("确定" + listSelectedPath.size() + "/9");
} //没有选择时button状态
private void setButtonDisable() {
mButtonConfirm.setBackgroundResource(R.drawable.shape_disable);
mButtonConfirm.setTextColor(Color.parseColor("#676767"));
mButtonConfirm.setEnabled(false);
mTextViewPreview.setEnabled(false);
mTextViewPreview.setTextColor(Color.parseColor("#BEBFBF"));
mButtonConfirm.setText("确定");
} /**
* 利用ContentProvider扫描手机中的图片。此方法在执行在子线程中
*/
private void getImages() {
new Thread(new Runnable() { @Override
public void run() {
Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver mContentResolver = ImageSelecteActivity.this.getContentResolver();
//仅仅查询jpeg和png的图片
// Cursor mCursor = mContentResolver.query(mImageUri, null,
// MediaStore.Images.Media.MIME_TYPE + "=? or "
// + MediaStore.Images.Media.MIME_TYPE + "=? or " + MediaStore.Images.Media.MIME_TYPE + "=?",
// new String[]{"image/jpeg", "image/png", "image/jpg"}, MediaStore.Images.Media.DATE_MODIFIED);
Cursor mCursor = mContentResolver.query(mImageUri, null, null, null,
MediaStore.Images.Media.DATE_MODIFIED);
if (mCursor == null) {
return;
}
//存放全部图片的路径
List<String> listAllPic = new ArrayList<String>();
while (mCursor.moveToNext()) {
//获取图片的路径
String path = mCursor.getString(mCursor
.getColumnIndex(MediaStore.Images.Media.DATA)); //获取该图片的父路径名
String parentName = new File(path).getParentFile().getName();
listAllPic.add(path); //依据父路径名将图片放入到mGruopMap中
if (!mGroupMap.containsKey(parentName)) {
List<String> chileList = new ArrayList<String>();
chileList.add(path);
mGroupMap.put(parentName, chileList);
} else {
mGroupMap.get(parentName).add(path);
}
}
//加入全部图片
mGroupMap.put("全部图片", listAllPic);
//通知Handler扫描图片完毕
mHandler.sendEmptyMessage(0);
mCursor.close();
}
}).start(); } //获取相冊目录列表
private void getGalleryList() {
Iterator<Map.Entry<String, List<String>>> iterator = mGroupMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, List<String>> next = iterator.next();
ImageBean imageBean = new ImageBean();
imageBean.setFileName(next.getKey());
imageBean.setFirstPicPath(next.getValue().get(0));
imageBean.setCount(next.getValue().size());
if (next.getKey().equals("全部图片"))
list.add(0, imageBean);
else
list.add(imageBean);
}
}
}

·mGroupMap:这个是以目录名为key,目录内的图片路径集合为value,也就是依照目录来分别存储了全部图片的路径。

·listPath:保存的是当前显示在界面上的目录内的图片路径集合

·listSelectedPath:保存用户选中的图片路径

·list:保存的是ImageBean的集合。ImageBean保存了目录名、里面首张图片的路径以及里面所包括图片的数量,当切换目录时用于显示

·getImages():这种方法就是用来扫描手机里图片并保存的,这是在子线程中执行的,显示这可能是一个耗时的任务。通过ContentProvider获取到一个包括全部图片的Cursor,然后遍历这个Cursor把所需的数据就保存在mGroupMap里面,最后利用Handler通知界面更新。
·getGalleryList():这种方法就是mGroupMap里面的数据来给list赋值,也就是产生一个现实目录列表所需的数据集合。

·GalleryPopupWindow也就是我们用于显示文件列表的,在67--84行就是一些GalleryPopupWindow的设置,调用showAtLocation方法把PopupWindow显示在距离底部50dp的位置,并设置了点击的回调,当切换了一个目录后要做的相关操作就在这里进行。GalleryPopupWindow再待会再详细看看

接下来再看看中间RecyclerView的Adapter

public class ImageSelectAdapter extends RecyclerView.Adapter<ImageSelectAdapter.NViewHolder> {

    private Context context;
private List<String> list = new ArrayList<>();
private OnCheckedChangedListener onCheckedChangedListener;
private List<Boolean> listChecked = new ArrayList<>(); public ImageSelectAdapter(Context context, List<String> list) {
this.context = context;
this.list.addAll(list);
setListCheched(list);
} public void update(List<String> list) {
this.list.clear();
this.list.addAll(list);
setListCheched(list);
notifyDataSetChanged(); } /**
* 设置listChecked的初始值
*
* @param list
*/
private void setListCheched(List<String> list) {
listChecked.clear();
for (int i = 0; i < list.size(); i++) {
listChecked.add(false);
}
} //当点击超过了九张图片,再点击的设置为false
public void setCheckedBoxFalse(int pos) {
listChecked.set(pos, false);
} public interface OnCheckedChangedListener {
/**
* @param isChecked 是否选中
* @param path 点击的图片路径
* @param cb 点击的CheckBox
* @param pos 点击的位置
*/
void onChanged(boolean isChecked, String path, CheckBox cb, int pos);
} public void setOnCheckedChangedListener(OnCheckedChangedListener onCheckedChangedListener) {
this.onCheckedChangedListener = onCheckedChangedListener;
} @Override
public NViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new NViewHolder(LayoutInflater.from(context).inflate(R.layout.item_image_select, parent, false));
} @Override
public void onBindViewHolder(final NViewHolder holder, final int position) {
Glide.with(context).load("file://" + list.get(position)).into(holder.iv);
holder.cb.setChecked(listChecked.get(position));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.cb.setChecked(!holder.cb.isChecked());
if (holder.cb.isChecked()) {
listChecked.set(position, true);
} else {
listChecked.set(position, false);
}
if (onCheckedChangedListener != null) {
onCheckedChangedListener.onChanged(holder.cb.isChecked(), list.get(position), holder.cb, position);
}
}
});
} @Override
public int getItemCount() {
return list.size();
} public class NViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.iv_itemImageSelect)
ImageView iv;
@BindView(R.id.cb_itemImageSelect)
CheckBox cb; public NViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
} }

这里Item的布局文件就是一个ImageView加一个CheckBox。依据选中状态改变CheckBox的状态,这里就不贴出来了。

·listChecked:这个集合是用来存储每一个位置是否Check的,假设在onBindViewHolder里面不设置CheckBox的状态的话,由于复用问题会出问题,所以想出了用一个集合来保存它们状态的方法,不知道大家有没有其它更好的方法。

·OnCheckedChangedListener:向外暴露的接口,把点击的位置等參数都传到Activity中去。

·update():这种方法用来更新界面的,没有採用直接调notifyDataSetChanged方法是由于,假设数据的数量变化了那么listChecked的数量也要发生变化才行这样才干相应。所以写了这种方法。

再接着看看GalleryPopupWindow

/**
* Created by lzy on 2017/2/8.
*/
public class GalleryPopupWindow extends PopupWindow {
private static final String TAG = "lzy"; RecyclerView mRecyclerView; private Activity activity;
private GalleryPopupWindow.OnItemClickListener onItemClickListener;
private List<ImageBean> list;
private GalleryAdapter adapter; public GalleryPopupWindow(Activity context, List<ImageBean> list) {
super(context);
this.activity = context;
this.list = list;
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View contentView = inflater.inflate(R.layout.popu_gallery, null);
initView(contentView); int h = context.getWindowManager().getDefaultDisplay().getHeight();
int w = context.getWindowManager().getDefaultDisplay().getWidth();
this.setContentView(contentView);
this.setWidth(w);
this.setHeight(ImageSelecteActivity.dp2px(350, context));
this.setFocusable(false);
this.setOutsideTouchable(true);
this.update(); setBackgroundDrawable(new ColorDrawable(000000000));
} public void notifyDataChanged() {
adapter.notifyDataSetChanged();
} private void initView(View contentView) {
mRecyclerView = (RecyclerView) contentView.findViewById(R.id.rv_gallery);
mRecyclerView.setLayoutManager(new LinearLayoutManager(activity));
adapter = new GalleryAdapter(list, activity);
adapter.setOnItemClickListener(new GalleryAdapter.OnItemClickListener() {
@Override
public void onItemClick(String fileName) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(fileName);
dismiss();
}
}
});
mRecyclerView.setAdapter(adapter); } //暴露点击的接口
public interface OnItemClickListener {
/**
* @param keyValue
*/
void onItemClick(String keyValue);
} public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
}

这个PopupWindow的布局文件就是一个RecyclerView,所以这里面也没什么。也就是设置RecyclerView。然后向外暴露一个点击的接口,用于Activity接收是点击了哪个目录,所以接口參数也就是目录名,再看看这个PopupWindow的Adapter

/**
* Created by lzy on 2017/2/8.
*/
public class GalleryAdapter extends RecyclerView.Adapter<GalleryAdapter.NViewHolder> { private Context context;
private List<ImageBean> list;
private OnItemClickListener onItemClickListener;
//用于记录是选中的哪一个目录
private int selectedPos; public GalleryAdapter(List<ImageBean> list, Context context) {
this.list = list;
this.context = context;
} public interface OnItemClickListener {
void onItemClick(String fileName);
} public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
} @Override
public NViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new NViewHolder(LayoutInflater.from(context).inflate(R.layout.item_gallery, parent, false));
} @Override
public void onBindViewHolder(NViewHolder holder, final int position) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectedPos = position;
notifyDataSetChanged();
if (onItemClickListener != null) {
onItemClickListener.onItemClick(list.get(position).getFileName());
}
}
});
if (position == selectedPos) {
holder.ivCheck.setVisibility(View.VISIBLE);
} else {
holder.ivCheck.setVisibility(View.GONE);
}
holder.tvCount.setText(list.get(position).getCount() + "张");
holder.tvName.setText(list.get(position).getFileName());
Glide.with(context).load("file://" + list.get(position).getFirstPicPath()).into(holder.iv);
} @Override
public int getItemCount() {
return list.size();
} public class NViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.iv_itemGallery)
ImageView iv;
@BindView(R.id.tv_itemGallery_name)
TextView tvName;
@BindView(R.id.tv_itemGallery_count)
TextView tvCount;
@BindView(R.id.iv_itemGallery_check)
ImageView ivCheck; public NViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
} }

这里有个接口是把点击的文件名称传递给PopupWindow。然后再给Activity。selectedPos是用来记录选择的是哪一个目录。显示相应的CheckBox。

这里就几乎相同完毕了,感兴趣的能够下载Demo来看看。

再说一下,这里显示图片都是採用的Glide。使用也非常方便,我们获取的图片路径都是文件路径。假设要转化为Bitmap也能够直接调用Glide的方法就能够轻松实现,例如以下所看到的:

Glide.with(this).load("file://" + listSelectedPath.get(i)).asBitmap().into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
Log.i(TAG, "onResourceReady: " + resource);
}
});

当中找寻控件都没有使用findViewById,而是採用的ButterKnife。节约了大量的时间,顺便说说导入的方法

在app以下的build.gradle中加入以下:

apply plugin: 'com.neenbedankt.android-apt'
apt 'com.jakewharton:butterknife-compiler:8.1.0'
compile 'com.github.bumptech.glide:glide:3.5.2'

项目以下的build.gradle

 //加入apt插件
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'

加入插件

File->Setting->Plugins  搜索zelezny。例如以下所看到的

当须要使用的时候。直接在光标移动到布局文件,点击Alt+Insert。选择Generate ButterKnife Injections

就出现例如以下界面,能够自己主动生成了

源代码地址:http://download.csdn.net/detail/lylodyf/9768761

Android实现本地图片选择及预览缩放效果仿春雨医生的更多相关文章

  1. JavaScript实现本地图片上传预览功能(兼容IE、chrome、FF)

    需要解决的问题有:本地图片如何在上传前预览.编辑:最近发现这个功能很多是基于flash实现的,很多JavaScript实现的代码兼容性都很差,特别是在IE和firefox和chrome三个浏览器上不兼 ...

  2. 微信小程序图片选择,预览和删除

    这里均用的是小程序原生api 废话不多说直接上栗子: <view class="addImv"> <!--这个是已经选好的图片--> <view wx ...

  3. jquery实现本地图片上传预览和限流处理

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

  4. JS实现上传本地图片前先预览

    <style type="text/css"> #preview /*这个就是预览的DIV的ID*/ { filter:progid:DXImageTransform. ...

  5. HTML5实现图片选择并预览

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs& ...

  6. Html5选择图片并及时预览图片

    以往想要实现图片预览基本都是先传至服务器后等返回链接地址才能进行预览,使用Html5选择图片并及时预览图片的代码如下,使用起来更爽了. <!DOCTYPE html> <html l ...

  7. input type=file 选择图片并且实现预览效果的实例

    为大家带来一篇input type=file 选择图片并且实现预览效果的实例. 通过<input />标签,给它指定type类型为file,可提供文件上传: accept:可选择上传类型, ...

  8. vue使用readAsDataURL实现选择图片文件后预览

    vue实现选择图片文件后预览 利用h5的api可以实现选择文件并实现预览 readAsDataURL 方法会读取指定的 Blob 或 File 对象.读取操作完成的时候,readyState 会变成已 ...

  9. js实现图片上传预览及进度条

    原文js实现图片上传预览及进度条 最近在做图片上传的时候,由于产品设计的比较fashion,上网找了比较久还没有现成的,因此自己做了一个,实现的功能如下: 1:去除浏览器<input type= ...

随机推荐

  1. Filenames and paths

    Files are organized into directories (also called ‘folders’). Every running program has a ‘current d ...

  2. BZOJ 1711 网络流

    思路: 神建图 源->饮料 边权为1 牛拆点 两个点之间的边权为1 饮料->左牛 边权为1 右牛->食品 边权为1 食品->汇边权为1 //By SiriusRen #incl ...

  3. 知方可补不足~powerDesign为模型添加注释(让生成的SQL有注释)

    事实上powerDesign本身就有这个功能,不需要我们修改它的生成器了,这种方法够简单! 一 打开表模型,选择column标签

  4. 线程1—Thread

    随便选择两个城市作为预选旅游目标.实现两个独立的线程分别显示10次城市名,每次显示后休眠一段随机时间(1000ms以内),哪个先显示完毕,就决定去哪个城市.分别用Runnable接口和Thread类实 ...

  5. error C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead解决方案

    vs2012使用c语言函数fopen操作文件时报错: 错误 1 error C4996: 'fopen': This function or variable may be unsafe. Consi ...

  6. Struts2的struts.xml的标准配置文档

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-/ ...

  7. 相机拍照友盟检测crash是为什么?

    友盟报错如下* setObjectForKey: object cannot be nil (key: UIImagePickerControllerOriginalImage)(null)(( 0 ...

  8. Ubuntu 18.04 安装 Broadcom Limited BCM43142无线网卡驱动

    系统默认没有集成 BCM43142无线网卡驱动可以通过下面的方法安装--------------------------------------------------------------root ...

  9. [洛谷P1343]地震逃生

    题目大意:有n个点m条单向边,每条边有一个容量.现有x人要分批从1走到n,问每批最多能走多少人,分几批运完(或输出无法运完). 解题思路:一看就是网络流的题目.每批最多能走多少人,即最大流.分几批运完 ...

  10. 简单记录一次REDO文件损坏报错 ORA-00333重做日志读取块出错

    一.故障描写叙述 首先是实例恢复须要用到的REDO文件损坏 二.解决方法 1.对于非当前REDO或者当前REDO可是无活动事务使用下面CLEAR命令: 用CLEAR命令重建该日志文件SQL>al ...