pull
activity_main
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.handmark.pulltorefresh.library.PullToRefreshListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/plv"></com.handmark.pulltorefresh.library.PullToRefreshListView> </LinearLayout>
item
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:layout_width="80dp" android:layout_height="80dp" android:id="@+id/img"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/tv" android:layout_toRightOf="@id/img"/> </RelativeLayout>
resultdata
package zhanghaijiao.bawei.com.zhanghaijiao180330.bean; import java.util.List; /** * Created by jane on 2018/3/30. */ public class ResultData { /** * code : 200 * msg : success * newslist : [{"ctime":"2018-03-30","title":"2.0T+9AT的大7座SUV,卖多少钱能让你放弃汉兰达/奥迪Q5?","description":"车买买","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62898269.static/640","url":"https://mp.weixin.qq.com/s?__biz=MzA5NTU1MjEwNA==&idx=4&mid=2668673664&sn=197feccde9aad5f1c47772235c541e3e"},{"ctime":"2018-03-30","title":"黑人的头发养活了中国的一座城,这里藏着一段屈辱的民族史","description":"微在Wezeit","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900480.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MzA5MjMzNTQyNw==&idx=1&mid=2656030884&sn=9a79b276f2c66c9b2694427d19ee5c72"},{"ctime":"2018-03-30","title":"朋友养了一只猛犬,网友本来是不相信的,直到靠近狗窝后.....","description":"大爱萌狗控","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900520.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MjM5NjQ0MDE1OQ==&idx=2&mid=2650063440&sn=42593507b8b2f992795fb8ed6c675a5a"},{"ctime":"2018-03-30","title":"中国最美的20个旅行目的地,走过10个以上,就算超级旅行达人。","description":"带着相机去旅行","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900363.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MzAxNjI1MzUwOA==&idx=3&mid=2247521649&sn=9c9c6d637348d975baa2c4352039f286"},{"ctime":"2018-03-30","title":"【入流】网红食物打造指南","description":"腾讯时尚","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-61887411.static/640","url":"https://mp.weixin.qq.com/s?__biz=MjM5MTIxOTEyMA==&idx=2&mid=2650591720&sn=e7e246e4bdf3c2659fd26f36b88697fa"},{"ctime":"2018-03-30","title":"深圳大学,我们不说再见...","description":"深圳全接触","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62811967.static/640","url":"https://mp.weixin.qq.com/s?__biz=MzI3MDAyMTUzOA==&idx=3&mid=2654766418&sn=b78ed1a957c065397506d10fb5fe1d8f"},{"ctime":"2018-03-30","title":"给女友打伞和给上级扶镜子是一样样儿的!","description":"丁香园","picUrl":"https://t1.qpic.cn/mblogpic/f01a972dbcc1060fd456/2000","url":"https://mp.weixin.qq.com/s?__biz=MTg0MzMwODA0MQ==&idx=2&mid=2653345924&sn=4e10623b69f593f82283d193ead0785e"},{"ctime":"2018-03-30","title":"这些车只卖10几万都是满分家用车 媳妇 丈母娘都爱你","description":"腾讯汽车","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-55422140.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MjM5NTAxMTg0MA==&idx=5&mid=2652994557&sn=a7d0d0e2774b77a5736e48ea8f879bb4"},{"ctime":"2018-03-30","title":"日裔球员晃断对手脚踝!随后的反应却爆发争议","description":"准者篮球训练营","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62351431.static/640","url":"https://mp.weixin.qq.com/s?__biz=MzA3MTQ4NjM3MQ==&idx=2&mid=2650627935&sn=0cae438f5695fcaea3c3da0f56bccae9"},{"ctime":"2018-03-30","title":"50岁中国辣妈西伯利亚-40℃拍照!外媒讥讽:纹身太显眼......","description":"带着相机去旅行","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62809095.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MzAxNjI1MzUwOA==&idx=2&mid=2247521649&sn=e28e87c51627775b713974b51c3cc66b"}] */ private int code; private String msg; private List<NewslistBean> newslist; public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public List<NewslistBean> getNewslist() { return newslist; } public void setNewslist(List<NewslistBean> newslist) { this.newslist = newslist; } public static class NewslistBean { /** * ctime : 2018-03-30 * title : 2.0T+9AT的大7座SUV,卖多少钱能让你放弃汉兰达/奥迪Q5? * description : 车买买 * picUrl : https://zxpic.gtimg.com/infonew/0/wechat_pics_-62898269.static/640 * url : https://mp.weixin.qq.com/s?__biz=MzA5NTU1MjEwNA==&idx=4&mid=2668673664&sn=197feccde9aad5f1c47772235c541e3e */ private String ctime; private String title; private String description; private String picUrl; private String url; public String getCtime() { return ctime; } public void setCtime(String ctime) { this.ctime = ctime; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getPicUrl() { return picUrl; } public void setPicUrl(String picUrl) { this.picUrl = picUrl; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } } }
JsoncacheDao
package zhanghaijiao.bawei.com.zhanghaijiao180330.db; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.util.Log; /** * Created by jane on 2018/4/1. */ public class JsonCacheDao { private MyHelper myHelper; public JsonCacheDao(Context context) { myHelper = new MyHelper(context); } //添加方法 public void insertData(String path,String json){ //得到一个可读可写的数据库 SQLiteDatabase database=myHelper.getWritableDatabase(); //先删除,再插入 database.delete("jsoncache"," urlpath=?",new String[]{path}); ContentValues contentValues=new ContentValues(); //key:一定要是数据表中的列名 contentValues.put("urlpath",path); contentValues.put("jsondata",json); //第二个参数:强制要插入null值的列的列名 long rowid = database.insert("jsoncache", null, contentValues); Log.d("zzz","插入的数据rowid:"+rowid); } //查询方法,根据url来查询数据 public String queryData(String path){ Log.d("zzz","---正在查询数据---"); String data=""; SQLiteDatabase db = myHelper.getWritableDatabase(); //查询 Cursor cursor = db.query("jsoncache", null, " urlpath=?", new String[]{path}, null, null, null); while (cursor.moveToNext()){ data=cursor.getString(cursor.getColumnIndex("jsondata")); } return data; } }
MyHelper
package zhanghaijiao.bawei.com.zhanghaijiao180330.db; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; /** * Created by jane on 2018/4/1. */ public class MyHelper extends SQLiteOpenHelper { //构造方法--确定数据库的名称,以及版本号 public MyHelper(Context context) { super(context, "mydb", null, 1); } //创建数据库时被回调-只会回调一次 //一般用于创建数据表,初使化表中的数据 @Override public void onCreate(SQLiteDatabase sqLiteDatabase) { //创建了一个jsoncache数据表 sqLiteDatabase.execSQL("create table jsoncache(id integer primary key autoincrement,urlpath text,jsondata text)"); } //数据库版本升级时回调 @Override public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { } }
NetStateUtil
import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkInfo; import zhanghaijiao.bawei.com.zhanghaijiao180330.R; /** * 得到网络状态的工具类 * Created by e531 on 2017/10/16. */ public class NetStateUtil { /* * 判断网络连接是否已开 * true 已打开 false 未打开 * */ public static boolean isConn(Context context){ boolean bisConnFlag=false; ConnectivityManager conManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo network = conManager.getActiveNetworkInfo(); if(network!=null){ bisConnFlag=network.isAvailable(); } return bisConnFlag; } /** * 当判断当前手机没有网络时选择是否打开网络设置 * @param context */ public static void showNoNetWorkDlg(final Context context) { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setIcon(R.mipmap.ic_launcher) // .setTitle(R.string.app_name) // .setMessage("当前无网络").setPositiveButton("设置", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 跳转到系统的网络设置界面 Intent intent = null; // 先判断当前系统版本 if(android.os.Build.VERSION.SDK_INT > 10){ // 3.0以上 intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS); }else{ intent = new Intent(); intent.setClassName("com.android.settings", "com.android.settings.WirelessSettings"); } context.startActivity(intent); } }).setNegativeButton("知道了", null).show(); } }
MainActivity
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; import java.util.List; import zhanghaijiao.bawei.com.zhanghaijiao180330.bean.ResultData; import zhanghaijiao.bawei.com.zhanghaijiao180330.db.JsonCacheDao; import zhanghaijiao.bawei.com.zhanghaijiao180330.utils.NetStateUtil; public class MainActivity extends AppCompatActivity { private PullToRefreshListView plv; private int pageIndex=1; private String webUrl="https://api.tianapi.com/wxnew/?key=48a7d7193e11bd2dd4a683b6e2f90a4f&num=10&page="+pageIndex; //定义一个大集合 private List<ResultData.NewslistBean> dataAll=new ArrayList<>(); private MyAdapter adapter; private int operType=1;//1:代表刷新 2:代表加载更多 private Handler myHanlder=new Handler(){ @Override public void handleMessage(Message msg) { List<ResultData.NewslistBean> lists=( List<ResultData.NewslistBean>)msg.obj; //显示数据 showData(lists); } }; private JsonCacheDao jsonCacheDao; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //1.找控件 plv = findViewById(R.id.plv); //构造dao类,实现表的添加与查询操作 jsonCacheDao = new JsonCacheDao(this); //2.初使化pulltoRefresh框架 initPlv(); //3.获取数据 //开启子线程请求网络 newThread+handler+httpUrlConnection请求网络数据 requestNetData(); } //设置适配器 private void setLvAdapter(){ if(adapter==null){ adapter=new MyAdapter(MainActivity.this,dataAll); plv.setAdapter(adapter); }else{ adapter.notifyDataSetChanged();//刷新 } } private void requestNetData() { //选进行网络是否连接的判断 if(NetStateUtil.isConn(this)){//联网状态 new Thread(){ @Override public void run() { try { //1.创建一个URL对象 URL url=new URL(webUrl); //2.打开连接 HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection(); //3.进行设置 urlConnection.setRequestMethod("GET"); urlConnection.setReadTimeout(5000); urlConnection.setConnectTimeout(5000); //4.获取响应码进行判断 int responseCode = urlConnection.getResponseCode(); if(responseCode==200){ //5.获取数据 InputStream inputStream = urlConnection.getInputStream(); String content=stremToString(inputStream); //插入到数据库 jsonCacheDao.insertData(webUrl,content); //进行解析 List<ResultData.NewslistBean> newslist = asyncJson(content); //发送消息 Message msg=Message.obtain(); msg.obj=newslist; myHanlder.sendMessage(msg); } } catch (Exception e) { e.printStackTrace(); } } }.start(); }else{//无网状态 Log.d("zzz","---无网状态,查询数据库中的数据---"); //NetStateUtil.showNoNetWorkDlg(this); Toast.makeText(this,"现在没有网络,请稍后重试!",Toast.LENGTH_SHORT).show(); //根据现在的url查询出相应的json数据 String s = jsonCacheDao.queryData(webUrl); //解析,展示 List<ResultData.NewslistBean> newslistBeans = asyncJson(s); showData(newslistBeans); } } /** * 对json串进行解析 * @param json * @return */ public List<ResultData.NewslistBean> asyncJson(String json){ Gson gson=new Gson();//json ResultData data=gson.fromJson(json, ResultData.class); //从对象中获取列表要显示的集体数据 List<ResultData.NewslistBean> newslist = data.getNewslist(); return newslist; } /** * 展示数据 * @param lists */ public void showData(List<ResultData.NewslistBean> lists){ if(operType==1){ dataAll.clear();//清空集合中的所有数据 } dataAll.addAll(lists); //设置适配器 setLvAdapter(); //关闭头尾刷新视图 plv.onRefreshComplete(); } private void initPlv() { //1.设置支持的模式 BOTH:支持上下拉刷新 PULL_FROM_END:只支持加载更多 PULL_FROM_START:只支持下拉刷新 plv.setMode(PullToRefreshBase.Mode.BOTH); //2.设置上下拉刷新的监听事件 plv.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener2<ListView>() { @Override public void onPullDownToRefresh(PullToRefreshBase<ListView> pullToRefreshBase) { //下拉刷新操作 operType=1; pageIndex=1; webUrl="https://api.tianapi.com/wxnew/?key=48a7d7193e11bd2dd4a683b6e2f90a4f&num=10&page="+pageIndex; requestNetData(); } @Override public void onPullUpToRefresh(PullToRefreshBase<ListView> pullToRefreshBase) { //上拉加载更多操作 operType=2; pageIndex++; webUrl="https://api.tianapi.com/wxnew/?key=48a7d7193e11bd2dd4a683b6e2f90a4f&num=10&page="+pageIndex; requestNetData(); } }); } //将流转换成字符串 public String stremToString(InputStream stream){ StringBuilder builder=new StringBuilder(); try { BufferedReader reader=new BufferedReader(new InputStreamReader(stream)); String str; while ((str=reader.readLine())!=null){ builder.append(str); } } catch (Exception e) { e.printStackTrace(); } return builder.toString(); } }
MyAdapter
package zhanghaijiao.bawei.com.zhanghaijiao180330; import android.content.Context; import android.graphics.Bitmap; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import com.nostra13.universalimageloader.core.DisplayImageOptions; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.ImageScaleType; import java.util.List; import zhanghaijiao.bawei.com.zhanghaijiao180330.bean.ResultData; /** * Created by jane on 2018/3/30. */ public class MyAdapter extends BaseAdapter { private Context context; private List<ResultData.NewslistBean> datas; //第二步:显示图片配置 private DisplayImageOptions options; public MyAdapter(Context context, List<ResultData.NewslistBean> datas) { this.context = context; this.datas = datas; options=new DisplayImageOptions.Builder() .cacheInMemory(true)//使用内存缓存 .cacheOnDisk(true)//使用磁盘缓存 .showImageOnLoading(R.mipmap.ic_launcher_round)//设置正在下载的图片 .showImageForEmptyUri(R.mipmap.ic_launcher_round)//url为空或请求的资源不存在时 .showImageOnFail(R.mipmap.ic_launcher_round)//下载失败时显示的图片 .bitmapConfig(Bitmap.Config.RGB_565)//设置图片色彩模式 .imageScaleType(ImageScaleType.EXACTLY)//设置图片的缩放模式 .build(); } @Override public int getCount() { return datas.size(); } @Override public Object getItem(int i) { return datas.get(i); } @Override public long getItemId(int i) { return i; } @Override public View getView(int i, View view, ViewGroup viewGroup) { ViewHolder holder; if(view==null){ view=View.inflate(context,R.layout.item,null); holder=new ViewHolder(); holder.img=view.findViewById(R.id.img); holder.textView=view.findViewById(R.id.tv); view.setTag(holder); }else{ holder= (ViewHolder) view.getTag(); } //第三步:下载图片 displayImage(图片路径,控件,设置类options) ImageLoader.getInstance().displayImage(datas.get(i).getPicUrl(),holder.img,options); holder.textView.setText(datas.get(i).getTitle()); return view; } class ViewHolder{ ImageView img; TextView textView; } }
MyApplication
package zhanghaijiao.bawei.com.zhanghaijiao180330; import android.app.Application; import android.os.Environment; import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache; import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; import java.io.File; /** * Created by jane on 2018/3/31. */ public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); //程序的入口 函数 //自定义缓存路径 sd卡下的piccache文件夹下 File cachefile=new File(Environment.getExternalStorageDirectory().getPath()+"/piccache"); //File cachefile1=getExternalCacheDir();//获取系统默认的sd卡缓存路径 ImageLoaderConfiguration configuration=new ImageLoaderConfiguration.Builder(this) .memoryCacheExtraOptions(480, 800)//缓存图片最大的长和宽 .threadPoolSize(2)//线程池的数量 .threadPriority(4) .memoryCacheSize(2*1024*1024)//设置内存缓存区大小 .diskCacheSize(20*1024*1024)//设置sd卡缓存区大小 .diskCache(new UnlimitedDiscCache(cachefile))//自定义缓存目录 .writeDebugLogs()//打印日志内容 .diskCacheFileNameGenerator(new Md5FileNameGenerator())//给缓存的文件名进行md5加密处理 .build(); ImageLoader.getInstance().init(configuration); } }