2012-08-31 12 views
22

En uno de nuestros métodos, usamos smoothScrolling en una vista de lista. Como este método no está disponible antes del Nivel 8 de API (FROYO), utilizamos la anotación TargetApi para evitar que se llame al método en las versiones anteriores del SDK.TargetApi no se tiene en cuenta

Como puede ver, nosotros do utilizamos la anotación de TargetApi tanto en la definición de la clase como en las declaraciones que usan los objetos de la clase. Esto es más de lo necesario.

Nuestro problema es que la anotación TargetApi no se tiene en cuenta y hace que nuestro emulador se cuelgue en la versión ECLAIR (SDK 7). Al rastrear, nos damos cuenta de que el código que solo debe ejecutarse en las versiones 8+ también se ejecuta en la versión 7.

¿Nos falta algo?

Este código está en un oyente:

@TargetApi(8) 
private final class MyOnMenuExpandListener implements OnMenuExpandListener { 
    @Override 
    public void onMenuExpanded(int position) { 
     doScrollIfNeeded(position); 
    } 

    @Override 
    public void onMenuCollapsed(int position) { 
     doScrollIfNeeded(position); 
    } 

    protected void doScrollIfNeeded(int position) { 
     if (mListViewDocuments.getLastVisiblePosition() - 2 < position) { 
      mListViewDocuments.smoothScrollToPosition(position + 1); 
     } 
    } 
} 

Y el detector se registra de esta manera:

@TargetApi(8) 
private void allowSmothScrollIfSupported() { 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { 
     //This if should not be necessary with annotation but it is not taken into account by emulator 
     Log.d(LOG_TAG, "Smooth scroll support installed."); 
     folderContentAdapter.setOnMenuExpandListener(new MyOnMenuExpandListener()); 
    } 
} 

Por cierto, que ejecuta el código en modo de depuración, por lo que el problema no está relacionado con ofuscación eliminando anotaciones.

+3

Por cierto, puede escribir '@TargetApi (Build.VERSION_CODES.FROYO)' en lugar de '@TargetApi (8)'. – Wyzard

+0

Tienes razón. Y para eso, su targetSDK debe ser lo más alto posible. – Snicolas

Respuesta

50

@TargetApi no impide que se ejecute ningún código, simplemente es para anotar el código y evitar errores del compilador para nuevas API una vez que sabe que solo las está llamando condicionalmente.

usted todavía tiene que añadir algo a lo largo de las líneas de

if (Build.VERSION.SDK_INT > 7){ 
    //... 
} 
+1

todo lo que hace es eliminar los errores de pelusa. compruebe [aquí] (http://tools.android.com/recent/lintapicheckhttp://tools.android.com/recent/lintapicheck) – nandeesh

+0

realmente?! Así parece. Pero parece realmente extraño tener un sistema diferente en lugar de @SuppressWarnings como solemos hacer para eludir los errores de pelusa. – Snicolas

+0

De hecho, es simplemente otra forma de anotación y el método de programación permite un control preciso de lo que se ejecuta. – Guykun

5

Con casi un año de más de pensar acerca de esto, me gustaría añadir un pequeño complemento a la respuesta @Guykun 's:

El @TargetApi solo será utilizado por las herramientas para decir a los desarrolladores "Oye, no utilices este método debajo de XXX SDK de Android". Típicamente pelusa.

Por lo tanto, si se quiere diseñar un método como:

if (Build.VERSION.SDK_INT > 7){ 
    //... 
} 

continuación, se debe añadir @TargetApi (7) a la firma de su método.

PERO, si se agrega una declaración más, y proporciona una alternativa que hace que funcione para todas las versiones de Android como:

if (Build.VERSION.SDK_INT > 7){ 
    //... 
} else { 
    //... 
} 

entonces debería no añadir @TargetApi (7) a la firma de su método. De lo contrario, otros desarrolladores pensarán que no pueden usar su método según el api nivel 7, pero de hecho, también les funcionaría.

Por lo tanto, esta anotación se debe utilizar, para el análisis estático, para indicar el nivel mínimo de API soportado por el método. Como en:

@TargetApi(7) 
public void foo() { 
    if (Build.VERSION.SDK_INT > 7){ 
     //... 
    else if (Build.VERSION.SDK_INT > 10){ 
     //... 
    } 
} 

y aún mejor, use constantes definidas en android.Build.VERSION_CODES.*.

Por cierto, habría notado que esto es inútil para los métodos privados, excepto para obtener un código más limpio y ayudar a promover el método público en el futuro.

+0

Esa es una respuesta a la pregunta de @Tom. – Snicolas

+0

Me gustaría pensar como usted, pero aquí es un extracto del código generado a partir asistente LoginActivity de Android Studio: '@TargetApi (Build.VERSION_CODES.HONEYCOMB_MR2) privada vacío showProgress (último espectáculo booleano) { si (Build.VERSION. SDK_INT> = Build.VERSION_CODES.HONEYCOMB_MR2) {// ... } else {// ... }} ' – nicobo

+0

sólo para hacer las cosas más claras, tal vez .. – Snicolas

1

Para forzar el error de pelusa al usar un método dirigido hacia un nivel Api más alto, puede usar RequiresApi en lugar de TargetApi y siempre que intente utilizar el método sin verificar el código de versión, obtendrá un error de compilación.

Esto es lo que el documentation dice acerca RequiresApi

Ésta es una finalidad similar a la anterior anotación @TargetApi, pero expresa más claramente que este es un requisito de la persona que llama, en lugar de ser utilizado para "suprimir" las advertencias dentro del método que exceden la minSdkVersion.

Cuestiones relacionadas