首页 > 代码库 > android 练习之路 (六)

android 练习之路 (六)

项目的github地址:https://github.com/Qunter/SearchAndCall

------------------------------------------------------------------------

今天做详情页以及列表的刷新,今天做完之后算暂时把最初版本的学校资讯给做完了

惯例,先上效果图

技术分享

PS:那个??的图片是因为我们学校有个校领导叫X??X的名字,结果维护官网的同学可能是图简单就直接切了个图丢进去,命名又没命名好,我想了一两个小时都没想出来怎么筛选跳过他,没办法了,只能下次跟上面提意见看看能不能改改了

就从简单的说起吧,首先是列表刷新,这个刷新之前在新建页面的时候已经把SwipeRefreshLayout丢进去了,所以只要在Activity里初始化,写好逻辑代码就行了

那么需要增加的是一个标志,代表是否是第一次加载数据,因为每次加载数据的方法都写在getJsoupContent()里了,我们没必要再写一个和这个差不多的方法,直接加个标志进去,判断一下,最后得出结果然后返回一个不一样的msg就行了

private boolean ifFirstInitData=http://www.mamicode.com/true;

那么还要多加个msg

private final int REFRESH=0x02;

以及对应的handler判断和adapter的刷新以及refresh标志的取消(不取消标志难道一直让他在那打转?笑)

case REFRESH:
                    adapter.notifyDataSetChanged();
                    Toast.makeText(getContext(),"刷新成功",Toast.LENGTH_SHORT).show();
                    schoolSwipeRefreshLayout.setRefreshing(false);
                    break;

然后在联网获取数据的方法getJsoupContent()加个if来判断标志位,决定到底发送哪条msg

if (ifFirstInitData){
            ifFirstInitData=false;
            handler.sendEmptyMessage(INITRECYLERVIEW);
        }else{
            handler.sendEmptyMessage(REFRESH);
        }

最后是全部代码

SchoolInfoFragmActivity.java

public class SchoolInfoFragmActivity extends Fragment {
    private List<SchoolInfo> schoolInfoList;
    private final int GETJSOUPCONTENT=0x00,INITRECYLERVIEW=0x01,REFRESH=0x02;
    private SwipeRefreshLayout schoolSwipeRefreshLayout;
    private SchoolInfoListAdapter adapter;
    private RecyclerView schoolRecyclerView;
    private boolean ifFirstInitData=http://www.mamicode.com/true;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case GETJSOUPCONTENT:
                    new Thread(runnable).start();
                    break;
                case INITRECYLERVIEW:
                    adapter = new SchoolInfoListAdapter(getContext(),schoolInfoList,schoolRecyclerView);
                    adapter.setOnItemClickListener(new SchoolInfoListAdapter.OnItemClickListener() {
                        @Override
                        public void onItemClick(View view, int position) {
                            //Log.e("onitemclickTag", schoolInfoList.get(position).getTitle());
                            Intent intent = new Intent(getContext(),SchoolDateilActivity.class);
                            intent.putExtra("dateilUrl",schoolInfoList.get(position).getPageUrl());
                            startActivity(intent);
                        }
                    });
                    schoolRecyclerView.setAdapter(adapter);
                    break;
                case REFRESH:
                    adapter.notifyDataSetChanged();
                    Toast.makeText(getContext(),"刷新成功",Toast.LENGTH_SHORT).show();
                    schoolSwipeRefreshLayout.setRefreshing(false);
                    break;
            }
        }
    };
    public static SchoolInfoFragmActivity newInstance() {
        return new SchoolInfoFragmActivity();
    }


    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        handler.sendEmptyMessage(GETJSOUPCONTENT);
        View view = inflater.inflate(R.layout.activity_school_info_fragm, container, false);
        schoolSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh_school);
        schoolSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                handler.sendEmptyMessage(GETJSOUPCONTENT);
            }
        });
        schoolRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view_school);
        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
        schoolRecyclerView.setLayoutManager(layoutManager);
        return view;

    }

    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            getJsoupContent();
        }
    };
    /**
     * 使用jsoup获取学校官网数据
     */
    private void getJsoupContent(){
        schoolInfoList = new ArrayList<>();
        String url = "http://www.jxut.edu.cn/";
        Connection conn = Jsoup.connect(url);
        // 修改http包中的header,伪装成浏览器进行抓取
        conn.header("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:32.0) Gecko/    20100101 Firefox/32.0");
        Document doc = null;
        try {
            doc = conn.get();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Elements elements = doc.select("[class=tabContent blog]");
        Elements elements1 = elements.select("font");
        Elements elements2 = elements1.select("a");
        Document dt = null;
        for(Element element : elements2){
            String Title = element.text();
            String PageUrl = element.attr("abs:href");
            Connection ct = Jsoup.connect(PageUrl);
            ct.header("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:32.0) Gecko/    20100101 Firefox/32.0");
            try {
                dt = ct.get();
            } catch (IOException e) {
                e.printStackTrace();
            }
            Elements elements3 = dt.select("[class=listpicabs_text_show]");
            String ImgUrl = "";
            if(elements3.select("img").first()==null){
            }else{
                ImgUrl = elements3.select("img").first().absUrl("src");
            }
            schoolInfoList.add(new SchoolInfo(Title,PageUrl,ImgUrl));
            Log.e("mytag", Title);
            Log.e("mytag", PageUrl );
            Log.e("mytag", ImgUrl );
        }
        if (ifFirstInitData){
            ifFirstInitData=false;
            handler.sendEmptyMessage(INITRECYLERVIEW);
        }else{
            handler.sendEmptyMessage(REFRESH);
        }

    }

}

那么刷新就解决了

接下来完成一下这个详情页

这里说到两个开源框架,一个是banner,主要是做图片轮播的框架,另外一个就比较常用了,glide图片加载框架,嘛,这个的话之前就说了要用框架来加载图片,只不过是想再自己做一遍加载再复习一下过程而已,那么现在开始就用框架来实现这个功能了

首先是添加依赖,然后sync一下,这国际惯例了

   //banner图片轮播依赖
    compile ‘com.youth.banner:banner:1.4.9‘

    //glide图片加载依赖
    compile "com.github.bumptech.glide:glide:3.7.0"

那么详情页,首先得有个页,有个layout

activity_dateil.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">


        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fitsSystemWindows="true">


            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/coll_toolbar_layout"
                android:layout_width="match_parent"
                android:layout_height="@dimen/detail_image_height"
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                app:contentScrim="?attr/colorPrimary"
                app:expandedTitleMarginEnd="96dp"
                app:layout_scrollFlags="scroll|exitUntilCollapsed">

                <FrameLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:fitsSystemWindows="true"
                    app:layout_collapseMode="parallax"
                    app:layout_collapseParallaxMultiplier="0.8"
                    app:layout_scrollFlags="scroll|snap|enterAlways|enterAlwaysCollapsed">

                    <com.youth.banner.Banner
                        xmlns:app="http://schemas.android.com/apk/res-auto"
                        android:id="@+id/detail_image"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:scaleType="centerCrop" />

                    <View
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:layout_gravity="bottom"
                        android:background="@drawable/black_bg" />

                    <TextView
                        android:id="@+id/detail_title"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="bottom"
                        android:layout_marginBottom="15dp"
                        android:padding="@dimen/activity_vertical_margin"
                        android:textColor="@android:color/white"
                        android:textSize="22sp" />

                    <TextView
                        android:id="@+id/detail_time"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="right|bottom"
                        android:layout_marginBottom="5dp"
                        android:padding="5dp"
                        android:textColor="@android:color/white"
                        android:textSize="16sp" />


                </FrameLayout>

            </android.support.design.widget.CollapsingToolbarLayout>


        </android.support.design.widget.AppBarLayout>

        <android.support.v4.widget.NestedScrollView
            android:id="@+id/detail_scroll_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:overScrollMode="never"
            android:scrollbars="vertical"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">


            <TextView
                android:id="@+id/detail_content"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:isScrollContainer="false"
                android:overScrollMode="never"
                android:scrollbars="vertical"
                android:textSize="18sp"/>


        </android.support.v4.widget.NestedScrollView>

    </android.support.design.widget.CoordinatorLayout>


</FrameLayout>

插句话,其实中间那个设置了背景的View可要可不要,之所以加只是为了在没有图片的时候有个过渡,直接空白的然后突然闪一张图片出来,感觉视觉效果不好吧

然后是做个glideImageLoder,当然了,banner的实现不一定要glide,但是必须得有个玩意来加载图片吧,那么得封装一下

GlideImageLoader.java

public class GlideImageLoader extends ImageLoader {
    @Override
    public void displayImage(Context context, Object path, ImageView imageView) {
        //具体方法内容自己去选择,次方法是为了减少banner过多的依赖第三方包,所以将这个权限开放给使用者去选择
        Glide.with(context.getApplicationContext())
                .load(path)
                .crossFade()
                .into(imageView);
    }
}

 

然后就直接把这个详情页对应的Activity写完就行了

public class SchoolDateilActivity extends BaseActivity {
    private String dateilUrl,detailContent;
    private List<String> dateilImgUrl = new ArrayList<String>();
    private Spanned contentsp;
    private TextView detailTitleTv,detailTimeTv,detailContentTv;
    private Banner banner;
    private String detailTitleString,detailTimeString;
    private final int GETDETAILDATA=http://www.mamicode.com/0x00,PUTVIEWSDATA=0X01;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case GETDETAILDATA:
                    new Thread(deailDataRunnable).start();
                    break;
                case PUTVIEWSDATA:
                    putViewsData();
                    initBanner();
                    detailTitleTv.setText(detailTitleString);
                    detailTimeTv.setText(detailTimeString);
                    break;
            }
        }
    };
    @Override
    protected void initVariablesAndService() {
        //获取详情页链接
        dateilUrl = getIntent().getExtras().get("dateilUrl").toString();
        handler.sendEmptyMessage(GETDETAILDATA);
    }

    @Override
    protected void initViews(Bundle savedInstanceState) {
        setContentView(R.layout.activity_dateil);
        detailTitleTv = (TextView) findViewById(R.id.detail_title);
        detailTimeTv = (TextView) findViewById(R.id.detail_time);
        detailContentTv = (TextView) findViewById(R.id.detail_content);
        banner = (Banner) findViewById(R.id.detail_image);
    }

    Runnable deailDataRunnable = new Runnable() {
        @Override
        public void run() {
            getDetailData();
        }
    };
    /**
     * 获取详情页所需数据
     */
    private void getDetailData(){
        Connection conn = Jsoup.connect(dateilUrl);
        // 修改http包中的header,伪装成浏览器进行抓取
        conn.header("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; rv:32.0) Gecko/    20100101 Firefox/32.0");
        Document doc = null;
        try {
            doc = conn.get();
        } catch (IOException e) {
            e.printStackTrace();
        }
        detailTitleString = doc.select("[class=listpicabs_text_title]").text();
        detailTimeString = doc.select("[class=listpicabs_text_info]").text();
        detailTimeString  = detailTimeString.substring(6,16);
        Elements detailImgUrlEles = doc.select("[class=listpicabs_text_show]").select("img");
        Element element = doc.select("span").first();
        doc.select("img").remove();
        for(Element et:detailImgUrlEles){
            dateilImgUrl.add(et.absUrl("src"));
            Log.e("detailimg", et.absUrl("src"));
        }
        Log.e("ttag", element.toString());
        detailContent = element.toString();
        while(detailContent.indexOf("<br> <br>")!=-1){
            detailContent = detailContent.replace("<br> <br>","<br>");
        }
        detailContent = detailContent.replace("。<br>","。<br> <br>");
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
            contentsp = Html.fromHtml(detailContent,Html.FROM_HTML_MODE_LEGACY);
        } else {
            contentsp = Html.fromHtml(detailContent);
        }
        handler.sendEmptyMessage(PUTVIEWSDATA);
    }
    private void putViewsData(){
        detailContentTv.setText(contentsp);
    }
    /**
     * 初始化Banner轮播
     */
    private void initBanner(){
        //设置图片加载器
        banner.setImageLoader(new GlideImageLoader());
        //设置图片集合
        banner.setImages(dateilImgUrl);
        //banner设置方法全部调用完毕时最后调用
        banner.start();
    }
}

这里可以看到banner和glide的使用方法都非常简单,glide自不用说,很多开发者都在用,banner的话,从这个initBanner方法中也可以看出,最简单的使用只需要在页面里设置个banner控件,然后在Activity代码里初始化,然后设置对应的图片加载方法类,然后设置图片的url,再start就完事了

那么今天也就做到这,后面的应该进度会比较快,因为很多功能都是我之前在这个项目前身的寻呼都实现好了的,往里面加就是了,在这些都做完之后,我也还得优化一下,把能够重用的都封装一下

android 练习之路 (六)