ساخت لیست علاقه مندی ها (Favorites)، با استفاده از SharedPreferences و همچنین، تلاش برای محتوا محور کردن برنامه اندروید و ساده تر شدن توسعه اطلاعاتی برنامه
در بیشتر برنامه های آموزشی و اطلاعاتی که به صورت تعدادی مبحث هستند، دو بخش ((جستجو)) و ((لیست علاقه مندی ها)) جزء بخش های اصلی و ضروری برنامه می باشند. قبلا در مبحثی دیگر، چگونگی ساخت قسمت جستجو در عنوان مبحث ها را شرح دادیم، اکنون در این مبحث قصد داریم که چگونگی ساخت لیست علاقه مندی ها را شرح بدهیم.
چون از SharedPreferences استفاده می کنیم، تا زمانی که کاربر، برنامه اندروید را uninstall نکند، اطلاعات مروبط به لیست علاقه مندی ها که به صورت SharedPreferences ذخیره شده است، باقی خواهد ماند و با خروج کاربر از برنامه اندروید، مشکلی برای آنها به وجود نمی آید.
اگر یادتان باشد، در مبحث مربوط به جستجو، ما برای سه مبحث، سه Activity می ساختیم و بنده در همانجا تذکر دادم که نباید در برنامه ها، بدین شیوه مباحث را بسازیم و مجبور نیستیم که برای تک تک مبحث ها، Activity های جداگانه بسازیم، بلکه می توانیم تنها یک Activity بسازیم و سپس بر اساس شماره مبحث ها، اطلاعات مبحث را در آن Activity نمایش بدهیم. در واقع، در مبحث جستجو، تنها می خواستیم منطق جستجو را آموزش بدهیم. اما اکنون، چون یک مبحث نیز در مورد چگونگی ساخت برنامه اندروید ((محتوا محور)) نوشته ام، بد نیست که در برخی مباحث، آن موارد را نیز به کار ببرم. بنابراین این بار کدها را به گونه ای می نویسم که برنامه اندروید، به راحتی قابل توسعه باشد.
در واقع، این مبحث، علاوه بر آموزش ساخت لیست علاقه مندی ها، چگونگی ساخت یک برنامه محتوا محور ساده را نیز آموزش می دهد، به گونه ای که مثلا اگر اکنون دارای 10 مبحث است، بنده اگر بخواهم آن را به 20 مبحث تغییر بدهم، تنها باید یکی از فایل های پروژه اندروید را باز کنم و عدد 10 نوشته شده در آن را به 20 تغییر بدهم و سپس، فایل strings.xml را باز کنم و تعداد 10 رشته (string) که برابر عنوان مبحث ها است و همچنین، 10 رشته دیگر که برابر متن آن مبحث ها می باشد را تعریف کنم. با این تغییرات، تعداد مباحث برنامه به 20 عدد افزایش می یابد، بدون اینکه بنده مجبور باشم که حتی یک خط از کدهای Activity های مختلف برنامه را تغییر بدهم.
دقت شود که در این برنامه اندروید، من تنها از فایل strings.xml برای تعریف محتوای اطلاعاتی برنامه استفاده کرده ام، شما می توانید انتخاب های دیگری مثل ذخیره در پایگاه داده SQLite ، ذخیره در فایل های HTML ، دریافت از اینترنت و ... را داشته باشید (یا ترکیبی از آنها)، که توضیحاتی در مورد آنها را می توانید در مبحث زیر بخوانید (در این برنامه اندروید، ساده ترین روش را انتخاب کرده ایم) :
آموزش شماره 2253
ابتدا بهتر است نگاهی به خود برنامه داشته باشیم. اولین Activity برنامه، شامل لیست تمامی مباحث آموزشی است (من تعداد 7 مبحث را انتخاب کرده ام) :

فهرست مبحث ها، با استفاده از ListView نمایش داده شده است. با اشاره بر روی یک item از ListView ، به مبحث متناظر با شماره آن، منتقل می شویم. مثلا من بر روی عنوان مبحث سوم اشاره می کنم :

در زیر محتوای هر مبحث، یک علامت ستاره وجود دارد (با استفاده از ImageView)، که اگر قبلا کاربر آن را به لیست علاقه مندی ها افزوده باشد، به رنگ طلایی است و اگر جزء لیست علاقه مندی ها نباشد، همین تصویر، اما با رنگ سیاه و سفید نمایش داده می شود. بنابراین کاربر با دیدن شکل ستاره و از رنگ آن، متوجه می شود که آیا این مبحث جزء لیست علاقه مندی ها هست یا نه.
برای اینکه مبحث به لیست علاقه مندی ها افزوده شود، بر روی ستاره اشاره می کنیم و بنابراین رنگ آن به رنگ طلایی تغییر پیدا می کند و پیامی نیز با عنوان ((به لیست علاقه مندی ها افزوده شد)) نمایش داده می شود (با استفاده از روش Toast) :

همچنین، اگر اکنون دوباره بر روی ستاره طلایی رنگ، اشاره کنیم، مبحث سوم از لیست علاقه مندی ها حذف شده، رنگ ستاره به سیاه و سفید تغییر پیدا می کند و پیامی با عنوان ((از لیست علاقه مندی ها حذف شد)) نمایش داده می شود :

برای ورود به Activity ای که در آن، لیست علاقه مندی ها نمایش داده می شود، یک آیکون (icon) در action bar برنامه اندروید، به شکل همان ستاره طلایی رنگ، قرار داده ایم. مثلا فرض کنید که من مبحث شماره هفتم را نیز به لیست علاقه مندی اضافه نمایم و سپس بر روی آیکون موجود در action bar ، اشاره کنم. لیست علاقه مندی ها به صورت زیر نمایش داده می شود (شامل مبحث های سوم و هفتم که قبلا آنها را به لیست علاقه مندی ها اضافه کرده ایم) :

برای نمایش لیست علاقه مندی ها، از یک ListView استفاده کرده ایم.
خوب اکنون به سراغ چگونگی کدنویسی پروژه اندروید می رویم و بخش های مختلف کدها را شرح خواهیم داد. توصیه می کنم فایل های پروژه اندروید را از انتهای مبحث، دانلود نمایید. در ادامه، ساختار پروزه اندروید را شرح می دهیم.
نام پروژه اندروید را برابر Favorites انتخاب کرده ایم (نام package برابر com.kelidestan.favorites انتخاب شده است. نام activity اصلی را برابر MainActivity انتخاب کرده ایم و فایل xml متناظر آن را هم برابر activity_main قرار داده ایم).
قبلا گفته بودم که اگر اطلاعاتی هست که در تعدادی از Activity های مختلف پروژه اندروید به کار می رود، نیازی نیست که مقدار آنها را در تک تک Activity ها تعریف کنید، بلکه می توانید یک کلاس (class) ساخته و مقادیر مورد نظرتان را در آن تعریف کنید و سپس در هر Activity که به آن مقدار نیاز دارید، یک شیء (object) از آن کلاس (class) بسازید و سپس مقدار مورد نظرتان را فراخوانی کنید. خوبی این روش این است که اگر بخواهید آن مقدار مورد نظر را تغییر بدهید، دیگر مجبور نیستید که تک تک آن Activity ها که در آنها، آن مقدار خاص به کار رفته است را باز و ویرایش نمایید. مقدار مورد نظر ما که در تعدادی از Activity های این پروژه اندروید به کار می رود، تعداد کل مبحث ها می باشد (که آن را برابر 7 انتخاب کرده ایم). بنابراین، یک کلاس با نام Globals ساخته ایم :

کدهای این کلاس (class)، به صورن زیر می باشد :
import android.app.Application;
public class Globals extends Application {
public int Subjects_total_number = 7;
}
در هر Activity که خواستیم نعداد کل مبحث ها را از کلاس Globals فراخوانی کنیم، ابتدا دو متغیر به صورت public و به صورت زیر تعریف می کنیم :
public Globals global = new Globals();
که در آن، global یک شیء (object) ساخته شده از کلاس Globals می باشد. سپس با کد زیر، تعداد کل مبحث ها را در متغیر Subjects_total_number ذخیره می کنیم :
دقت کنید که نام Subjects_total_number را می توانستیم متفاوت با نام تعریف شده در کلاس Globals تعریف کنیم، اما من ترجیح دادم که یکسان باشند.
اکنون نگاهی به کدهای فایل strings.xml می اندازیم :

کدهای فایل strings.xml به صورت زیر می باشد :
<resources>
<string name="app_name">Favorites</string>
<string name="action_settings">Settings</string>
<string name="hello_world">Hello world!</string>
<string name="title_activity_favorites">لیست علاقه مندی ها</string>
<string name="favorites">لیست علاقه مندی ها</string>
<string name="title_activity_show__subjects">نمایش مبحث ها</string>
<string name="favorites_added">به لیست علاقه مندی ها افزوده شد</string>
<string name="favorites_removed">از لیست علاقه مندی ها حذف شد</string>
<string name="subject_1">آموزش اول</string>
<string name="subject_2">آموزش دوم</string>
<string name="subject_3">آموزش سوم</string>
<string name="subject_4">آموزش چهارم</string>
<string name="subject_5">آموزش پنجم</string>
<string name="subject_6">آموزش ششم</string>
<string name="subject_7">آموزش هفتم</string>
<string name="subject_text_1">متن مربوط به آموزش اول</string>
<string name="subject_text_2">متن مربوط به آموزش دوم</string>
<string name="subject_text_3">متن مربوط به آموزش سوم</string>
<string name="subject_text_4">متن مربوط به آموزش چهارم</string>
<string name="subject_text_5">متن مربوط به آموزش پنجم</string>
<string name="subject_text_6">متن مربوط به آموزش ششم</string>
<string name="subject_text_7">متن مربوط به آموزش هفتم</string>
</resources>
دقت شود که نام رشته (string) متناظر با عنوان مبحث های آموزشی را به شکل کلی زیر تعریف می کنیم :
که در آن، N برابر شماره مبحث می باشد (از شماره 1 تا 7). همچنین رشته (string) متناظر با متن مبحث های آموزشی، به شکل کلی زیر تعریف می شود :
که در آن، N برابر شماره مبحث می باشد (از شماره 1 تا 7).
اینکه در ابتدا، کلاس Globals و همچنین کدهای فایل strings.xml را شرح دادیم، به این دلیل است که چنانچه شما قصد داشته باشید که در آینده تعداد مبحث ها را افزایش بدهید، تنها با این دو سر و کار دارید. مثلا فرض کنید که من بخواهم تعداد مبحث ها را به 10 تا افزایش بدهم، برای این منظور، ابتدا کلاس Globals را باز می کنم و عدد 7 را به 10 تبدیل می کنم و سپس فایل strings.xml را باز کرده و سه رشته برای عنوان مبحث ها (از شماره 8 تا شماره 10) و سه رشته نیز برای متن مبحث ها (از شماره 8 تا شماره 10)، مطابق شکل کلی که شرح داده شد، می سازم.
برای پروژه اندروید، تعدادی عکس به کار برده ایم که در پوشه drawable-hdpi قرار گرفته اند :

عکس arrow.png را در item های ListView مربوط به لیست علاقه مندی ها به کار برده ایم (برای زیبایی بیشتر). عکس هایی که در انتهای نام آنها، کلمه background وجود دارد، به عنوان پس زمینه Activity ها به کار رفته اند و تنها برای زیباتر کردن برنامه اندروید می باشند. ic_launcher.png هم که همان آیکون (icon) برنامه اندروید می باشد. اما دو عکس favorite_selected.png و favorite_not_selected.png مهم می باشند و برای لیست علاقه مندی ها ضروری هستند. این دو عکس، هر دو به شکل ستاره هستند (ستاره ای که در لیست علاقه مندی ها نمایش می دهیم)، یکی به رنگ طلایی و دیگری به صورت سیاه و سفید.
همان طور که قبلا گفتیم، اطلاعات مربوط به لیست علاقه مندی ها (اینکه مباحث در لیست علاقه مندی ها قرار دارند یا خیر) را با استفاده از SharedPreferences ذخیره می کنیم. برای استفاده از SharedPreferences ، یک کلاس (class) با نام Prefs ساخته ایم :

کدهای کلاس Prefs را به صورت زیر نوشته ایم :
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
public class Prefs extends PreferenceActivity {
public int Subjects_total_number;
public Globals global = new Globals();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
Subjects_total_number = global.Subjects_total_number;
// for favorites
Boolean [] favorites = new Boolean [Subjects_total_number];
for(int x = 1; x < Subjects_total_number+1; x++){
String each_subject = "subject_" + String.valueOf(x);
favorites [x] = prefs.getBoolean(each_subject, false);
}
}
}
یک آرایه از جنس Boolean و با نام favorites تعریف می کنیم، که هر عنصر آن، متناظر با رشته ای (string) به شکل کلی زیر است :
که در آن، N برابر شماره مبحث است. چون آرایه از جنس Boolean است، بنابراین هر عنصر از آرایه، می تواند مقدار true یا false داشته باشد که ما مقدار true برای یک مبحث را به این صورت در نظر می گیریم که آن مبحث در لیست علاقه مندی ها قرار دارد و مقدار false را هم به این صورت در نظر می گیریم که آن مبحث در لیست علاقه مندی ها قرار ندارد. مثلا فرض کنید که بخواهیم ببینیم که آیا مبحث شماره 4 در لیست علاقه مندی ها قرار دارد یا نه، برای این منظور، باید ببینیم در آرایه favorites ، عنصری که با رشته subject_4 شناسایی می شود، مقدارش برابر true است یا برابر false . مثلا اگر مقدار false باشد، یعنی مبحث شماره 4 در لیست علاقه مندی قرار ندارد. حال فرض کنید که بخواهیم آن را به لیست علاقه مندی ها اضافه کنیم، بنابراین باید کدهایی بنویسیم که مقدار false متناظر با subject_4 در آرایه favorites ، به مقدار true تبدیل شود.
در صورت تمایل، برای آشنایی بیشتر با SharedPreferences ، نگاهی به کلید زیر بیندازید :
آموزش شماره 288
اکنون بهتر است کد مربوط به نمایش آیکون (icon) لیست علاقه مندی ها در action bar (در نوار بالای برنامه اندروید) را شرح بدهیم، که با اشاره کاربر بر روی آن، به Activity نمایش لیست علاقه مندی ها، منتقل می شود. برای این منظور، فایل menu.xml در پوشه menu از پروزه اندروید را ساخته ایم :

کدهای فایل menu.xml به صورت زیر می باشند :
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/itemFavorites"
android:icon="@drawable/favorite_selected"
android:showAsAction="ifRoom|withText"
android:title="@string/favorites">
</item>
</menu>
که در آن، تنها یک item تعریف کرده ایم که عکس متناظر با آن، برابر favorite_selected از پوشه های drawable (یعنی همان عکس ستاره طلایی رنگ) انتخاب شده است و متن متناظر با آن را برابر رشته (string) با نام favorites تعریف شده در فایل strings.xml انتخاب کرده ایم.
ساخت فایل menu.xml ، تنها شیوه نمایش را تعیین کرده است و علاوه بر آن، در هر Activity که می خواهیم آیکون (icon) مورد نظرمان در action bar نمایش داده شود، باید یک سری کد بنویسیم. آن کدها بر اساس دو روش (method) با نام های onCreateOptionsMenu و onOptionsItemSelected می باشند که در بخش پایانی کدهای Activity های برنامه، آنها را نوشته ایم. بنابراین در ادامه که کدهای Activity ها را شرح می دهیم، به آنها نیز توجه داشته باشید. مثلا بخشی از کد فایل MainActivity.java که در این زمینه است را ذکر می کنیم :
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.itemFavorites:
startActivity(new Intent(MainActivity.this, Favorites.class));
return true;
default:
return true;
}
}
حال قصد داریم که Activity های برنامه را شرح بدهیم. ابتدا به سراغ Activity با نام MainActivity می رویم که برای نمایش لیست مبحث های موجود در برنامه اندروید به کار می رود (Activity اصلی برنامه اندروید که در ابتدا نمایش داده می شود) :

فایل MainActivity.java ، فایل مربوط به Activity می باشد و فایل xml متناظر با آن (که در واقع ساختار گرافیکی Activity را مشخص می کند) نیز، فایل activity_main.xml است. با توجه به اینکه در آن، از یک ListView برای نمایش فهرست مبحث ها استفاده کرده ایم، بنابراین ساختار هر ردیف (هر item) از ListView را هم در فایل list_item_subjects.xml تعیین کرده ایم.
کدهای فایل activity_main.xml به صورت زیر می باشد :
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/subjects_list_background"
android:orientation="vertical"
tools:context=".MainActivity" >
<!-- List View -->
<ListView
android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
کدهای فایل list_item_subjects.xml که تعیین کننده ساختار گرافیکی هر ردیف (هر item) از ListView می باشد، عبارت است از :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="@+id/textView1"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="8dp"
android:gravity="center"
android:textSize="20sp" />
<ImageView
android:id="@+id/imageView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
کدهای فایل MainActivity.java که همان کدهای java مربوط به Activity است، به صورت زیر می باشد :
import android.app.ListActivity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends ListActivity {
public ListView lv;
public Globals global = new Globals();
public int Subjects_total_number;
public String[] Subjects;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Subjects_total_number = global.Subjects_total_number;
Subjects = new String[Subjects_total_number];
for(int x = 1; x < Subjects_total_number+1; x = x+1) {
String this_subject = "subject_" + String.valueOf(x);
int resID = getResources().getIdentifier(this_subject, "string", getPackageName());
Subjects[x-1] = getResources().getString(resID);
}
setListAdapter(new MyAdapter(this,
android.R.layout.simple_list_item_1, R.id.textView1,
Subjects));
lv = getListView();
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, final View view,
int position, long id) {
Intent i = new Intent(getApplicationContext(), Show_Subjects.class);
String Subject_number = String.valueOf(position+1);
i.putExtra("subject_number", Subject_number);
startActivity(i);
}
});
}
private class MyAdapter extends ArrayAdapter<String>{
public MyAdapter(Context context, int resource, int textViewResourceId,
String[] strings) {
super(context, resource, textViewResourceId, strings);
// TODO Auto-generated constructor stub
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.list_item_subjects, parent, false);
String[] items = Subjects;
TextView tv = (TextView) row.findViewById(R.id.textView1);
tv.setText(items[position]);
return row;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.itemFavorites:
startActivity(new Intent(MainActivity.this, Favorites.class));
return true;
default:
return true;
}
}
}
اکنون بخش های مهم کدهای فوق را توضیح می دهیم. با کدهای زیر، عنوان مبحث ها را در یک آرایه رشته ای با نام Subjects ذخیره کرده ایم :
Subjects = new String[Subjects_total_number];
for(int x = 1; x < Subjects_total_number+1; x = x+1) {
String this_subject = "subject_" + String.valueOf(x);
int resID = getResources().getIdentifier(this_subject, "string", getPackageName());
Subjects[x-1] = getResources().getString(resID);
}
کد زیر، چگونکی عمل کردن ListView بعد از اشاره کاربر بر روی یک item از آن را شرح می دهد :
@Override
public void onItemClick(AdapterView<?> parent, final View view,
int position, long id) {
Intent i = new Intent(getApplicationContext(), Show_Subjects.class);
String Subject_number = String.valueOf(position+1);
i.putExtra("subject_number", Subject_number);
startActivity(i);
}
});
همان طور که مشاهده می کنید، با استفاده از Intent ، به Activity با نام Show_Subjects منتقل می شویم که همان Activity طراحی شده برای نمایش محتوای مبحث ها می باشد. آن Activity ، یک رشته شامل شماره مبحث مورد نظر را دریافت می کند و سپس بر اساس آن شماره، محتویات مبحث را نمایش می دهد. بنابراین ما شماره متناظر با item اشاره شده را با نام subject_number به Show_Subjects می فرستیم. یعنی با این خط از کدها :
در کلاس MyAdapter ، این خط از کدها مهم می باشد :
TextView tv = (TextView) row.findViewById(R.id.textView1);
tv.setText(items[position]);
که توسط آنها، عنوان مبحث ها را در TextView تعریف شده در فایل list_item_subjects.xml (که برای ساختار هر ردیف از ListView می باشد) نمایش می دهیم.
اکنون قصد داریم Activity ساخته شده برای نمایش محتوای مبحث ها را شرح بدهیم که دارای نام Show_Subjects می باشد :

فایل مربوط به این Activity ، دارای نام Show_Subjects.java می باشد و نام فایل xml متناظر با آن برابر show_subjects.xml است.
کدهای فایل show_subjects.xml عبارتند از :
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/subjects_background"
android:orientation="vertical"
tools:context=".Show_Subjects" >
<TextView
android:id="@+id/textView1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:gravity="right"
android:textSize="20sp"
android:text="@string/hello_world" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:gravity="right"
android:textSize="20sp"
android:text="@string/hello_world" />
<TableRow
android:id="@+id/tableRow1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" >
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/favorite_not_selected" />
</TableRow>
</LinearLayout>
که شامل دو TextView است که یکی برای نمایش عنوان مبحث و دیگری برای نمایش متن مبحث به کار می رود. در زیر آن دو، یک ImageView قرار می گیرد که عکس ستاره را به ما نمایش می دهد و بر اساس رنگ ستاره، می توانیم تشخیص بدهیم که این مبحث در لیست علاقه مندی ها وجود دارد یا خیر و با اشاره بر روی آن، می توانیم به لیست اضافه کنیم و یا از لیست حذفش کنیم (توضیحات کامل را در ابتدای همین مبحث آموزشی، با عکس ها، شرح دادیم).
کدهای فایل Show_Subjects.java عبارتند از :
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class Show_Subjects extends Activity {
public String Subject_number;
public SharedPreferences shared;
public SharedPreferences.Editor editor;
Globals global = new Globals();
public ImageView iv_favorites;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.show_subjects);
iv_favorites = (ImageView) findViewById(R.id.imageView1);
Bundle extras = getIntent().getExtras();
if (extras != null) {
Subject_number = extras.getString("subject_number");
}
TextView tv1 = (TextView) findViewById(R.id.textView1);
String stringName_1 = "subject_" + String.valueOf(Subject_number);;
int resID_1 = getResources().getIdentifier(stringName_1, "string", getPackageName());
tv1.setText(resID_1);
TextView tv2 = (TextView) findViewById(R.id.textView2);
String stringName_2 = "subject_text_" + String.valueOf(Subject_number);;
int resID_2 = getResources().getIdentifier(stringName_2, "string", getPackageName());
tv2.setText(resID_2);
// Favorites
shared = getSharedPreferences("Prefs", MODE_PRIVATE);
editor = shared.edit();
final int subject_number_int = Integer.parseInt(Subject_number);
final String this_subject = "subject_" + String.valueOf(subject_number_int);
final Boolean b1 = shared.getBoolean(this_subject, false);
if (b1){
iv_favorites.setImageResource(R.drawable.favorite_selected);
}else{
iv_favorites.setImageResource(R.drawable.favorite_not_selected);
}
iv_favorites.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Boolean b2 = shared.getBoolean(this_subject, false);
if (b2){
editor.putBoolean(this_subject, false);
editor.apply();
iv_favorites.setImageResource(R.drawable.favorite_not_selected);
// show message
String message = getResources().getString(R.string.favorites_removed);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}else{
editor.putBoolean(this_subject, true);
editor.apply();
iv_favorites.setImageResource(R.drawable.favorite_selected);
// show message
String message = getResources().getString(R.string.favorites_added);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.itemFavorites:
startActivity(new Intent(Show_Subjects.this, Favorites.class));
return true;
default:
return true;
}
}
}
بخش های مهم کدها را در ادامه شرح می دهیم.
با کدهای زیر، ابتدا شماره مبحث را که با نام subject_number به این Activity ارسال کرده ایم، دریافت کرده و سپس بر اساس آن، عنوان مبحث و همچنین متن مبحث را از فایل strings.xml فراخوانی کرده و در دو TextView نمایش می دهیم :
if (extras != null) {
Subject_number = extras.getString("subject_number");
}
TextView tv1 = (TextView) findViewById(R.id.textView1);
String stringName_1 = "subject_" + String.valueOf(Subject_number);;
int resID_1 = getResources().getIdentifier(stringName_1, "string", getPackageName());
tv1.setText(resID_1);
TextView tv2 = (TextView) findViewById(R.id.textView2);
String stringName_2 = "subject_text_" + String.valueOf(Subject_number);;
int resID_2 = getResources().getIdentifier(stringName_2, "string", getPackageName());
tv2.setText(resID_2);
با کدهای زیر، بر اساس SharedPreferences ، چک می کنیم که آیا مبحث در لیست علاقه مندی ها قرار دارد یا نه (بر اساس مقدار true یا false ذخیره شده) و سپس بر اساس آن، شکل مناسب برای نمایش یکی از دو عکس ستاره (طلایی یا سیاه و سفید) را در ImageView نمایش می دهیم تا کاربر، وضعیت مبحث از نظر قرارگیری در لیست علاقه مندی ها را بداند :
shared = getSharedPreferences("Prefs", MODE_PRIVATE);
editor = shared.edit();
final int subject_number_int = Integer.parseInt(Subject_number);
final String this_subject = "subject_" + String.valueOf(subject_number_int);
final Boolean b1 = shared.getBoolean(this_subject, false);
if (b1){
iv_favorites.setImageResource(R.drawable.favorite_selected);
}else{
iv_favorites.setImageResource(R.drawable.favorite_not_selected);
}
کدهای زیر، برای تغییر وضعیت مبحث از نظر قرارگیری در لیست علاقه مندی ها می باشد (تغییر مقدار ذخیره شده توسط SharedPreferences و همچنین تغییر شکل فعلی نمایش داده شده)، زیرا اگر کاربر بر روی شکل ستاره اشاره کند، باید وضعیت آن مبحث تغییر داده شود و شکل نمایش داده شده در ImageView نیز عوض شود. همچنین یک پیام کوتاه نیز توسط روش Toast به کاربر نمایش داده می شود تا تغییر وضعیت را تذکر بدهد :
@Override
public void onClick(View v) {
Boolean b2 = shared.getBoolean(this_subject, false);
if (b2){
editor.putBoolean(this_subject, false);
editor.apply();
iv_favorites.setImageResource(R.drawable.favorite_not_selected);
// show message
String message = getResources().getString(R.string.favorites_removed);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}else{
editor.putBoolean(this_subject, true);
editor.apply();
iv_favorites.setImageResource(R.drawable.favorite_selected);
// show message
String message = getResources().getString(R.string.favorites_added);
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
}
});
حال می خواهیم کدهای Activity در نظر گرفته شده برای نمایش لیست علاقه مندی ها را شرح بدهیم. این Activity دارای نام Favorites می باشد :

فایل مربوط به این Activity ، دارای نام Favorites.java می باشد و فایل xml متناظر با آن، فایل favorites.xml است. این Activity بر اساس یک ListView ، فهرست مبحث های قرار گرفته در لیست علاقه مندی ها را نمایش می دهد. فایل list_item_favorites.xml ساختار گرافیکی هر ردیف (هر item) از این ListView را تعیین می کند.
کدهای فایل list_item_favorites.xml عبارتند از :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TableRow
android:id="@+id/tableRow1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:src="@drawable/arrow" />
<TextView android:id="@+id/favorites_textView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dip"
android:textSize="16dip"
android:textStyle="bold"/>
</TableRow>
</LinearLayout>
برای زیبایی بیشتر، عکس یک فلش را نیز در ساختار هر ردیف از ListView قرار داده ایم (در ImageView).
کدهای فایل favorites.xml عبارتند از :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/favorites_background"
android:orientation="vertical" >
<!-- List View -->
<ListView
android:id="@+id/list_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
</LinearLayout>
کدهای فایل Favorites.java عبارتند از :
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
public class Favorites extends Activity {
public int Subjects_total_number;
public Globals global = new Globals();
public List<String> Favorites_numbers;
public List<String> Favorites_strings;
// List view
private ListView lv;
// Listview Adapter
ArrayAdapter<String> adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.favorites);
// Listview Data
Favorites_strings = new ArrayList<String>();
Favorites_numbers = new ArrayList<String>();
final SharedPreferences shared = getSharedPreferences("Prefs", MODE_PRIVATE);
Subjects_total_number = global.Subjects_total_number;
for(int x = 1; x < Subjects_total_number+1; x = x+1) {
String each_subject = "subject_" + String.valueOf(x);
Boolean b = shared.getBoolean(each_subject, false);
if(b){
String this_subject = "subject_" + String.valueOf(x);
int resID = getResources().getIdentifier(this_subject, "string", getPackageName());
Favorites_strings.add(getResources().getString(resID));
String x_string = String.valueOf(x);
Favorites_numbers.add(x_string);
}
}
lv = (ListView) findViewById(R.id.list_view);
// Adding items to listview
adapter = new ArrayAdapter<String>(this, R.layout.list_item_favorites, R.id.favorites_textView, Favorites_strings);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, final View view,
int position, long id) {
String favorite_number = Favorites_numbers.get(position);
Intent i = new Intent(getApplicationContext(), Show_Subjects.class);
i.putExtra("subject_number", favorite_number);
startActivity(i);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.itemFavorites:
startActivity(new Intent(Favorites.this, Favorites.class));
return true;
default:
return true;
}
}
}
بخش های مهم کدها را در ادامه شرح می دهیم.
در کدهای زیر، ابتدا بر اساس اطلاعاتی که توسط SharedPreferences ذخیره شده اند، مبحث هایی را که جزء لیست علاقه مندی ها می باشند را تشخیص داده و عنوان آنها و همچنین شماره آنها را در دو آرایه با نام های Favorites_strings و Favorites_numbers ذخیره می کنیم تا برای نمایش در ListView به کار روند :
Favorites_strings = new ArrayList<String>();
Favorites_numbers = new ArrayList<String>();
final SharedPreferences shared = getSharedPreferences("Prefs", MODE_PRIVATE);
Subjects_total_number = global.Subjects_total_number;
for(int x = 1; x < Subjects_total_number+1; x = x+1) {
String each_subject = "subject_" + String.valueOf(x);
Boolean b = shared.getBoolean(each_subject, false);
if(b){
String this_subject = "subject_" + String.valueOf(x);
int resID = getResources().getIdentifier(this_subject, "string", getPackageName());
Favorites_strings.add(getResources().getString(resID));
String x_string = String.valueOf(x);
Favorites_numbers.add(x_string);
}
}
کدهای زیر تعیین کرده است که اگر کاربر بر روی یک مبحث اشاره کرد، به Activity مخصوص نمایش محتوای مبحث ها منتقل بشود (Activity با نام Show_Subjects) و محتوای مبحث را ببیند :
@Override
public void onItemClick(AdapterView<?> parent, final View view,
int position, long id) {
String favorite_number = Favorites_numbers.get(position);
Intent i = new Intent(getApplicationContext(), Show_Subjects.class);
i.putExtra("subject_number", favorite_number);
startActivity(i);
}
});
دقت شود که شماره مبحث را با نام subject_number ، به Show_Subjects فرستاده ایم زیرا Show_Subjects شماره مبحث را دریافت کرده و سپس محتوای آن را نمایش می دهد.
فایل های پروژه اندروید را می توانید از لینک های زیر دریافت کنید :


سلام
خسته نباشید میگم بهتون سایتتون عالیه
واقعا دنبال این آموزش بودم
ولی من با یه قسمتش مشکل دارم


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


دوباره سلام
نمیدونم چرا پیامم کامل نیومد.. معذرت میخوام..
با اجرا شدنش مشکلی ندارم..
منظورم از مشکل اینه که..اگه بخوام بجز عنوان و خودِ متن یه عکس هم اضافه کنم چیکار باید کنم..؟
یه خواهش دیگه هم داشتم...معذرت میخوام..
چیجوری میشه امکان جستجو رو اضافه کرد؟
هر کاری کردم نتونستم به برنامه قابلیت جستجو رو اضافه کنم..
اگه راهنماییم کنین یه دنیا ممنون میشم ازتون
به جرأت میتونم بگم بهترین سایت آموزشی هستین
واقعا ممنون


سلام من اگر بخواهم لیست علاقه مندی ها رو از وب سرویس بگیرم باید کجای این قسمت رو تغییر بدم یعنی یه لیست دارم که از وب سرویس دیافت میکنم و محتوای هرکدوم هم از وب سرویس دیافت میکنم برای اینکه به صورت یک لیست اون ها رو هم ذخیره کنم باید چه کار کرد یا کجای این کدهای شمارو تغییر داد ممنون


سلام.
ما اطلاعات مربوط به لیست علاقه مندی را با استفاده از SharedPreferences ذخیره کرده ایم، چون شما می خواهید آن را با web service طراحی کنید، باید تمامی کدهای مربوط به ذخیره، تغییر و دریافت توسط SharedPreferences را به web service تغییر بدهید.
در مورد استفاده از web service ، دسته کلید زیر را ببینید :
به عنوان مثال، در فایل Favorites.java که برای نمایش لیست علاقه مندی ها است، کد زیر را داریم که دو آرایه با نام های Favorites_strings و Favorites_numbers را برایمان می سازد تا در ListView نمایش داده شوند :
شما باید این دو آرایه را بر اساس دریافت اطلاعات لیست علاقه مندی از web service بنویسید.
همچنین مراحل دیگر مثل ذخیره لیست علاقه مندی (با ارسال به سرور اینترنتی) و تغییرات آنها را نیز باید در Activity های دیگر تغییر بدهید.
توصیه می شود ابتدا طراحی پایگاه داده در سمت سرور (برای ذخیره اطلاعات لیست علاقه مندی کاربران) و همچنین کار با web service و تبادل اطلاعات بین آن و برنامه اندروید را تمرین کنید و سپس این سورس کد را مطابق میل خود تغییر دهید.


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


سلام.
البته توصیه بنده این است که از ساخت Activity های جداگانه پرهیز شود، مگر در مواردی که واقعا نیاز داشته باشید.
در مورد تغییرات مورد نظر شما، برای اینکه تغییرات به کمترین حد کدنویسی نیاز داشته باشد، شما همین ساختار که یک شماره به اکتیویتی Show_Subjects ارسال می کند را نگه دارید و تنها در اکتیویتی Show_Subjects ، کدها را به این صورت تغییر دهید که بر اساس شماره دریافتی، کاربر به یک Activity دلخواه هدایت شود.
یعنی مثلا لیستی از نام Activity ها و شماره متناظر با آنها خواهید داشت و بعد بر اساس شماره دریافت شده، به Activity متناظر با آن شماره خواهیم رفت.
سرعت اجرای کدها به حدی است که کاربر متوجه نمی شود که اکتیویتی Show_Subjects در این میان اجرا می گردد (البته به شرطی که مواردی مثل تاخیر یا انیمیشن یا ... در اجرای Show_Subjects نداشته باشیم).


سلام
ممنون از آموزش های فوق العاده تون
یه سوال داشتم..اگه بخوایم تو همین پروژه با کلیک روی هر آیتم لیست ویو ، برنامه یه فایل متنی خاص رو از پوشه ی assets بخونه و توی یک تکست ویو نمایش بده ، باید کدارو چطوری تغییر بدیم؟لطفا راهنمایی کنید


سوال دیگه ای هم داشتم اینه که اگر بخوایم با دو دکمه ی (Button) مختلف به همون کلاس MainActivity ارجاع بدیم(با روش Intent) ،به شرط این که آیتم های لیست ویو هر بار با سلیقه ی خودمون چینش بشن(یعنی ترتیب آیتم ها تکراری نباشه)،چطوری میشه این کارو انجام داد؟
لطفا این یکی رو حتما جواب بدید خیلی ضروریه....پیشاپیش ممنونم


سلام ممنون از سایت خیلی خوبتون عالی هستین
من یه سوال دارم ممنون میشم جواب بدید .
اگه بخوام به جای لیست ویو که در main activity وجود داره از button استفاده کنم و بعد از لمس باتن مستقیم به اکتیویتی مورد نظر هدایت بشم باید کدوم قسمت کدها رو تغییر بدم؟
بازم ممنونم ازتون چون من برنامه نویسی رو از سایت شمایاد گرفتم لطفا به سوالم جواب بدید


سلام خسته نباشید.
تمام کارهایی رو که در آموزش گفته بودید انجام دادم اما اکشن بار حذف شده(AppCompatActivity) در آموزش به (ListActivity) تبدیل شده.
الان نمیدونم چیکار کنم ممنون میشم راهنمایی کنید(جان من)


ممنونم
اموزشتون عالی بود
یا علی


سلام
ممنون از آموزش بسیار مفید و زیباتون.
فقط یه سوال، من یه مشکلی دارم):
اپ من شامل 15 فصل هستش که هر فصلش شامل 30 تا 40 تا متن (نکته) هستش.
وقتی که میزان گلوبال رو تغییر میدم فقط سر فصلها رو میتونم بنویسم.... اون نکته رو چجوری بنویسم


سلامی دوباره
دوست عزیز آقای admin یه راهنمایی بفرما....لطفاً
اگه بجای string فایل عکس همون imageview را داشته باشیم. اون وقت لیست علاقهمندی رو چطوری درست میکنیم.
لطف کنید جواب بدید.
سپاس


وقت بخیر
میشه بگید کد رو چجوری باید تغییر بدم که وقتی روی یه آیتم کلیک شد اکتیویتی مربوط به اون اجرا شه(من برای هر موضوع یک اکتیویتی جدا درنظر گرفتم) و نیازی به ارسال آیدی نباشه.


سلام روزتون بخیر...
ببخشید برای اینکه یک textview فقط بره تو لیست علاقه مندی ها، باید چی بنویسیم؟
من یه اپ نوشتم ک ی لایه داره ک توش 10تا etxtview وجود داره، برا هرکدوم یه toggleButton جداگانه قرار دادم.. اما نمیدونم چی بنویسم که هر textview که کاربر انتخاب کرد بره تو لیست علاقه مندی ها... ممنون میشم راهنماییم کنین