Действительно ли это является дорогостоящим, чтобы сделать array.length или list.count в цикле

Начиная с API 19 (KitKat) почти невозможно напрямую записать содержимое SDcard как простое File, потому что они смонтированы как ТОЛЬКО ЧТЕНИЕ, по крайней мере, для пользователя по умолчанию (система все еще может писать в него).

DocumentsProvider API довольно запутанный (даже образец в документах трудно читаемый), поэтому было добавлено DocumentFile для имитации поведения File для более легкого доступа.

Предполагая, что пользователь уже предоставил разрешения на чтение / запись для хранения, нам нужно получить URI документа корневого каталога SDcard (в Activity):

var sdCardUri : Uri? = null

private fun requestSDCardPermissions(){
    if(Build.VERSION.SDK_INT < 24){
        startActivityForResult(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), REQ_PICK_DIRECTORY)
        return
    }
    // find removable device using getStorageVolumes
    val sm = getSystemService(Context.STORAGE_SERVICE) as StorageManager
    val sdCard = sm.storageVolumes.find { it.isRemovable }
    if(sdCard != null){
        startActivityForResult(sdCard.createAccessIntent(null), REQ_SD_CARD_ACCESS)
    }
}

Перед тем, как пользователю API 24 нужно открыть средство выбора документов и вручную выберите SD-карту сами. Это не идеально, но команда Android упустила из виду тот факт, что отсутствует API SD-карт.

В более новой версии getStorageVolumes() позволяет нам находить SD-карту через код и отображать только явное предупреждение пользователю о том, что к нему будет произведен доступ. Это НЕ тот же диалог, что и у разрешения на чтение / запись.

Теперь для обработки полученного Uri нам нужно только взять data.data результата. Это может быть хорошим местом для сохранения его в общих настройках, чтобы не просить пользователя снова и снова:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    if(requestCode == REQ_SD_CARD_ACCESS || requestCode == REQ_PICK_DIRECTORY){
        if(resultCode == RESULT_OK) {
            if(data == null){
                Log.e(TAG, "Error obtaining access")
            }else{
                sdCardUri = data.data
                Log.d("StorageAccess", "obtained access to $sdCardUri")
                // optionally store uri in preferences as well here { ... }
            }
        }else
            Toast.makeText(this, "access denied", Toast.LENGTH_SHORT).show()
        return
    }
    super.onActivityResult(requestCode, resultCode, data)
}

Я пропущу большинство проверок ошибок / проверок существующих файлов, но теперь вы можете использовать полученные sdCardUri ] вот так (копирование файла «sample.txt» из корня внутреннего хранилища в корень SDcard):

private fun copyToSDCard(){
    val sdCardRoot = DocumentFile.fromTreeUri(this, sdCardUri)
    val internalFile = File(Environment.getExternalStorageDirectory(), "sample.txt")
    // get or create file
    val sdCardFile = sdCardRoot.findFile("sample.txt") ?: sdCardRoot.createFile(null, "sample.txt")
    val outStream = contentResolver.openOutputStream(sdCardFile.uri)
    outStream.write(internalFile.readBytes())
    outStream.flush()
    outStream.close()
    Toast.makeText(this, "copied to SDCard", Toast.LENGTH_SHORT).show()
}

И наоборот (из SDcard во внутреннее хранилище):

private fun copyToInternal(){
    val sdCardRoot = DocumentFile.fromTreeUri(this, sdCardUri)
    val internalFile = File(Environment.getExternalStorageDirectory(), "sample.txt")
    val sdCardFile = sdCardRoot.findFile("sample.txt")
    val inStream = contentResolver.openInputStream(sdCardFile.uri)
    internalFile.writeBytes(inStream.readBytes())
    inStream.close()
    Toast.makeText(this, "copied to internal", Toast.LENGTH_SHORT).show()
}

20
задан Konrad Rudolph 4 November 2008 в 18:57
поделиться

6 ответов

Это не дорогостоящее в C#. С одной стороны, нет никакого “calculation“: запросы длины являются в основном элементарной операцией благодаря встраиванию. И во-вторых, потому что ( по словам его разработчиков ), компилятор распознает этот шаблон доступа и на самом деле оптимизирует любые (избыточные) граничные проверки на доступ на элементах массива.

И между прочим, я полагаю, что что-то подобное верно для современных виртуальных машин JavaScript, и если это уже не будет, то это будет очень скоро, так как это - тривиальная оптимизация.

29
ответ дан 30 November 2019 в 00:05
поделиться
  1. Все массивы .NET имеют поле, содержащее длину массива, таким образом, длина не вычисляется при использовании, но во время создания.

  2. виртуальная машина .NET очень хороша в устранении граничных проверок, когда это возможно, это - один из тех случаев, куда граничная проверка перемещена вне цикла (в большинстве ситуаций, и если не это - всего 2 инструкции наверху).

Редактирование:

Устранение Граничной проверки Массива

5
ответ дан 30 November 2019 в 00:05
поделиться

Я верю, используете ли Вы количество Linq () дополнительный метод, затем это может вычислить каждый раз, когда это называют.

0
ответ дан 30 November 2019 в 00:05
поделиться

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

0
ответ дан 30 November 2019 в 00:05
поделиться

Почти на любом языке ответ будет, "он зависит".

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

Это вряд ли будет определено спецификацией языка, все же.

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

, Но остерегаются других потоков...

3
ответ дан 30 November 2019 в 00:05
поделиться

Если это - что-нибудь как Java, это должен быть O (1) операция.

я нашел следующую ссылку полезной: http://www.devguru.com/Technologies/Ecmascript/Quickref/array.html

0
ответ дан 30 November 2019 в 00:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: