@GeekDroid's 的答案是正确的,但我想我会提供更多信息来帮助澄清。
I've also created a library that will return the file path from an Uri when selecting a File from MediaStore.
我创建了一个类,它将在您的应用程序目录中复制/创建一个新文件。这是在后台线程上完成的,应该这样做。
我还创建了一个回调接口来获取“状态”并显示ProgressBar
这是接口(你可以改变名字和回调):
interface CallBackTask {
void onCopyPreExecute();
void onCopyProgressUpdate(int progress);
void onCopyPostExecute(String path, boolean wasSuccessful, String reason);
}
这里是复制文件的类:
public class CopyFileAsyncTask extends AsyncTask<Uri, Integer, String> {
private Uri mUri;
private CallBackTask callback;
private WeakReference<Context> mContext;
private String pathPlusName;
private File folder;
private Cursor returnCursor;
private InputStream is = null;
private String errorReason = "";
DownloadAsyncTask(Uri uri, Context context, CallBackTask callback) {
this.mUri = uri;
mContext = new WeakReference<>(context);
this.callback = callback;
}
@Override
protected void onPreExecute() {
callback.onCopyPreExecute();
Context context = mContext.get();
if (context != null) {
folder = context.getExternalFilesDir("Temp");
returnCursor = context.getContentResolver().query(mUri, null, null, null, null);
try {
is = context.getContentResolver().openInputStream(mUri);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
int post = values[0];
callback.onCopyProgressUpdate(post);
}
@Override
protected String doInBackground(Uri... params) {
File file = null;
int size = -1;
try {
try {
if (returnCursor != null && returnCursor.moveToFirst()){
if (mUri.getScheme() != null)
if (mUri.getScheme().equals("content")) {
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
size = (int) returnCursor.getLong(sizeIndex);
}else if (mUri.getScheme().equals("file")) {
File ff = new File(mUri.getPath());
size = (int) ff.length();
}
}
}
finally {
if (returnCursor != null)
returnCursor.close();
}
pathPlusName = folder + "/" + getFileName(mUri, mContext.get());
file = new File(folder + "/" + getFileName(mUri, mContext.get()));
BufferedInputStream bis = new BufferedInputStream(is);
FileOutputStream fos = new FileOutputStream(file);
byte[] data = new byte[1024];
long total = 0;
int count;
while ((count = bis.read(data)) != -1) {
if (!isCancelled()) {
total += count;
if (size != -1) {
publishProgress((int) ((total * 100) / size));
}
fos.write(data, 0, count);
}
}
fos.flush();
fos.close();
} catch (IOException e) {
errorReason = e.getMessage();
}
return file.getAbsolutePath();
}
private String getFileName(Uri uri, Context context) {
String result = null;
if (uri.getScheme() != null) {
if (uri.getScheme().equals("content")) {
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
}
if (cursor != null) {
cursor.close();
}
}
}
if (result == null) {
result = uri.getPath();
assert result != null;
int cut = result.lastIndexOf('/');
if (cut != -1) {
result = result.substring(cut + 1);
}
}
return result;
}
protected void onPostExecute(String result) {
if(result == null){
callback.onCopyPostExecute(pathPlusName, false, errorReason);
}else {
callback.onCopyPostExecute(pathPlusName, true, "");
}
}
}
在您的Activity 中,您应该执行以下操作:
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class ExampleActivity extends AppCompatActivity implements CallBackTask{
Button someBtn;
Uri someUri = .... //This is just an example, you should provide your own Uri
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
someBtn = findViewById(R.id.someBtn);
someBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
CopyFileAsyncTask asyntask = new CopyFileAsyncTask(someUri, ExampleActivity.this, ExampleActivity.this);
asyntask.execute();
}
});
}
ProgressBar mProgressBar;
TextView percentText;
private AlertDialog mdialog;
@Override
public void onCopyPreExecute() {
final AlertDialog.Builder mPro = new AlertDialog.Builder(new ContextThemeWrapper(this, R.style.myDialog));
@SuppressLint("InflateParams") final View mPView = LayoutInflater.from(this).inflate(R.layout.dailog_layout, null);
percentText = mPView.findViewById(R.id.percentText);
mProgressBar = mPView.findViewById(R.id.mProgressBar);
mProgressBar.setMax(100);
mPro.setView(mPView);
mdialog = mPro.create();
mdialog.show();
}
@Override
public void onCopyProgressUpdate(int progress) {
String progressPlusPercent = progress + "%";
percentText.setText(progressPlusPercent);
mProgressBar.setProgress(progress);
}
@Override
public void onCopyPostExecute(String path, boolean wasSuccessful, String reason) {
if (mdialog != null && mdialog.isShowing()) {
mdialog.cancel();
}
if (wasSuccessful){
Toast.makeText(this, "File was created at - "+path, Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "Error - "+reason, Toast.LENGTH_SHORT).show();
}
}
}
您可以随时取消复制文件,方法是调用:
if (asyntask!=null){
asyntask.cancel(true);
}
如果您想完全按照我的方式实现它并在复制文件时显示ProgressBar,那么这里是我的对话框的布局和样式:
R.style.myDialog:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name="myDialog" parent="Theme.AppCompat.Dialog.Alert">
<item name="android:windowNoTitle">true</item>
<item name="android:background">#fff</item>
<item name="android:windowBackground">@null</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
</resources>
R.layout.dailog_layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:id="@+id/loadContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:padding="20dp">
<RelativeLayout
android:id="@+id/dotRel"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/percentText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginBottom="15dp"
android:text="0 %"
android:textColor="@android:color/black"
android:textSize="25sp" />
<ProgressBar
android:id="@+id/mProgressBar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="5dp"
android:layout_below="@+id/percentText"
android:progressDrawable="@drawable/progressbar" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
这是复制文件时的对话框:
结论:
通过上述方式,您的文件将被复制到/storage/emulated/0/Android/data/yourPackageName/files/Temp/YourFile.jpg。在复制文件时,将显示一个进度对话框,以百分比表示进度(这对于复制大文件很有用)。如果复制文件时出错,原因将在onCopyPostExecute中提供
这将适用于文件和内容 Uri。