Отмена отправки сообщения HTTP на сервер во время записи — Android

Я схожу с ума, пытаясь понять это. Я рассмотрел возможные решения на SO, в том числе используя отделку, убивает процесс, убивая приложение, следующие 5 (1, 2, 3, 4, 5) и многое другое, но, похоже, ни один из них не справился с задачей.

Что я в настоящее время могу сделать:

В настоящее время у меня есть функция, позволяющая открыть пользовательский диалог File Dialog из моего основного приложения. В этом диалоговом окне я выбираю конкретный файл для загрузки на сервер. Сервер — это просто сервер Apache на моем локальном компьютере, который подключен к той же сети Wi-Fi, что и Samsung S4, на котором я запускаю приложение. Я могу выбрать файл для загрузки, который запускает новое действие и показывает диалог прогресса. Предполагая, что сервер, Wi-Fi и телефон правильно подключены друг к другу, файл загружается, как и ожидалось. Этот процесс загрузки файла использует запрос HTTP Post.

Что я пытаюсь сделать:

Я хочу иметь возможность отменить загрузку файла в любой момент, но особенно в середине записи файла на сервер. Это мотивируется тремя основными сценариями: 1) Если файл огромен, загрузка занимает целую вечность, и пользователь хочет остановить загрузку, вернитесь в диалоговое окно «Файл» и выберите другой файл для загрузки, 2) Если пользователь выбрал не тот файл и хочет вернуться в диалог файлов, чтобы выбрать правильный, и 3) Если сервер не подключен должным образом, сообщение HTTP зависает, и пользователь хочет прекратить загрузку файла, а затем вернуться после того, как все правильно подключен.

Что я пробовал до сих пор:

Первым делом я попытался просто отменить диалог прогресса, как показано ниже:

DialogInterface.OnCancelListener onCancelListener = new DialogInterface.OnCancelListener() {

@Override
public void onCancel(DialogInterface dialog) {
finish();
}
};

dialog = ProgressDialog.show(UploadToServer.this, "", "Uploading file...", true, true, onCancelListener);

Это, однако, все еще позволило загрузке завершиться.

Во-вторых, я попытался просто прервать поток загрузки файла (используя Thread.interrupt), но загрузка файла все еще завершена.

Третье, что я попытался, это отключить соединение HttpURLC. Я попробовал это с синхронизацией соответствующих блоков кода и без них, но загрузка файла все еще завершена. Было бы сгенерировано исключение, сообщающее, что сокет был закрыт, но он не генерировался до тех пор, пока не попытался получить код ответа сервера, а не сразу, когда он начал писать, как я ожидал.

Четвертая (и главная) вещь, которую я попытался, — закрыть DataOutputStream при нажатии кнопки «Назад». Я попробовал это с синхронизацией соответствующих блоков кода и без них, но загрузка файла все еще завершена. Однако, если я закрою DataOutputStream до того, как начну запись в буфер на сервере, поток закроется, я получу IOException, и загрузка файла будет успешно отменена. Я не могу понять, как отменить загрузку файла после начала записи данных на сервер.

В других публикациях о SO люди предлагают использовать finish (), System.exit (0), android.os.Process.killProcess (android.os.Process.myPid ()), HttpClient, AsyncTask и множество других вещей, но ни один из них на самом деле не является тем, что я ищу, кроме, возможно, AsyncTask, хотя я все еще не уверен, что это то, что я ищу.

Возможно ли то, что я пытаюсь сделать? У меня есть чувство, что это не может быть …

Я надеюсь, что мой вопрос достаточно ясен и конкретен. Если нет, пожалуйста, дайте мне знать, что я могу уточнить, что я пропустил, а что нет абсолютно никакого смысла! = Р

FileDialog Code:

package com.example.<package_name>;

import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
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.util.Log;

import com.example.<package_name>.ListenerList.FireHandler;
import com.example.<package_name>.utils.UploadToServer;

public class FileDialog extends Activity {
public static boolean cancelled;
private static final String PARENT_DIR = "..";
private final String TAG = getClass().getName();
private String[] fileList;
private File currentPath;

public interface FileSelectedListener {
void fileSelected(File file);
}

public interface DirectorySelectedListener {
void directorySelected(File directory);
}

private ListenerList<FileSelectedListener> fileListenerList = new ListenerList<FileDialog.FileSelectedListener>();
private ListenerList<DirectorySelectedListener> dirListenerList = new ListenerList<FileDialog.DirectorySelectedListener>();
private final Activity activity;
private boolean selectDirectoryOption;
private String fileEndsWith;

/**
* @param activity
* @param initialPath
*/
public FileDialog(Activity activity, File path) {
this.activity = activity;
if (!path.exists())
path = Environment.getExternalStorageDirectory();
loadFileList(path);
}

/**
* @return file dialog
*/
public Dialog createFileDialog() {
Dialog dialog = null;
AlertDialog.Builder builder = new AlertDialog.Builder(activity);

builder.setTitle("Select a file to upload. Current path = "+ currentPath.getPath());
if (selectDirectoryOption) {
builder.setPositiveButton("Select directory",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.d(TAG, currentPath.getPath());
fireDirectorySelectedEvent(currentPath);
}
});
}

builder.setItems(fileList, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
String fileChosen = fileList[which];
File chosenFile = getChosenFile(fileChosen);
cancelled = true;
if (chosenFile.isDirectory()) {
loadFileList(chosenFile);
dialog.cancel();
dialog.dismiss();
showDialog();
} else {
Intent intent = new Intent(activity, UploadToServer.class);
Bundle fileInfo = new Bundle();
fileInfo.putString(
UploadToServer.UPLOAD_FILE_DIRECTORY_KEY,
currentPath.getPath());
fileInfo.putString(UploadToServer.UPLOAD_FILE_NAME_KEY,
chosenFile.getName());
intent.putExtras(fileInfo); // Pass the file info to the
// UploadToServer activity
activity.startActivity(intent);
fireFileSelectedEvent(chosenFile);
}
}
});

dialog = builder.show();
return dialog;
}

public void addFileListener(FileSelectedListener listener) {
fileListenerList.add(listener);
}

public void removeFileListener(FileSelectedListener listener) {
fileListenerList.remove(listener);
}

public void setSelectDirectoryOption(boolean selectDirectoryOption) {
this.selectDirectoryOption = selectDirectoryOption;
}

public void addDirectoryListener(DirectorySelectedListener listener) {
dirListenerList.add(listener);
}

public void removeDirectoryListener(DirectorySelectedListener listener) {
dirListenerList.remove(listener);
}

/**
* Show file dialog
*/
public void showDialog() {
createFileDialog().show();
}

private void fireFileSelectedEvent(final File file) {
fileListenerList
.fireEvent(new FireHandler<FileDialog.FileSelectedListener>() {
@Override
public void fireEvent(FileSelectedListener listener) {
listener.fileSelected(file);
}
});
}

private void fireDirectorySelectedEvent(final File directory) {
dirListenerList
.fireEvent(new FireHandler<FileDialog.DirectorySelectedListener>() {
@Override
public void fireEvent(DirectorySelectedListener listener) {
listener.directorySelected(directory);
}
});
}

private void loadFileList(File path) {
this.currentPath = path;
List<String> r = new ArrayList<String>();
if (path.exists()) {
if (path.getParentFile() != null)
r.add(PARENT_DIR);
FilenameFilter filter = new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
File sel = new File(dir, filename);
if (!sel.canRead())
return false;
if (selectDirectoryOption)
return sel.isDirectory();
else {
boolean endsWith = fileEndsWith != null ? filename
.toLowerCase().endsWith(fileEndsWith) : true;
return endsWith || sel.isDirectory();
}
}
};
String[] fileList1 = path.list(filter);
for (String file : fileList1) {
r.add(file);
}
}
fileList = (String[]) r.toArray(new String[] {});
}

private File getChosenFile(String fileChosen) {
if (fileChosen.equals(PARENT_DIR))
return currentPath.getParentFile();
else
return new File(currentPath, fileChosen);
}

public void setFileEndsWith(String fileEndsWith) {
this.fileEndsWith = fileEndsWith != null ? fileEndsWith.toLowerCase()
: fileEndsWith;
}
}

class ListenerList<L> {
private List<L> listenerList = new ArrayList<L>();

public interface FireHandler<L> {
void fireEvent(L listener);
}

public void add(L listener) {
listenerList.add(listener);
}

public void fireEvent(FireHandler<L> fireHandler) {
List<L> copy = new ArrayList<L>(listenerList);
for (L l : copy) {
fireHandler.fireEvent(l);
}
}

public void remove(L listener) {
listenerList.remove(listener);
}

public List<L> getListenerList() {
return listenerList;
}
}

Код UploadToServer:

package com.example.<package_name>.utils;

import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.example.<package_name>.FileDialog;
import com.example.<package_name>.R;

public class UploadToServer extends Activity {

/**
* The key for the upload file path value passed through the start-up
* intent.
*/
public static final String UPLOAD_FILE_DIRECTORY_KEY = "UploadToServer.uploadFileDirectory";
/**
* The key for the upload file name value passed through the start-up
* intent.
*/
public static final String UPLOAD_FILE_NAME_KEY = "UploadToServer.uploadFileName";

TextView messageText;
Button uploadButton;
int serverResponseCode = 0;
ProgressDialog dialog = null;

String upLoadServerUri = null;

private String uploadFileDirectory;
private String uploadFileName;

private FileUploadRunnable fileUploadRunnable;

@Override
public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_upload_to_server);

Bundle fileInfo = getIntent().getExtras();
uploadFileDirectory = fileInfo.getString(UPLOAD_FILE_DIRECTORY_KEY);
uploadFileName = fileInfo.getString(UPLOAD_FILE_NAME_KEY);

messageText = (TextView) findViewById(R.id.messageText);

messageText.setText("Uploading file path :- " + uploadFileDirectory
+ "/" + uploadFileName);

/************* Php script path ****************/
upLoadServerUri = "http://<server_ip>/UploadToServer.php";

DialogInterface.OnCancelListener onCancelListener = new DialogInterface.OnCancelListener() {

@Override
public void onCancel(DialogInterface dialog) {
finish();
}
};

dialog = ProgressDialog.show(UploadToServer.this, "",
"Uploading file...", true, true, onCancelListener);

messageText.setText("uploading started.....");

fileUploadRunnable = new FileUploadRunnable(uploadFileDirectory,
uploadFileName);

new Thread(fileUploadRunnable).start();
}

@Override
public void onBackPressed() {
if (fileUploadRunnable != null) {
fileUploadRunnable.cancelUpload();
}
super.onBackPressed();
}

private class FileUploadRunnable implements Runnable {

private final String uploadFileDirectory;
private final String uploadFileName;
private HttpURLConnection conn;
private final Object dosLock;
private boolean doUpload;
DataOutputStream dos;

public FileUploadRunnable(String uploadFileDirectory,
String uploadFileName) {
this.uploadFileDirectory = uploadFileDirectory;
this.uploadFileName = uploadFileName;
conn = null;
Lock = new Object();
doUpload = true;
dos = null;
}

@Override
public void run() {
uploadFile(uploadFileDirectory + "/" + uploadFileName);
}

/**
* cancel the current upload
*/
public void cancelUpload() {
synchronized (dosLock) {
if (dos != null) {
try {
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
doUpload = false;
}
}

private void uploadFile(String sourceFileUri) {

String fileName = sourceFileUri;
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 1 * 1024 * 1024;
File sourceFile = new File(sourceFileUri);

if (!sourceFile.isFile()) {

dialog.dismiss();

Log.e("uploadFile", "Source File not exist :"+ uploadFileDirectory + uploadFileName);

runOnUiThread(new Runnable() {
public void run() {
messageText.setText("Source File not exist :"+ uploadFileDirectory + uploadFileName);
}
});

return;

} else {
try {
// open a URL connection to the Servlet
URL url = new URL(upLoadServerUri);

// Open a HTTP connection to the URL
conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true); // Allow Inputs
conn.setDoOutput(true); // Allow Outputs
conn.setUseCaches(false); // Don't use a Cached Copy
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("ENCTYPE", "multipart/form-data");
conn.setRequestProperty("Content-Type",
"multipart/form-data;boundary=" + boundary);
conn.setRequestProperty("uploaded_file", fileName);

synchronized (dosLock) {

if (!doUpload) {
return;
}

dos = new DataOutputStream(conn.getOutputStream());

dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"uploaded_file\";filename=\""+ fileName + "\"" + lineEnd);

dos.writeBytes(lineEnd);

} // end synchronization block

FileInputStream fileInputStream = new FileInputStream(
sourceFile);

// create a buffer of maximum size
bytesAvailable = fileInputStream.available();

bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];

// read file and write it into form...
bytesRead = fileInputStream.read(buffer, 0, bufferSize);

while (bytesRead > 0) {

synchronized (dosLock) {
dos.write(buffer, 0, bufferSize);
bytesAvailable = fileInputStream.available();
bufferSize = Math
.min(bytesAvailable, maxBufferSize);
bytesRead = fileInputStream.read(buffer, 0,
bufferSize);
}
}

// send multipart form data necesssary after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

// Responses from the server (code and message)
serverResponseCode = conn.getResponseCode();
String serverResponseMessage = conn.getResponseMessage();

Log.i("uploadFile", "HTTP Response is : "+ serverResponseMessage + ": " + serverResponseCode);

if (serverResponseCode == 200) {

runOnUiThread(new Runnable() {
public void run() {

String msg = "File Upload Completed.\n\n See uploaded file here : \n\n"+ " http://www.androidexample.com/media/uploads/"+ uploadFileName;

messageText.setText(msg);
Toast.makeText(UploadToServer.this,
"File Upload Complete.",
Toast.LENGTH_SHORT).show();
}
});
}

// close the streams //
fileInputStream.close();
dos.flush();
dos.close();

} catch (MalformedURLException ex) {

dialog.dismiss();
ex.printStackTrace();

runOnUiThread(new Runnable() {
public void run() {
messageText
.setText("MalformedURLException Exception : check script url.");
Toast.makeText(UploadToServer.this,
"MalformedURLException", Toast.LENGTH_SHORT)
.show();
}
});

Log.e("Upload file to server", "error: " + ex.getMessage(),
ex);
} catch (IOException e) {
// TODO if doUpload is false here, then this is expected, so pop-up a toast.
// TODO if doUpload is true here, then this is NOT expected, so open an error dialog.

} catch (Exception e) {
// TODO this is for unexpected exceptions, so open an error dialog.

dialog.dismiss();
e.printStackTrace();

runOnUiThread(new Runnable() {
public void run() {
messageText.setText("Got Exception : see logcat ");
Toast.makeText(UploadToServer.this,
"Got Exception : see logcat ",
Toast.LENGTH_SHORT).show();
}
});
Log.e("Upload file to server Exception",
"Exception : " + e.getMessage(), e);
}
dialog.dismiss();

} // End else block
}
}
}

Код сервера:

UploadToServer.php

<?php

$file_directory = 'uploads/';
$file_name = 'configuration.xml';
$file_path = $file_directory . $file_name;
if(move_uploaded_file($_FILES['uploaded_file']['tmp_name'], $file_path)) {
echo "success";
} else{
echo "fail";
}
?>

Мой код адаптирован из эта кодовая база.

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]