La conférence « ProTips » de Mathias Seguy (Android2EE).
Cette conférence a eu lieu lors du BarCamp de la DroidCon Paris, Lundi 17 Juin 2013.
Si vous êtes un JUG ou un AUG et que cette conférence vous interesse, n'hésitez pas à me contacter.
Si vous souhaitez apprendre la technologie Android, contacter moi: mathias.seguy@android2ee.com, je suis formateur Android et les formations Android que je dispense sont exceptionnelles.
Speaker:Mathias est le fondateur de la société Android2ee spécialisée dans la technologie Android.
Il est :
• formateur Android,
• expert logiciel Android,
• speaker Android sur de grandes conférences Java : AndroidCon, Devoxx France, Eclipse Day Toulouse, JCertif Africa, Toulouse JUG, CocoAhead,…
• Rédacteur Android sur Developpez.com ;
• Programmateur Android : MyLight, MyTorch, MySensors, JCertifMobile disponibles sur GooglePlay ;
• Docteur en Mathématiques Fondamentales et Ingénieur de l’ENSEEIHT ;
• Expert technique de l’agence nationale de la recherche française ;
Il présentera au cours de cette conférence sa vision sur la mise en place d’une architecture d’une application Android pertinente et partagera les meilleurs pro-tips (astuces de pro) de sa connaissance. A ne pas manquez.
Mathias Séguy
mathias.seguy@android2ee.com
Fondateur Android2EE
Formation – Expertise – Consulting Android.
Ebooks pour apprendre la programmation sous Android.
2. Android2EE est référencé en tant qu’organisme de formation, vous pouvez faire prendre en charge tout ou partie
du montant de cette formation par votre OPCA. Cette formation Initiation avancée à Android est éligible au titre
du DIF et CIF.
Lieu : Paris, Toulouse, Lyon
Durée : 3 jours
Prix : 1680 €
Lieu : Paris, Toulouse, Lyon
Durée : 5 jours
Prix : 2980 €
Lieu : Paris, Toulouse, Lyon
Durée : 3 jours
Prix : 1780 €
5. 5
From Google I/O And Devoxx
Ce chapitre est un extrait des « meilleurs » proTips donnés par les équipes Google lors des GoogleI/O, notamment :
•Android ProTips, Reto Meier, Google I/O 2011
•Making Good Apps Great , Reto Meier, Google I/O 2012
•Google I_O 2013 - Android Protips_ Making Apps Work Like Magic , Reto Meier, Google I/O 2013
•Android Graphics, Animations and Tips & Tricks, Romain Guy & Chet Haase, Devoxx 2010
Merci à eux pour ces présentations.
6. 6
Statics as Temporaries
Utiliser des variables statiques pour vos variables
temporaires
public boolean pointInArea(int x, int y, Area area) {
Point testPoint = new Point(x, y);
return area.intersect(testPoint);
}
static final Point tmpPoint = new Point();
public boolean pointInArea(int x, int y, Area area) {
tmpPoint.x = x;
tmpPoint.y = y;
return area.intersect(tmpPoint.yPoint);
}
Autoboxing creates Objects
Utiliser les types primitifs, l’AutoBoxing créé des
objets!
Est équivalent à
float x = 5;
Float y = x;
doSomething(x);
void doSomething(Float z) {}
float x = 5;
Float y = new Float(x);
doSomething(new Float(x));
void doSomething(Float z) {}
Recycle those Bitmaps
Les ressources sont limitées,
recyclez vos Bitmaps le plus tôt
possible (n’attendez pas la
méthode finalize())
Vous pensez que cela aide:
Mais en fait vous souhaitez:
// done using this one, clear
reference
myBitmap = null;
// done using this one, recycle it
myBitmap.recycle();
From Android Graphics, Animations and Tips & Tricks, Romain Guy & Chet Haase, Devoxx 2010
7. 7
Use ViewStub
La ViewStub permet le lazy loading de layouts.
<ViewStub
android:id="@+id/stub_import"
android:inflatedId="@+id/panel_import"
android:layout="@layout/progress_overlay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
findViewById(R.id.stub_import).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub)
findViewById(R.id.stub_import)).inflate();id/stub_import
id/panel_import
From Android Graphics, Animations and Tips & Tricks, Romain Guy & Chet Haase, Devoxx 2010
8. 8
Use merge et include
<!-- The merge tag must be the root tag -->
<merge
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Content -->
</merge>
<!– The include tag is the one to use-->
<LinearLayout …>
<include layout="@layout/subLayout" />
<LinearLayout> .. </LinearLayout>
</LinearLayout>
Without merge With merge
From Android Graphics, Animations and Tips & Tricks, Romain Guy & Chet Haase, Devoxx 2010
9. 9
Compounds Drawables
Utiliser les balises android:drawable*** pour mettre des
images à droite, à gauche … de vos composants héritant
de TextView (TextView, Button, EditText,…)
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/icon" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello"
android:drawableLeft="@drawable/icon" />
Balises
android:drawableBottom
android:drawableEnd
android:drawablePadding
android:drawableRight
android:drawableStart
android:drawableTop
From Android Graphics, Animations and Tips & Tricks, Romain Guy & Chet Haase, Devoxx 2010
10. 10
ListView and ArrayAdpater : Use ViewHolder and convertView
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text, parent, false);
holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.icon = (ImageView) convertView.findViewById(R.id.icon);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(DATA[position]);
holder.icon.setImageBitmap((position & 1) ==? mIcon1 : mIcon2);
return convertView;
}
static class ViewHolder {
TextView text;
ImageView icon;
}
From Android Graphics, Animations and Tips & Tricks, Romain Guy & Chet Haase, Devoxx 2010
11. 11
UUID : Unique User ID
L’ UUID Pattern permet détecter l'utilisateur plutôt que les installations. Si vous avez besoin d’identifier de manière unique l'utilisateur qui
possède l’application, ce pattern est à utiliser.
private static String uniqueID = null;
private static final String PREF_UNIQUE_ID = "PREF_UNIQUE_ID";
public synchronized static String id(Context context) {
if (uniqueID == null) {
SharedPreferences sharedPrefs =
context.getSharedPreferences(PREF_UNIQUE_ID, Context.MODE_PRIVATE
);
uniqueID = sharedPrefs.getString(PREF_UNIQUE_ID, null);
if (uniqueID == null) {
uniqueID = UUID.randomUUID().toString();
Editor editor = sharedPrefs.edit();
editor.putString(PREF_UNIQUE_ID, uniqueID);
editor.commit();
}
}
return uniqueID;
}
Android ProTips, Reto Meier, Google I/O 2011
13. 13
KeyBoard and EditText : Customize KeyBoard and set Action
Quand vous définissez un champ de type EditText vous devez définir :
• Son type de clavier 7
• L’action IME
• (et le Hint)
<EditText
android:id="@+id/editEmailInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/compose_email_hint"
android:imeOptions="actionSend|flagNoEnterAction"
android:inputType="textShortMessage|
textAutoCorrect|
textCapSentences" />
Android ProTips, Reto Meier, Google I/O 2011
EditText.OnEditorActionListener myActionListener = new
EditText.OnEditorActionListener() {
@Override
public boolean onEditorAction(EditText v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
// do here your stuff f
return true;
}
return false;
}
};
14. 14
Always be asynchronous
Rendez tout asynchrone en utilisant les
Handler, Asynctask, IntentService (le système
des Intents quoi), AsyncQueryHandler (le
GetContentResolver en un sens), Loader
(abstractClass) and CursorLoader (HoneyComb
only).
public class TutoActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor> {
SimpleCursorAdapter mAdapter;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// …
// Create an empty adapter we will use to display the loaded data.
mAdapter = new SimpleCursorAdapter(this,android.R.layout.simple_list_item_2, null,
new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
new int[] { android.R.id.text1, android.R.id.text2 }, 0);
listView.setAdapter(mAdapter);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
getLoaderManager().initLoader(0, null, this);
}
// Callbacks
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri baseUri = MyContentProvider.CONTENT_URI;
return new CursorLoader(this, baseUri, null, null, null, null);
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
}
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
Android ProTips, Reto Meier, Google I/O 2011
15. 15
Use the big cookies strategy when possible
Préférez transférer un gros paquet de données au travers d’internet quand c’est possible plutôt que plein de petits paquets.
Making Good Apps Great, Reto Meier, Google I/O 2012
int prefetchCacheSize = DEFAULT_PREFETCH_CACHE;
switch (activeNetwork.getType()) {
case ConnectivityManager.TYPE_WIFI:
prefetchCacheSize = MAX_PREFETCH_CACHE;
break;
case ConnectivityManager.TYPE_MOBILE): {
switch (telephonyManager.getNetworkType()) {
case TelephonyManager.NETWORK_TYPE_LTE:
case TelephonyManager.NETWORK_TYPE_HSPAP:
prefetchCacheSize *= 4; break;
case TelephonyManager.NETWORK_TYPE_EDGE:
case TelephonyManager.NETWORK_TYPE_GPRS:
prefetchCacheSize /= 2; break;
default: break;
} break;
}
default: break;
}
16. Use AndroidBeam
Parce que c'est tout simple d'échanger des données entre deux devices.
Send Receive
16
Android Protips_ Making Apps Work Like Magic, Reto Meier, Google I/O 2013
public void onResume() {
super.onResume();
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcAdapter.setNdefPushMessageCallback(new CreateNdefMessageCallback() {
public NdefMessage createNdefMessage(NfcEvent event) {
NdefMessage message = createMessage();
return message;
}
}, this);
// ...}
private void createMessage() {
String mimeType = "application/com.myapp.nfcbeam";
byte[] mimeBytes = mimeType.getBytes(Charset.forName("US-ASCII"));
String payLoad = ""; // TODO Contextualized payload.;
NdefMessage nfcMessage = new NdefMessage(new NdefRecord[] {
new NdefRecord(ndefRecord.TNF_MIME_MEDIA, mimeByes, new
byte[], payload.getBytes()),
NdefRecord.createApplicationRecord("com.myapp.nfcbeam") });
}
private void extractPayload(Intent beamIntent) {
Parcelable[] messages = beamIntent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefAdapter message = (NdefMessage)message[0];
NdefRecord record = message.getRecords()[0];
String payload = new String(record.getPayload());
navigateTo(payload);
}
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/com.myapp.nfcbeam"/>
</intent-filter>
17. Location
Utiliser le ServiceGooglePlay, il connait vos utilisateurs mieux que vous.
17
Android Protips_ Making Apps Work Like Magic, Reto Meier, Google I/O 2013
private void connectLBS() {
int gpsExists = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (gpsExists == ConnectionResult.SUCCESS) {
mLocationClient = new LocationClient(this, this, this);
mlocationClient.connect();
}
}
@Override
public void onConnected(Bundle connectionHint) {
requestUpdates(mlocationClient);
}
private void requestUpdates(LocationClient mlocationClient) {
LocationRequest request = LocationRequest.create();
request.setInterval(minTime);
request.setPriority(lowPowerMoreImportantThanAccuracy ?
LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY :
LocationRequest.PRIORITY_HIGH_ACCURACY);
mlocationClient.requestLocationUpdates(request, new LocationListener() {
@Override
public void onLocationChanged(Location location) {
updateLocation(location);
}
});
}
18. Activity Recognition
Adapter vos applications au contexte utilisateur (devant la télé, en voiture, en vélo, à pied...).
18
Android Protips_ Making Apps Work Like Magic, Reto Meier, Google I/O 2013
Intent intent = new Intent(this, ActivityRecognitionIntentService.class);
intent.setAction(MyActivity.ACTION_STRING);
PendingIntent pi =
PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURR
ENT);
mActivityRecognitionClient.requestActivityUpdates(interval, pi);
@Override
protected void onHandleIntent(Intent intent) {
if (intent.getAction() == MyActivity.ACTION_STRING) {
if (ActivityRecognitionResult.hasResult(intent)) {
ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
DetectedActivity detectedActivity = result.getMostProbableActivity();
int activityType = detectedActivity.getType();
if (activityType == DetectedActivity.STILL)
setUpdateSpeed(PAUSED);
else if (activityType == DetectedActivity.IN_VEHICLE)
setUpdateSpeed(FASTER);
else
setUpdateSpeed(REGULAR);
}
}
}
19. TextToSpeech : TTS
De parlez à vos utilisateurs, parfois c'est super.
Initialize Use
19
Android Protips_ Making Apps Work Like Magic, Reto Meier, Google I/O 2013
private void initTextToSpeech() {
Intent intent = new Intent(Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(intent, TTS_DATA_CHECK);
}
protected void onActivityResult(int request, int result, Intent data) {
if (request == TTS_DATA_CHECK &&
result == Engine.CHECK_VOICE_DATA_PASS) {
tts = new TextToSpeech(this, new OnInitListener() {
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS)
ttsIsInit = true;
}
});
} else
startActivity(new Intent(Engine.ACTION_INSTALL_TTS_DATA);
}
private void say(String text) {
if (tts != null && ttisIsInit)
tts.speak(text, TextToSpeech.QUEUE_ADD, null);
}
20. Speech Recognition
D'écouter vos utilisateurs, parfois c'est encore plus super.
Record Consume
20
Android Protips_ Making Apps Work Like Magic, Reto Meier, Google I/O 2013
private void requestVoiceInput() {
Intent intent = new
Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
getString(R.String.voice_input_prompt);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE,
Locale.ENGLISH);
startActivityForResult(intent, VOICE_RECOGNITION);
}
@Override
protected void onActivityResult(int request, int result, Intent data)
{
if (request == VOICE_RECOGNITION && result ==
RESULT_OK) {
ArrayList<String> results =
data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
String mostLikelyResult = results[0];
useSpeechInput(mostLikelyResult);
}
}
22. 22
From Google I/O 2012
Ce chapitre est un extrait de la conférence des Google I/O 2012 :
•Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012
Qui est exceptionnel sur la lutte contre la fragmentation, un très grand moment, merci à eux.
23. 23
Be Lazy
Utiliser une classe abstraite qui sera instanciée par une factory et renverra l’implémentation correspondant à le version du système.
Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012
public abstract class VersionedLoremIpsum {
public abstract String doLorem();
public abstract int doIpsum();
}
public class EclairLoremIpsum
extends VersionedLoremIpsum {
public String doLorem() {
// do lorem, Eclair-style
}
public abstract int doIpsum() {
// deliver ipsum, a là Eclair
}
}
public class FroyoLoremIpsum
extends EclairLoremIpsum {
public String doLorem() {
String l = super.doLorem();
// additional processing
return l;
}
public abstract int doIpsum() {
...
Activity
VersionedLoremIpsum li;
li=VLIFactory.get()
VLIFactory
public static VersionedLoremIpsum get(
int sdk = Build.VERSION.SDK_INT;
if (sdk <= Build.VERSION_CODES.ECLAIR) {
li = new EclairLoremIpsum();
} else if (sdk <=
Build.VERSION_CODES.FROYO) {
li = new FroyoLoremIpsum();
} else {
li = new GingerbreadLoremIpsum();
}
)
24. 24
Resources are your best friend, use them.
Utilisez des booléens pour savoir quelle est la version du système. Ils s’utilisent dans le code et dans le Manifest.xml.
Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012
Manifest
<receiver android:name="MyPreICSAppWidget"
android:enabled="@bool/preICS">
...
</receiver>
<receiver android:name="MyPostICSAppWidget"
android:enabled="@bool/postICS">
...
</receiver>
SomeWhere in java
Resources res = getResources();
boolean postICS =
res.getBoolean(R.bool.postICS);
if (postICS) {
// do something cool and cutting-edge
} else {
// do something old-school but elegant!
}
Resvalues-v14bools.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="postICS">true</bool>
<bool name="preICS">false</bool>
</resources>
Resvaluesbools.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="postICS">false</bool>
<bool name="preICS">true</bool>
</resources>
25. 25
Construisez vos Layouts dynamiquement en fonction de la version système.
Utilisez merge et include pour construire des IHM qui s’adaptent à la version de manière transparente.
Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012
Reslayoutmain.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout ...
<!-- non multi-versioned stuff here -->
<include layout="@layout/desserts" />
<!-- more non multi-versioned stuff here -->
</LinearLayout>
Reslayoutdesserts.xml
<?xml ... ?>
<merge xmlns:android="...">
<CheckBox ... />
<CheckBox ... />
<CheckBox ... />
...
</merge>
Reslayout-v11desserts.xml
<?xml ... ?>
<merge xmlns:android="...">
<Switch ... />
<Switch ... />
<Switch ... />
...
</merge>
26. 26
Hériter du thème de la version.
Restez cohérent avec le thème du SDK de l’appareil cible, conservez une application cohérente avec l’appareil.
Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012
MyTheme
resvaluestheme.xml
<style name=" MyBaseTheme" parent="@android:style/Theme" />
<style name="MyTheme" parent="MyBaseTheme">
<style name="MyButtonStyle" parent="@android:style/Widget.Button">
resvalues-v11theme.xml
<style name=" MyBaseTheme" parent="@android:style/Theme.Holo" />
<style name="MyButtonStyle" parent="@android:style/Widget.Holo.Button">
MyBaseTheme
Theme Theme.Holo
27. 27
Utiliser les Fragments et l’ActionBar sur toutes vos versions.
Ayez une application identique quelque soit la version du système et utilisez le même fichier de layout.
Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012
public class SpeakerDetailFragmentHC extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.speaker_detail, container, false);
return view;
}
public class SpeakerDetailFragment extends android.support.v4.app.Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.speaker_detail, container, false);
return view;
}
public class BaseActivityHC extends Activity{...}
public class BaseActivityLegacy extends android.support.v4.app.FragmentActivity {...}android.support.v4.app.ActionBarActivity
28. private void pushInboxNotifications() {
Notification notification = new Notification.Builder(this)
.setContentTitle("10 New emails for me")
.setContentText("subject")
.setSmallIcon(android.R.drawable.ic_menu_agenda)
.setStyle(Notification.InboxStyle)
.addLine("Line 1, i can add more if i want")
.addAction(R.drawable.icon,R.string.notification_message,new PendingIntent(....))
.setSound(aSound)
.build();
NotificationManager
notificationManager=(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notification);
}
28
Utiliser les notifications PreJB, PostJB.
Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012
if version >= JellyBean
use Notification.Builder
else
use NotificationCompat.Builder
29. 29
L’ordre des boutons a changé depuis ICS.
Avant ICS le bouton OK est à gauche, le bouton non ou cancel à droite.
Après ICS le bouton OK est à droite, le bouton non ou cancel à gauche.
Multiversioning Android, Bruno Oliveira & Adam Powell , Google I/O 2012
32. 32
MinSDK=11 ?o? Utiliser le parrallel pattern.
Deux types d'animation incompatibles : Avant (TweenAnimation) Après (ObjectAnimator, ViewProperty) HoneyComb.
CodeDependent Chet Haase http://graphics-geek.blogspot.fr/.
Be short.
Le temps d'animation par défaut est de 300 ms.
Cela dépend de l'objet à animer (une vue, une activité ce n'est pas un bouton).
Be Amazing... but once.
Les animations longues, belles et délirantes deviennent ennuyeuses au bout de 3.
Remplacer les par des animations efficaces au bout de 3.
Si en développement votre animation ne vous pourrit pas la vie alors elle ne pourrira pas celle de vos utilisateurs.
Thanks Chet.
Depuis HoneyComb, les animations sont améliorées, simplifiées et super flexibles.
Dev.Bytes nous poste des tutos de 3 minutes pour nous les apprendre.
Merci à Chet Haase pour tout ça.
33. <LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:id="@+id/container"/>
33
MinSDK=16.
Ajoutez cette balise à vos Layouts.
Dès qu'un changement est détecté, il sera automatiquement animé pour le plaisir de vos utilisateurs.
Dev.Bytes Chet Haase LayoutTransChanging https://www.youtube.com/watch?v=55wLsaWpQ4g.
// Note that this assumes a LayoutTransition is set on the container, which is the
// case here because the container has the attribute "animateLayoutChanges" set to true
// in the layout file. You can also call setLayoutTransition(new LayoutTransition()) in
// code to set a LayoutTransition on any container.
LayoutTransition transition = container.getLayoutTransition();
// New capability as of Jellybean; monitor the container for *all* layout changes
// (not just add/remove/visibility changes) and animate these changes as well.
transition.enableTransitionType(LayoutTransition.CHANGING);
34. // Create bitmap to be re-used, based on the size of one of the bitmaps
mBitmapOptions = new BitmapFactory.Options();
//Set for asking only the width and height of the bitmap, not the bitmap itself
mBitmapOptions.inJustDecodeBounds = true;
//With that option, bitMap is not load, but its size is set in mBitmapOptions.outWidth
and mBitmapOptions.outHeight
BitmapFactory.decodeResource(getResources(), R.drawable.a, mBitmapOptions);
//Then create bitmap object (still not displaying any drawable)
mCurrentBitmap = Bitmap.createBitmap(mBitmapOptions.outWidth,
mBitmapOptions.outHeight, Bitmap.Config.ARGB_8888);
//Then change the inJustDecode for asking the bitmap itself
mBitmapOptions.inJustDecodeBounds = false;
//Then define where the loaded bitmap will be drop in the
mBitmapOptions.inSampleSize = 1;
//and finally load it (as mBitmapOptions.inBitmap = mCurrentBitmap, the loaded bitmap
will be in mCurrentBitmap)
BitmapFactory.decodeResource(getResources(), R.drawable.a, mBitmapOptions);
imageview.setImageBitmap(mCurrentBitmap);
34
MinSDK=15.
Créer un objet BitMap et réutilisé le pour charger les images suivantes.
Dev.Bytes Chet Haase Bitmap Allocation https://www.youtube.com/watch?v=rsQet4nBVi8
mCurrentIndex = (mCurrentIndex + 1) % imageIDs.length;
BitmapFactory.Options bitmapOptions = null;
if (reuseBitmapAllocation) {
}
long startTime = System.currentTimeMillis();
mCurrentBitmap = BitmapFactory.decodeResource(getResources(),
imageIDs[mCurrentIndex], bitmapOptions);
imageview.setImageBitmap(mCurrentBitmap);
Premier chargement Chargements Suivants
mBitmapOptions.inBitmap = mCurrentBitmap;
// Re-use the bitmap by using BitmapOptions.inBitmap
bitmapOptions = mBitmapOptions;
bitmapOptions.inBitmap = mCurrentBitmap;
Allocation Mémoire et Garbage optimisés
Rapidité de chargement accrue
35. Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.drawable.jellybean_statue);
originalImageView.setImageBitmap(bitmap);
for (int i = 2; i < 10; ++i) {
addScaledImageView(bitmap, i, container);
}
35
MinSDK=15.
Créer un objet BitMap et réutilisé le pour charger les images suivantes.
Dev.Bytes Chet Haase LayoutTransChanging
private Bitmap addScaledImageView(Bitmap original, int sampleSize, LinearLayout container) {
// inSampleSize tells the loader how much to scale the final image, which it does at
// load time by simply reading less pixels for every pixel value in the final bitmap.
// Note that it only scales by powers of two, so a value of two results in a bitmap
// 1/2 the size of the original and a value of four results in a bitmap 1/4 the original
// size. Intermediate values are rounded down, so a value of three results in a bitmap 1/2
// the original size.
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
Bitmap scaledBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.jellybean_statue, bitmapOptions);
return scaledBitmap;
}
Chargement normal
bitmapOptions.inSampleSize = sampleSize;
Chargement réduit
36. static class MyView extends View {
Bitmap mBitmap;
Paint paint = new Paint();
int mShapeX, mShapeY;
int mShapeW, mShapeH;
public MyView(Context context, AttributeSet attrs, int defStyle) {...; setupShape();}
public MyView(Context context, AttributeSet attrs) {...; setupShape();}
public MyView(Context context) {{...; setupShape();}
private void setupShape() {Initialisation des objets graphiques...}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//Initialisation des tailles des composants et des positions
mShapeX = (w - mBitmap.getWidth()) / 2;
}
36
MinSDK=14.
Animer vos vues. Vous pouvez en redéfinir une ou bien le mettre en place directement dans votre activité.
Dev.Bytes Chet Haase Bouncer https://www.youtube.com/watch?v=vCTcmPIKgpM
Initialisation de votre custom View
37. Dev.Bytes Chet Haase Bouncer https://www.youtube.com/watch?v=vCTcmPIKgpM
37
MinSDK=14.
Mise en place de l'animation.
1. Définir et lancer l'animation.
void startAnimation() {
// This variation uses an ObjectAnimator. The ObjectAnimator automatically animate the target object for
us, so we no longer need to listen for frame updates and do that work ourselves.
ObjectAnimator anim = getObjectAnimator();
anim.setRepeatCount(ValueAnimator.INFINITE);
anim.setRepeatMode(ValueAnimator.REVERSE);
anim.setInterpolator(new AccelerateInterpolator());
anim.start();}
ObjectAnimator getObjectAnimator() {
}
public void setShapeY(int shapeY) {
//Set the new value
mShapeY = shapeY;
//Calculate the dirty area and ask to redraw it
int minY = mShapeY;int maxY = mShapeY + mShapeH;minY = Math.min(mShapeY, minY);
maxY = Math.max(mShapeY + mShapeH, maxY);
//ask to redraw the rectangle area
invalidate(mShapeX, minY, mShapeX + mShapeW, maxY);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, mShapeX, mShapeY, paint);}
return ObjectAnimator.ofInt(this, "shapeY", 0, (getHeight() - mShapeH));
2. Construire l'ObjectAnimator
3. Mettre a jour les données graphiques
Calculer la zone a redessiner
Demander le redraw
4. Dessiner l'objet
38. // Create the AnimationDrawable in which we will store all frames of the animation
final AnimationDrawable animationDrawable = new AnimationDrawable();
for (int i = 0; i < 10; ++i) {
animationDrawable.addFrame(createDrawableForFrameNumber(i), 300);
}
// Run until we say stop
animationDrawable.setOneShot(false);
imageview.setImageDrawable(animationDrawable);
animationDrawable.start();
38
MinSDK=14.
Animer vos vues. Vous pouvez en redéfinir une ou bien le mettre en place directement dans votre activité.
Dev.Bytes Chet Haase KeyframeAnimation https://www.youtube.com/watch?v=V3ksidLf7vA
AnimationDrawable
private BitmapDrawable createDrawableForFrameNumber(int frameNumber) {
Bitmap bitmap = Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.GRAY);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setTextSize(80);
paint.setColor(Color.BLACK);
canvas.drawText("Frame " + frameNumber, 40, 220, paint);
return new BitmapDrawable(getResources(), bitmap);
}
Building a Bitmap from scratch
39. 39
From Google I/O 2013
By Chet Haase and Romain Guy
Google I/o 2013 Romain Guy - Chet Haase "A Moving Experience" http://graphics-geek.blogspot.fr/2013/06/devbytes-animating-listview-deletion.html
mListView.setEnabled(false);
v.animate().setDuration(duration).alpha(endAlpha).translationX(endX).
withEndAction(new Runnable() {
@Override
public void run() {
// Restore animated values
v.setAlpha(1);
v.setTranslationX(0);
}});
0.Lancement de l'animation dans View.OnTouchListener# MotionEvent.ACTION_UP
animateRemoval(mListView, v);
40. Google I/o 2013 Romain Guy - Chet Haase "A Moving Experience" http://graphics-geek.blogspot.fr/2013/06/devbytes-animating-listview-deletion.html
40
From Google I/O 2013
By Chet Haase and Romain Guy
private void animateRemoval(final ListView listview, View viewToRemove) {
observer.removeOnPreDrawListener(this);
for (int i = 0; i < listview.getChildCount(); ++i) {
child.setTranslationY(delta);
if (firstAnimation) {
child.animate().withEndAction(new Runnable() {
public void run() {
mBackgroundContainer.hideBackground();
mSwiping = false;
mListView.setEnabled(true);
}
});
mItemIdTopMap.clear();
return true;}});
final ViewTreeObserver observer = listview.getViewTreeObserver();
observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
public boolean onPreDraw() {
child.animate().setDuration(MOVE_DURATION).translationY(0);
1.Récupération du ViewTreeObserver
2.Ajout du Listener PreDraw
3.Mise en place de l'animation dans le preDraw