آموزش خواندن Rss در برنامه نویسی اندروید
سلام دوستان در این سری از آموزش های برنامه نویسی اندروید به آموزش خواندن Rss در برنامه نویسی اندروید می پردازیم این آموزش به در خواست یکی از کاربران ایجاد شده است با ما همراه باشید. باید ابتدا اشاره کنیم ممکن است rss بعضی از سایت ها سفارشی شده باشید و برنامه نتواند آن ها را بخواند ولی به طور معمول rss بیشتر سایت ها شبیه هم هستند.
قبل از هرچیز وارد فایل Build.gradle شده و کتاب خانه های زیر را اضافه کنید.(در بخش dependencies)
1 2 3 | compile 'com.android.support:appcompat-v7:25.0.1' compile 'com.android.support:recyclerview-v7:25.0.1' compile 'com.android.support:design:25.0.1' |
سپس پروژه رو Sync کنید (علت خطاهای گریدل را برای شما بررسی کردیم کافی است در سایت سرچ کنید )
بخش activity_main.xml ما همانند زیر می شود.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.sample.foo.simplerssreader.MainActivity"> <Button android:id="@+id/fetchFeedButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:text="Fetch" /> <android.support.design.widget.TextInputLayout android:id="@+id/textInputLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginEnd="@dimen/activity_horizontal_margin" android:layout_toStartOf="@id/fetchFeedButton" android:hint="Rss feed source"> <EditText android:id="@+id/rssFeedEditText" android:layout_width="match_parent" android:layout_height="wrap_content" /> </android.support.design.widget.TextInputLayout> <TextView android:id="@+id/feedTitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/textInputLayout" android:text="Feed Title: " /> <TextView android:id="@+id/feedDescription" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/feedTitle" android:text="Feed Description: " /> <TextView android:id="@+id/feedLink" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/feedDescription" android:text="Feed Link: " /> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefreshLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/feedLink" android:layout_marginTop="@dimen/activity_vertical_margin"> <android.support.v7.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" /> </android.support.v4.widget.SwipeRefreshLayout> </RelativeLayout> |
و بخش layout ما شامل یک دکمه سه تا TextView یک input یا همان EditText و یک SwipeRefreshLayout و یک Recycler view (دوست عزیزی که سوال پرسیده بود گفتن در Recyclerview قرار بدهیم به همین علت از آن هم استفاده کردیم.) SwipeRefreshLayout به کاربر اجازه می دهد تا زمانی که از بالا به پایین بروی اکتیویتی کشید یک progress bar قشنگ به نمایش در می آید و صفحه را تازه سازی (refresh) می کند به طور مثال برای دریافت دیتا صفحه refresh می شود.
قبلتر ما recyclerview را توضیح دادیم. حالا باید برای recycler view ایتم های آن را درست کنیم یعنی مقدارهایی که می خواهد نمایش داده شود.
پس مثل زیر عمل می کنیم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/titleText" android:layout_width="match_parent" android:layout_height="wrap_content" android:textStyle="bold" /> <TextView android:id="@+id/descriptionText" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/linkText" android:layout_width="match_parent" android:layout_height="wrap_content" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="@color/colorAccent" /> </LinearLayout> |
کد بالا هر ایتم از Recycler view را به وجود می آورد یعنی کل کد بالا شبیه به یک لیست در یک ایتم قرار می گیرد.
برای اینکه مقدارها را در هرکدوم از آنها ست بشه باید یک کلاسی درست کنیم که title و description و link را در هر یکی از آیتم های Recycler view قرار دهد.
1 2 3 4 5 6 7 8 9 10 | public class RssFeedModel { public String title; public String link; public String description; public RssFeedModel(String title, String link, String description) { this.title = title; this.link = link; this.description = description; } } |
حالا برای اینکه مقدار ها در هر item ست بشن (قرار داده شوند) باید برای کلاس بالا یک آداپتور درست کنیم پس مثل زیر عمل می کنیم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import java.util.List; /** * Created by Jeferson on 27/11/2017. */ public class RssFeedListAdapter extends RecyclerView.Adapter<RssFeedListAdapter.FeedModelViewHolder> { private List<RssFeedModel> mRssFeedModels; public static class FeedModelViewHolder extends RecyclerView.ViewHolder { private View rssFeedView; public FeedModelViewHolder(View v) { super(v); rssFeedView = v; } } public RssFeedListAdapter(List<RssFeedModel> rssFeedModels) { mRssFeedModels = rssFeedModels; } @Override public FeedModelViewHolder onCreateViewHolder(ViewGroup parent, int type) { View v = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_rss_feed, parent, false); FeedModelViewHolder holder = new FeedModelViewHolder(v); return holder; } @Override public void onBindViewHolder(FeedModelViewHolder holder, int position) { final RssFeedModel rssFeedModel = mRssFeedModels.get(position); ((TextView)holder.rssFeedView.findViewById(R.id.titleText)).setText(rssFeedModel.title); ((TextView)holder.rssFeedView.findViewById(R.id.descriptionText)).setText(rssFeedModel.description); ((TextView)holder.rssFeedView.findViewById(R.id.linkText)).setText(rssFeedModel.link); } @Override public int getItemCount() { return mRssFeedModels.size(); } } |
و بعد از آن کد های مربوط به MainActivty.java را قرار می دهیم.(در ادامه آنها را توضیح خواهیم داد)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | import android.os.AsyncTask; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.util.Log; import android.util.Xml; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private RecyclerView mRecyclerView; private EditText mEditText; private Button mFetchFeedButton; private SwipeRefreshLayout mSwipeLayout; private TextView mFeedTitleTextView; private TextView mFeedLinkTextView; private TextView mFeedDescriptionTextView; private List<RssFeedModel> mFeedModelList; private String mFeedTitle; private String mFeedLink; private String mFeedDescription; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView); mEditText = (EditText) findViewById(R.id.rssFeedEditText); mFetchFeedButton = (Button) findViewById(R.id.fetchFeedButton); mSwipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout); mFeedTitleTextView = (TextView) findViewById(R.id.feedTitle); mFeedDescriptionTextView = (TextView) findViewById(R.id.feedDescription); mFeedLinkTextView = (TextView) findViewById(R.id.feedLink); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mFetchFeedButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { new FetchFeedTask().execute((Void) null); } }); mSwipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { new FetchFeedTask().execute((Void) null); } }); } public List<RssFeedModel> parseFeed(InputStream inputStream) throws XmlPullParserException, IOException { String title = null; String link = null; String description = null; boolean isItem = false; List<RssFeedModel> items = new ArrayList<>(); try { XmlPullParser xmlPullParser = Xml.newPullParser(); xmlPullParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); xmlPullParser.setInput(inputStream, null); xmlPullParser.nextTag(); while (xmlPullParser.next() != XmlPullParser.END_DOCUMENT) { int eventType = xmlPullParser.getEventType(); String name = xmlPullParser.getName(); if(name == null) continue; if(eventType == XmlPullParser.END_TAG) { if(name.equalsIgnoreCase("item")) { isItem = false; } continue; } if (eventType == XmlPullParser.START_TAG) { if(name.equalsIgnoreCase("item")) { isItem = true; continue; } } Log.d("MainActivity", "Parsing name ==> " + name); String result = ""; if (xmlPullParser.next() == XmlPullParser.TEXT) { result = xmlPullParser.getText(); xmlPullParser.nextTag(); } if (name.equalsIgnoreCase("title")) { title = result; } else if (name.equalsIgnoreCase("link")) { link = result; } else if (name.equalsIgnoreCase("description")) { description = result; } if (title != null && link != null && description != null) { if(isItem) { RssFeedModel item = new RssFeedModel(title, link, description); items.add(item); } else { mFeedTitle = title; mFeedLink = link; mFeedDescription = description; } title = null; link = null; description = null; isItem = false; } } return items; } finally { inputStream.close(); } } private class FetchFeedTask extends AsyncTask<Void, Void, Boolean> { private String urlLink; @Override protected void onPreExecute() { mSwipeLayout.setRefreshing(true); mFeedTitle = null; mFeedLink = null; mFeedDescription = null; mFeedTitleTextView.setText("Feed Title: " + mFeedTitle); mFeedDescriptionTextView.setText("Feed Description: " + mFeedDescription); mFeedLinkTextView.setText("Feed Link: " + mFeedLink); urlLink = mEditText.getText().toString(); } @Override protected Boolean doInBackground(Void... voids) { if (TextUtils.isEmpty(urlLink)) return false; try { if(!urlLink.startsWith("http://") && !urlLink.startsWith("https://")) urlLink = "http://" + urlLink; URL url = new URL(urlLink); InputStream inputStream = url.openConnection().getInputStream(); mFeedModelList = parseFeed(inputStream); return true; } catch (IOException e) { Log.e(TAG, "Error", e); } catch (XmlPullParserException e) { Log.e(TAG, "Error", e); } return false; } @Override protected void onPostExecute(Boolean success) { mSwipeLayout.setRefreshing(false); if (success) { mFeedTitleTextView.setText("Feed Title: " + mFeedTitle); mFeedDescriptionTextView.setText("Feed Description: " + mFeedDescription); mFeedLinkTextView.setText("Feed Link: " + mFeedLink); // Fill RecyclerView mRecyclerView.setAdapter(new RssFeedListAdapter(mFeedModelList)); } else { Toast.makeText(MainActivity.this, "Enter a valid Rss feed url", Toast.LENGTH_LONG).show(); } } } } |
توضیح کد بالا از حوصله این بخش خارج است اما ما بخش هایی رو که مهم است به طور سریع به آنها اشاره می کنیم ما ابتدا یک کلاس ایجاد کردیم تا rss را parse کند یعنی اطلاعات رو به صورت درست برای نمایش دهد و کلی از بخش ها بررسی می شود به طور مثال اگر کاربر سایت رو بدون http یا https وارد کند ما خودمان به آن http اضافه می کنیم دوست عزیزمون اشاره کرده بود فقط یک مقدار دریافت شود به همین علت در ابتدا برای سه تا TextView داریم که اطلاعات اولی در آن قرار گرفته می شود سپس بقیه آن در recycler view قرار می گیرد برای sync بودن برنامه هم ما از Async task استفاده کردیم. این آموزش به درخواست یکی از دوستان ایجاد شده است و استفاده از این آموزش نیاز به پیش نیازی هایی دارد.
و در اخر شما باید دسترسی استفاده از اینترنت را در AndroidManifest.xml قرار دهید.
1 | <uses-permission android:name="android.permission.INTERNET" /> |
این آموزش هم به پایان رسید.
موفق باشید.
عالییییی
خواهش می کنم
موفق باشید
سلام
تو ریسایکلر که نشون میده موضوع title با description همخونی نداره یه چک بفرمایید