به شبکه متصل شوید

برای انجام عملیات شبکه در برنامه‌تان، مانیفست شما باید شامل اجازه‌های زیر باشد:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

روال‌های مطلوب برای ارتباطات شبکه ایمن

قبل‌از افزودن عملکرد شبکه‌سازی به برنامه‌تان، باید مطمئن شوید که داده‌ها و اطلاعات درون برنامه‌تان هنگام انتقال ازطریق شبکه ایمن می‌مانند. برای انجام این کار، این روال‌های مطلوب امنیت شبکه را دنبال کنید:

  • مقدار داده‌های کاربر حساس یا شخصی را که ازطریق شبکه منتقل می‌کنید به حداقل برسانید.
  • همه ترافیک شبکه را از برنامه‌تان ازطریق SSL ارسال کنید.
  • پیکربندی امنیت شبکه ایجاد کنید که به برنامه‌تان اجازه می‌دهد به مراجع صدور گواهی (CA) سفارشی اعتماد کند یا مجموعه مراجع صدور گواهی سیستم را که برای ارتباط امن به آن‌ها اعتماد دارد محدود کند.

برای اطلاعات بیشتر درباره نحوه اعمال اصول شبکه‌سازی ایمن، نکات امنیتی شبکه‌سازی را ببینید.

انتخاب کارخواه HTTP

اکثر برنامه‌های متصل به شبکه از HTTP برای ارسال و دریافت داده استفاده می‌کنند. پلاتفرم Android شامل کارخواه HttpsURLConnection است که از TLS، بارگذاری و بارگیری جاری‌سازی، زمان‌های استراحت قابل‌پیکربندی، IPv6، و ادغام اتصال پشتیبانی می‌کند.

کتابخانه‌های طرف سوم که میاناهای برنامه‌سازی کاربردی سطح بالاتری برای عملیات شبکه‌سازی ارائه می‌دهند نیز دردسترس هستند. این کتابخانه‌ها از ویژگی‌های راحتی مختلفی پشتیبانی می‌کنند، مانند سریال‌سازی بدنه‌های درخواست و واگرد سریال‌سازی بدنه‌های پاسخ.

  • Retrofit: یک کارخواه HTTP با ایمنی تایپی برای JVM از Square که بر روی OkHttp ساخته شده است. Retrofit به شما امکان می‌دهد میانای کارخواه را به‌صورت اعلانی ایجاد کنید و از چندین کتابخانه سریال‌سازی پشتیبانی می‌کند.
  • Ktor: یک کارخواه HTTP از JetBrains، که کاملاً برای Kotlin ساخته شده و با روال‌های مشترک کار می‌کند. Ktor از موتورها، سریال‌سازها، و پلاتفرم‌های مختلفی پشتیبانی می‌کند.

حل‌وفصل کردن پُرسمان‌های ساناد

دستگاه‌هایی که Android نسخه ۱۰ (سطح میانای برنامه‌سازی کاربردی ۲۹) و بالاتر را اجرا می‌کنند، از پشتیبانی داخلی برای جستجوهای DNS تخصصی ازطریق جستجوهای متن ساده و حالت DNS-over-TLS برخوردارند. DnsResolver API وضوح عمومی و ناهمگام ارائه می‌دهد که به شما امکان می‌دهد SRV، NAPTR، و انواع دیگر رکورد را جستجو کنید. تجزیه پاسخ به برنامه واگذار می‌شود.

در دستگاه‌هایی که از Android 9 (سطح میانای برنامه کاربردی ۲۸) و پایین‌تر استفاده می‌کنند، رافع سامانه نام دامنه پلاتفرم فقط از رکوردهای A و AAAA پشتیبانی می‌کند. این ابزار به شما امکان می‌دهد نشانی‌های IP مرتبط با یک نام را جستجو کنید، اما از انواع دیگر سوابق پشتیبانی نمی‌کند.

برای برنامه‌های مبتنی بر NDK، به android_res_nsend مراجعه کنید.

کپسوله‌سازی عملیات شبکه با مخزن

برای ساده کردن فرایند انجام عملیات شبکه و کاهش تکرار کد در بخش‌های مختلف برنامه‌تان، می‌توانید از الگوی طراحی مخزن استفاده کنید. مخزن کلاسی است که عملیات داده را مدیریت می‌کند و انتزاع API تمیزی را روی برخی داده‌ها یا منابع خاص ارائه می‌دهد.

می‌توانید از Retrofit برای اعلام واسطی استفاده کنید که روش HTTP، نشانی وب، آرگومان‌ها، و نوع پاسخ را برای عملیات شبکه مشخص می‌کند، مانند مثال زیر:

کاتلین

interface UserService {
    @GET("/users/{id}")
    suspend fun getUser(@Path("id") id: String): User
}

جاوا

public interface UserService {
    @GET("/user/{id}")
    Call<User> getUserById(@Path("id") String id);
}

در کلاس مخزن، توابع می‌توانند عملیات شبکه را کپسوله‌سازی کنند و نتایج آن‌ها را نمایش دهند. این کپسوله‌سازی تضمین می‌کند که مؤلفه‌هایی که مخزن را فراخوانی می‌کنند نیازی به دانستن نحوه ذخیره داده‌ها ندارند. هرگونه تغییرات آتی در نحوه ذخیره داده‌ها نیز به کلاس مخزن محدود می‌شود. برای مثال، ممکن است تغییری از راه دور داشته باشید، مانند به‌روزرسانی نقاط پایانی API، یا ممکن است بخواهید ذخیره‌سازی محلی را پیاده‌سازی کنید.

کاتلین

class UserRepository constructor(
    private val userService: UserService
) {
    suspend fun getUserById(id: String): User {
        return userService.getUser(id)
    }
}

جاوا

class UserRepository {
    private UserService userService;

    public UserRepository(
            UserService userService
    ) {
        this.userService = userService;
    }

    public Call<User> getUserById(String id) {
        return userService.getUser(id);
    }
}

برای جلوگیری از ایجاد رابط کاربری غیرپاسخگو، عملیات شبکه را در رشته اصلی انجام ندهید. به‌طور پیش‌فرض، Android از شما می‌خواهد عملیات شبکه را در رشته‌ای غیراز رشته اصلی میانای کاربر انجام دهید. اگر سعی کنید عملیات شبکه را در رشته اصلی انجام دهید، NetworkOnMainThreadException پرتاب می‌شود.

در نمونه کد قبلی، عملیات شبکه درواقع راه‌اندازی نمی‌شود. فراخواننده UserRepository باید رشته‌بندی را بااستفاده از کوروتین‌ها یا بااستفاده از تابع enqueue() پیاده‌سازی کند. برای اطلاعات بیشتر، codelab دریافت داده از اینترنت را ببینید، که نحوه پیاده‌سازی رشته‌بندی بااستفاده از کوروتین‌های Kotlin را نشان می‌دهد.

حفظ شدن درصورت تغییر پیکربندی

وقتی تغییری در پیکربندی رخ می‌دهد، مثلاً چرخش صفحه‌نمایش، قطعه یا فعالیت شما ازبین می‌رود و دوباره ایجاد می‌شود. هر داده‌ای که در وضعیت نمونه برای فعالیت قطعه شما ذخیره نشده باشد، که فقط می‌تواند مقادیر کمی داده را نگه دارد، ازبین می‌رود. اگر این اتفاق بیفتد، ممکن است لازم باشد درخواست‌های شبکه‌تان را دوباره انجام دهید.

می‌توانید از ViewModel استفاده کنید تا داده‌هایتان در تغییرات پیکربندی حفظ شود. مؤلفه ViewModel برای ذخیره و مدیریت داده‌های مرتبط با واسط کاربر به‌گونه‌ای طراحی شده است که از چرخه حیات آگاه باشد. بااستفاده از UserRepository قبلی، ViewModel می‌تواند درخواست‌های شبکه لازم را انجام دهد و نتیجه را بااستفاده از LiveData به قطعه یا فعالیت شما ارائه دهد:

کاتلین

class MainViewModel constructor(
    savedStateHandle: SavedStateHandle,
    userRepository: UserRepository
) : ViewModel() {
    private val userId: String = savedStateHandle["uid"] ?:
        throw IllegalArgumentException("Missing user ID")

    private val _user = MutableLiveData<User>()
    val user = _user as LiveData<User>

    init {
        viewModelScope.launch {
            try {
                // Calling the repository is safe as it moves execution off
                // the main thread
                val user = userRepository.getUserById(userId)
                _user.value = user
            } catch (error: Exception) {
                // Show error message to user
            }

        }
    }
}

جاوا

class MainViewModel extends ViewModel {

    private final MutableLiveData<User> _user = new MutableLiveData<>();
    LiveData<User> user = (LiveData<User>) _user;

    public MainViewModel(
            SavedStateHandle savedStateHandle,
            UserRepository userRepository
    ) {
        String userId = savedStateHandle.get("uid");
        Call<User> userCall = userRepository.getUserById(userId);
        userCall.enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                if (response.isSuccessful()) {
                    _user.setValue(response.body());
                }
            }

            @Override
            public void onFailure(Call<User> call, Throwable t) {
                // Show error message to user
            }
        });
    }
}

برای کسب اطلاعات بیشتر درباره این موضوع، راهنماهای مرتبط زیر را ببینید: