项目解析一:仿csdn 代码解析(TabLayout,Viewpager,FragmentPagerAdapter)
2017-09-09 16:00
609 查看
今天做完录音机需求后观察几个项目后觉得解析代码知道如何使用是很重要的,现在从一个仿csdn的apk入手。公司的ubuntu电脑的外网被禁止了,只能访问csdn和博客园,晚上回去截图。
1.从MainActivity开始解析:
贴上代码
public class MainActivity extends BaseActivity {
// mViewpager.setOffscreenPageLimit(4);
initData();
}
}
关键xml如下:
显然最为关键的就是后面两个控件:TabLayout,ViewPager,首先看到TabLayout,这个控件和viewpagerIndicator类似,都是和viewpager组合提供来回切换来切换不同的viewpager,使用前需要在应用的Build.gradle中添加support.design支持库(注意:必须和v7包的版本相同),这里可以看下app/builb.gradle中的
android {
compileSdkVersion 23
buildToolsVersion “23.0.2”
}
dependencies {
compile fileTree(dir: ‘libs’, include: [‘*.jar’])
testCompile ‘junit:junit:4.12’
compile ‘com.android.support:design:23.1.1’
compile ‘com.android.support:support-v4:23.1.1’
compile ‘com.android.support:cardview-v7:23.1.1’
compile files(‘libs/picasso-2.5.2.jar’)
}
看下在这个项目中的使用:
setupWithViewPager():将viewpager和TabLayout绑定
看下这个方法的源码:
/**
* The one-stop shop for setting up this {@link TabLayout} with a {@link ViewPager}.
*
*
This method will:
*
* Add a {@link ViewPager.OnPageChangeListener} that will forward events to
* this TabLayout.
* Populate the TabLayout’s tabs from the ViewPager’s {@link PagerAdapter}.
* Set our {@link TabLayout.OnTabSelectedListener} which will forward
* selected events to the ViewPager
*
*
*
* @see #setTabsFromPagerAdapter(PagerAdapter)
* @see TabLayoutOnPageChangeListener
* @see ViewPagerOnTabSelectedListener
*/
public void setupWithViewPager(@NonNull ViewPager viewPager) {
final PagerAdapter adapter = viewPager.getAdapter();
if (adapter == null) {
throw new IllegalArgumentException(“ViewPager does not have a PagerAdapter set”);
}
//初始化时候将Tablayout设置为弱引用的类型
public TabLayoutOnPageChangeListener(TabLayout tabLayout) {
mTabLayoutRef = new WeakReference<>(tabLayout);
}
//监听Tab页面滑动状态的改变,将现在的滑动状态赋给之前状态并设置当前状态为当前的state
@Override
public void onPageScrollStateChanged(int state) {
mPreviousScrollState = mScrollState;
mScrollState = state;
}
//页面滑动后,进行一系列判断,满足条件后将setScrollPosition(下面解析)
//当页面被选定的时候回调的方法,如果该Tablayout不为空并且该position也不为空就给tablayout设置当前的pager位置,并且将当前状态设置为Viewpager.SCROLL_STATE_IDLE
//设置滑动的位置代码:
而这个动画又是什么?看下:
回到MainActivity,此时执行initData()。上面代码有注释解释,有时间我想研究下FragmentPageradapter以及他的父类PagerAdapter.现在开始研究MainFragment.
//newInstance和new的区别
public static MainFragment newInstance(int pos) {
Bundle args = new Bundle();
args.putInt(NEWS_TYPE, pos);
MainFragment fragment = new MainFragment();
fragment.setArguments(args);
return fragment;
}
/**
* 初始化父布局,recycleview列表view,和依附在主activity上的线性布局
*RecycleView:
*你想要控制其显示的方式,请通过布局管理器LayoutManager
*你想要控制Item间的间隔(可绘制),请通过ItemDecoration
*你想要控制Item增删的动画,请通过ItemAnimator
*你想要控制点击、长按事件,请自己写(擦,这点尼玛。)
*/
private void initView() {
mSwipeRefresh = (SwipeRefreshLayout) getView().findViewById(R.id.id_swiperefresh);
mSwipeRefresh.setColorSchemeResources(R.color.colorPrimary, R.color.colorPrimary,
R.color.colorPrimary, R.color.colorPrimary);
mRecycleView = (RecyclerView) getView().findViewById(R.id.id_recycleview);
mManager = new LinearLayoutManager(getActivity());
mRecycleView.setLayoutManager(mManager);
mRecycleView.setItemAnimator(new DefaultItemAnimator());//设置Item增加、移除动画
}
}
流程分析:在MainActivity中首先通过一个单例模式得到MainFragment的对象,然后通过new MainFragment得到对象,进入fragment的生命周期,在onCreateView中加载布局fragment_main,布局关键如下
之后进入onActivityCreated,这里获取上下文,初始化mNewsItemDao = new NewsItemDao(mContext);我们去NewsItemDao中看一下:
public class NewsItemDao {
进入DBHelper看下
NewsItem实体类:
**注:在往数据库中插入数据的时候,首先应该有一个ContentValues的对象所以:
ContentValues initialValues = new ContentValues();
initialValues.put(key,values);
SQLiteDataBase sdb ;
sdb.insert(database_name,null,initialValues);
插入成功就返回记录的id否则返回-1;
就可以插入一行数据**
至于NewsItemBiz:
// //获取文字的评论链接
// Element comments = doc.select(“td.comm”).select(“a”).first();
// String commentLink = “http://m.csdn.net/” + comments.attr(“href”);
// news.setCommentsLink(commentLink);
// Log.i(“clj”, “comments link =” + commentLink);
// 获得文章中的第一个detail
Element detail = doc.select(“div.wrapper”).first();
//获取title
Element title = detail.select(“h1”).first();
news.setTitle(title.text());
//infor
Element infor = detail.select(“div.infor”).first();
news.setInfor(infor.text());
Elements elements = detail.select(“.text p”);
StringBuffer buffer = new StringBuffer();
for (Element element : elements) {
element.select(“img”).attr(“width”, “100%”).attr(“style”, “”);
buffer.append(“
”);
buffer.append(element.html());
buffer.append(“
“);
Log.i(“clj”, buffer.toString());
}
news.setTexts(buffer.toString());
return news;
}
}
今天先写到这里。
1.从MainActivity开始解析:
贴上代码
public class MainActivity extends BaseActivity {
private TabLayout mTab; private ViewPager mViewpager; private FragmentPagerAdapter mAdapter; private String[] titles; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTab = (TabLayout) findViewById(R.id.id_tablayout); mViewpager = (ViewPager) findViewById(R.id.id_viewpager);
// mViewpager.setOffscreenPageLimit(4);
initData();
}
private void initData() { titles = new String[]{getResources().getString(R.string.yejie), getResources().getString(R.string.yidong) , getResources().getString(R.string.yunjisuan), getResources().getString(R.string.yanfa)}; //设置Viewpager的adapter,FragmentPagerAdapter继承自pageradapter mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) { @Override public Fragment getItem(int position) { //单例模式,进入MainFragment return MainFragment.newInstance(position); } @Override public int getCount() { return titles.length; } @Override public CharSequence getPageTitle(int position) { return titles[position % titles.length]; } }; mViewpager.setAdapter(mAdapter); //设置Tablayout和viewpager绑定 mTab.setupWithViewPager(mViewpager); }
}
关键xml如下:
<ImageButton android:id="@+id/id_imb_topbar_icon" android:layout_width="wrap_content" android:layout_height="match_parent" android:background="@null" android:src="@drawable/topbar_icon_bg" /> <TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_toRightOf="@id/id_imb_topbar_icon" android:gravity="center_vertical" android:text="@string/csdn" android:textColor="@color/white" android:textSize="@dimen/textsize_20" /> </RelativeLayout> <android.support.design.widget.TabLayout android:id="@+id/id_tablayout" style="@style/tablayoutStyle" android:layout_width="match_parent" android:layout_height="wrap_content" /> <android.support.v4.view.ViewPager android:id="@+id/id_viewpager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" />
显然最为关键的就是后面两个控件:TabLayout,ViewPager,首先看到TabLayout,这个控件和viewpagerIndicator类似,都是和viewpager组合提供来回切换来切换不同的viewpager,使用前需要在应用的Build.gradle中添加support.design支持库(注意:必须和v7包的版本相同),这里可以看下app/builb.gradle中的
android {
compileSdkVersion 23
buildToolsVersion “23.0.2”
defaultConfig { applicationId "com.vann.csdn" minSdkVersion 18 targetSdkVersion 23 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }
}
dependencies {
compile fileTree(dir: ‘libs’, include: [‘*.jar’])
testCompile ‘junit:junit:4.12’
compile ‘com.android.support:design:23.1.1’
compile ‘com.android.support:support-v4:23.1.1’
compile ‘com.android.support:cardview-v7:23.1.1’
compile files(‘libs/picasso-2.5.2.jar’)
}
看下在这个项目中的使用:
setupWithViewPager():将viewpager和TabLayout绑定
看下这个方法的源码:
/**
* The one-stop shop for setting up this {@link TabLayout} with a {@link ViewPager}.
*
*
This method will:
*
* Add a {@link ViewPager.OnPageChangeListener} that will forward events to
* this TabLayout.
* Populate the TabLayout’s tabs from the ViewPager’s {@link PagerAdapter}.
* Set our {@link TabLayout.OnTabSelectedListener} which will forward
* selected events to the ViewPager
*
*
*
* @see #setTabsFromPagerAdapter(PagerAdapter)
* @see TabLayoutOnPageChangeListener
* @see ViewPagerOnTabSelectedListener
*/
public void setupWithViewPager(@NonNull ViewPager viewPager) {
final PagerAdapter adapter = viewPager.getAdapter();
if (adapter == null) {
throw new IllegalArgumentException(“ViewPager does not have a PagerAdapter set”);
}
// First we'll add Tabs, using the adapter's page titles setTabsFromPagerAdapter(adapter); // Now we'll add our page change listener to the ViewPager viewPager.addOnPageChangeListener(new TabLayoutOnPageChangeListener(this)); // Now we'll add a tab selected listener to set ViewPager's current item setOnTabSelectedListener(new ViewPagerOnTabSelectedListener(viewPager)); // Make sure we reflect the currently set ViewPager item //如果adapter的view数目大于0 if (adapter.getCount() > 0) { //得到当前viewpager的item,如果curlitem不等于现在选择的item if (getSelectedTabPosition() != curItem) { selectTab(getTabAt(curItem)); } } } 这个方法首先是获取传递过来的viewpager的adapter,然后进行了一次为空判断,之后调用了这个方法setTabsFromPagerAdapter,可以看下: /** * Populate our tab content from the given {@link PagerAdapter}. * <p> * Any existing tabs will be removed first. Each tab will have it's text set to the value * returned from {@link PagerAdapter#getPageTitle(int)} * </p> * * @param adapter the adapter to populate from */ public void setTabsFromPagerAdapter(@NonNull PagerAdapter adapter) { removeAllTabs(); for (int i = 0, count = adapter.getCount(); i < count; i++) { addTab(newTab().setText(adapter.getPageTitle(i))); } } 这个方法首先移除所有的view,然后遍历adapter的所有view,如下: /** * Return the number of views available. */ public abstract int getCount(); 然后将这些view加到tab中,返回上面,就执行viewPager.addOnPageChangeListener(new TabLayoutOnPageChangeListener(this));为TabLayout设置页面变化的监听并将这个监听设置给viewpager,因此,我们可以看下TabLayoutOnPageChangeListener的实现: public static class TabLayoutOnPageChangeListener implements ViewPager.OnPageChangeListener { private final WeakReference<TabLayout> mTabLayoutRef; private int mPreviousScrollState; private int mScrollState;
//初始化时候将Tablayout设置为弱引用的类型
public TabLayoutOnPageChangeListener(TabLayout tabLayout) {
mTabLayoutRef = new WeakReference<>(tabLayout);
}
//监听Tab页面滑动状态的改变,将现在的滑动状态赋给之前状态并设置当前状态为当前的state
@Override
public void onPageScrollStateChanged(int state) {
mPreviousScrollState = mScrollState;
mScrollState = state;
}
//页面滑动后,进行一系列判断,满足条件后将setScrollPosition(下面解析)
@Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { final TabLayout tabLayout = mTabLayoutRef.get(); if (tab 4000 Layout != null) { // Update the scroll position, only update the text selection if we're being // dragged (or we're settling after a drag) final boolean updateText = (mScrollState == ViewPager.SCROLL_STATE_DRAGGING) || (mScrollState == ViewPager.SCROLL_STATE_SETTLING && mPreviousScrollState == ViewPager.SCROLL_STATE_DRAGGING); tabLayout.setScrollPosition(position, positionOffset, updateText); } }
//当页面被选定的时候回调的方法,如果该Tablayout不为空并且该position也不为空就给tablayout设置当前的pager位置,并且将当前状态设置为Viewpager.SCROLL_STATE_IDLE
@Override public void onPageSelected(int position) { final TabLayout tabLayout = mTabLayoutRef.get(); if (tabLayout != null && tabLayout.getSelectedTabPosition() != position) { // Select the tab, only updating the indicator if we're not being dragged/settled // (since onPageScrolled will handle that). tabLayout.selectTab(tabLayout.getTabAt(position), mScrollState == ViewPager.SCROLL_STATE_IDLE); } } }
//设置滑动的位置代码:
public void setScrollPosition(int position, float positionOffset, boolean updateSelectedText) { //不做处理直接返回 if (mIndicatorAnimator != null && mIndicatorAnimator.isRunning()) { return; } //不作处理直接返回 if (position < 0 || position >= mTabStrip.getChildCount()) { return; } // Set the indicator position and update the scroll to match mTabStrip.setIndicatorPositionFromTabPosition(position, positionOffset); scrollTo(calculateScrollXForTab(position, positionOffset), 0); // Update the 'selected state' view as we scroll if (updateSelectedText) { setSelectedTabView(Math.round(position + positionOffset)); }
而这个动画又是什么?看下:
void animateIndicatorToPosition(final int position, int duration) { final boolean isRtl = ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL; final View targetView = getChildAt(position); final int targetLeft = targetView.getLeft(); final int targetRight = targetView.getRight(); final int startLeft; final int startRight; if (Math.abs(position - mSelectedPosition) <= 1) { // If the views are adjacent, we'll animate from edge-to-edge startLeft = mIndicatorLeft; startRight = mIndicatorRight; } else { // Else, we'll just grow from the nearest edge final int offset = dpToPx(MOTION_NON_ADJACENT_OFFSET); if (position < mSelectedPosition) { // We're going end-to-start if (isRtl) { startLeft = startRight = targetLeft - offset; } else { startLeft = startRight = targetRight + offset; } } else { // We're going start-to-end if (isRtl) { startLeft = startRight = targetRight + offset; } else { startLeft = startRight = targetLeft - offset; } } } //在此处初始化mIndicatorAnimator ValueAnimatorCompat animator = mIndicatorAnimator = ViewUtils.createAnimator(); animator.setInterpolator(AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR); animator.setDuration(duration); animator.setFloatValues(0, 1); animator.setUpdateListener(new ValueAnimatorCompat.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimatorCompat animator) { final float fraction = animator.getAnimatedFraction(); setIndicatorPosition( AnimationUtils.lerp(startLeft, targetLeft, fraction), AnimationUtils.lerp(startRight, targetRight, fraction)); } }); animator.setListener(new ValueAnimatorCompat.AnimatorListenerAdapter() { @Override public void onAnimationEnd(ValueAnimatorCompat animator) { mSelectedPosition = position; mSelectionOffset = 0f; } @Override public void onAnimationCancel(ValueAnimatorCompat animator) { mSelectedPosition = position; mSelectionOffset = 0f; } }); animator.start(); mCurrentAnimator = animator; } }
回到MainActivity,此时执行initData()。上面代码有注释解释,有时间我想研究下FragmentPageradapter以及他的父类PagerAdapter.现在开始研究MainFragment.
public class MainFragment extends Fragment { public static final int LOAD_REFRESH = 0x01; public static final int LOAD_MORE = 0x02; public static final String TIP_ERROR_NO_NETWORK = "没有网络连接"; public static final String TIP_ERROR_NO_SERVICE = "服务器错误"; public static final String NEWS_TYPE = "NEWS_TYPE"; private Context mContext; //默认新闻类型 private int newsType = Constant.NEWS_TYPE_YANFA; //当前页面 private int curPage = 1; //业务处理类 private NewsItemBiz mNewsItemBiz; private SwipeRefreshLayout mSwipeRefresh; private RecyclerView mRecycleView; private LinearLayoutManager mManager; private NewsAdapter mAdapter; //是否从服务器下载数据 private boolean isLoadFromService; //与数据库交互 private NewsItemDao mNewsItemDao;
//newInstance和new的区别
public static MainFragment newInstance(int pos) {
Bundle args = new Bundle();
args.putInt(NEWS_TYPE, pos);
MainFragment fragment = new MainFragment();
fragment.setArguments(args);
return fragment;
}
@Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_main, container, false); } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mContext = getActivity(); mNewsItemDao = new NewsItemDao(mContext);//对新闻的操作,包含创建数据库 mNewsItemBiz = new NewsItemBiz(); initView(); mSwipeRefresh.post(new Runnable() { @Override public void run() { // Runnable为了能够第一次进入页面的时候显示加载进度条 mSwipeRefresh.setRefreshing(true); } }); initData(); initEvent(); new DownLoadTask().execute(LOAD_REFRESH); }
/**
* 初始化父布局,recycleview列表view,和依附在主activity上的线性布局
*RecycleView:
*你想要控制其显示的方式,请通过布局管理器LayoutManager
*你想要控制Item间的间隔(可绘制),请通过ItemDecoration
*你想要控制Item增删的动画,请通过ItemAnimator
*你想要控制点击、长按事件,请自己写(擦,这点尼玛。)
*/
private void initView() {
mSwipeRefresh = (SwipeRefreshLayout) getView().findViewById(R.id.id_swiperefresh);
mSwipeRefresh.setColorSchemeResources(R.color.colorPrimary, R.color.colorPrimary,
R.color.colorPrimary, R.color.colorPrimary);
mRecycleView = (RecyclerView) getView().findViewById(R.id.id_recycleview);
mManager = new LinearLayoutManager(getActivity());
mRecycleView.setLayoutManager(mManager);
mRecycleView.setItemAnimator(new DefaultItemAnimator());//设置Item增加、移除动画
}
private void initEvent() { mSwipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { new DownLoadTask().execute(LOAD_REFRESH); } }); mRecycleView.setOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); int last = mManager.findLastVisibleItemPosition(); if (newState == RecyclerView.SCROLL_STATE_IDLE && last + 1 == mAdapter.getItemCount() && mAdapter.getItemCount() > 1) { new DownLoadTask().execute(LOAD_MORE); } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); } }); mAdapter.setOnItemClickLitener(new NewsAdapter.OnItemClickLitener() { @Override public void onItemClick(View view, int position) { NewsItem item = mAdapter.getDatas().get(position); NewsInfoActivity.actionStart(mContext, item.getLink()); } @Override public void onItemLongClick(View view, int position) { } }); } private void initData() { Bundle bundle = getArguments(); newsType = bundle.getInt(NEWS_TYPE, Constant.NEWS_TYPE_YEJIE); mAdapter = new NewsAdapter(mContext); mRecycleView.setAdapter(mAdapter); } class DownLoadTask extends AsyncTask<Integer, Void, String> { @Override protected String doInBackground(Integer... params) { switch (params[0]) { case LOAD_REFRESH: return refreshData(); case LOAD_MORE: return loadMoreData(); } return null; } @Override protected void onPostExecute(String result) { if (null == result) { mAdapter.setIsLoading(false); mAdapter.setmError(null); } else { mAdapter.setmError(result); mAdapter.setIsLoading(true); Snackbar.make(mSwipeRefresh, result, Snackbar.LENGTH_LONG).show(); } mSwipeRefresh.setRefreshing(false); mAdapter.notifyDataSetChanged(); } } private String refreshData() { if (NetUtil.isOnline(mContext)) {//判断是否有网 curPage = 1; try { List<NewsItem> items = mNewsItemBiz.getNewsItems(newsType, curPage); if (!items.isEmpty()) { mAdapter.setDatas(items); mNewsItemDao.refreshData(newsType, items); } isLoadFromService = true; } catch (CommonException e) { e.printStackTrace(); isLoadFromService = false; return TIP_ERROR_NO_SERVICE; } } else { List<NewsItem> items = mNewsItemDao.getNewsItems(curPage, newsType); if (!items.isEmpty()) { mAdapter.setDatas(items); isLoadFromService = false; } return TIP_ERROR_NO_NETWORK; } return null; } private String loadMoreData() { mAdapter.setIsLoading(true); if (isLoadFromService) { curPage++; try { List<NewsItem> items = mNewsItemBiz.getNewsItems(newsType, curPage); mAdapter.addDatas(items); mNewsItemDao.addNewsItems(items); } catch (CommonException e) { e.printStackTrace(); return e.getMessage(); } } else { curPage++; List<NewsItem> items = mNewsItemDao.getNewsItems(curPage, newsType); mAdapter.addDatas(items); return TIP_ERROR_NO_NETWORK; } return null; }
}
流程分析:在MainActivity中首先通过一个单例模式得到MainFragment的对象,然后通过new MainFragment得到对象,进入fragment的生命周期,在onCreateView中加载布局fragment_main,布局关键如下
<android.support.v4.widget.SwipeRefreshLayout android:id="@+id/id_swiperefresh" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/id_recycleview" android:layout_width="match_parent" android:layout_height="match_parent" /> </android.support.v4.widget.SwipeRefreshLayout>
之后进入onActivityCreated,这里获取上下文,初始化mNewsItemDao = new NewsItemDao(mContext);我们去NewsItemDao中看一下:
public class NewsItemDao {
public static final int PERPAGE_ITEM_COUNT = 6; private DBHelper mHelper; //列 public static final String[] COLUMNS = {"title", "link", "imgLink", "content", "date", "newsType"}; public NewsItemDao(Context context) { mHelper = new DBHelper(context);//创建名为csdn的数据库 } /** * 更新表数据 * * @param newsType * @param items */ public void refreshData(int newsType, List<NewsItem> items) { SQLiteDatabase db = mHelper.getWritableDatabase();//读写数据库 try { db.beginTransaction();//开启事务 String sql = "delete from " + mHelper.TABLE_CSDN + " where newsType=?"; db.execSQL(sql, new Object[]{newsType}); for (NewsItem item : items) { if (null != item) { ContentValues values = new ContentValues(); values.put(COLUMNS[0], item.getTitle()); values.put(COLUMNS[1], item.getLink()); values.put(COLUMNS[2], item.getImgLink()); values.put(COLUMNS[3], item.getContent()); values.put(COLUMNS[4], item.getDate()); values.put(COLUMNS[5], item.getNewsType()); db.insert(mHelper.TABLE_CSDN, null, values); } } db.setTransactionSuccessful(); } catch (Exception e) { e.printStackTrace(); } finally { db.endTransaction(); db.close(); } } /** * 添加新闻列表 * * @param items */ public void addNewsItems(List<NewsItem> items) { if (null == items || items.isEmpty()) { return; } SQLiteDatabase db = mHelper.getWritableDatabase(); try { db.beginTransaction(); for (NewsItem item : items) { if (null == item) { continue; } ContentValues values = new ContentValues(); values.put(COLUMNS[0], item.getTitle()); values.put(COLUMNS[1], item.getLink()); values.put(COLUMNS[2], item.getImgLink()); values.put(COLUMNS[3], item.getContent()); values.put(COLUMNS[4], item.getDate()); values.put(COLUMNS[5], item.getNewsType()); db.insert(mHelper.TABLE_CSDN, null, values); } db.setTransactionSuccessful(); } catch (Exception e) { e.printStackTrace(); } finally { db.endTransaction(); db.close(); } } public List<NewsItem> getNewsItems(int page, int newsType) { List<NewsItem> items = new ArrayList<>(); SQLiteDatabase db = mHelper.getWritableDatabase(); int offset = (page - 1) * PERPAGE_ITEM_COUNT; String sql = "select title,link,imgLink,content,date,newsType "+" from " + mHelper.TABLE_CSDN + " where newsType=? limit ?,?"; try { db.beginTransaction(); Cursor cursor = db.rawQuery(sql, new String[]{newsType + "", offset + "", PERPAGE_ITEM_COUNT + ""}); cursor.moveToFirst(); for (int i = 0; i < cursor.getCount(); i++) { NewsItem item = new NewsItem(); item.setTitle(cursor.getString(0)); item.setLink(cursor.getString(1)); item.setImgLink(cursor.getString(2)); item.setContent(cursor.getString(3)); item.setDate(cursor.getString(4)); item.setNewsType(cursor.getInt(5)); items.add(item); cursor.moveToNext(); } db.setTransactionSuccessful(); } catch (Exception e) { e.printStackTrace(); } finally { c984 db.endTransaction(); db.close(); } return items; }}
进入DBHelper看下
public class DBHelper extends SQLiteOpenHelper { public static final int DB_VERSION = 1; public static final String DB_NAME = "csdn"; public static final String TABLE_CSDN = "tb_csdn"; public DBHelper(Context context) { //创建"csdn"数据库 super(context, DB_NAME, null, DB_VERSION); } //执行建立表语句 @Override public void onCreate(SQLiteDatabase db) { db.execSQL("create table if not exists " + TABLE_CSDN + "(id integer primary key autoincrement, title,text,link text," + "imgLink text,content text,date text,newsType integer);"); } //更新数据库,判断版本 @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { if (oldVersion < newVersion) { db.execSQL("drop table if exists " + TABLE_CSDN); onCreate(db); } } }
NewsItem实体类:
public class NewsItem { private int id; //标题 private String title; //链接 private String link; //图片连接 private String imgLink; //内容 private String Content; //发布时间 private String date; //类型 private int newsType; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getLink() { return link; } public void setLink(String link) { this.link = link; } public String getImgLink() { return imgLink; } public void setImgLink(String imgLink) { this.imgLink = imgLink; } public String getContent() { return Content; } public void setContent(String content) { Content = content; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public int getNewsType() { return newsType; } public void setNewsType(int newsType) { this.newsType = newsType; } @Override public String toString() { return "newsItem[id="+id+",title="+title+",link="+link+",imgLink="+imgLink +",content="+Content+",date="+date+",newsType="+newsType; } } ContentValues 和HashTable类似都是一种存储的机制 但是两者最大的区别就在于,contenvalues只能存储基本类型的数据,像string,int之类的,不能存储对象这种东西,而HashTable却可以存储对象。
**注:在往数据库中插入数据的时候,首先应该有一个ContentValues的对象所以:
ContentValues initialValues = new ContentValues();
initialValues.put(key,values);
SQLiteDataBase sdb ;
sdb.insert(database_name,null,initialValues);
插入成功就返回记录的id否则返回-1;
就可以插入一行数据**
至于NewsItemBiz:
public class NewsItemBiz { public List<NewsItem> getNewsItems(int newsType, int curPage) throws CommonException { List<NewsItem> newsItems = new ArrayList<>(); String url = UrlUtil.getUrl(newsType, curPage); String htmlStr = DataUtil.doGet(url); NewsItem item = null; Document doc = Jsoup.parse(htmlStr); Elements units = doc.getElementsByClass("unit"); for (int i = 0; i < units.size(); i++) { item = new NewsItem(); item.setNewsType(newsType); Element unit = units.get(i); Element h1 = unit.getElementsByTag("h1").get(0); Element ha = h1.child(0); item.setTitle(h1.text()); item.setLink(ha.attr("href")); Element h4 = unit.getElementsByTag("h4").get(0); Element ago = h4.getElementsByClass("ago").get(0); item.setDate(ago.text()); Element dl_ele = unit.getElementsByTag("dl").get(0); Element dt_ele = dl_ele.child(0); try { // 可能没有图片 Element img_ele = dt_ele.child(0); String imgLink = img_ele.child(0).attr("src"); item.setImgLink(imgLink); } catch (IndexOutOfBoundsException e) { } Element dd_ele = dl_ele.child(1); item.setContent(dd_ele.text()); newsItems.add(item); } return newsItems; } public NewsDetail getNewsDetial(String html) { NewsDetail news = new NewsDetail(); Document doc = Jsoup.parse(html);
// //获取文字的评论链接
// Element comments = doc.select(“td.comm”).select(“a”).first();
// String commentLink = “http://m.csdn.net/” + comments.attr(“href”);
// news.setCommentsLink(commentLink);
// Log.i(“clj”, “comments link =” + commentLink);
// 获得文章中的第一个detail
Element detail = doc.select(“div.wrapper”).first();
//获取title
Element title = detail.select(“h1”).first();
news.setTitle(title.text());
//infor
Element infor = detail.select(“div.infor”).first();
news.setInfor(infor.text());
Elements elements = detail.select(“.text p”);
StringBuffer buffer = new StringBuffer();
for (Element element : elements) {
element.select(“img”).attr(“width”, “100%”).attr(“style”, “”);
buffer.append(“
”);
buffer.append(element.html());
buffer.append(“
“);
Log.i(“clj”, buffer.toString());
}
news.setTexts(buffer.toString());
return news;
}
}
今天先写到这里。
相关文章推荐
- TabLayout+Fragment+ViewPager+FragmentStatePagerAdapter实现Tab标签
- TabLayout、ViewPager、FragmentPagerAdapter实现新闻导航栏
- TabLayout与ViewPager和Fragment、FragmentPagerAdapter的合用
- ViewPager+TabLayout+Fragment懒加载机制完全解析
- TabLayout与ViewPager和Fragment、FragmentPagerAdapter的合用
- TabLayout+Fragment+ViewPager+FragmentStatePagerAdapter实现Tab标签
- TabLayout与ViewPager和Fragment、FragmentPagerAdapter的配合使用
- 笔记(二)TabLayout + ViewPager + FragmentPagerAdapter 组合用法
- TabLayout+ViewPager+Fragment(代码)
- ViewPager+TabLayout+Fragment懒加载机制完全解析
- TabLayout与ViewPager和Fragment、FragmentPagerAdapter的合用
- 使用TabLayout、ViewPager和Fragment实现顶部菜单可滑动切换
- TabLayout 和 ViewPager 组合显示Fragment
- FragmentPagerAdapter+ViewPager实现Tab切换效果
- Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager
- TabLayout两种添加tab方式,结合ViewPager+Fragment实现常见界面视图
- Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager
- TabLayout让Fragment在ViewPager中的滑动切换更优雅
- Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager
- Android项目Tab类型主界面大总结 Fragment+TabPageIndicator+ViewPager