КОТ++
Прикладное программирование
Системное программирование
Программирование микроконтроллеров

640 Кб должно хватить для любых задач. (c) Билл Гейтс

Поиск по тегам

Опубликовано
Комментарии 0

Давно не прогал под андроид, и вот опять. Говорил я уже или нет, но дико не люблю разработку под android, потому что с появлением новых версий андроида мы получаем несовместимость старых уже опробованных функций, а версии обновляются чаще чем пишутся статьи и туториалы. А если ещё добавить к этому уравнению обилие китайских прошивок, в которых поведение системы не так предсказуемо как в официальных, то при разработке на android вместо написания приложения приходится заниматься исследованиями того, какие функции работают иначе на различных прошивках.

В этой статье как уже было ясно, я бы хотел поговорить о создании файлов на android. И так, андроид предлагает нам два способа записи: на внутреннюю память и на внешнюю. Для записи на внутреннюю нам не нужны никакие разрешения, мы просто должны записать в:

context.getDataDir()
– этот метод вернёт скрытую директорию приложения, то есть файлы потом будут доступны только приложению, которое их записало. Хорошо, безопасность и всё такое, но, а что если нужно записать в галерею или документы, или просто в какое-то общее хранилище? Тогда мы должны писать во внешнюю помять и просить разрешения WRITE_EXTERNAL_STORAGE. В некоторых туториалах пишут, что это разрешение для записи на sd карту, но если следовать здравому смыслу, то под external понимается память, которая не internal, а internal – это память, которая доступна только одному приложению, которое и пишет эти файлы. То есть external – это не то внешнее что на sd карте, а то внешнее что доступно всем, то есть общее хранилище, которое нам и нужно. К слову, в Android Q уже не нужно это разрешение и там «гении» из гугла придумали что-то новое для разработчиков.

Добавляем разрешение, пишем код для записи в файл, но не работает. Ах да, с Android 6.0 у нас же появились runtime разрешения, и для записи во внешнее хранилище нужно запросить разрешение прямо из кода. Пишем:

//проверяем принято ли данное разрешение
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
{   
        //запрашиваем разрешение у пользователя
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
}

Ага круто, теперь то мы действительно можем записывать файлы. Пишем:
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
File file = new File(path, FILE_NAME);
FileWriter fileWriter = new FileWriter(file, true);
fileWriter.append(data);
fileWriter.flush();
fileWriter.close();

Проверяем на телефоне, файл есть, так теперь подключаем телефон к компьютеру и ищем наш файл. Файла нет, класс! Windows не видит файл или android не даёт увидеть файл? Ну, конечно, виноват android, кто же ещё. Смысл в том, что android должен просканить media, найти новый файл и тогда каким-то чудом он покажет файл винде. Делается это так:
MediaScannerConnection.scanFile(context, new String[]{filePath}, null, null);

Таким образом мы заставляем андроид просканить медиа и показать файл в windows. К слову при перезаписи файла, надо снова выполнять метод scanFile, иначе windows не видит изменений. Но, конечно, вышесказанное справедливо только для windows 7, на windows 10 я не проверял, а linux вероятно всего и так всё увидит, но линуксом не пользуются рядовые пользователи, поэтому обсуждать тут это не буду.

На этом всё, я думаю в статью ещё есть что добавить, поэтому если есть неясные моменты на данную тему, то спрашивайте в комментариях.

Теги , , ,
Автор

Опубликовано
Комментарии 0

Разрабатывая одно приложение наткнулся на ошибку в переводе времени из одного часового пояса в другой.
Требовалось написать функцию перевода из текущей тайм зоны в тайм зону Москвы.

Получилась такая функция:

public Date getMskDateTime(Date d)
{ SimpleDateFormat dateFormatGmt = new SimpleDateFormat(«yyyy-MMM-dd HH:mm:ss»); dateFormatGmt.setTimeZone(TimeZone.getTimeZone(«GMT+3»));

SimpleDateFormat dateFormatLocal = new SimpleDateFormat(«yyyy-MMM-dd HH:mm:ss»); TimeZone tz = TimeZone.getDefault(); dateFormatLocal.setTimeZone(tz); try { return dateFormatLocal.parse(dateFormatGmt.format(d)); } catch (ParseException e) { return new Date(); } }

После были замечены баги, время переводится не всегда верно.
Проверяю у себя (моё локальное GMT+5) всё отлично работает, у другого же человека, у которого локальное GMT+6, время переводится неверно.
Перевожу у себя на GMT+6 и выявляю ту же ошибку. Перевожу на GMT+7 и опять всё верно переводит.
Т.е. при переводе на GMT+3: GMT+5 переводит на 2 часа, GMT+6 переводит опять на 2 часа (должен на 3), GMT+7 переводит на 4 часа как и должен.
Чудеса!
Ставлю у себя GMT+6. Вывожу то, что хранится в TimeZone.getDefault(). Вижу GMT+6.
Принудительно ставлю GMT+6 вместо default:

TimeZone.getTimeZone(«GMT+6»);

И всё снова верно работает. МАГИЯ!
Думаю, что это баг андроида. Тестил на своём 4.4.

Решил прикрутить небольшой костыль, чтобы избавиться от проблемы.
В итоге решение выглядит так:

public Date getMskDateTime(Date d)
{ SimpleDateFormat dateFormatGmt = new SimpleDateFormat(«yyyy-MMM-dd HH:mm:ss»); dateFormatGmt.setTimeZone(TimeZone.getTimeZone(«GMT+3»));

SimpleDateFormat dateFormatLocal = new SimpleDateFormat(«yyyy-MMM-dd HH:mm:ss»); TimeZone tz = TimeZone.getDefault(); long hours = TimeUnit.MILLISECONDS.toHours(tz.getRawOffset()); long minutes = TimeUnit.MILLISECONDS.toMinutes(tz.getRawOffset()) – TimeUnit.HOURS.toMinutes(hours); minutes = Math.abs(minutes); tz = TimeZone.getTimeZone(String.format(«GMT+%d:%02d», hours, minutes)); dateFormatLocal.setTimeZone(tz); try { return dateFormatLocal.parse(dateFormatGmt.format(d)); } catch (ParseException e) { return new Date(); } }

Теги , , ,
Автор