021-88881776

آموزش شبکه و APIها در Java

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

کار با HTTP requests و ارتباط با سرور از طریق REST API

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

مفهوم REST API

REST (که مخفف “Representational State Transfer” است) یک معماری برای توسعه سرویس‌های وب است که به کمک پروتکل HTTP عملیات‌های مختلف مانند ارسال، دریافت، حذف و به‌روزرسانی داده‌ها را انجام می‌دهد. REST API یک رابط برنامه‌نویسی است که به کمک آن می‌توان از طریق HTTP با سرورهای RESTful ارتباط برقرار کرد.

در REST API، معمولاً از چهار عمل اصلی HTTP برای تعامل با منابع استفاده می‌شود:

GET: برای دریافت داده‌ها از سرور.
POST: برای ارسال داده‌ها به سرور.
PUT: برای به‌روزرسانی داده‌ها در سرور.
DELETE: برای حذف داده‌ها از سرور.

ارسال درخواست GET به یک API

در مثال زیر، ما یک درخواست GET به یک API RESTful ارسال می‌کنیم تا داده‌ها را از سرور دریافت کنیم. این درخواست به آدرس https://jsonplaceholder.typicode.com/posts ارسال می‌شود، که یک API رایگان است و برای آزمایش استفاده می‌شود.

کد نمونه:

import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class HttpExample {
    public static void main(String[] args) throws Exception {
        // آدرس URL هدف که به آن درخواست ارسال می‌کنیم
        URL url = new URL("https://jsonplaceholder.typicode.com/posts");

        // ایجاد ارتباط HTTP
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        // تعیین روش درخواست HTTP (در اینجا GET)
        connection.setRequestMethod("GET");

        // خواندن پاسخ از سرور
        InputStreamReader reader = new InputStreamReader(connection.getInputStream());
        int data = reader.read();
        
        // نمایش داده‌های دریافتی به صورت متنی
        while (data != -1) {
            System.out.print((char) data);
            data = reader.read();
        }
        
        // بستن جریان خواندن داده‌ها
        reader.close();
    }
}

توضیحات کد:
آدرس URL: در ابتدا یک شیء از نوع URL ایجاد می‌کنیم که شامل آدرس REST API است که قرار است به آن درخواست بفرستیم.

ایجاد ارتباط HTTP: برای برقراری ارتباط با سرور، از HttpURLConnection استفاده می‌کنیم. این کلاس به ما این امکان را می‌دهد که درخواست‌های HTTP را ارسال کنیم و پاسخ‌های سرور را دریافت کنیم.

تعیین روش درخواست: با استفاده از متد setRequestMethod، نوع درخواست HTTP را مشخص می‌کنیم. در این مثال، از GET استفاده کرده‌ایم که برای دریافت داده‌ها از سرور است.

خواندن داده‌های پاسخ: پس از ارسال درخواست، برای دریافت پاسخ از سرور از InputStreamReader استفاده می‌کنیم. این کلاس به ما اجازه می‌دهد تا داده‌هایی که از سرور دریافت می‌کنیم را به صورت رشته‌های متنی بخوانیم.

نمایش داده‌ها: داده‌هایی که از سرور دریافت می‌شوند را در حلقه‌ای می‌خوانیم و چاپ می‌کنیم. این داده‌ها معمولاً به صورت JSON یا متن ساده خواهند بود.

بستن جریان: پس از خواندن تمام داده‌ها، باید جریان ورودی را ببندیم تا منابع سیستم آزاد شوند.

نکات مهم:

Status Code: در این کد ما به جزئیات وضعیت پاسخ (status code) اشاره نکردیم، اما معمولاً بررسی وضعیت پاسخ سرور نیز بسیار مهم است. مثلاً اگر کد وضعیت 200 OK دریافت کنیم، به این معنی است که درخواست موفقیت‌آمیز بوده است. در غیر این صورت باید کدهای خطای مختلف مانند 404 Not Found یا 500 Internal Server Error را بررسی کنیم.

Headers: معمولاً در درخواست‌های HTTP باید هدرهایی مانند نوع محتوا (Content-Type) یا کلیدهای احراز هویت (Authorization) را تنظیم کنید. در این کد، این موارد به سادگی نادیده گرفته شده‌اند، اما در موارد واقعی باید این هدرها را به درخواست اضافه کنید.

استفاده از JSON در پاسخ

بیشتر API‌ها برای تبادل داده‌ها از فرمت JSON استفاده می‌کنند. بنابراین، بعد از دریافت داده‌ها از سرور، ممکن است بخواهید آن‌ها را پردازش کرده و به ساختارهای داده‌ای جاوا تبدیل کنید. در این صورت، می‌توانید از کتابخانه‌هایی مانند Gson یا Jackson استفاده کنید.

برای مثال، فرض کنید پاسخ سرور به صورت JSON است و شما می‌خواهید این داده‌ها را به اشیاء جاوا تبدیل کنید. در این صورت می‌توانید از Gson برای تبدیل JSON به شیء جاوا استفاده کنید.

نمونه تبدیل JSON به شیء جاوا:

import com.google.gson.Gson;

class Post {
    int id;
    String title;
    String body;
}

public class GsonExample {
    public static void main(String[] args) {
        String json = "{\"id\": 1, \"title\": \"Post Title\", \"body\": \"Post Body\"}";
        Gson gson = new Gson();
        
        // تبدیل JSON به شیء جاوا
        Post post = gson.fromJson(json, Post.class);
        
        System.out.println("ID: " + post.id);
        System.out.println("Title: " + post.title);
        System.out.println("Body: " + post.body);
    }
}

در این کد، با استفاده از Gson، پاسخ JSON به یک شیء جاوا تبدیل می‌شود که می‌توان آن را راحت‌تر پردازش کرد. کار با HTTP requests و ارتباط با سرور از طریق REST API یکی از مهارت‌های پایه‌ای در توسعه برنامه‌های تحت وب است. در این مقاله، شما یاد گرفتید که چگونه از کلاس HttpURLConnection برای ارسال درخواست‌های HTTP استفاده کنید و داده‌ها را از سرور دریافت کنید. همچنین، با استفاده از Gson می‌توانید داده‌های JSON را به شیء جاوا تبدیل کنید. این مفاهیم به شما این امکان را می‌دهند که به راحتی با API‌های مختلف ارتباط برقرار کنید و داده‌ها را پردازش کنید.

استفاده از Retrofit برای ارتباط با API‌ها

Retrofit یکی از محبوب‌ترین و قدرتمندترین کتابخانه‌های جاوا است که برای تعامل با REST API‌ها طراحی شده است. این کتابخانه توسط Square توسعه یافته و هدف اصلی آن ساده‌سازی فرآیند ارسال HTTP requests و دریافت پاسخ‌ها از سرور است. در مقایسه با استفاده مستقیم از HttpURLConnection یا سایر کتابخانه‌های مشابه، Retrofit کدنویسی را بسیار راحت‌تر کرده و مدیریت خطاها، پردازش داده‌ها و انجام درخواست‌های پیچیده را ساده‌تر می‌کند.

مزایای استفاده از Retrofit

سادگی استفاده: Retrofit با یک API ساده و قابل فهم، ارسال درخواست‌های پیچیده را آسان‌تر می‌کند. این کتابخانه به طور خودکار تبدیل داده‌های JSON به اشیاء جاوا و بالعکس را انجام می‌دهد.

پشتیبانی از انواع مختلف درخواست‌ها: Retrofit از تمامی متدهای HTTP مانند GET, POST, PUT, DELETE پشتیبانی می‌کند و می‌تواند درخواست‌های پیچیده با پارامترهای مختلف را نیز مدیریت کند.

مدیریت آسان پاسخ‌ها: Retrofit به شما این امکان را می‌دهد که به راحتی پاسخ‌های سرور را با انواع مختلف (مانند JSON یا XML) پردازش کنید. این کتابخانه به کمک Converter Factory داده‌ها را به نوع دلخواه تبدیل می‌کند.

پشتیبانی از درخواست‌های غیرهمزمان (Asynchronous): Retrofit به راحتی درخواست‌ها را به صورت غیرهمزمان ارسال می‌کند، بنابراین شما می‌توانید از مسدود شدن رابط کاربری جلوگیری کرده و عملکرد بهتری را ارائه دهید.

نصب Retrofit در پروژه

برای استفاده از Retrofit در پروژه‌های جاوا، ابتدا باید آن را به فایل build.gradle پروژه اضافه کنید. به این ترتیب، می‌توانید از نسخه‌های جدید Retrofit و دیگر اجزای آن استفاده کنید.

اضافه کردن Retrofit به پروژه:

// اضافه کردن Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'

// اضافه کردن Gson Converter برای تبدیل JSON به اشیاء جاوا
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'

در این کد، GsonConverterFactory به Retrofit اضافه می‌شود تا بتواند داده‌های JSON را به اشیاء جاوا تبدیل کند. این کار برای تعامل با API‌هایی که خروجی JSON دارند ضروری است.

ساختار اصلی Retrofit

ApiService Interface: در Retrofit، ابتدا باید یک interface برای تعریف درخواست‌های HTTP ایجاد کنید. این interface شامل متدهایی است که هرکدام نمایانگر یک درخواست HTTP هستند. هر متد از نوع Call<T> است که T نوع داده‌ای است که قرار است به صورت پاسخ دریافت کنید.

Retrofit Builder: سپس یک شیء از Retrofit ایجاد می‌کنیم که در آن base URL سرور و هرگونه Converter لازم (مانند Gson) تعریف می‌شود.

ارسال درخواست: با استفاده از Retrofit، می‌توانیم درخواست‌ها را به صورت همزمان یا غیرهمزمان ارسال کنیم. برای درخواست‌های غیرهمزمان از متد enqueue() استفاده می‌شود که اجازه می‌دهد پاسخ سرور در یک Thread جداگانه پردازش شود.

کد نمونه استفاده از Retrofit

در اینجا یک مثال ساده از استفاده از Retrofit برای ارسال یک درخواست GET به یک REST API آورده شده است که اطلاعات پست‌ها را از یک سرور دریافت می‌کند.

کد:

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
import java.util.List;

// تعریف Interface برای ارتباط با API
interface ApiService {
    @GET("posts")  // مشخص کردن endpoint
    Call<List<Post>> getPosts();
}

// کلاس اصلی برای اجرای Retrofit
public class RetrofitExample {
    public static void main(String[] args) {
        // ساخت Retrofit با base URL و converter
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("https://jsonplaceholder.typicode.com/")  // آدرس پایه API
                .addConverterFactory(GsonConverterFactory.create())  // اضافه کردن Gson Converter برای پردازش JSON
                .build();

        // ایجاد ApiService از Retrofit
        ApiService apiService = retrofit.create(ApiService.class);

        // ارسال درخواست غیرهمزمان GET به API
        Call<List<Post>> call = apiService.getPosts();

        // ارسال درخواست و پردازش پاسخ به صورت غیرهمزمان
        call.enqueue(new Callback<List<Post>>() {
            @Override
            public void onResponse(Call<List<Post>> call, Response<List<Post>> response) {
                if (response.isSuccessful()) {
                    // چاپ لیست پست‌ها در صورت موفقیت
                    System.out.println(response.body());
                } else {
                    // در صورت بروز خطا، اطلاعات بیشتر از پاسخ نمایش داده می‌شود
                    System.out.println("Error: " + response.code());
                }
            }

            @Override
            public void onFailure(Call<List<Post>> call, Throwable t) {
                // در صورت بروز مشکل در ارتباط، خطا چاپ می‌شود
                t.printStackTrace();
            }
        });
    }
}

// مدل Post برای ذخیره داده‌ها
class Post {
    int id;
    String title;
    String body;
}

توضیحات کد:

تعریف API Interface (ApiService):

این interface شامل متد getPosts() است که یک درخواست GET به endpoint posts ارسال می‌کند.
متد Call<List<Post>> نوع داده‌ای است که از API دریافت می‌کنیم. در این مثال، یک لیست از اشیاء Post دریافت می‌کنیم که شامل فیلدهای id, title, و body است.

ساخت Retrofit Instance:

Retrofit.Builder() برای ساخت یک شیء Retrofit استفاده می‌شود. در اینجا baseUrl مشخص می‌کند که سرور اصلی کجا قرار دارد، و GsonConverterFactory.create() برای تبدیل پاسخ JSON به اشیاء جاوا استفاده می‌شود.
ارسال درخواست:

با استفاده از enqueue() درخواست به صورت غیرهمزمان ارسال می‌شود. در صورتی که پاسخ سرور دریافت شود، متد onResponse() فراخوانی می‌شود و در صورتی که خطایی رخ دهد، متد onFailure() اجرا می‌شود.

مدل داده (Post):

این کلاس یک مدل ساده است که داده‌های دریافتی از API را در خود ذخیره می‌کند.

پردازش خطا و وضعیت پاسخ

یکی از ویژگی‌های مفید Retrofit این است که مدیریت خطاها را ساده می‌کند. در متد onResponse()، شما می‌توانید وضعیت پاسخ (HTTP Status Code) را بررسی کنید تا ببینید آیا درخواست موفقیت‌آمیز بوده است یا خیر. برای مثال، اگر کد وضعیت 200 OK دریافت کنید، به این معنی است که درخواست موفقیت‌آمیز بوده است. در غیر این صورت، باید کد وضعیت را بررسی کرده و بر اساس آن اقدام کنید. با استفاده از Retrofit، تعامل با REST API‌ها در جاوا به مراتب ساده‌تر و کارآمدتر از استفاده از کتابخانه‌های استاندارد HTTP است. این کتابخانه به طور خودکار کارهای زیادی را برای شما انجام می‌دهد، از جمله پردازش JSON، مدیریت درخواست‌های همزمان و غیرهمزمان، و برخورد با خطاها. اگر به دنبال یک روش ساده و سریع برای ارتباط با API‌ها در جاوا هستید، Retrofit گزینه‌ای عالی است.

کار با JSON و Gson برای پارس کردن داده‌های JSON

یکی از مهم‌ترین بخش‌ها در تعامل با API‌ها، پارس کردن داده‌های JSON است. JSON (JavaScript Object Notation) فرمت متنی استاندارد است که برای انتقال داده‌ها بین سرور و کلاینت استفاده می‌شود. هنگامی که شما با API‌های مختلف کار می‌کنید، معمولاً پاسخ‌ها به صورت JSON خواهند بود. در جاوا برای پردازش داده‌های JSON، یکی از محبوب‌ترین کتابخانه‌ها Gson است که توسط Google توسعه داده شده است. این کتابخانه به شما این امکان را می‌دهد تا داده‌های JSON را به راحتی به اشیاء جاوا تبدیل کنید و بالعکس.

چرا از Gson استفاده کنیم؟

سادگی: Gson به طور قابل توجهی ساده است و به راحتی می‌توان از آن برای تبدیل JSON به اشیاء جاوا یا برعکس استفاده کرد.
پشتیبانی از انواع داده‌ها: Gson از انواع مختلف داده‌ها مانند لیست‌ها، آرایه‌ها، و کلاس‌های پیچیده پشتیبانی می‌کند.
سفارشی‌سازی: شما می‌توانید فرآیند تبدیل داده‌ها را سفارشی کنید و تغییرات دلخواه را در نحوه تبدیل مقادیر اعمال کنید.
سرعت: Gson نسبت به بسیاری از کتابخانه‌های دیگر سرعت بالایی دارد و می‌تواند در شرایط مختلف بهینه عمل کند

نصب Gson

برای استفاده از Gson در پروژه جاوا، ابتدا باید آن را به فایل build.gradle خود اضافه کنید:

implementation 'com.google.code.gson:gson:2.8.8'

این خط کد کتابخانه Gson را به پروژه شما اضافه می‌کند.

تبدیل JSON به اشیاء جاوا

یکی از اصلی‌ترین کاربردهای Gson، تبدیل داده‌های JSON به اشیاء جاوا است. فرض کنید یک رشته JSON از سرور دریافت کرده‌اید و می‌خواهید آن را به یک شیء جاوا تبدیل کنید تا به راحتی با آن کار کنید. در Gson، این کار با استفاده از متد fromJson() انجام می‌شود.

کد نمونه برای تبدیل JSON به شیء جاوا:

import com.google.gson.Gson;

class Post {
    int id;
    String title;
    String body;
}

public class GsonExample {
    public static void main(String[] args) {
        // یک رشته JSON که شامل اطلاعات پست است
        String json = "{\"id\": 1, \"title\": \"Post Title\", \"body\": \"Post Body\"}";

        // ایجاد شیء Gson برای تبدیل JSON به شیء جاوا
        Gson gson = new Gson();
        
        // تبدیل JSON به شیء جاوا از نوع Post
        Post post = gson.fromJson(json, Post.class);

        // نمایش اطلاعات شیء جاوا
        System.out.println("ID: " + post.id);
        System.out.println("Title: " + post.title);
        System.out.println("Body: " + post.body);
    }
}

توضیحات کد:
تعریف مدل داده (Post):

ابتدا یک کلاس Post با سه فیلد id, title و body تعریف کرده‌ایم که قرار است داده‌های JSON به این فیلدها نقشه‌گذاری شوند.
ایجاد شیء Gson:

سپس یک شیء از کلاس Gson ساخته می‌شود که برای تبدیل داده‌های JSON به اشیاء جاوا از آن استفاده می‌کنیم.
تبدیل JSON به شیء جاوا:

متد fromJson() برای تبدیل رشته JSON به شیء جاوا استفاده می‌شود. در این مثال، رشته JSON حاوی داده‌های پست است که به شیء Post تبدیل می‌شود.
چاپ اطلاعات شیء جاوا:

پس از تبدیل JSON به شیء جاوا، اطلاعات آن را با استفاده از متدهای دسترسی (getter) نمایش می‌دهیم.

تبدیل اشیاء جاوا به JSON

علاوه بر تبدیل JSON به اشیاء جاوا، Gson این امکان را نیز فراهم می‌کند که اشیاء جاوا را به فرمت JSON تبدیل کنید. این کار به وسیله متد toJson() انجام می‌شود.

کد نمونه برای تبدیل شیء جاوا به JSON:

import com.google.gson.Gson;

class Post {
    int id;
    String title;
    String body;
}

public class GsonExample {
    public static void main(String[] args) {
        // ایجاد شیء Post
        Post post = new Post();
        post.id = 1;
        post.title = "Post Title";
        post.body = "Post Body";

        // ایجاد شیء Gson
        Gson gson = new Gson();
        
        // تبدیل شیء جاوا به JSON
        String json = gson.toJson(post);

        // نمایش رشته JSON
        System.out.println(json);
    }
}

توضیحات کد:
تعریف شیء جاوا:

ابتدا یک شیء از کلاس Post ایجاد کرده و مقادیر آن را تعیین می‌کنیم.
تبدیل شیء جاوا به JSON:

سپس با استفاده از متد toJson() شیء Post را به رشته JSON تبدیل می‌کنیم. این رشته شامل اطلاعات id, title و body از شیء جاوا است.
نمایش رشته JSON:

در نهایت، رشته JSON تولید شده را چاپ می‌کنیم که مشابه این خواهد بود:

{"id":1,"title":"Post Title","body":"Post Body"}

کار با مجموعه‌ها و لیست‌ها

یکی از ویژگی‌های مفید Gson این است که می‌توان با استفاده از آن لیست‌ها و مجموعه‌ها را نیز به راحتی پردازش کرد. برای مثال، اگر بخواهید یک آرایه یا لیست از اشیاء جاوا را به JSON تبدیل کنید یا بالعکس، می‌توانید از ساختار زیر استفاده کنید.

کد نمونه برای تبدیل لیست از اشیاء جاوا به JSON و بالعکس:

import com.google.gson.Gson;
import java.util.Arrays;
import java.util.List;

class Post {
    int id;
    String title;
    String body;
}

public class GsonListExample {
    public static void main(String[] args) {
        // ایجاد لیست از اشیاء Post
        List<Post> posts = Arrays.asList(
            new Post(1, "Post 1", "Body 1"),
            new Post(2, "Post 2", "Body 2"),
            new Post(3, "Post 3", "Body 3")
        );

        // ایجاد شیء Gson
        Gson gson = new Gson();
        
        // تبدیل لیست اشیاء جاوا به JSON
        String json = gson.toJson(posts);

        // نمایش رشته JSON
        System.out.println(json);

        // تبدیل JSON به لیست اشیاء جاوا
        List<Post> postList = gson.fromJson(json, List.class);
        
        // نمایش اطلاعات پست‌ها
        for (Post p : postList) {
            System.out.println("ID: " + p.id + ", Title: " + p.title + ", Body: " + p.body);
        }
    }
}

نکات مهم در استفاده از Gson:

محدودیت‌های Gson:

Gson تنها از کلاس‌های عمومی (public) پشتیبانی می‌کند. بنابراین اگر بخواهید از آن برای تبدیل داده‌های خاصی استفاده کنید، باید مطمئن شوید که کلاس‌ها و فیلدهای مورد نظر دسترسی عمومی دارند.
سفارشی‌سازی تبدیل‌ها:

Gson این امکان را فراهم می‌کند که تبدیل داده‌ها را به صورت سفارشی انجام دهید. به عنوان مثال، می‌توانید یک TypeAdapter تعریف کنید تا نحوه تبدیل خاصی برای یک نوع داده مشخص انجام شود.
مراقب بافرها باشید:

در هنگام تبدیل داده‌های پیچیده‌تر، مانند آرایه‌ها یا نقشه‌ها (maps)، لازم است که از انواع داده‌ها با دقت استفاده کنید.با استفاده از Gson، شما می‌توانید به راحتی داده‌های JSON را به اشیاء جاوا تبدیل کنید و بالعکس. این کتابخانه به شما کمک می‌کند که به سرعت با داده‌های JSON تعامل داشته باشید و آن‌ها را به شکل‌های مختلف پردازش کنید. با پشتیبانی از انواع مختلف داده‌ها و امکان سفارشی‌سازی فرآیند تبدیل، Gson یکی از ابزارهای ضروری برای هر توسعه‌دهنده جاوا است که با API‌ها و داده‌های JSON کار می‌کند.

انجام عملیات‌های Asynchronous با استفاده از AsyncTask

در برنامه‌های شبکه‌ای، برخی از درخواست‌ها زمان‌بر هستند، مانند درخواست‌های HTTP به سرورهای دور یا پردازش داده‌های بزرگ. اگر این عملیات‌ها به صورت همزمان (synchronous) انجام شوند، رابط کاربری (UI) برنامه مسدود شده و تجربه کاربری خراب می‌شود. برای جلوگیری از این مشکل، باید عملیات‌های زمان‌بر به صورت غیرهمزمان (asynchronous) انجام شوند تا رابط کاربری همچنان پاسخگو باقی بماند. در زبان جاوا، یکی از ابزارهای رایج برای انجام عملیات‌های غیرهمزمان، کلاس AsyncTask است.

مزایای استفاده از AsyncTask

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

ساده‌سازی کار با Thread‌ها: AsyncTask یک راه ساده و کاربرپسند برای انجام کارهای غیرهمزمان ارائه می‌دهد. نیازی به مدیریت دستی Thread‌ها یا استفاده از کتابخانه‌های پیچیده برای مدیریت همزمانی نیست.

تعامل با UI پس از اتمام عملیات: پس از اتمام عملیات غیرهمزمان، AsyncTask به راحتی می‌تواند نتیجه را به رابط کاربری منتقل کرده و تغییرات لازم را در UI اعمال کند.

ساختار AsyncTask

کلاس AsyncTask به صورت عمومی شامل سه پارامتر است:

پارامتر ورودی (Params): این پارامتر داده‌هایی است که به متد doInBackground() ارسال می‌شود. معمولاً ورودی‌ها به عنوان آرگومان‌های تابع ارسال می‌شوند (مانند آدرس URL‌ها یا داده‌های لازم برای پردازش).

نتیجه خروجی (Progress): این پارامتر برای نمایش وضعیت پیشرفت عملیات در حین انجام کار استفاده می‌شود. این معمولاً برای نمایش درصد پیشرفت یا وضعیت‌های مشابه به کار می‌رود.

نتیجه نهایی (Result): این پارامتر داده‌هایی است که پس از اتمام عملیات به متد onPostExecute() ارسال می‌شود و برای به‌روزرسانی رابط کاربری استفاده می‌شود.

نحوه عملکرد AsyncTask

متد doInBackground(): این متد عملیات‌های زمان‌بر را انجام می‌دهد. این عملیات در یک Thread جداگانه انجام می‌شود و به همین دلیل UI مسدود نمی‌شود.

متد onPostExecute(): پس از اتمام عملیات در doInBackground(), نتیجه به متد onPostExecute() ارسال می‌شود که در آن می‌توان به رابط کاربری دسترسی پیدا کرد و داده‌ها را به روزرسانی کرد.

متد onPreExecute() (اختیاری): این متد قبل از شروع عملیات فراخوانی می‌شود و برای آماده‌سازی مواردی مانند نمایش یک ProgressBar یا هر پیش‌نیاز دیگری استفاده می‌شود.

متد onProgressUpdate() (اختیاری): در صورت نیاز می‌توانید در حین انجام عملیات به‌روزرسانی‌هایی در UI انجام دهید، مانند نمایش پیشرفت عملیات.

نمونه کد استفاده از AsyncTask

در اینجا یک نمونه ساده از نحوه استفاده از AsyncTask برای انجام یک عملیات شبکه‌ای آورده شده است. در این مثال، یک درخواست HTTP به صورت غیرهمزمان انجام می‌شود و پس از اتمام، نتیجه در رابط کاربری نمایش داده می‌شود.

کد:

import android.os.AsyncTask;

public class NetworkTask extends AsyncTask<String, Void, String> {
    @Override
    protected void onPreExecute() {
        // قبل از شروع عملیات (برای نمایش ProgressBar یا پیغام)
        System.out.println("در حال انجام درخواست شبکه‌ای...");
    }

    @Override
    protected String doInBackground(String... urls) {
        // عملیات شبکه‌ای در اینجا انجام می‌شود
        // به عنوان مثال، ارسال درخواست HTTP یا دریافت داده
        try {
            // اینجا می‌توانید درخواست HTTP یا عملیات زمان‌بر دیگری انجام دهید
            Thread.sleep(2000); // شبیه‌سازی یک عملیات زمان‌بر
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "نتیجه درخواست";  // نتیجه عملیات
    }

    @Override
    protected void onPostExecute(String result) {
        // پس از اتمام عملیات، نتیجه به اینجا منتقل می‌شود
        // اینجا می‌توان داده‌ها را در رابط کاربری نمایش داد
        System.out.println("عملیات کامل شد: " + result);
    }
}

توضیحات کد:
متد onPreExecute():

این متد قبل از شروع عملیات فراخوانی می‌شود. در اینجا می‌توانیم کارهایی مانند نمایش یک ProgressBar یا پیام “در حال انجام…” انجام دهیم.
متد doInBackground():

این متد در پس‌زمینه اجرا می‌شود و عملیات اصلی مانند درخواست‌های HTTP یا سایر کارهای زمان‌بر را انجام می‌دهد. در این مثال، از Thread.sleep() برای شبیه‌سازی یک عملیات زمان‌بر استفاده شده است.
متد onPostExecute():

پس از پایان عملیات در doInBackground(), نتیجه به این متد ارسال می‌شود و می‌توانیم آن را در رابط کاربری نمایش دهیم. در اینجا پیام “عملیات کامل شد” به همراه نتیجه چاپ می‌شود.

استفاده از AsyncTask در عملیات‌های شبکه‌ای

وقتی که نیاز دارید با سرور ارتباط برقرار کنید (برای مثال ارسال درخواست HTTP)، باید از AsyncTask برای جلوگیری از مسدود شدن رابط کاربری استفاده کنید. به طور معمول، شما باید تمام عملیات‌های زمان‌بر مانند ارسال درخواست‌های GET یا POST را در داخل doInBackground() انجام دهید. پس از آن، می‌توانید نتیجه را به UI برگردانید و تغییرات لازم را در رابط کاربری اعمال کنید.

نمونه استفاده برای ارسال درخواست HTTP:

import android.os.AsyncTask;
import java.net.HttpURLConnection;
import java.net.URL;

public class NetworkTask extends AsyncTask<String, Void, String> {
    @Override
    protected String doInBackground(String... urls) {
        // ارسال درخواست HTTP به سرور
        String result = "";
        try {
            URL url = new URL(urls[0]);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");

            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                // دریافت پاسخ از سرور
                result = "پاسخ موفق: " + connection.getResponseCode();
            } else {
                result = "خطا در ارتباط با سرور: " + connection.getResponseCode();
            }
        } catch (Exception e) {
            e.printStackTrace();
            result = "خطا در انجام درخواست";
        }
        return result;  // نتیجه به onPostExecute ارسال می‌شود
    }

    @Override
    protected void onPostExecute(String result) {
        // نمایش نتیجه در رابط کاربری
        System.out.println(result);
    }
}

 

نکات مهم:
AsyncTask محدودیت‌هایی دارد:

AsyncTask در نسخه‌های جدید اندروید (نسخه 11 و بالاتر) به عنوان روش توصیه‌شده برای انجام عملیات‌های غیرهمزمان شناخته نمی‌شود و به جای آن، از دیگر روش‌ها مانند ExecutorService, HandlerThread یا WorkManager برای انجام عملیات‌های پس‌زمینه استفاده می‌شود.
عدم استفاده از AsyncTask برای عملیات‌های طولانی مدت:

برای انجام عملیات‌های بسیار زمان‌بر یا عملیات‌هایی که نیاز به چندین مرحله دارند، بهتر است از روش‌های پیشرفته‌تری مانند RxJava یا Coroutines در جاوا/اندروید استفاده کنید.

دقت به Thread‌ها:

همه عملیات‌ها در doInBackground() در یک Thread جداگانه انجام می‌شود، بنابراین شما نمی‌توانید به طور مستقیم از این متد به UI دسترسی پیدا کنید. تنها متدهایی که می‌توانند به UI دسترسی داشته باشند، onPreExecute() و onPostExecute() هستند.

AsyncTask یک ابزار بسیار مفید برای انجام عملیات‌های غیرهمزمان در اندروید و جاوا است. این ابزار به شما این امکان را می‌دهد که بدون مسدود کردن رابط کاربری، عملیات زمان‌بر را انجام دهید. با استفاده از AsyncTask، می‌توانید کارهایی مانند ارسال درخواست‌های HTTP، پردازش داده‌ها یا هر نوع عملیات پس‌زمینه دیگر را انجام داده و پس از اتمام، نتیجه را به رابط کاربری منتقل کنید. اگرچه در نسخه‌های جدیدتر اندروید از تکنیک‌های پیشرفته‌تری برای مدیریت عملیات‌های غیرهمزمان استفاده می‌شود، AsyncTask هنوز یکی از روش‌های کاربردی و ساده برای پروژه‌های ساده‌تر است.

مدیریت ارتباطات شبکه‌ای در پس‌زمینه

در برنامه‌نویسی شبکه‌ای، یکی از چالش‌های اساسی مدیریت عملیات زمان‌بر است، به ویژه زمانی که برنامه با سرورهای خارجی یا منابع اینترنتی ارتباط برقرار می‌کند. اگر این درخواست‌ها به صورت همزمان یا در همان Thread رابط کاربری انجام شوند، ممکن است رابط کاربری (UI) مسدود شود و تجربه کاربری ضعیفی ایجاد شود. برای جلوگیری از این مشکل، می‌توان از مدیریت ارتباطات شبکه‌ای در پس‌زمینه استفاده کرد. در این بخش، به بررسی روش‌های مختلف برای انجام عملیات‌های غیرهمزمان در پس‌زمینه می‌پردازیم.

دلایل نیاز به انجام عملیات‌ها در پس‌زمینه:

جلوگیری از مسدود شدن UI: انجام عملیات‌های زمان‌بر مانند ارسال درخواست‌های HTTP یا پردازش داده‌ها باید در Thread جداگانه‌ای انجام شوند تا از مسدود شدن رابط کاربری جلوگیری شود.
مدیریت بهینه منابع: هنگامی که چندین درخواست به طور همزمان در حال انجام هستند، باید به گونه‌ای این درخواست‌ها مدیریت شوند که عملکرد سیستم بهینه باقی بماند.

روش‌های مختلف برای انجام عملیات‌های غیرهمزمان در جاوا:

1. استفاده از ExecutorService
ExecutorService یکی از ابزارهای اصلی در جاوا برای انجام عملیات‌های همزمان است. این ابزار به شما این امکان را می‌دهد که درخواست‌ها را در Thread‌های جداگانه مدیریت کنید و به راحتی تعداد Thread‌ها و نحوه اجرای آن‌ها را کنترل کنید.

مزایای استفاده از ExecutorService:

مقیاس‌پذیری: می‌توانید تعداد Thread‌ها را مدیریت کرده و از Thread Pool برای بهینه‌سازی استفاده از منابع سیستم بهره ببرید.
مدیریت خطاها: ExecutorService ابزارهایی برای مدیریت خطاها و وضعیت‌های مختلف (مانند زمان‌بندی یا لغو عملیات) ارائه می‌دهد.
آسانی در استفاده: رابط ساده‌ای برای استفاده از Thread‌ها ارائه می‌دهد، که برنامه‌نویس را از پیچیدگی‌های مدیریت Thread‌ها بی‌نیاز می‌کند.

نحوه استفاده از ExecutorService:

در اینجا یک نمونه ساده از استفاده از ExecutorService برای ارسال درخواست HTTP به سرور آورده شده است:

import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NetworkTaskWithExecutor {
    public static void main(String[] args) {
        // ایجاد یک Thread pool با 3 Thread
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // ارسال یک درخواست HTTP به صورت غیرهمزمان
        executorService.submit(() -> {
            try {
                URL url = new URL("https://jsonplaceholder.typicode.com/posts");
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");
                
                if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                    System.out.println("پاسخ موفق: " + connection.getResponseCode());
                } else {
                    System.out.println("خطا در ارتباط: " + connection.getResponseCode());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        // پس از اتمام کار، باید Thread pool را خاموش کنیم
        executorService.shutdown();
    }
}

در این مثال:

Executors.newFixedThreadPool(3) یک Thread Pool با سه Thread ایجاد می‌کند.
درخواست HTTP به صورت غیرهمزمان در یک Thread جداگانه ارسال می‌شود.
پس از اتمام کار، باید shutdown() را برای بستن Thread Pool فراخوانی کنید.

2. استفاده از Handler

در اندروید و جاوا، می‌توان از Handler برای ارسال پیام‌ها و دستورات به Thread‌های دیگر استفاده کرد. این روش بیشتر در اپلیکیشن‌های اندروید کاربرد دارد، جایی که نیاز به ارسال داده‌ها از Thread‌های پس‌زمینه به Thread رابط کاربری (UI Thread) است.

مزایای استفاده از Handler:

انتقال داده‌ها بین Thread‌ها: می‌توان پیام‌ها و داده‌ها را به راحتی از Thread‌های پس‌زمینه به UI Thread ارسال کرد.
سادگی در استفاده: استفاده از Handler برای مدیریت Thread‌ها بسیار ساده است و به راحتی می‌توان داده‌ها را از یک Thread به Thread دیگر منتقل کرد.
نمونه کد استفاده از Handler:
در اینجا یک مثال ساده آورده شده است که نشان می‌دهد چگونه می‌توان از Handler برای ارسال داده‌ها از Thread پس‌زمینه به UI Thread استفاده کرد:

import android.os.Handler;
import android.os.Looper;

public class NetworkTaskWithHandler {
    public static void main(String[] args) {
        // ایجاد Handler برای ارسال پیام‌ها به UI Thread
        Handler handler = new Handler(Looper.getMainLooper());

        // اجرای عملیات در Thread پس‌زمینه
        new Thread(() -> {
            // انجام عملیات شبکه‌ای (مثلاً ارسال درخواست HTTP)
            String result = "پاسخ درخواست HTTP";

            // ارسال نتیجه به UI Thread
            handler.post(() -> {
                // اینجا می‌توانیم داده‌ها را در رابط کاربری نمایش دهیم
                System.out.println(result);
            });
        }).start();
    }
}

در این مثال:

Handler برای ارسال داده‌ها از Thread پس‌زمینه به UI Thread استفاده می‌شود.
عملیات اصلی در یک Thread جدید انجام شده و پس از اتمام، نتیجه با استفاده از handler.post() به UI ارسال می‌شود.

3. استفاده از FutureTask و Callable

برای انجام عملیات‌های غیرهمزمان و دریافت نتیجه پس از اتمام، می‌توان از FutureTask و Callable استفاده کرد. این روش به شما این امکان را می‌دهد که یک Task را در Thread پس‌زمینه اجرا کنید و پس از پایان آن، نتیجه را دریافت کنید.

مزایای استفاده از FutureTask:

دریافت نتیجه پس از اتمام: به راحتی می‌توان نتیجه عملیات را از Thread پس‌زمینه دریافت کرد.
مدیریت زمان‌بندی: می‌توانید مدت زمانی که باید برای عملیات منتظر بمانید را مدیریت کنید.
نمونه کد استفاده از FutureTask:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

public class NetworkTaskWithFuture {
    public static void main(String[] args) {
        // ایجاد ExecutorService برای مدیریت Thread‌ها
        ExecutorService executorService = Executors.newFixedThreadPool(1);

        // ایجاد Callable برای انجام عملیات شبکه‌ای
        Callable<String> callable = () -> {
            // عملیات زمان‌بر (مثلاً درخواست HTTP)
            return "نتیجه درخواست HTTP";
        };

        // ایجاد FutureTask
        FutureTask<String> futureTask = new FutureTask<>(callable);

        // ارسال FutureTask به ExecutorService
        executorService.submit(futureTask);

        try {
            // دریافت نتیجه پس از اتمام عملیات
            String result = futureTask.get();
            System.out.println(result);  // نمایش نتیجه
        } catch (Exception e) {
            e.printStackTrace();
        }

        // بستن ExecutorService
        executorService.shutdown();
    }
}

در این مثال:

Callable برای انجام عملیات‌ها استفاده شده و نتیجه آن توسط FutureTask دریافت می‌شود.
futureTask.get() منتظر می‌ماند تا نتیجه پس از اتمام عملیات در Thread پس‌زمینه دریافت شود.
برای مدیریت درخواست‌های شبکه‌ای در پس‌زمینه و جلوگیری از مسدود شدن رابط کاربری، استفاده از ابزارهایی مانند ExecutorService, Handler و FutureTask در جاوا بسیار مهم است. این روش‌ها به شما این امکان را می‌دهند که عملیات‌های زمان‌بر مانند درخواست‌های HTTP یا پردازش داده‌ها را در Thread‌های جداگانه انجام دهید و نتیجه آن را به رابط کاربری منتقل کنید. انتخاب روش مناسب بستگی به نیازهای خاص برنامه دارد، اما استفاده از این ابزارها می‌تواند به بهبود عملکرد و تجربه کاربری کمک زیادی کند.

نتیجه‌گیری

در این مقاله، با مفاهیم شبکه و APIها در Java آشنا شدیم و یاد گرفتیم که چگونه می‌توان با استفاده از ابزارهای مختلف، عملیات‌های شبکه‌ای و ارتباط با سرورها را به صورت کارآمد مدیریت کرد. از HTTP requests و REST API گرفته تا کتابخانه‌های محبوب مانند Retrofit برای تعامل ساده‌تر با APIها، و همچنین ابزارهایی مانند Gson برای پارس کردن داده‌های JSON، همگی به شما کمک می‌کنند تا برنامه‌های قدرتمند و انعطاف‌پذیری ایجاد کنید.

همچنین با بررسی AsyncTask و روش‌های مدیریت عملیات شبکه‌ای در پس‌زمینه مانند ExecutorService و Handler، دیدیم که چگونه می‌توان از مسدود شدن رابط کاربری جلوگیری کرده و عملکرد برنامه را بهینه کرد. در نهایت، تسلط بر شبکه و APIها در Java نه تنها باعث افزایش مهارت‌های برنامه‌نویسی شما می‌شود، بلکه شما را قادر می‌سازد تا برنامه‌هایی کاربرپسند و سریع ایجاد کنید. با مطالعه و تمرین بیشتر، می‌توانید این مفاهیم را در پروژه‌های واقعی به کار ببرید و برنامه‌های جاوا را به سطح حرفه‌ای‌تری برسانید.

 

آموزش شبکه و APIها در Java

دیدگاه های شما

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *