Видите, вы здесь не правы
@Override
public int getCount() {
return 0;
}
Сделайте это
@Override
public int getCount() {
return songs.size();
}
Также удалите эти два метода:
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
Объяснение [1110 ] Адаптер использует метод getCount
(), чтобы определить размер списка, и просмотр повторного просмотра, который вы возвращаете 0, означает, что у вас есть 0 элементов в просмотре списка. На самом деле нам нужно вернуть общий размер элементов, который составляет songs.size()
.
Надеюсь, что это даст вам правильное руководство.
Я знаю, что люди, ненавидят для использования их, но это - идеальная ситуация для a goto
в C.
int func( void** mem1, void** mem2 )
{
int retval = 0;
*mem1 = malloc(SIZE);
if (!*mem1) {
retval = 1;
goto err;
}
*mem2 = malloc(SIZE);
if (!*mem2) {
retval = 1;
goto err;
}
// ...
goto out;
// ...
err:
if( *mem1 ) free( *mem1 );
if( *mem2 ) free( *mem2 );
out:
return retval;
}
Это немного спорно, но я думаю goto
подход, используемый в ядре Linux на самом деле, работает вполне прилично в этой ситуации:
int get_item(item_t* item)
{
void *mem1, *mem2;
int ret=-ENOMEM;
/* allocate memory */
mem1=malloc(...);
if(mem1==NULL) goto mem1_failed;
mem2=malloc(...);
if(mem2==NULL) goto mem2_failed;
/* take a lock */
if(!mutex_lock_interruptible(...)) { /* failed */
ret=-EINTR;
goto lock_failed;
}
/* now, do the useful work */
do_stuff_to_acquire_item(item);
ret=0;
/* cleanup */
mutex_unlock(...);
lock_failed:
free(mem2);
mem2_failed:
free(mem1);
mem1_failed:
return ret;
}
Это - то, где goto является соответствующим, по-моему. Я раньше следовал за anti-goto догмой, но я изменил это, когда было указано мне, что делают {...} В то время как (0); компиляции к тому же коду, но не так легко читать. Просто следуйте некоторым основным правилам, как не движение назад с ними, сведение к минимуму их, только использование их для состояний ошибки, и т.д...
int func(void **mem1, void **mem2)
{
*mem1 = NULL;
*mem2 = NULL;
*mem1 = malloc(SIZE);
if(!*mem1)
goto err;
*mem2 = malloc(SIZE);
if(!*mem2)
goto err;
return 0;
err:
if(*mem1)
free(*mem1);
if(*mem2)
free(*mem2);
*mem1 = *mem2 = NULL;
return 1;
}
Вызывающая сторона делает что-либо полезное с блоками памяти, которые были правильно выделены перед отказом? В противном случае вызываемый должен обработать освобождение.
Одна возможность сделать очистку эффективно использует do..while(0)
, который позволяет break
где Ваш пример return
s:
int func(void **mem1, void **mem2)
{
*mem1 = NULL;
*mem2 = NULL;
do
{
*mem1 = malloc(SIZE);
if(!*mem1) break;
*mem2 = malloc(SIZE);
if(!*mem2) break;
return 0;
} while(0);
// free is NULL-safe
free(*mem1);
free(*mem2);
return 1;
}
Если Вы делаете много выделений, Вы могли бы хотеть использовать Ваш freeAll()
функция, чтобы сделать очистку здесь также.
Мой собственный наклон состоит в том, чтобы создать функцию аргумента переменной, которая освобождает всех ненулевых указателей. Затем вызывающая сторона может обработать ошибочный случай:
void *mem1 = NULL;
void *mem2 = NULL;
if (func(&mem1, &mem2)) {
freeAll(2, mem1, mem2);
return 1;
}
Лично; У меня есть библиотека отслеживания ресурсов (в основном сбалансированное двоичное дерево), и у меня есть оболочки для всех функций распределения.
Ресурсы (такие как память, сокеты, дескрипторы файлов, семафоры и т. Д. - все, что вы выделяете и освобождаете), может принадлежать set.
У меня также есть библиотека обработки ошибок, в которой первым аргументом каждой функции является набор ошибок, и если что-то пойдет не так, функция, в которой возникла ошибка, отправляет ошибку в набор ошибок.
Если установлена ошибка содержит ошибку, ни одна функция не выполняется . (У меня есть макрос в верхней части каждой функции, которая вызывает ее возврат.)
Итак, несколько маллоков выглядят так:
mem[0] = malloc_wrapper( error_set, resource_set, 100 );
mem[1] = malloc_wrapper( error_set, resource_set, 50 );
mem[2] = malloc_wrapper( error_set, resource_set, 20 );
Нет необходимости проверять возвращаемое значение, потому что, если возникает ошибка, никакие следующие функции не будут выполняться , например следующие маллоки никогда не возникают.
Итак, когда мне приходит время освободить ресурсы (скажем, в конце функции, когда все ресурсы, используемые внутри этой функции, были помещены в набор), я освобождаю набор , Это всего лишь один вызов функции.
res_delete_set( resource_set );
Мне не нужно специально проверять ошибки - в моем коде нет if (), проверяющих возвращаемые значения, что делает его поддерживаемым; Я считаю, что расширение встроенной проверки ошибок ухудшает удобочитаемость и, следовательно, ремонтопригодность. У меня просто хороший простой список вызовов функций.
Это art , человек: -)
res_delete_set( resource_set );
Мне не нужно специально проверять ошибки - в моем коде нет if (), проверяющих возвращаемые значения, что делает его поддерживаемым; Я считаю, что расширение встроенной проверки ошибок ухудшает удобочитаемость и, следовательно, ремонтопригодность. У меня просто хороший простой список вызовов функций.
Это art , человек: -)
res_delete_set( resource_set );
Мне не нужно специально проверять ошибки - в моем коде нет if (), проверяющих возвращаемые значения, что делает его поддерживаемым; Я считаю, что расширение встроенной проверки ошибок ухудшает удобочитаемость и, следовательно, ремонтопригодность. У меня просто хороший простой список вызовов функций.
Это art , человек: -)
Это удобочитаемая альтернатива:
int func(void **mem1, void **mem2) {
*mem1 = malloc(SIZE);
*mem2 = malloc(SIZE);
if (!*mem1 || !*mem2) {
free(*mem2);
free(*mem1);
return 1;
}
return 0;
}
Если приведенные выше операторы goto по какой-то причине вызывают у вас ужас, вы всегда можете сделать что-то вроде этого:
int func(void **mem1, void **mem2)
{
*mem1 = malloc(SIZE);
if (!*mem1) return 1;
*mem2 = malloc(SIZE);
if (!*mem2) {
/* Insert free statement here */
free(*mem1);
return 1;
}
return 0;
}
Я использую этот метод довольно регулярно, но только когда очень ясно, что происходит.
Я немного напуган всеми рекомендациями по выражению goto!
Я обнаружил, что использование goto приводит к путанице в коде, что с большей вероятностью приведет к ошибкам программиста. Сейчас я предпочитаю полностью избегать его использования, за исключением самых экстремальных ситуаций. Я почти никогда им не пользовался. Не из-за академического перфекционизма, а из-за того, что год или больше спустя всегда кажется сложнее вспомнить общую логику, чем с альтернативой, которую я предлагаю.
Быть тем, кто любит рефакторинг вещей, чтобы минимизировать мою возможность забыть вещи (например, очистка указателя), я бы сначала добавил несколько функций. Я предполагаю, что вполне вероятно, что я буду многократно использовать их в одной программе. Функция imalloc () будет выполнять операцию malloc с косвенным указателем; ifree () отменит это. cifree () освободит память условно.
Имея это под рукой, моя версия кода (с третьим аргументом, для демонстрации) будет такой:
// indirect pointer malloc
int imalloc(void **mem, size_t size)
{
return (*mem = malloc(size));
}
// indirect pointer free
void ifree(void **mem)
{
if(*mem)
{
free(*mem);
*mem = NULL;
}
}
// conditional indirect pointer free
void cifree(int cond, void **mem)
{
if(!cond)
{
ifree(mem);
}
}
int func(void **mem1, void **mem2, void **mem3)
{
int result = FALSE;
*mem1 = NULL;
*mem2 = NULL;
*mem3 = NULL;
if(imalloc(mem1, SIZE))
{
if(imalloc(mem2, SIZE))
{
if(imalloc(mem3, SIZE))
{
result = TRUE;
}
cifree(result, mem2);
}
cifree(result, mem1);
}
return result;
}
Я предпочитаю иметь только один возврат из функции , в конце. Прыгать между ними быстро (и, на мой взгляд, довольно грязно). Но что более важно, позволяет легко случайно обойти связанный код очистки.