כשעובדים עם כללי שמירה, חשוב שתגיעו לרמת הספציפיות הנכונה כדי לוודא שאתם נהנים מהיתרונות של הכללים, תוך שמירה על התנהגות האפליקציה. בקטעים הבאים מוסבר על דפוסים מומלצים ועל דברים שכדאי להימנע מהם בכללי שמירה.
דפוסים מומלצים בכללי שמירה
כללי שמירה מוגדרים היטב הם ספציפיים ככל האפשר, ופועלים לפי הדפוסים הבאים:
במפרט המחלקה, תמיד מציינים מחלקה ספציפית, מחלקה בסיסית או במידת אפשר מחלקה עם הערות, כמו בדוגמאות הבאות:
-keepclassmembers class com.example.MyClass { void someSpecificMethod(); }-keepclassmembers ** extends com.example.MyBaseClass { void someSpecificMethod(); }-keepclassmembers @com.example.MyAnnotation class ** { void someSpecificMethod(); }במידת האפשר, כדאי להשתמש בהערות בקוד המקור ואז לטרגט את ההערות האלה ישירות בכללי השמירה. כך נוצר קישור ברור ומפורש בין הקוד לבין הכללים ששומרים עליו, וההגדרה הופכת ליציבה יותר, קלה יותר להבנה ופחות נוטה להישבר כשהקוד משתנה.
לדוגמה, בקטע הקוד הבא אפשר לראות איך שומרים את המחלקה MyClass, וגם מחלקות אחרות שמוגדרות להן הערות באמצעות
@com.example.DisplayComponent:// In the source code @com.example.DisplayComponent class MyClass { /* ... */ } // In the keep rules -keep @com.example.DisplayComponent class * {*;}מומלץ לתת להערות שמות שמספקים הקשר משמעותי לסיבה שבגללה חלקי הקוד נשמרים. לדוגמה, אפשר להשתמש ב-
@DisplayComponentבאפליקציה שבה רכיבי התצוגה דורשים לשמור חלקים מסוימים.ככל שאפשר, צריך להצהיר על מפרט הגורמים ולהפנות רק לחלקים של המחלקה שצריך לשמור כדי שהאפליקציה תפעל. מומלץ לא ליישם כלל על מחלקה שלמה על ידי הגדרה של היקף הגורמים האופציונלי כ-
{ *; }, אלא אם יש בכך צורך מובהק.-keepclassmembers com.example.MyClass { void someSpecificMethod(); void @com.example.MyAnnotation *; }אם אתם משתמשים באפשרות הגלובלית
repackageclasses, אל תציינו את שם החבילה האופציונלי. ציון של השם הזה יהפוך את קובצי ה-DEX לקטנים יותר, כי הקידומת של החבילה מושמטת בשמות המחלקה שנארזים מחדש.חשוב לבסס כללי שמירה לגבי כל הפריטים שהגישה אליהם מתבצעת באמצעות reflection. גם אם פריטים כאלה נשמרים על ידי R8 ללא כללי שמירה מפורשים, חשוב להקפיד להטמיע כללים בפועל. שינויים עתידיים בקוד עלולים לגרום לכך ש-R8 לא ישמור יותר את הפריטים האלה.
כדי להשתמש ברפלקציה בקוד שלכם, אתם יכולים להשתמש ב-Jetpack Keep כדי ליצור כללי שמירה שקל יותר לתחזק. כל הערה נמצאת בקוד שמבצע את ההשתקפות, כך שאם משנים את הקוד, מעדכנים או מסירים את ההערה שלו באותו מקום. כך הכללים לא ישמרו קוד שהאפליקציה כבר לא משקפת. Lint גם מסמן קריאות רפלקטיביות שלא נוספו להן הערות.
כשאפשר, כדאי להשתמש ב-
-assumenosideeffectsאו ב--convertchecknotnullכדי לבצע אופטימיזציה של בדיקות null, כי זה יכול להקטין משמעותית את גודל ה-DEX של האפליקציה. מידע נוסף זמין במאמר סוגי כללים נוספים.
אם אתם לא יכולים לפעול לפי ההנחיות האלה, אתם יכולים לבודד באופן זמני את הקוד שצריך לשמור בחבילה ייעודית ולהחיל את כלל השמירה על החבילה. עם זאת, זה לא פתרון לטווח הארוך. מידע נוסף זמין במאמר הטמעת אופטימיזציות באופן הדרגתי. כדי להשתמש בכלל שמירה לחבילה, מגדירים כלל שמירה כמו בדוגמה הבאה:
-keepclassmembers class com.example.pkg.** { *; }
מה לא לעשות
לתחביר של כלל השמירה יש הרבה אפשרויות, אבל כדי ליהנות מיתרונות מדידים ומתמשכים בביצועים, אנחנו ממליצים לא להשתמש באפשרויות הבאות:
- אל תשתמשו בכללי שמירה שחלים על כל החבילה, כמו
-keep class com.example.pkg.** { *; }לטווח ארוך. אפשר להשתמש בהם באופן זמני כדי לעקוף בעיות בהגדרת R8. מידע נוסף זמין במאמר בנושא הגבלת היקף האופטימיזציה. באופן כללי, צריך להיזהר עם תווים כלליים – חשוב לוודא ששומרים רק את הקוד שצריך. - במידת האפשר, כדאי להימנע מספריות שמציעות להעתיק ולהדביק כללי שמירה כשמשתמשים בהן, במיוחד כללי שמירה שחלים על כל החבילה. בספריות שמיועדות לפעול בצורה טובה ב-Android, מומלץ להימנע ככל האפשר משימוש ב-reflection, ולהטמיע כללי שמירה על נתונים של צרכנים כשהדבר נדרש.
- מומלץ להימנע משימוש באופרטור ההיפוך
!בכללי השמירה, כי זה יכול לגרום לכלל לפעול בטעות על כמעט כל מחלקה באפליקציה.
אם אתם לא מצליחים לפעול לפי הכללים האלה, יכול להיות שאתם משתמשים ב-reflection פתוח בהיקף מאוד גדול. כדאי להימנע מ-reflection או מהספרייה באמצעות reflection (ראו את המקרה לדוגמה של Gson).