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

Для некоторых людей программирование является такой же внутренней потребностью, подобно тому, как коровы дают молоко, или писатели стремятся писать. (с) Николай Безруков

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

Опубликовано
Комментарии 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(); } }

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