2012-08-31 9 views
22

In uno dei nostri metodi, utilizziamo smoothScrolling in una visualizzazione elenco. Poiché questo metodo non è disponibile prima dell'API Livello 8 (FROYO), abbiamo utilizzato l'annotazione TargetApi per impedire che il metodo venga richiamato nelle precedenti versioni dell'SDK.TargetApi non preso in considerazione

Come potete vedere, abbiamo do utilizzare l'annotazione TargetApi sia nella definizione della classe che nelle istruzioni che utilizzano gli oggetti della classe. Questo è più del necessario.

Il nostro problema è che l'annotazione TargetApi non viene presa in considerazione e rende il nostro emulatore bloccato nella versione ECLAIR (SDK 7). Tracciando, ci rendiamo semplicemente conto che il codice che dovrebbe essere eseguito solo nelle versioni 8+ viene eseguito anche nella versione 7.

Manca qualcosa?

Questo codice è in un ascoltatore:

@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); 
     } 
    } 
} 

e l'ascoltatore è registrato in questo modo:

@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()); 
    } 
} 

A proposito, abbiamo eseguire il codice in modalità debug, in modo che il problema non è legato alla offuscamento rimozione annotazioni.

+3

BTW, è possibile scrivere '@TargetApi (Build.VERSION_CODES.FROYO)' invece di '@TargetApi (8)'. – Wyzard

+0

Hai ragione. E per questo il tuo target SDK deve essere il più alto possibile. – Snicolas

risposta

50

@TargetApi non impedisce l'esecuzione di alcun codice, è solo per annotare il codice e prevenire errori del compilatore per le nuove API una volta che si è certi che le chiamate solo in modo condizionale.

hai ancora bisogno di aggiungere qualcosa sulla falsariga di

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

tutto ciò che fa è rimuovere gli errori lint. controllare [qui] (http://tools.android.com/recent/lintapicheckhttp://tools.android.com/recent/lintapicheck) – nandeesh

+0

davvero ?! Sembra così. Ma sembra davvero strano avere un sistema diverso piuttosto che @SuppressWarnings, come facciamo di solito per aggirare gli errori di lint. – Snicolas

+0

In effetti, è solo un'altra forma di annotazione e il metodo programmatico consente un controllo preciso di ciò che viene eseguito. – Guykun

5

Con quasi un anno di più pensando a questo, vorrei aggiungere un piccolo complemento alla risposta @Guykun s':

@TargetApi sarà utilizzato solo dagli strumenti per dire agli sviluppatori "Ehi, non usare questo metodo sotto XXX android SDK". In genere lint.

Quindi, se si progetta un metodo come:

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

allora si dovrebbe aggiungere @TargetApi (7) per la firma del metodo.

MA, se si aggiunge un'istruzione else, e fornire un'alternativa che lo fa funzionare per tutte le versioni di Android, come:

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

allora si dovrebbe non aggiungere @TargetApi (7) alla firma del tuo metodo. Altrimenti, altri sviluppatori penseranno che non possano usare il tuo metodo belw api livello 7, ma in effetti, funzionerebbe anche per loro.

Quindi questa annotazione deve essere utilizzata, per l'analisi statica, per indicare il livello di API minimo supportato dal metodo. Come in:

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

e, ancora meglio, utilizzare le costanti definite in android.Build.VERSION_CODES.*.

BTW, avresti notato che questo è inutile per i metodi privati, ad eccezione di ottenere un codice più pulito e contribuire a promuovere il metodo pubblico in futuro.

+0

Questa è una risposta alla domanda di @Tom. – Snicolas

+0

penserei come voi, ma qui è un estratto dal codice generato dal wizard LoginActivity di Android Studio: '@TargetApi (Build.VERSION_CODES.HONEYCOMB_MR2) private void showProgress (Final Show booleano) { se (Build.VERSION. SDK_INT> = Build.VERSION_CODES.HONEYCOMB_MR2) {// ... } else {// ... }} ' – nicobo

+0

Giusto per rendere le cose più chiare, forse .. – Snicolas

1

Per imporre errore pelucchi quando si utilizza un metodo mirato verso una maggiore livello di API, è possibile utilizzare al posto di RequiresApiTargetApi e ogni volta che si tenta di utilizzare il metodo senza controllare il codice di versione, si otterrà errore di compilazione.

Questo è ciò che l'documentation dice di RequiresApi

Questo è uno scopo simile a più vecchio di annotazione @TargetApi, ma esprime più chiaramente che si tratta di un obbligo per il chiamante, invece di essere utilizzato per gli avvisi di "soppressione" all'interno del metodo che superano la minSdkVersion.

Problemi correlati