Статьи

Firebase для Android: Хранение файлов

Во время конференции Google I / O 2016 года Firebase была вновь представлена ​​сообществу разработчиков как основной инструмент для обеспечения быстрой внутренней поддержки веб-страниц и мобильных приложений. Этот учебник познакомит вас с функциями хранения и поиска файлов, доступными для ваших приложений Android.

Чтобы узнать больше о базе данных Firebase в реальном времени, аналитике, отчетах о сбоях и аутентификации, ознакомьтесь с некоторыми другими нашими учебными пособиями здесь, на Envato Tuts + .

Для краткости мы пропустим общий процесс установки Firebase в вашем приложении для Android и консоли Firebase. Если вы впервые пробуете Firebase в приложении, я советую сначала прочитать статью Ашрафа Хатибелагала « Начало работы с Firebase для Android» .

  • Android SDK
    Начните с Firebase для Android
    Ашраф Хатхибелагал

Прежде чем вы сможете начать использовать Firebase Storage, вам нужно будет либо удостовериться, что ваш пользователь аутентифицирован, либо изменить правила требования аутентификации в консоли Firebase, чтобы позволить неаутентифицированным пользователям получать доступ и загружать файлы. Для простоты мы сделаем последнее. Давайте начнем с перехода в раздел «Хранилище» Firebase, выбрав « Хранилище» в левой колонке навигации.

Навигация по разделу хранилища Firebase

Далее вы увидите две вкладки вверху экрана « Хранилище» : « Файлы и правила» .

Вкладка «Правила» в хранилище Firebase

Выберите вкладку « Правила » и в строке allow read, write: if request.auth != null; , измените != на == и нажмите кнопку ОПУБЛИКОВАТЬ .

Правила аутентификации для доступа к хранилищу Firebase

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

Хотя возможность загружать файлы из приложения великолепна, иногда вам просто нужно хранить файлы где-нибудь, к чему можно легко получить доступ и вставить в ваше приложение. Это где возможность загружать файлы вручную из консоли Firebase вступает в игру. На вкладке « Файлы » вы увидите синюю кнопку « Загрузить файл» .

Кнопка для ручной загрузки файлов в хранилище Firebase

Нажмите на него и выберите файл, который вы хотите загрузить, и он появится в вашем хранилище Firebase.

Загруженный файл

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

Сведения о загруженном файле

Теперь, когда у вас есть файл, сохраненный в Firebase, давайте продолжим и запустим его в приложение. Мы будем использовать простой макет в нашей MainActivity который содержит ImageView с id изображения.

01
02
03
04
05
06
07
08
09
10
<?xml version=»1.0″ encoding=»utf-8″?>
<RelativeLayout xmlns:android=»http://schemas.android.com/apk/res/android»
    android:layout_width=»match_parent»
    android:layout_height=»match_parent»>
 
    <ImageView
        android:id=»@+id/image»
        android:layout_width=»wrap_content»
        android:layout_height=»wrap_content» />
</RelativeLayout>

Чтобы получить доступ к файлам Firebase Storage, вам сначала нужно получить ссылку на объект FirebaseStorage , а затем создать StorageReference на StorageReference на URL вашего проекта и файл, который вы хотите загрузить. URL-адрес вашего проекта можно найти в верхней части раздела « Файлы » хранилища в консоли Firebase.

1
2
FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference storageRef = storage.getReferenceFromUrl(«gs://tutsplus-firebase.appspot.com»).child(«android.jpg»);

Затем вы можете создать объект File и попытаться загрузить StorageReference файл, вызвав getFile в StorageReference с новым объектом File переданным в качестве параметра. Поскольку эта операция происходит асинхронно, вы можете добавить OnSuccessListener и OnFailureListener к вашему вызову для обработки любого непредвиденного обстоятельства.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
try {
    final File localFile = File.createTempFile(«images», «jpg»);
    storageRef.getFile(localFile).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
        @Override
        public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
            Bitmap bitmap = BitmapFactory.decodeFile(localFile.getAbsolutePath());
            mImageView.setImageBitmap(bitmap);
 
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception exception) {
        }
    });
} catch (IOException e ) {}

В onSuccess() из OnSuccessListener вы можете взять объект FileDownloadTask.TaskSnapshot и извлечь файл, в котором мы будем устанавливать изображение для нашего ImageView .

Изображение, загруженное из хранилища Firebase, отображается в приложении

Если вам нужно только загрузить файл как byte[] и не нужно его как файл, что является более вероятным случаем при загрузке изображения в ImageView , то вы можете извлечь байты аналогичным образом.

1
2
3
4
5
6
7
8
final long ONE_MEGABYTE = 1024 * 1024;
storageRef.getBytes(ONE_MEGABYTE).addOnSuccessListener(new OnSuccessListener<byte[]>() {
    @Override
    public void onSuccess(byte[] bytes) {
        Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        mImageView.setImageBitmap(bitmap);
    }
});

Могут быть ситуации, когда вам не нужны фактические данные для сохраненного файла, а скорее вам понадобится URL. Вы можете сделать это аналогично последним двум примерам, используя метод getDownloadUrl() в StorageReference , который даст вам Uri указывающий на местоположение файла.

1
2
3
4
5
6
7
storageRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
    @Override
    public void onSuccess(Uri uri) {
        Log.e(«Tuts+», «uri: » + uri.toString());
        //Handle whatever you’re going to do with the URL here
    }
});

Приведенный выше метод распечатает URL-адрес изображения, которое мы вручную загрузили ранее в Android Monitor.

1
E/Tuts+: uri: https://firebasestorage.googleapis.com/v0/b/tutsplus-firebase.appspot.com/o/android.jpg?alt=media&token=1828111c-78e7-4640-b418-c65e7571576a

Теперь, когда вы знаете, как загружать файлы из Firebase, пришло время поработать над загрузкой. Как вы видели при загрузке из Firebase Storage, процессы для каждой формы ваших данных довольно схожи. Загрузка ничем не отличается, поэтому мы просто погрузимся в то, как вы можете перемещать файлы из своего приложения в Firebase Storage.

Как и при загрузке, вам необходимо получить ссылку на объект FirebaseStorage и создать ссылку на место хранения вашего нового файла в качестве StorageReference . Для этого примера мы покажем ic_launcher.png в нашем ImageView , а затем загрузим его в виде массива байтов.

1
2
FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference storageReference = storage.getReferenceFromUrl(«gs://tutsplus-firebase.appspot.com»).child(«ic_launcher.png»);

Далее нам нужно получить байтовый массив из изображения, хранящегося в памяти через ImageView . Это делается путем извлечения его как Bitmap , сжатия его в ByteArrayOutputStream , а затем превращения его в byte[] .

1
2
3
4
5
6
7
8
9
mImageView.setDrawingCacheEnabled(true);
mImageView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
mImageView.layout(0, 0, mImageView.getMeasuredWidth(), mImageView.getMeasuredHeight());
mImageView.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(mImageView.getDrawingCache());
 
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
byte[] data = outputStream.toByteArray();

Наконец, вы можете создать UploadTask , вызвав putBytes(byte[]) чтобы загрузить изображение в Firebase. С этой UploadTask также могут быть OnSuccessListener и OnFailureListener .

01
02
03
04
05
06
07
08
09
10
UploadTask uploadTask = storageReference.putBytes(data);
uploadTask.addOnFailureListener(new OnFailureListener() {
    @Override
    public void onFailure(@NonNull Exception exception) {
    }
}).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
    }
});

Когда вы проверяете страницу хранилища Firebase Console, вы должны увидеть ic_launcher.png в вашем списке файлов.

Детали из программно загруженного изображения

Теперь, когда вы знаете, как загрузить массив байтов, два других типа загрузки должны быть достаточно интуитивно понятными. Допустим, у нас есть текстовый файл с именем test.txt в нашей папке сырых ресурсов. Мы можем прочитать это в InputStream и затем загрузить его с помощью putStream(InputStream) из StorageReference .

1
2
3
4
5
6
FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference storageReference = storage.getReferenceFromUrl(«gs://tutsplus-firebase.appspot.com»).child(«test.txt»);
 
InputStream stream = getResources().openRawResource(R.raw.test);
 
UploadTask uploadTask = storageReference.putStream(stream);
Список загруженных изображений, включая текстовый файл из InputStream

Загрузка существующего файла так же проста: просто получите ссылку на файл и вызовите putFile(Uri) с URI, указывающим на ваш файл. Для этого примера мы просто создадим пустой временный файл в нашем коде.

01
02
03
04
05
06
07
08
09
10
FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference storageReference = storage.getReferenceFromUrl(«gs://tutsplus-firebase.appspot.com»).child(«test2.txt»);
 
File file = null;
try {
    file = File.createTempFile(«test2», «txt»);
} catch( IOException e ) {
 
}
UploadTask uploadTask = storageReference.putFile(Uri.fromFile(file));
Загрузка необработанных файлов в хранилище Firebase

Несмотря на то, что файлы, которые мы загрузили до сих пор, были небольшими, в некоторых случаях вы можете загружать файлы большего размера, что займет достаточно много времени. Firebase предоставляет несколько методов с UploadTask , которые позволят вам контролировать процесс загрузки и прослушивать прогресс и изменения состояния. Эти методы включают pause() , resume() и cancel() . pause() и resume() позволят вам приостановить и возобновить UploadTask , тогда как cancel() полностью остановит его. Кроме того, вы можете использовать OnPauseListener и OnProgressListener чтобы отслеживать ход загрузки и состояния паузы.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
mPause = (Button) findViewById(R.id.pause);
mResume = (Button) findViewById(R.id.resume);
 
mPause.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        mUploadTask.pause();
    }
});
 
mResume.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        mUploadTask.resume();
    }
});
 
 
FirebaseStorage storage = FirebaseStorage.getInstance();
StorageReference storageReference = storage.getReferenceFromUrl(«gs://tutsplus-firebase.appspot.com»).child(«image.jpg»);
 
InputStream stream = getResources().openRawResource(R.raw.image);
 
mUploadTask = storageReference.putStream(stream);
 
mUploadTask.addOnPausedListener(new OnPausedListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onPaused(UploadTask.TaskSnapshot taskSnapshot) {
        Log.e(«Tuts+», «upload paused!»);
    }
});
 
mUploadTask.addOnProgressListener(new OnProgressListener<UploadTask.TaskSnapshot>() {
    @Override
    public void onProgress(UploadTask.TaskSnapshot taskSnapshot) {
        Log.e(«Tuts+», «Bytes uploaded: » + taskSnapshot.getBytesTransferred());
    }
});

Приведенный выше код позволит вам контролировать процесс загрузки для довольно большого (в данном случае 1 МБ) изображения и видеть, как его состояния изменяются в журнале Android при нажатии кнопок паузы и возобновления.

1
2
3
E/Tuts+: Bytes uploaded: 524288
E/Tuts+: upload paused!
E/Tuts+: Bytes uploaded: 786432

Как может засвидетельствовать любой разработчик Android, иногда жизненный цикл активности Android может вызывать непредвиденные проблемы. Одним из распространенных источников проблем являются прослушиватели, которые длятся дольше, чем их родительская Activity , что может иметь место в случае прослушивателей успеха / неудач, подключенных к задаче хранения Firebase.

Если действие уничтожается и воссоздается (например, при повороте экрана) во время выполнения задачи, вы можете получить NullPointerException завершении задачи. Чтобы избежать этого, вам нужно сохранить StorageReference в виде String в вашем Bundle состояния out в onSaveInstanceState(Bundle) , а затем извлечь его и добавить прослушиватели успеха в каждый FileDownloadTask или FileUploadTask связанный с этим StorageReference .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
 
    if (mStorageReference != null) {
        outState.putString(EXTRA_STORAGE_REFERENCE_KEY, mStorageReference.toString());
    }
}
 
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
 
    final String stringRef = savedInstanceState.getString(EXTRA_STORAGE_REFERENCE_KEY);
 
    if (stringRef == null) {
        return;
    }
 
    mStorageReference = FirebaseStorage.getInstance().getReferenceFromUrl(stringRef);
    List<FileDownloadTask> tasks = mStorageReference.getActiveDownloadTasks();
    for( FileDownloadTask task : tasks ) {
        task.addOnSuccessListener(this, new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
            @Override
            public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
                Log.e(«Tuts+», «download successful!»);
            }
        });
    }
}

В этом уроке вы много узнали о Firebase и его доступных опциях для хранения файлов. Теперь вы сможете загружать и скачивать файлы, контролировать передачу данных и обрабатывать изменения жизненного цикла вашего приложения во время выполнения транзакции.

Несмотря на то, что мы только что коснулись того, что вы можете делать в Firebase, понимание этого инструмента, мы надеемся, позволит вам расширить возможности ваших собственных приложений и предоставит пользователям отличный опыт.

А пока, ознакомьтесь с некоторыми другими нашими статьями по разработке Android!

  • Начало работы Создание приложения для проектирования материалов

  • Фоновое аудио в Android с MediaSessionCompat

  • Как начать работу с шаблоном приложения для Android

  • Что нового в Android Studio 2.2?