یوشا

دست نوشته ها و تجربیات شخصی

یوشا

دست نوشته ها و تجربیات شخصی

شهید دکتر مصطفی چمران: می گویند تقوا از تخصص لازمتر است، آنرا می پذیرم، اما می گویم آنکس که تخصص ندارد و کاری را می پذیرد بی تقواست!

طبقه بندی موضوعی
تبلیغات
Blog.ir بلاگ، رسانه متخصصین و اهل قلم، استفاده آسان از امکانات وبلاگ نویسی حرفه‌ای، در محیطی نوین، امن و پایدار bayanbox.ir صندوق بیان - تجربه‌ای متفاوت در نشر و نگهداری فایل‌ها، ۳ گیگا بایت فضای پیشرفته رایگان Bayan.ir - بیان، پیشرو در فناوری‌های فضای مجازی ایران

1- با اضافه کردن خاصیت android:supportsRtl="true" در تگ application فایل AndroidManifiest.xml، مشکل راست به چپ صفحات preferences تون حل خواهد شد. (برای اندروید 4.2 به بعد)

 

2- آیا میدونید هیچ تفاوتی بین fill_parent و match_parent در خاصیت عناصر گرافیکی وجود نداره و هر دو دارای مقدار 1- هستند؟

این مسئله فقط یک تغییر نام جزیی بوده که از API 8 به بعد صورت گرفته و پیشنهاد شده که از match_parent استفاده بشه.

 

3- از انجایی که SharedPreference ها عملیات read/write برروی دیسک انجام میدن و معمولاً هم در متد OnCreate() یا OnResume() فراخوانی و load می شن، پس بهتره در thread غیر از UI اعمال بشن، تا برنامه رو دچار وقفه نکنن.

همچنین لازم نیست نگران تعدد عملیات باشید، چراکه SharedPreference یک شی Singleton هست و فقط یکبار بارگذاری میشه.

 

4- در بیشتر مواقع با استفاده از عبارات زیر در تعاریف HttpURLConnection کدتون، خطای recvfrom failed: ECONNRESET (Connection reset by peer) برطرف خواهد شد:

System.setProperty("http.keepAlive", "false");
myHttpUrlConnection.setRequestProperty("connection", "close");

 

5- برای حل مشکل GC overhead limit exceeded در برنامه Eclipse کافیه ظرفیت حافظه Heap این برنامه رو در فایل eclipse.ini تغییر بدید:

-XX:MaxPermSize=1024m
-Xms512m
-Xmx1024m

6- نکته جزیی: آیا میدونید کال بک onCancel() فقط توسط دستور cancel() صدا زده میشه؟

 

7- با استفاده از تگ <include> قادر خواهید بود از طراحی Layout های تکراری اجتناب کنید، و Layout های مشترک/تکراری رو re-use کنید!

 

8- فراموش نکنید که ViewHolder خلاصه ترین و بهترین گزینه برای هندل کردن عناصر گرافیکی ListView هستش.

 

9- آیا میدونید مقدار DEBUG در فایل BuildConfig.java تنها زمانی false میشه که برنامه بصورت Signed Application Package کامپایل/export بشه؟

راه ساده برای اطلاع رسانی:

if (<MY-PACKAGE-NAME>.BuildConfig.DEBUG)
{
   Log.wtf(LOG_TAG, "DEBUG-MODE IS ONE!");
}

نکته: این فایل Build.Config.java بصورت خودکار تولید و در مسیر /gen/<MY-PACKAGE-NAME>/BuildConfig.java قرار داره.

 

10- جهت افزایش سرعت برنامه Android Studio میتونید:

1- پلاگین های بلااستفاده رو از مسیر File -> Settings -> Plugins غیرفعال کنید:

Android Games
Copyright
CVS Integeration
Mercurial integration
hg4idea
Subversion integration
Task management

2- از منوی File حالت PowerSaving برنامه Android Studio رو فعال کنید.

3- یک درایو SSD خریداری کنید!

 

11- آیا میدونید در HttpURLConnection باید redirect ها رو بصورت دستی هندل کنید؟

به این صورت که ابتدا کد header ارسال شده از طرف سرور رو توسط getResponseCode بررسی می کنید، اگر با HTTP_MOVED_TEMP یا HTTP_MOVED_PERM یا HTTP_SEE_OTHER برابر بود، توسط getHeaderField محتوای فیلد Location و Set-Cookie رو بازیابی می کنید و مجدداً درخواست دیگه ای با URL جدید بهمراه کوکی ارسال می کنید.

 

12- آیا می دونید هنگامی که دستگاه با وضعیت low internal storage space مواجه میشه، اندروید بصورت خودکار cache برنامه ها رو(بدون اطلاع رسانی) پاک میکنه؟

 

13- (بطور پیشفرض) اگر برنامه ای رو از طریق صفحه Home باز کنید، اکتیویتی Main برنامه بازمیشه، درصورتی که اگر همون برنامه رو از طریق صفحه Recent apps باز کنید، آخرین اکتیویتی که درش حضور داشتید باز میشه. (در اندروید 2 به بعد)

 

14- نکته جزیی برای API 17 به قبل: به دلایل امنیتی، گوگل پیشنهاد کرده که در حین کار با دستور getSharedPreferences، از حالت MODE_PRIVATE استفاده کنید.

چرا؟ چون این حالت تعیین می کنه فقط برنامه ای که اون preference رو ساخته بتونه بهش دسترسی داشته باشه، و نه دیگر برنامه ها.

MODE_PRIVATE: File creation mode: the default mode, where the created file can only be accessed by the calling application (or all applications sharing the same user ID).

نکته: این فایل preference بطور پیشفرض در مسیر /data/data/<YOUR-PACKAGE-NAME>/shared_prefs/ دستگاه تون قرار داره.

 

15- نکته جزیی: SharedPreference ها برای ذخیره تنظیمات برنامه هستند، و نه ذخیره data ی برنامه!

 

16- SharedPreferences.commit() یا SharedPreferences.apply() ؟

apply: در اندروید 2.3 به بعد تعبیه شده، هیچ return ای بعد از انجام عملیات نداره(چه failure بشه چه success)، کمی سریعتر از commit هستش، داده ها رو بصورت asynchronously ذخیره میکنه(thread ش رو قفل نمی کنه)، اطلاعات رو سریعاً در RAM ثبت میکنه و بعد روی دیسک ذخیره میکنه و...

commit: در همه نسخ اندروید وجود داره، مقدار return ش نسبت به failure/success شدن boolean هستش، کمی کندتر از apply هستش، داده ها رو بصورت synchronously ذخیره میکنه(thread ش رو قفل می کنه)، اطلاعات رو مستقیماً برروی دیسک ذخیره میکنه و بهتره بکمک multi-threading طراحی بشه...

 

17- یک تابع پیشنهادی بهبود یافته برای استفاده از دستورات commit/apply:

public static final void iCommit(final SharedPreferences.Editor editor)
{
   if (Build.VERSION.SDK_INT >= 9) // Gingerbread
   {
      editor.apply();
   }
   else
   {
      new Thread()
      {
         @Override
         public void run()
         {
            editor.commit();
         }
      }.start();
   }
}

 

18- فراموش نکنید برای استفاده از اینترفیس OnSharedPreferenceChangeListener و کال بک onSharedPreferenceChanged() باید shared preferences رو در متد OnResume() و OnPause() ثبت کنید:

@Override
protected final void onResume()
{
    getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    super.onResume(); // Call at last.
}

@Override
protected final void onPause()
{
    getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
    super.onPause(); // Call at last.
}

 

19- دقت کنید که کاربرد و رفتار اینترفیس OnPreferenceChangeListener با OnSharedPreferenceChangeListener متفاوته!

اینترفیس OnPreferenceChangeListener زمانی فعال میشه که تغییری در کلیدش صورت بگیره(یک کلید)، اما OnSharedPreferenceChangeListener زمانی فعال میشه که تغییری در کل SharedPreference صورت بگیره... همچنین برای استفاده از کال بک OnPreferenceChangeListener باید کلید رو توسط findPreference ثبت کنید تا بتونه رویدادها رو شنود کنه.

 

20- در بیشتر مواقع دلیل رخداد اثتثنای NoClassDefFoundError android.os.AsyncTask باگیه که در Google Play Service وجود داره و بسادگی با روش زیر قابل حله:

try
{
    Class.forName("android.os.AsyncTask"); // Fix AsyncTask bug.
}
catch (final ClassNotFoundException exception)
{

}

 

21- دیده شده در خیلی از برنامه ها برای قراردادن فضاهای Blank در layout برنامه، از عنصر TextView یا حتی LinearLayout استفاده شده! در صورتی که باید از عنصر <View> یا <Space> (برای API 14 به بعد) استفاده بشه، اون هم به این شکل:

برای اندروید های 2 به بعد
<View android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"/>

برای اندروید های 4 به بعد
<Space android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"/>

 

22- در بعضی موارد با اضافه کردن header های زیر در HttpClient یا UrlConnection تون، مشکل FileNotFoundException رفع خواهد شد:

"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*"
"User-Agent", "Mozilla/5.0 ( compatible ) "

 

23- آیا می دونید در try/finally بلوک finally همیشه اجرا میشه، بجز زمانی که System.exit صدا زده بشه یا VM بسته بشه یا StackOverflowException پرتاب بشه؟

نکته: درصورتی که دستور System.exit استثنای SecurityException رو پرتاب کنه، بلوک finally اجرا خواهد شد.

 

24- در بعضی موارد با استفاده از getText().clear() بجای setText("")، خطای X on inactive InputConnection برطرف خواهد شد.

 

25- همچنین در بعضی موارد، با بستن Keyboard برنامه قبل از بستن شدن Fragment/Activity، خطای showStatusIcon on inactive InputConnection برطرف خواهد شد:

@Override
protected void onPause()
{
    super.onPause();
    View _view = getCurrentFocus();

    if (_view != null)
    {
        final InputMethodManager _imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
        if (_imm != null)
        {
            _imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
        }
        _view.clearFocus();
        _view.setFocusable(false);
    }
}

 

26- در صورتی که از UrlConnection برای POST استفاده می کنید و با خطای ProtocolException: content-length promised x bytes, but received 0 مواجه شدید(در اندروید 4 به بعد)، بدونید که نباید Content-Length رو خودتون تنظیم کنید و باید به عهده خود UrlConnection بذارید تا تنظیمش کنه... پس اون خط رو حذف کنید.

 

27- برای اینکه کیبورد نرم افزاری، در حالت landscape تمام صفحه رو پوشش نده، باید:

- خاصیت android:windowSoftInputMode="adjustResize" رو به تگ Activity فایل AndroidManifiest.xml اضافه کنید.

- یا خاصیت android:imeOptions="flagNoExtractUi" رو به تگ EditText فایل layout اضافه کنید.

 

28- یک تابع پیشنهادی بهبود یافته برای استفاده از ClipboardManager، سازگار با تمام نسخه های اندروید:

public static final void copyToClipboard(final Context context, final EditText edit_text)
{
    final ClipboardManager _clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);

    if (_clipboardManager != null)
    {
        if (Build.VERSION.SDK_INT >= 3) // Honeycomb
        {
            final ClipData _clipData = ClipData.newPlainText(" ", edit_text.getText().toString());
            _clipboardManager.setPrimaryClip(_clipData);
        }
        else
        {
            _clipboardManager.setText(edit_text.getText().toString());
        }
    }
}

 

29- نکته جزیی: فراموش نکنید که داده نوع NULL همیشه یک مقدار Invalid/نامعتبر هستش و هرچیزی بجز NULL یک مقدار Valid/معتبر هستش، حنی ""

 

30- نکاتی درباره متد toString() و valueOf():

- متد valueOf در پشت پرده متده toString رو صدا می زنه.

- از نظر سرعت، متد toString کمی سریعتر از متد valueOf هستش.

- valueOf رو میشه گفت flexible تره و بازه دیتایی بیشتری رو قبول می کنه.

- اگر داده ورودی به این متد ها NULL باشه، متد toString استثنای NullPointerException پرتاب میکنه، در صورتی که متد valueOf رشته "null" رو برمیگردونه(null-safe هستش).

- valueOf یک متد static هستش، درصورتی که toString یک متد object.

 

31- یادتون باشه که تنها دلیل استفاده از ابزارهای اتوماسیون build(مثل gradle, maven, phing, ant) فقط کاهش خطاهای انسانی و صرفه جویی در زمان هستش.

 

32- از Java 6 به بعد(JDBC 4.0) دیگر نیازی به لود کردن درایور دیتابیس توسط دستور Class.forname یا registerDriver نیست، اینکار توسط JVM بصورت خودکار انجام میشه. (درصورت وجود فایل Driver)

 

33- همیشه اطلاعات ورودی/کاربر رو قبل از ثبت کردن در log، ابتدا فیلترسازی کنید!

 

34- هرگز از اعداد منفی برای تعیین Status/Exit code استفاده نکنید. از انجاییکه برای سیستم هر چیزی جز عدد 0 به FALSE ترجمه میشه و بسیاری از زبانها قابلیت return کردن اعداد منفی برای Status/Exit code رو ندارن، بهترین مقدار اعداد 0 یا مثبت هستن.

 

35- کاربردها و اهداف بلوک های static:

- برای initialize کردن کدهای استاتیک(static) که هنگام Load شدن کلاس(توسط classloader) اعمال بشن

public static Map<String, String> myField = new HashMap<String, String>();

static
{
   myField.put("Test name", "Test value");
   // ...
}

- برای initialize کردن کلاسهای master

public class MasterClass
{
   static
   {
      SlaveClass.initialize();
      // ...
   }
}

- بارگذاری کتابخانه های Native

static
{
   System.loadLibrary("TestLibrary");
}

توجه: باید فیلدهای static در بلوک static قرار بگیرند و initialize بشن و نه در constructor! اینها بخشی از class definition هستن و نه object.

 

36- نکاتی راجب الگوهای طراحی DAO و Repository:

هردو object-oriented هستن

هردو زیر مجموعه Integration Tier Design Pattern هستن

هردو در لایه DAL یا persistence layer قرار دارن و برای پیاده سازی این لایه ها استفاده میشن

هردو میتونن Object یا دسته ای از Objects رو return کنن

هردو میتونن برای دور نگه داشتن application از تکنولوژی زیرساختی data source استفاده بشن(در واقع یک  uniform data access API)

DAO به data source نزدیکتره اما Repository به application نزدیکتره

از DAO بیشتر برای دسترسی به Entities استفاده میشه و از Repository بیشتر برای سرهم کردن چند کلاس/خروجی DAO

از DAO برای مخفی سازی مباحث سطح پایین data source و پیچیدگی ها استفاده میشه

DAO معمولاً به data source vendor خاصی وابسته نیست

DAO معمولاً table محور هست اما Repository معمولاً Object محور

 

37- نکاتی راجب الگوهای Dependency Injection, Service Locator, Inversion of Control:

- الگوی Dependency Inversion Principle (DIP) منتسب به تجزیه کردن کد هستش، به این صورت که کلاسهای سطح بالا نباید به قسمت های سطح پایینتر وابستگی مستقیم داشته باشه، بلکه باید توسط لایه abstract یا interface به سطوح پایینتر وابستگی داشته باشند.

- Dependency Injection یک الگو هست اما Container و Inversion of Control یک روش برای اجرای الگوی DI.

- توسط الگوی Inversion of Control قادرید dependency اشیا رو بعد از compile یا در محیط production هم تغییر بدید.

 

38- تفاوت Service Locator با الگوهای DI:

- Service Locator امکان resolve کردن dependency رو "از داخل کلاس" فراهم میکنه. اما DI امکان inject کردن dependency رو "از خارج کلاس" فراهم میکنه.

- همه dependency ها به Service Locator وابسته میشن(خود یک dependency هستش). اما DI فقط یکبار هنگام startup فراخوانی میشه.

- dependency در DI (نوع constructor) صریح و مشخص inject میشه اما در Service Locator اینطور نیست.

- خوانایی در الگوی Service Locator پایین تر از DI هستش.

 

39- نکته جزیی: در دنیای Java واژه Entity درواقع همون Model یا POJO هستش که به یک Table در دنیای database اشاره داره.

 

40- همیشه از language keywords(مثل int, string, float) بجای base class type(مثل Integer, String, Double) استفاده کنید.

 

مقالات مرتبط

نکات و اصول مهم در برنامه نویسی Java/Android

#2 - نکات و اصول مهم در برنامه نویسی Java/Android

#4 - نکات و اصول مهم در برنامه نویسی Java/Android

#5 - نکات و اصول مهم در برنامه نویسی Java/Android

#6 - نکات و اصول مهم در برنامه نویسی Java/Android

#7 - نکات و اصول مهم در برنامه نویسی Java/Android

نظرات (۱)

۰۶ آبان ۹۵ ، ۱۳:۱۳ فرهاد حسن‌پور
ممنون بهرمند شدیم.
کاربران بیان میتوانند بدون نیاز به تأیید، نظرات خود را ارسال کنند.
اگر قبلا در بیان ثبت نام کرده اید لطفا ابتدا وارد شوید، در غیر این صورت می توانید ثبت نام کنید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">