Mahan PoorYazdanKhah
Mahan PoorYazdanKhah
خواندن ۱۰ دقیقه·۵ سال پیش

Intent در اندروید

همانطور که می دانید از دستور Intent برای جابه جایی بین اکتیویتی ها (Activitys) و همچنین انجام کارهایی مثل ارسال اس ام اس، بازکردن مرورگر و... استفاده می‌شود.

Intent ها به سه دسته تقسیم می‌شوند که عبارتند از:

1. واضح یا Explicit intent

2. مطلق یا Implicit intent

3. فیلتر ها یا Intent-filter

Explicit Intent همانطور که از اسمش معلومه 'آشکار' یا 'مشخص' هستش. منظور از آشکار و مشخص بودن Intent این است که در این نوع، اکتیویتی ها مشخص هستند و در واقع از اکتیوتی هایی که داخل برنامه تان هست استفاده می‌کنید مانند مثال زیر که میخواهیم از اکتیوتی 1 به اکتیویتی 2 برویم:

Intent intent = new Intent(Activity1.this, Activity2.class); startActivity(intent);

احتمالاً حدس میزنید که Implicit intent دقیقا برخلاف Intent قبلی باشد و شما می توانید به هر اکتیویتی بروید و از هر سرویسی استفاده کنید. زمانی که شما از این نوع Intent استفاده میکنید IDE لیست بلند بالایی از سرویس هایش را برای شما نشان می دهد که هرکدام برای کاری هستند. درواقع وقتی قصد دارید اندروید برای شما کاری را انجام دهد و برایتان مهم نیست که چه اکتیویتی یا چه سرویسی آن کار را انجام می دهد، باید از این نوع Intent ها استفاده کنید به مثال زیر توجه کنید:

اشتراک گذاری لینک با Intent در اندروید

Intent intent = new Intent(Intent.ACTION_SEND); intent.setType(&quottext/plain&quot); intent.putExtra(Intent.EXTRA_TEXT,&quotآدرس اینترنتی&quot); startActivity(Intent.createChooser(intent, &quotاشتراک گذاری به وسیله ...&quot));

در مثال بالا از Intent خواسته شده که آدرس اینترنتی را بازکند. اهمیتی ندارد که کاربر با چه مرورگری یا خارج از برنامه آن را باز می‌کند، مهم این است که کاربر به آن آدرس اینترنتی دسترسی داشته باشد. البته می‌توان اینکه با چه مرورگری بازشود و دیگر عناصر را کنترل کرد.

ارسال ایمیل با Intent در اندروید

Intent emailIntent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(&quotmailto&quot,&quotexample@gmail.com&quot, null)); emailIntent.putExtra(Intent.EXTRA_SUBJECT, &quotعنوان&quot); emailIntent.putExtra(Intent.EXTRA_TEXT, &quotمتن ایمیل&quot); startActivity(Intent.createChooser(emailIntent, &quotSend email...&quot));

ارسال smsبا Intent در اندروید

Uri uri = Uri.parse(&quotsmsto:12346556&quot); Intent SMSintent= new Intent(Intent.ACTION_SENDTO, uri); SMSintent.putExtra(&quotsms_body&quot, &quotمتن اس ام اس &quot); startActivity(SMSintent);

Intent-filter اینگونه عمل می کنند که وقتی از طریق Intent در خواستی برای اندروید فرستاده شد، اندروید همه ی نرم افزار هایی که برای انجام آن در خواست مناسب هستند را تشخیص و برای کاربر لیست می کند، تا کاربر نرم افزار دلخواه خود را برای انجام آن درخواست انتخاب کند. در واقع اندروید به وسیله ی Intent-filter ها تشخیص می دهد که چه نرم افزار هایی امکان اجرای آن درخواست را دارد.

یک Intent-filter مشخص می کند که نرم افزار شما قادر است چه نوع در خواست هایی را اجرا کند. در واقع Intent-filter، قابلیت های نرم افزار شما را تعریف می کند. اگر برای یک اکتیوتی یا سرویس Intent-filter تعریف نشود، آن اکتیویتی فقط به صورت واضح یا (Explicit Intent) قابلیت فراخوانی دارد.

برای تعریف Intent-filter ها دو راه وجود دارد:

1. تعریف آن ها در AndroidManifest

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

در روش اول وقتی نرم افزار نصب می شود، اندروید تمام Intent-filter هایی که تعریف کرده اید را ثبت می کند. با این کار اگر کاربر درخواستی را ارسال کند که در Intent-filter شما تعریف شده باشد که برنامه شما توانایی انجام درخواست را دارد، برنامه شما به کاربر پیشنهاد داده می شود. نیازی نیست که نرم افزار شما درحال اجرا یا قبلا اجرا شده باشد؛ چرا که قبلا در اندروید ثبت شده که برنامه شما این توانایی را دارد.

به مثال زیر توجه کنید:

<activity android:name=”.ActivityExample” android:label=”Example”> <intent-filter> <action android:name=”android.intent.action.VIEW” /> <category android:name=”android.intent.category.DEFAULT”/> <data android:schema=”https”/> </intent-filter> </activity>

در مثال بالا نرم افزار به عنوان مرورگر وب در اندروید ثبت می شود؛ حالا تمام ادرس های اینترنتی که با https شروع شود برنامه شما هم به عنوان نرم افزار پیشنهادی به کاربر نمایش داده میشود.

BroadCastReceiver رو اگه بخوایم ساده بیان کنیم به معنی فالگوش وایسادن میشه. وقتی درخواستی توسط کاربر ارسال میشه اندروید با استفاده از BroadCast درخواست رو اعلام میکنه و هر نرم افزاری که Reciver برای اون BroadCast تعریف کرده باشه، به کاربر پیشنهاد داده میشه.

در مورد این مبحث در یه مقاله جداگونه کامل حرف می زنیم. استفاده اصلی این قسمت در فروشگاه های اینترنتی است که شما با استفاده از یک لینک که بین سایت و اپلیکیشن مشترک است اپلیکیشن خود را باز کرده و محصول مورد نظر را نمایش می دهید.

ارسال و دریافت اطلاعات

همانطور که گفته شد از Intent برای جابه جایی بین اکتیویتی ها و انجام کارها استفاده می شود و گاهاً نیاز است که همراه با آن اطلاعاتی ارسال شود. در واقع یک Intent دارای یک فرآیند از اطلاعات پایه ای می باشد که آن اطلاعات عبارتند از کاری که می خواهیم انجام بدیم؛ از جمله اکشن (Action) و نوع (Type) که برای هر نوع در خواست می تواند متفاوت باشد و حتی اطلاعات بیشتر یا کمتری مورد نیاز باشد. برای این دسته از اطلاعات که ضروری هستند و باید همراه با Intent ارسال شود از متد های ()getAction و ()getType استفاده می کنیم.

Putextra در اندروید چیست؟

همانطور که مشاهده می کنید متد putextra در Intent های بالا استفاده شده. حال می خواهیم توضیحات بیشتری در مورد putextra به شما بدهیم. ممکن است بخواهید غیر از اطلاعات ضروری، داده های دیگری را همراه با Intent ارسال کنید. برای اینکه داده ای یا آبجکتی را همراه با Intent ارسال کنیم از متد putextra استفاده می کنیم. فرض کنید در اکتیوتی اول یک عنوان دارید که وقتی کاربر یکی از آن ها را انتخاب کرد، در اکتیوتی دوم قرار است که اطلاعات بیشتری در مورد آن عنوان کسب کند. برای اینکه عنوان را از اکتیوتی اول به اکتیوتی دوم پاس دهیم به روش زیر عمل می کنیم:

Intent intent = new Intent(Activity1.this, Activity2.class); intent.putExtra(“KEY”, Value); startActivity(intent);

همانطور که مشاهده می کنید داده اضافی توسط متد putextra به Intent اضافه شده و همراه با آن ارسال میشود.

putextra دو پارامتر دارد:

  • Key
  • Value

پارامتر اول در واقع کلید داده ای است که فرستادیم و پارامتر دوم خود داده.

کلید از نوع String است و داده ما از انواع متغییر های اصلی (int, String و...) می باشد.

حال که از اکتیوتی 1 مقداری را ارسال کردیم، باید از اکتیوتی 2 آن را دریافت کنیم.

روش دریافت به صورت زیر است:

Bundle extras = getIntent().getExtras(); if (extras != null) { String value = extras.getString(&quotKey&quot); }

خط اخر که متغییری از نوع String است به مقدار ارسالی از اکتیویتی 1 بستگی دارد و به این صورت است که اگر از اکتیوتی 1 چه نوع داده ای ارسال شده.

برای مثال اگر در اکتیویتی اول یک مقدار عددی که int می باشد ارسال شود در اکتیوتی دوم باید متغییر تعریفی از نوع int و Bundle با متد ()getint دریافت شود.

در مثال های بالا طریقه ارسال یک متغییر از اکتیوتی به اکتیوتی دیگری را برای شما توضیح دادیم. اما اگر قرار باشد که آبجکتی ارسال شود چه؟!

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

اینبار قصد داریم از اکتیویتی 1 آبجکتی را به اکتیویتی 2 ارسال کنیم. مانند روش قبل با استفاده از متد putextra آبجکت را در Intent قرار میدهیم و به اکتیوتی 2 ارسال میکنیم:

Intent intent = new Intent(Activity1.this, Activity2.class); Example obj_example = new Example(); intent.putExtra(&quotobject&quot, obj_example ); startActivity(intent);

به نظر میرسد همه چیز درست است اما کامپایلر از این خط کد خطا می گیرد و میگوید که نمی توانید این مقدار را ارسال کنید!

برای حل این مشکل باید به کلاس آن آبجکت رفته و اینترفیس Serializable را در این کلاس implements کنیم. با این کار خاصیت سریالایز شدن برای کلاس فراهم می شود و می تواند از طریق Intent ارسال شود.

class Example implements Serializable { //TODO }

در زمان دریافت آبجکت در اکتیوتی 2 نیز به روش قبل عمل می کنیم:

Bundle bundle = getIntent().getExtras(); if (bundle != null) { Example example = bundle.getObject(&quotobject&quot); }

این بار نیز کامپایلر از شما خطا میگیرد

برای گرفتن آبجکت کافی است به روش زیر عمل کنیم:

Example example = getIntent().getSerializableExtra(&quotobject&quot);

در مثال بالا دیدیم که اینترفیس Serializable در کلاس آبجکت implements شد. اگر بخواهیم یک آبجکت جاوا (برای مثال Person، Car، Employee، و...) را انتقال بدیم، باید یکسری اقدامات اضافی انجام بدیم تا بتونیم اطلاعات رو منتقل کنیم. برای انجام این کار، شئ ما باید یا به Serializable یا به Parcelable تبدیل بشه.

Serializable چیست؟

Serializable یک رابط استاندارد جاوا است. اما بخشی از Android SDK نیست. بسیار ساده و آسونه. فقط با اجرای این رابط کاربری یک شئ جاوا آمادست تا از یک Activity به Activity دیگری منتقل بشه. در تکه کد زیر می‌توانید ببینید که این رابط کاربری چقدر ساده است.

import java.io.Serializable; public class Person implements Serializable { private String firstName; private String lastName; private int age; public Person(String firstName, String lastName, int age){ this.firstName = firstName; this.lastName = lastName; this.age = age; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }

از آنجا که Serializable یک رابط نشانگر است، ما مجبور نیستیم کلی متد های دیگر را امپلیمنت کنیم. هنگامی که ما "POJO" خود را با آن علامتگذاری میکنیم، جاوا سعی خواهد کرد که آن را سریالایز کند.

البته این روش ساده عیب هم دارد. استفاده از آن موجب می‌شود در طول مسیر تعداد زیادی اشیاء اضافی ایجاد شود. این اتفاق باعث تولید زباله‌های زیادی برای زباله جمع کن (garbage collection) می‌شود. در نتیجه عملکرد را ضعیف کرده و تخلیه باتری سریعتر است.

Parcelable چیست؟

Parcelable یک رابط دیگر است. این رابط بخشی از Android SDK است. در حال حاضر، Parcelable به طور خاصی طراحی شده است که هیچ شئ اضافی در هنگام استفاده از آن وجود دارد. در قطعه کد زیر می‌توانید یک نمونه استفاده از رابط Parcelable را مشاهده کنید:

import android.os.Parcel; import android.os.Parcelable; public class Person implements Parcelable { private String firstName; private String lastName; private int age; public Person(String firstName, String lastName, int age){ this.firstName = firstName; this.lastName = lastName; this.age = age; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(this.firstName); dest.writeString(this.lastName); dest.writeInt(this.age); } protected Person(Parcel in) { this.firstName = in.readString(); this.lastName = in.readString(); this.age = in.readInt(); } public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() { @Override public Person createFromParcel(Parcel source) { return new Person(source); } @Override public Person[] newArray(int size) { return new Person[size]; } }; }

البته، استفاده از Parcelable نیز معایبی را دارد! از آنجا که کدهای boilerplate، POJO را از بالا نگه می دارد، درک آن بسیار سخت است.

Parselable VS Serializable در اندروید

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

اولین تیم در پشت این ایده است که Parcelable سریعتر و بهتر از Serializable است. البته، این اطلاعات در پشت این بیانیه وجود دارد.

نتایج آزمایشات فیلیپ برول (Philippe Breault) نشان می دهد که Parcelable بیش از 10 برابر سریعتر از Serializable است. بعضی از مهندسان گوگل نیز این بیانیه را پشت سر می گذارند.

در حال حاضر تیم دوم ادعا می کند که همه ما آن را اشتباه انجام می دهیم! و استدلال آنها به اندازه کافی منطقی است!

به گفته آنها، روال پیش فرض Serializable کندتر از Parcelable است و در اینجا ما توافق بین دو طرف را داریم! بله، این غیرعادی است که همه اینها را مقایسه کنید! از آنجا که با Parcelable ما در واقع در حال نوشتن کد سفارشی هستیم. کد به طور خاص برای آن POJO ایجاد شده است. بنابراین هیچ زباله ای ایجاد نمی شود و نتایج بهتر است. اما با روشی پیش فرض Serializable، ما به فرایند سریال سازی خودکار جاوا تکیه می کنیم. ظاهرا این فرآیند سفارشی نیست و مقدار زیادی زباله ایجاد می کند! بنابراین، نتایج بدتر.

اکنون روشی دیگر وجود دارد. تمام فرایند اتوماتیک پشت Serializable را می توان با کد سفارشی جایگزین کرد که از روش ()writeObject و ()readObject استفاده می کند. این روش ها خاص هستند. اگر ما می خواهیم رویکرد سریالی را در ترکیب با رفتار سریال سازی سفارشی تکیه کنیم، باید این دو روش را با همان امضای دقیق به عنوان یکی از زیر وارد کنیم:

private void writeObject(java.io.ObjectOutputStream out) throws IOException; private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; private void readObjectNoData() throws ObjectStreamException;

اما این چگونه کار می کند! در حال حاضر، در این دو روش می توانیم منطق دلخواهمان را پیاده کنیم. اگر انجام شود به درستی، زباله مرتبط با روش پیش فرض Serializable دیگر عامل نخواهد بود!

و در حال حاضر مقایسه بین Parcelable و Serializable سفارشی به نظر من عادلانه است! نتایج ممکن است شگفت انگیز باشد! روشی سفارشی Serializable بیش از 3 برابر سریعتر برای نوشتن و 1.6 برابر سریعتر برای خواندن از Parcelable است.

به نظر من، تفاوت در سرعت بین دو رویکرد در اکثر موارد تقریبا ناچیز است. بنابراین، در پایان روز، مهمتر از آن است که کار را انجام دهیم و کاربران شاد داشته باشیم، تا برنامه ای با 0.000042 میلی ثانیه سریعتر اجرا شود.

در قسمت سورس سایت پروژه اندروید خوبی در مورد افزایش لایک و فالوور اینستاگرام منتشر کردیم. با استفاده از این لینک می تونید این پروژه رایگان را ببینید.

یکی از مشکلات مهمی که همه برنامه نویس های اندرویدی دارند اجرای برنامه روی گوشی خودشون هستش!!! پیشنهاد می کنم مقاله اجرای اپلیکیشن با WIFI در اندروید را بخونید تا از دست کابل بازی راحت بشید.

intent در اندرویدintentandroid studioبرنامه نویسی
شاید از این پست‌ها خوشتان بیاید