اتصال اندروید به وب سرویس Restful با استفاده از Retrofit و Asp.net ، اپلیکیشن های اندرویدی را میتوان با استفاده از چندین کتابخانه ازجمله کتابخانه Volley و Retrofit به سرور متصل کرد و همچنین دستورات سرور نیز میتواند به زبان های مختلفی از جمله Asp.net و php باشد.
همچنین برای دانلود سورس پروژه میتونید به کانال تلگرام ما مراجعه کنید.
در این آموزش ما از Retrofit استفاده میکنیم. اگر آموزش مربوط به کتابخانه Retrofit را مطاله کرده باشید قطعا میدانید که علاوه بر امنیت بالایی که از آن برخوردار است مهم ترین ویژگی آن کم کردن کار برنامه نویس به جهت تبدیل جیسون به مدل POJO میباشد.
(POJO یا Plain Old Java Object در واقع همان کلاس های ساده معمولی جاوا است که از کلاس دیگری ارث نبرده اند و تنها برا ی معرفی یک شی بکار میروند)
در این آموزش قصد داریم که با استفاده از دستورات asp.net در سرور و retrofit در اندروید یک اتصال ایمن بین اپلیکیشن و سرور ایجاد کنیم و اطلاعات را ردوبدل کنیم.
REST یا Representational State Transfer که بیشتر در مورد اپلیکیشن های تحت وب استفاده میشود در واقع ساختار یا معماری خاصی برای انتقال داده به سرور استفاده میشود.
این ساختار برروی پروتکل HTTP است و افعال استاندارد این پروتکل که قابل درک برای وب سرویس نیز میباشد شامل GET, POST, PUT, DELETE
API یا Application Programming Interface نیز رابط و واسطی بین اپلیکیشن اندروید و سرور است.
پس در نهایت میتوان گفت RESTful Api درواقع به معنی Api هایی است که از معماری Rest پیروی میکنند.
**اگر میخواید بیشتر با این مبحث آشنا بشید حتما این مقاله رو مطالعه کنید**
خب بریم سراغ پروژه , ما قصد داریم پروژه ای طراحی کنیم که اطلاعات اشخاص شامل نام و فامیل را از کاربر بگیرد و در بانک سرور (SQL Server) ذخیره کند
و همچنین آپشن های حذف و ویرایش و خواندن تمامی اطلاعات از بانک نیز در اختیار کاربر قرار دهد تا به صورت آنلاین با استفاده از api با بانک در ارتباط باشد.
خب پس مراحلی که باید به ترتیب طی بشوند تا به نتیجه برسیم به ترتیب زیر است
۱-ایجاد بانک در SQL Server
۲-ایجاد پروژه asp.net mvc و متصل کردن بانک به پروژه
۳-کدنویسی دستورات asp جهت اعمال تغییرات برروی بانک
۴-ایجاد پروژه اندروید استودیو و متصل کردن آن به سرور
همین! به همین راحتی میتونیم یه اپلیکیشن تحت سرور بسازیم.
۱-ایجاد بانک در SQL Server
خب پس بریم سراغ مرحله اول :
یک دیتابیس ساده با یک جدول به صورت زیر ایجاد میکنیم ما اسم دیتابیس رو T_WebApiApp و اسم جدول هم Person تعیین کردیم
خب بانک ما آماده ست حالا باید بریم سراغ مرحله دوم کار یعنی پروژه asp.net
پس ویژوال استودیو رو اجرا کنید و یک پروژه جدید از نوع Asp.net Web Application
و سپس نوع Web Api رو انتخاب کنید و پروژه تون رو تحویل بگیرید!خب همونطور که میبینید یکسری کنترلر و ویو های آماده هم برای راحتی کار در اختیارتون گذاشته اما ما باهاشون کاری نداریم !
حالا باید بانک رو به پروژه متصل کنیم پس روی فولدر Model کلیک راست میکنیم و گزینه Add و سپس ADO.NET Entity Model رو انتخاب میکنیم
خب حالا مراحل ایجاد اتصال رو باید طی کنیم , مرحله اول که اسم مدل رو باید انتخاب کنیم و میریم به مرحله بعد که باید نوع محتوی مدل رو انتخاب کنیم که گزینه EF Designer From Database رو انتخاب میکنیم
مرحله بعد باید کانکشن رو ایجاد کنیم پس روی گزینه New Connection کلیک میکنیم و طبق تصویر زیر ServerName رو یک نقطه ( . ) یا اسم کامل سرور قرار میدیم و Refresh رو میزنیم و در قسمت Select or Enter database name دیتابیسی رو که ایجاد کردیم رو انتخاب میکنیم
خب بعد از build شدن پروژه میبینیم که دیتابیس به صورت کامل به پروژه اضافه شده پس میتونیم به اطلاعات داخلش دسترسی کامل داشته باشیم هرنوع عملی رو روشون پیاده کنیم.
خب حالا میریم سراغ مرحله سوم و کد نویسی asp برای اعمال تغییرات روی بانک
برای اینکار اول روی فولدر Controllers کلیک راست میکنیم و گزینه Add وبعد گزینه Controller رو کلیک میکنیم. یک اسم مرتبط براش تعیین میکنیم(ما اسمش رو StudentApiController گذاشتیم) و بعد هم کدنویسی رو شروع میکنیم
۳-کدنویسی دستورات asp جهت اعمال تغییرات برروی بانک
قبل از نوشتن هرمتد باید یک شی از مدلی که به پروژه متصل کردیم ایجاد کنیم و با استفاده از آن به بانک دسترسی کامل پیدا کنیم
T_WebApiAppEntities db = new T_WebApiAppEntities();
متد insert برای ایجاد یک رکورد داخل جدول:
ما دونوع متد ایجاد اطلاعات رو داریم یکی از آنها اطلاعات کاربر رو به صورت شی از کلاس میگیرد
و دیگری به صورت فیلد , فیلد اطلاعات را میگیرد و ذخیره میکند که در اندروید تفاوت این دو را در Retrofit مشاهده خواهیم کرد
//اضافه در جدول با دریافت مستقیم شی public JsonResult insertObjStu(Person person) { //اضافه به کلاس و ذخیره در بانک db.Person.Add(person); db.SaveChanges(); //آخرین رکورد جدول را میگیرد Person p = db.Person.ToList().Last(); //ساختار آن را تبدیل به جیسون میکند و به عنوان خروجی برمیگرداند var jsondata = Json(p, JsonRequestBehavior.AllowGet); return jsondata; } //ایجاد رکورد با دریافت فیلدها به صورت جدا public JsonResult insertStudent(String name, String family) { Person person = new Person() { Name = name, Family = family, }; //اضافه به کلاس و ذخیره در بانک db.Person.Add(person); db.SaveChanges(); //آخرین رکورد جدول را میگیرد Person stu = db.Person.ToList().Last(); //ساختار آن را تبدیل به جیسون میکند و به عنوان خروجی برمیگرداند var jsondata = Json(stu, JsonRequestBehavior.AllowGet); return jsondata; }
متد ویرایش رکورد براساس id آن
public String updateStudent(Person person) { Person selectedStu = db.Person.Find(person.Id); //اگر مقدار شناسه ارسالی در جدول موجود باشد مقادیر همان رکورد تغییر میباند if (selectedStu != null) { selectedStu.Name = person.Name; selectedStu.Family = person.Family; db.Entry(selectedStu).State = EntityState.Modified; db.SaveChanges(); return "success"; } else return "failed"; }
public String deleteStudent(int id) { String response; Person selectedStu = db.Person.Find(id); if (selectedStu != null) { db.Person.Remove(selectedStu); db.SaveChanges(); response = "successful deleted"; } else response = "incorrect id"; return response; }
public JsonResult getAll() { ListPerson list; list = db.Person.ToList(); var jsonData = Json(list, JsonRequestBehavior.AllowGet); return jsonData;
خب دستورات سرور ما هم تمام شد میتونیم هرکدام از این متدهارا در مرورگر کروم یا Postman تست کنیم تا با اطمینان کامل در اپ جاگذاری کنیم برای مثال ما متد insert را در postman بدین صورت تست میکنیم
خب اینم از مرحله سوم حالا باید بریم سراغ مرحله اخر و ایجاد پروژه اندروید و اتصال به سرور :
خب یک پروژه اندروید ایجاد میکنیم در ساده ترین حالت ممکن از نوع Blank Activity و ابتدای کار میریم ولایه activity_main.xml رو طراحی میکنیم
اما قبل از شروع به طراحی چون که ما میخواهیم از Constraint layout برای طراحی خود استفاده کنیم به دلیل مزایای زیاد از جمله کاهش میزان کدنویسی پس باید در گردل برنامه تغییراتی ایجاد کنیم !
ابتدا مطابق تصویر کلاس (build.gradle(project :Retrofit را باز کرده و در قسمت repositories
مقادیر زیر را قرارم میدهیم
maven { url 'https://maven.google.com' }
compile 'com.android.support.constraint:constraint-layout:1.0.2' compile 'com.android.support:design:25.3.1'
حال دستورات طراحی فایل xml
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" tools:context="com.tejariapp.mdn.serverapi.MainActivity"> <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_id" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="24dp" android:layout_marginLeft="24dp" android:layout_marginRight="24dp" android:layout_marginStart="24dp" android:layout_marginTop="16dp" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_marginBottom="8dp" app:layout_constraintVertical_bias="0.0" app:layout_constraintBottom_toTopOf="@+id/insert"> <EditText android:id="@+id/id" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="right" android:hint="@string/id" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_name" android:layout_width="0dp" android:layout_height="63dp" android:layout_marginBottom="8dp" android:layout_marginEnd="24dp" android:layout_marginLeft="24dp" android:layout_marginRight="24dp" android:layout_marginStart="24dp" android:layout_marginTop="16dp" app:layout_constraintBottom_toTopOf="@+id/insert" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/input_layout_id" app:layout_constraintVertical_bias="0.0"> <EditText android:id="@+id/name" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="right" android:hint="@string/name" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_family" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginEnd="24dp" android:layout_marginLeft="24dp" android:layout_marginRight="24dp" android:layout_marginStart="24dp" android:layout_marginTop="16dp" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/input_layout_name" android:layout_marginBottom="8dp" app:layout_constraintBottom_toTopOf="@+id/read" app:layout_constraintVertical_bias="0.0"> <EditText android:id="@+id/family" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="right" android:hint="@string/family" /> </android.support.design.widget.TextInputLayout> <Button android:id="@+id/insert" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onFuncClick" android:text="insert" app:layout_constraintLeft_toRightOf="@+id/read" app:layout_constraintRight_toLeftOf="@+id/delete" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginBottom="8dp" /> <Button android:id="@+id/read" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:onClick="onFuncClick" android:text="read" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/insert" /> <Button android:id="@+id/update" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:onClick="onFuncClick" android:text="update" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@+id/delete" app:layout_constraintRight_toRightOf="parent" /> <Button android:id="@+id/delete" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:onClick="onFuncClick" android:text="delete" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@+id/insert" app:layout_constraintRight_toLeftOf="@+id/update" /> <android.support.v7.widget.RecyclerView android:id="@+id/personList" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginEnd="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginStart="8dp" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" android:layout_marginBottom="24dp" app:layout_constraintBottom_toTopOf="@+id/insert" android:layout_marginTop="24dp" app:layout_constraintTop_toBottomOf="@+id/input_layout_family" /> </android.support.constraint.ConstraintLayout> </ScrollView>
خب همانطور که داخل کدهای فایل xml مشاهده میکنید ما یک RecyclerView داریم که باید تمامی اطلاعات را از سرور گرفته و در لیست آیتم به آیتم نمایش دهد
پس مشخصا باید این آیتم هارا نیز طراحی کنیم پس لایه جدیدی با عنوان list_item.xml ایجاد میکنیم و به صورت زیر طراحی میکنیم
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <android.support.v7.widget.CardView android:id="@+id/personCard" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginTop="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"> <android.support.constraint.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/id" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginTop="8dp" android:text="@string/id" android:textColor="@android:color/background_dark" android:textSize="15sp" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginRight="8dp" android:layout_marginTop="8dp" android:text="@string/name" android:textColor="@android:color/background_dark" android:textSize="15sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/id" app:layout_constraintVertical_bias="0.0" /> <TextView android:id="@+id/family" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginTop="8dp" android:text="@string/family" android:textColor="@android:color/background_dark" android:textSize="15sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_bias="1.0" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/name" app:layout_constraintTop_toBottomOf="@+id/id" app:layout_constraintVertical_bias="0.0" /> </android.support.constraint.ConstraintLayout> </android.support.v7.widget.CardView> </android.support.constraint.ConstraintLayout>
خب حالا طراحی های لازم رو انجام دادیم و حالا باید بریم سراغ کدنویسی
قبل شروع به کار چون ما میخواهیم از رتروفیت استفاده کنیم پس نیاز است که کتابخانه های مورد نیاز خود را در گردل کامپایل کنیم پس عبارات زیر را اضافه و sync میکنیم
compile 'com.google.code.gson:gson:2.6.2' compile 'com.squareup.retrofit2:retrofit:2.0.2' compile 'com.squareup.retrofit2:converter-gson:2.0.2'
خب حال باید بریم سراغ اصل ماجرا پس در ابتدای کار باید مدل (POJO)خود را طراحی کنیم . پس با اضافه کردن کلاس جدیدی در پکیج مورد نظر و نام گذاری Person شروع به کدنویسی مدل میکنیم
توجه داشته باشید که مدل باید دقیقا مطابق بانکی باشد که ایجاد کردید
package com.tejariapp.mdn.serverapi; import com.google.gson.annotations.SerializedName; /** * Created by Marjan on 29/09/2017. */ public class Person{ @SerializedName("Id") private int pID; @SerializedName("Name") private String pName; @SerializedName("Family") private String pFamily; public Person(int id,String pName,String pFamily){ this.pID=id; this.pName=pName; this.pFamily=pFamily; } public Person(String pName,String pFamily){ this.pName=pName; this.pFamily=pFamily; } public int getpID() { return pID; } public String getpFamily() { return pFamily; } public String getpName() { return pName; } }
.
دلیل استفاده از @serializedName قبل از تعریف فیلد ها این است که رتروفیت متوجه شود که فیلد هایی که به صورت جیسون به برنامه ارسال میشود هرکدام متعلق به کدام فیلد مدل ما هستند.
حال زمان آن است که interface با عنوان TaskService که درخواست های مارا همراه با پارامتر های ارسالی و آدرس EndPoint به همراه نوع درخواست ارسال میکند
package com.tejariapp.mdn.serverapi; import java.util.List; import okhttp3.ResponseBody; import retrofit2.Call; import retrofit2.http.Body; import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.GET; import retrofit2.http.POST; /** * Created by Marjan on 26/09/2017. */ public interface TaskService { @GET("StudentApi/getAll") Call<List<Person>> getPersons(); @POST("StudentApi/insertObjStu") Call<Person> addNewPerson(@Body Person person); @FormUrlEncoded @POST("StudentApi/insertObjStu") Call<Person> addNewPerson(@Field("name") String name , @Field("family") String family); @POST("StudentApi/updateStudent") Call<ResponseBody> updatePersonInfo(@Body Person person); @FormUrlEncoded @POST("StudentApi/deleteStudent") Call<ResponseBody> deletePeronInfo(@Field("id") int id); }
حال کلاس دیگری با عنوان ServiceGenerator ایجاد میکنیم وظیفه این کلاس این است که بیس درخواست به سرور را ایجاد کند
و در ادامه برای ایجاد هر request یا درخواست به سرور تنها یک شی از این کلاس برا ما کافی باشد
package com.tejariapp.mdn.serverapi; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.io.IOException; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import retrofit2.converter.gson.GsonConverterFactory; /** * Created by Marjan on 26/09/2017. */ public class ServiceGenerator { private static final String URL = "http://10.0.2.2:62813/"; private TaskService apiService; public ServiceGenerator() { OkHttpClient okClient = new OkHttpClient.Builder() .addInterceptor( new Interceptor() { @Override public Response intercept(Interceptor.Chain chain) throws IOException { Request original = chain.request(); // Request customization: add request headers Request.Builder requestBuilder = original.newBuilder() .header("Host", "localhost") //cues it want to run as local in local server .method(original.method(), original.body()); Request request = requestBuilder.build(); return chain.proceed(request); } }) .build(); Gson gson = new GsonBuilder() .setDateFormat("yyyy-MM-dd'T'HH:mm:ssZ") .create(); retrofit2.Retrofit restAdapter = new retrofit2.Retrofit.Builder() .baseUrl(URL) .addConverterFactory(GsonConverterFactory.create(gson)) .client(okClient) .build(); apiService = restAdapter.create(TaskService.class); } public TaskService getService() { return apiService; } }
در کدهای فوق اگر به URL توجه کنید ما از http://10.0.2.2:62813 استفاده کردیم که برای سرور لوکال برروی دستگاه شبیه ساز خوداندروید استودیو استفاده میشود.
(توضیحات اضافه درارتباط با آدرس url این است که زمانی که ما پروژه asp خود را اجرا میکردیم آدرس api ما بدین صورت بود localhost:62813
و حال در اندروید استودیو باید بجای localhost از آدرس ۱۰٫۰٫۲٫۲ استفاده کنیم و این تنها قابل اجرا برروی شبیه ساز پیشفرض خود اندروید استودیو است)
حال باید Adapter ی سفارشی شده مناسب با داده های مطابق با مدل خود که از سرور به دست ما میرسد ایجاد کنیم
پس کلاس جدیدی ایجاد میکنیم با عنوان CustomAdapter و چنین کدنویسی میکنیم
package com.tejariapp.mdn.serverapi; import android.support.v7.widget.CardView; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import java.util.ArrayList; /** * Created by Marjan on 15/10/2017. */ public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.MyViewHolder> { private ArrayList<Person> personsList; customAdapterInterface customAdapterInterface; public CustomAdapter(ArrayList<Person> personsList, customAdapterInterface customAdapterInterface){ this.customAdapterInterface=customAdapterInterface; this.personsList=personsList; } public interface customAdapterInterface { void onCustomListItemClick(int position); } @Override public CustomAdapter.MyViewHolder onCreateViewHolder( ViewGroup parent, int viewType) { View view= LayoutInflater.from(parent.getContext()) .inflate(R.layout.list_item_layout,parent,false); return new MyViewHolder(view); } @Override public void onBindViewHolder(CustomAdapter.MyViewHolder holder , final int position) { Person person=personsList.get(position); holder.mIDView.setText(String.valueOf(person.getpID())); holder.mNameView.setText(person.getpName()); holder.mFamilyView.setText(person.getpFamily()); holder.mCardView.setTag(position); } @Override public int getItemCount() { return personsList.size(); } public class MyViewHolder extends RecyclerView.ViewHolder { private TextView mIDView; private TextView mNameView; private TextView mFamilyView; private CardView mCardView; public MyViewHolder(final View itemView) { super(itemView); mIDView=(TextView)itemView.findViewById(R.id.id); mNameView=(TextView)itemView.findViewById(R.id.name); mFamilyView=(TextView)itemView.findViewById(R.id.family); mCardView=(CardView)itemView.findViewById(R.id.personCard); mCardView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int pos=(int)v.getTag(); customAdapterInterface.onCustomListItemClick(pos); } }); } } }
حال تنها زمان آن رسیده که درخواست های خود را به سرور ارسال کنیم و نتیجه ای که این همه براش زحمت کشیدیم رو بگیریم!
پس در ActivityMain که از interface درون CustomAdapter که در بالا ایجاد کردیم implements شده ,
و در متد آن گفته شده که مقادیر فیلدهای ایتم کلیک شده در EditText های مربوطه قرار گیرند
@Override public void onCustomListItemClick(int position) { Person person = personsList.get(position); mIdView.setText(String.valueOf(person.getpID())); mNameView.setText(person.getpName()); mFamilyView.setText(person.getpFamily()); }
در بخش onCreate اکتیویتی ,شی هارا تعریف میکنیم
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); serviceGenerator = new ServiceGenerator(); mIdView = (EditText) findViewById(R.id.id); mNameView = (EditText) findViewById(R.id.name); mFamilyView = (EditText) findViewById(R.id.family); personList=new ArrayList(); customAdapter = new CustomAdapter(personsList, this); recyclerView = (RecyclerView) findViewById(R.id.personList); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(customAdapter); read(); }
همانگونه که مشخص است ما از متد read هنگام لود شدن برنامه استفاده کرده ایم
و مشخصا این متد مسئول دریافت تمامی اطلاعات بانک از سرور و جایگذاری در RecyclerView است پس این چنین کدنویسی میشود
public void read() { personsList.clear(); customAdapter.notifyDataSetChanged(); Call<List<Person>> call = serviceGenerator. getService().getPersons(); call.enqueue(new Callback<List<Person>>() { @Override public void onResponse(Call<List<Person>> call, Response<List<Person>> response) { for (Person person : response.body()) { Log.d("PERSON : ", person.getpName() + person.getpFamily()); personsList.add(person); customAdapter.notifyDataSetChanged(); } } @Override public void onFailure(Call<List<Person>> call, Throwable t) { Log.d("ON GET PERSON BUG", t.toString()); } }); }
همانگونه که مشخص است در onResponse یکی یکی شی هایی که براساس کلاس Person دریافت شده اند
را در ارایه اضافه و همچنین اداپتر لیست را از تغییر آگاه میکند.
متد insert در سرور نیز بدین شکل است
private void insert() { if (!checkInsertEmpty()) { final String name = mNameView.getText().toString().trim(); final String family = mFamilyView.getText().toString().trim(); Call<Person> call = serviceGenerator.getService(). addNewPerson(new Person(name, family)); call.enqueue(new Callback<Person>() { @Override public void onResponse(Call<Person> call, Response<Person> response) { Person person=response.body(); personsList.add(new Person(person.getpID(),person.getpName() ,person.getpFamily())); customAdapter.notifyItemInserted(personsList.size() - 1); clearTexts(); } @Override public void onFailure(Call<Person> call, Throwable t) { Log.d("ON INSERT PERSON BUG", t.toString()); } }); } }
متد checkInsertEmpty که مشخصا چک میکند که مقادیر جهت ارسال به سرور و ذخیره در بانک وارد شده اند یاخیر
درصورت درست وارد شدن مقادیر اطلاعات به سرور با متد addNewPerson و ارسال یک شی از مدل Person اقدام به ذخیره میکند
و در صورت گرفتن response از سرور که یک شی از مدل Person (اخرین شی اضافه شده در بانک) است آن را به ارایه اطلاعات اضافه میکند و لیست را هم از این تغییر مطلع میکند
//if return true means it has empty error private boolean checkInsertEmpty() { String name = mNameView.getText().toString().trim(); String family = mFamilyView.getText().toString().trim(); boolean flag = false; if (name.isEmpty()) { mNameView.setError(getResources().getString(R.string.emptyError)); flag = true; } if (family.isEmpty()) { mFamilyView.setError(getResources().getString(R.string.emptyError)); flag = true; } return flag; }
در قسمت کدنویسی سرور برای ایجاد یک رکورد جدید ما دونوع متد نوشتیم که در این قسمت فقط از متدی که شی را به عنوان ورودی دریافت میکرد استفاده میکنیم
اما شما میتوانید از هردونوع ارسال استفاده کنید چون هردو نوع در اینترفیس تعریف شده اند
متد Update نیز مشابه متد insert است با این تفاوت که درصورت گرفتن response درست از سرور, فیلدی از آرایه لیست با id ارسال شده را تنها تغییر میدهد
public void update() { if (!checkInsertEmpty() && !checkIDEmpty()) { final int id = Integer.parseInt(mIdView.getText().toString().trim()); final String name = mNameView.getText().toString().trim(); final String family = mFamilyView.getText().toString().trim(); final int pos=getIdPos(id); Call<ResponseBody> call = serviceGenerator.getService(). updatePersonInfo(new Person(id, name, family)); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { String responseResult=null; try { responseResult=response.body().string(); } catch (IOException e) { e.printStackTrace(); } if (responseResult.equals("success")) { personsList.set(pos, new Person(id, name, family)); customAdapter.notifyItemChanged(pos); clearTexts(); }else{ mIdView.setError(getResources().getString(R.string.idError)); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.d("on Failer", t.toString()); } }); } }
private int getIdPos(int id) { int pos = -1; for (int i = 0; i < personsList.size(); i++) { if (personsList.get(i).getpID() == id) { pos = i; break; } } return pos; }
وهمچنین متد checkIdEmpty و clearText
//if return true means it has empty error private boolean checkIDEmpty() { String id = String.valueOf(mIdView.getText().toString()); if (id.isEmpty()) { mIdView.setError(getResources().getString(R.string.emptyError)); return true; } else return false; } private void clearTexts(){ mIdView.setText(""); mNameView.setText(""); mFamilyView.setText(""); }
و تنها متد حذف یا delete رکورد از سرور باقی مانده که برای این متد نیز تنها کافی است شناسه یا id رکورد را به سرور جهت حذف , ارسال کنیم و درصورت دریافت response صحیح از سرور آن آیتم را از لیست نیز حذف کنیم
public void delete() { if (!checkIDEmpty()) { final int id = Integer.parseInt(mIdView.getText().toString().trim()); final int pos=getIdPos(id); Call<ResponseBody> call = serviceGenerator. getService().deletePeronInfo(id); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { try { String responseResult = response.body(). string(); if (responseResult.equals("successful deleted")) { personsList.remove(pos); customAdapter.notifyDataSetChanged(); clearTexts(); }else { mIdView.setError(getResources(). getString(R.string.idError)); } } catch (IOException e) { e.printStackTrace(); } } @Override public void onFailure(Call<ResponseBody> call, Throwable t) { Log.d("DELETE on Failure", t.toString()); } }); } }
پروژه به اتمام رسید. حالا میتونید برنامه رو روی یک شبیه ساز پیشفرض اندرویداستودیو اجرا کنید و بدین صورت نتیجه بگیرید
برای دانلود سورس پروژه میتونید به کانال تلگرام ما مراجعه کنید
موفق و خوشحال باشید 🙂
10 Comments
سلام . اموزش جامع و کاملی ارائه دادید . خیلی ممنون
یه سوال .اگر دراین بین کسی این اطلاعات رو که در قالب http داره ارسال و دریافت میشه ، توسط ابزار های شبکه شنود کنه ، و تمامی اطلاعاتی از قبل api , token و… رو بدست بیاره ، باید چه کاری انجام داد ؟
سلام
اگر در راه رسیدن به مقصد کسی موفق به شنود شه که میتونید با الگوریتم JWT تاحد زیادی مانع درک مقادیر برای اون شخص شید
اما اگر زمانی که به مقصد رسید هم بخوایم مانع شنود شیم میتونیم از الگوریتم های دیگه رمز نگاری برای رمز کردن اطلاعات مثل AES , RSA , .. که یک کلید توافقی بین اپ اندروید و سرور دارند ٫ استفاده کنیم
سلام
ممنون ب خاطر آموزشتون
من در قسمت اندروید گام ب گام هر کاری گفتید انجام دادم اما خطای زیر را میدهد
هنگام insert java.lang.NullPointerException
.MainActivity$4.onResponse(MainActivity.java:178)
با سلام
سوالتون رو واضح تر بفرمایید
با احترام
سلام
ببخشید Controllers را از چه مدلی انتخاب کنیم؟
mvc یا web api ?
با سلام
کنترلر از نوع Web api هست
با احترام
شسلام ببخشید سورس پروژه asp.net را از کجا دانلو نماییم مندر import کردن کلاس ها به مشکل برخوردم.
با سلام
وارد کانال تلگرام پروگران به آدرس @progrun شوید و عبارت زیر را جستجو کنید سپس سورس را میتوانید دانلود کنید
اتصال اندروید به #وب_سرور با Restful API با استفاده از Asp.net و #Retrofit
با احترام
با سلام و تشکر بابت آموزش خوبتون
این آموزش رو میشه با Volley هم آموزش بدید
سلام خداقوت .سپاس ازآموزش خوبتون
ببخشید میه سورس کد قسمت SQL Server هم قرار بدید؟