среда, 1 июля 2015 г.

Меню

Ruby On Rails

Linux


Android


AngularJS

Android. Get absolute path of image

Во многих Android приложениях требуется работа с изображениями, будь то выбор фото из галереи или съемка с помощью камеры. Зачастую, после выполнения этих действий необходимо манипулировать файлом изображения, записанным в память телефона.

В каждом из этих случаев путь к изображению можно получить из Intent, переданный в метод onActivityResult:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    Uri imagePath = data.getData();
}

Однако если вы захотите использовать этот путь для доступа к файлу, у вас ничего не получится.

Решение

Чтобы получить абсолютный путь к файлу в памяти телефона, воспользуйтесь этим методом:

private String getImagePath(Intent data) {
    Uri path = data.getData();

    String[] filePathColumn = { MediaStore.Images.Media.DATA };

    Cursor cursor = getActivity().getContentResolver().query(path,
            filePathColumn, null, null, null);
    cursor.moveToFirst();

    int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
    String picturePath = cursor.getString(columnIndex);
    cursor.close();

    return picturePath;
}



Android. Upload file to server.

Многие мобильные приложения оперируют изображениями и другими файлами, которые нужно отправлять на сервер. В системе Android это не является тривиальной задачей.

Общая теория и проблемы


Обычно для отправки файлов на сервер используется POST запрос протокола HTTP с типом содержимого multipart/form-data.

Сообщение такого типа состоит из нескольких частей, каждая из которых представляет собой содержимое некоторого элемента формы. Каждый элемент имеет заголовок, в котором указано имя элемента и тип контента. Передаваемый файл является одним их таких элементов.

Данный тип запроса используется и для передачи файлов с Android устройств. Однако Android не умеет создавать данные для передачи такого запроса в отличие от веб браузеров. Это приходится делать вручную.

В сети существуют библиотеки для формирования multipart запросов, однако они очень сложны в установке, что не стоит потраченного времени.


Реализация


Приведу сразу весь класс для загрузки изображений с комментариями. Класс представляет из себя AsyncTask, в котором выполняется POST запрос с типом содержимого multipart. Передаваемый файл записывается как один элемент multipart запроса.

/**
 * Загружает файл на сервер
 */
public class FilesUploadingTask extends AsyncTask<Void, Void, String> {

    // Конец строки
    private String lineEnd = "\r\n";
    // Два тире
    private String twoHyphens = "--";
    // Разделитель
    private String boundary =  "----WebKitFormBoundary9xFB2hiUhzqbBQ4M";

    // Переменные для считывания файла в оперативную память
    private int bytesRead, bytesAvailable, bufferSize;
    private byte[] buffer;
    private int maxBufferSize = 1*1024*1024;

    // Путь к файлу в памяти устройства
    private String filePath;

    // Адрес метода api для загрузки файла на сервер
    public static final String API_FILES_UPLOADING_PATH = "127.0.0.1/upload";

    // Ключ, под которым файл передается на сервер
    public static final String FORM_FILE_NAME = "file1";

    public FilesUploadingTask(String filePath) {
        this.filePath = filePath;
    }

    @Override
    protected String doInBackground(Void... params) {
        // Результат выполнения запроса, полученный от сервера
        String result = null;

        try {
            // Создание ссылки для отправки файла
            URL uploadUrl = new URL(API_FILES_UPLOADING_PATH);

            // Создание соединения для отправки файла
            HttpURLConnection connection = (HttpURLConnection) uploadUrl.openConnection();

            // Разрешение ввода соединению
            connection.setDoInput(true);
            // Разрешение вывода соединению
            connection.setDoOutput(true);
            // Отключение кеширования
            connection.setUseCaches(false);

            // Задание запросу типа POST
            connection.setRequestMethod("POST");

            // Задание необходимых свойств запросу
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);

            // Создание потока для записи в соединение
            DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());

            // Формирование multipart контента

            // Начало контента
            outputStream.writeBytes(twoHyphens + boundary + lineEnd);
            // Заголовок элемента формы
            outputStream.writeBytes("Content-Disposition: form-data; name=\"" +
                    FORM_FILE_NAME + "\"; filename=\"" + filePath + "\"" + lineEnd);
            // Тип данных элемента формы
            outputStream.writeBytes("Content-Type: image/jpeg" + lineEnd);
            // Конец заголовка
            outputStream.writeBytes(lineEnd);

            // Поток для считывания файла в оперативную память
            FileInputStream fileInputStream = new FileInputStream(new File(filePath));

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

            // Считывание файла в оперативную память и запись его в соединение
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);

            while (bytesRead > 0) {
                outputStream.write(buffer, 0, bufferSize);
                bytesAvailable = fileInputStream.available();
                bufferSize = Math.min(bytesAvailable, maxBufferSize);
                bytesRead = fileInputStream.read(buffer, 0, bufferSize);
            }

            // Конец элемента формы
            outputStream.writeBytes(lineEnd);
            outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

            // Получение ответа от сервера
            int serverResponseCode = connection.getResponseCode();

            // Закрытие соединений и потоков
            fileInputStream.close();
            outputStream.flush();
            outputStream.close();

            // Считка ответа от сервера в зависимости от успеха
            if(serverResponseCode == 200) {
                result = readStream(connection.getInputStream());
            } else {
                result = readStream(connection.getErrorStream());
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }

    // Считка потока в строку
    public static String readStream(InputStream inputStream) throws IOException {
        StringBuffer buffer = new StringBuffer();
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

        String line;
        while ((line = reader.readLine()) != null) {
            buffer.append(line);
        }

        return buffer.toString();
    }
}

Использование


Чтобы загрузить файл на сервер, запустите выполнение AsyncTask:

new FilesUploadingTask(filePath).execute();