工作内容:
1.网络编程之URL
2.JSON数据解析
3.异步任务
学习分享:
一、网络编程之URL;(用于请求服务器,获取到JSON字符串)
主要遇到的是:请求数据的方式 POST,GET的差异
GET :少量数据,请求参数跟在请求网址后面 — 不安全
POST :大量数据,请求参数放在请求的正文里 — 相对安全些,可以携带数据存入服务器
二、JSON数据解析(JSON字符串解析)
主要步骤:
1.请求服务器(返回一个JSON字符串)
2.将JSON字符串解析成一个一个的对象(可以JSON数据中的键看作是属性,值就是对应的属性值)
JSON字符串解析:
1.获取最外层的JSONObject object = new JSONObject(JSON字符串)
2.逐层解析,遇到“{}”表示是一个JSONObject ,遇到“[]”,表示是一个JSONArray(JSON数组)
常用方法:
JSONObject.getJSONObject(String key)//用于对象下面一层还是对象的情况
JSONArray array = JSONObject.getJSONArray(String key)//用于对象下面是数组的情况
for(int i=0;i<array.length(),i++)
JSONObject object = array.get(i)//i表示数组下标//获取JSONArray数组中的JSONObject
String str = array.getString(i)//数组中的数据是一个字符串数组【用JSONArray去获取,不能用String[]去获取】,在去遍历array中的字符串
三、异步任务(异步任务泛型类AsyncTask)
唤起异步任务:new NewsShowAsyncTask().execute(URLString)//生成异步类对象,并调用execute()执行异步任务(这里只传入了一个参数【是可以传入很多参数的】)
1.异步任务执行顺序
准备步:(UI中执行)
protected void onPreExecute(){ ... }
第二步:后台执行的方法(非Ui中执行)
protectedList<info> doInBackground(String ... parms){ //参数说明:可以变参数(可以传入一组/多个参数)
List<info> infos = getInfos(parms[0]);//调用耗时方法,如果子传入了一个参数则这里的parms[0]就是那个参数
return info;
}
第三步:(Ui中执行)//设置进度(与后台任务同步执行)
protected void onProgressUpdate(Integer...params){ ... }
第四步:Ui中执行(后台任务执行完成后执行)
protected void onPostExecute( List<info> infos ){
super.onPostExecute(infos);
}
【注意:打断异步任务,可以在onStop()方法中用异步对象调用cancel(true)表示允许在异步任务执行过程中被打断,再在doInBackground中调用if(isCancelled){retrun}允许执行过程中被打断,则直接return null结束此方法执行】
代码演示:
Activity代码(异步任务类)(需修改:填入自己申请的apikey)(数据源于“阿凡达”api数据,国内新闻和时事新闻)
import android.content.Intent; import android.graphics.Color; import android.net.Uri; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.EditText; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.Toast; import com.plane.people.planebattle.adapter.NewsShowRecyAdapter; import com.plane.people.planebattle.base.RecylerItemClickListener; import com.plane.people.planebattle.obj.NewsContent; import com.plane.people.planebattle.tool.InputUtil; import com.plane.people.planebattle.url.GetObjFromJSONUtil; import java.util.ArrayList; import java.util.List; public class NewsShowActivity extends AppCompatActivity implements View.OnClickListener,RecylerItemClickListener{ private String searchInfo = ""; //接收上一个界面传过来的搜索条件 private Toolbar toolbar; private RecyclerView recyclerView; private ImageView imageView; //搜索图标 private EditText editText; //搜索栏的输入框 private NewsShowRecyAdapter adapter; private List<NewsContent> list; private String url = "http://api.avatardata.cn/ActNews/Query?key=填入自己申请的apikey&keyword="; private String urlString = ""; //请求json数据的网址和请求参数组成的字符串 private ProgressBar progressBar;//异步任务执行完成后圆形进度条消失(隐藏和gone都可以) //判断是否搜索到数据,没搜索到就会进行第二次搜索,最后以此弹出消息提醒用户“未搜索到相关信息” private boolean isFailure = false; private NewsShowAsyncTask newsShowAsyncTask; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_news_show); initView(); initData(); } private void initView() { list = new ArrayList<>(); recyclerView = (RecyclerView)findViewById(R.id.rv_nsa); progressBar = (ProgressBar)findViewById(R.id.pb_nsa); imageView = (ImageView)findViewById(R.id.iv_layout_searline_summer); editText = (EditText)findViewById(R.id.et_layout_searline_summer); InputUtil.setInputKeyboardDisappear(this,editText); //输入键盘消失 //设置标题栏toolbar toolbar = (Toolbar)findViewById(R.id.toolbar_news_show); toolbar.setTitle("新闻搜索"); toolbar.setTitleTextColor(Color.WHITE); toolbar.setNavigationIcon(R.drawable.back); setSupportActionBar(toolbar); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); imageView.setOnClickListener(this);//添加搜索点击事件 //设置recyclerView adapter = new NewsShowRecyAdapter(list); LinearLayoutManager manager = new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false); recyclerView.setLayoutManager(manager); recyclerView.setAdapter(adapter); adapter.setRecylerItemClickListener(this); } private void initData() { newsShowAsyncTask = new NewsShowAsyncTask();//生成异步任务类对象 //获取从上一个界面传过来的搜索条件 Intent intent = this.getIntent(); if(intent != null){ searchInfo = intent.getStringExtra("searchinfo"); } urlString = url+searchInfo; /** * 执行异步任务 * 传入一个参数 */ new NewsShowAsyncTask().execute(urlString); } //点击搜索事件 @Override public void onClick(View v) { searchInfo = editText.getText().toString(); //判断用户有无填入搜索内容 if(searchInfo.length()!=0) { progressBar.setVisibility(View.VISIBLE); urlString = url + searchInfo; new NewsShowAsyncTask().execute(urlString);//唤起异步任务类,并传入参数 editText.clearFocus(); InputUtil.setInputKeyboardDisappear(this, editText); }else{ Toast.makeText(this,"请输入新闻内容",Toast.LENGTH_SHORT).show(); } } //点击事件,打开网页 @Override public void onRecylerItemClick(View view, int position) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(list.get(position).getUrlString())); startActivity(intent); } /** * 异步任务类(泛型) * parmas 泛型参数类型(new NewsShowAsyncTask().execute(urlString);)urlString的类型 * progress 表示进度的值类型 * result 返回值类型 */ class NewsShowAsyncTask extends AsyncTask<String,Integer,List<NewsContent>> { @Override protected List<NewsContent> doInBackground(String... params) { List<NewsContent> newsContents = null; //后台去找数据 if(isCancelled()){//假如允许在执行过程中被打断 return null; }else{ newsContents = GetObjFromJSONUtil.getNewsContent(params[0]); if (newsContents.size()==0){//如果没找到数据,去找国内新闻来填充空白 isFailure = true; //判断是否进行过2次加载 String url = "http://api.avatardata.cn/GuoNeiNews/Query?key=填入自己申请的apikey&page=1&rows=50"; newsContents = GetObjFromJSONUtil.getInChinaNewsContent(url); } } return newsContents; } /** * UI线程执行,后台执行完成后执行 * 回调函数 * newsContents是后台执行完成后返回的数据 * 在这里直接用 */ @Override protected void onPostExecute(List<NewsContent> newsContents) { super.onPostExecute(newsContents); list.clear();//清除list中的数据 list.addAll(newsContents); adapter.notifyDataSetChanged(); progressBar.setVisibility(View.INVISIBLE); //判断是否进行了2次搜索 if(isFailure){ Toast.makeText(NewsShowActivity.this,"未搜索到相关内容",Toast.LENGTH_SHORT).show(); isFailure = false; } } } @Override protected void onStop() { super.onStop(); //设置允许在(异步任务正在执行中打断其继续执行) newsShowAsyncTask.cancel(true); } }请求JSON数据
import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; /** * Created by Administrator on 2016/9/9. */ public class JSONUtil { private JSONUtil(){} //不允许创建对象 /** * @param UrlString 请求服务器网址+参数(网址?参数) * @return 返回结果 */ public static String request(String UrlString) { BufferedReader reader = null; String result = null; StringBuffer sbf = new StringBuffer(); try {//生成URL对象 URL url = new URL(UrlString); //建立连接 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoInput(true);//设置读取 /** * 请求方式 GET POST * GET :少量数据,请求参数跟在请求网址后面 — 不安全 * POST :大量数据,请求参数放在请求的正文里 — 相对安全些,可以携带数据存入服务器 */ connection.setRequestMethod("GET"); // 填入apikey到HTTP header connection.setRequestProperty("apikey", "1b003ee9be62dfbef84e61ff07f54bc2"); connection.connect();//连接 InputStream is = connection.getInputStream();//获取返回的流 reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));//转化成字符缓冲流 String strRead = null; while ((strRead = reader.readLine()) != null) { sbf.append(strRead);//将读取到的Json字符串放入sbf中 sbf.append("\r\n");//换行 } reader.close();//关闭流 connection.disconnect();//关闭连接 result = sbf.toString(); } catch (Exception e) { e.printStackTrace(); } return result; } }解析JSON数据
/** * 解析Json字符串(搜索国内新闻) * @param urlString Json字符串 * @return */ public static List<NewsContent> getInChinaNewsContent(String urlString){ List<NewsContent> list = new ArrayList<>();//返回的list初始化 String jsonString = JSONUtil.request(urlString); try { JSONObject jsonObject = new JSONObject(jsonString);//获取最外层的JSONObject //判断是否连接成功 if ("Succes".equals(jsonObject.getString("reason"))) { // Log.e("***国内新闻***", "获取到数据"+jsonObject.toString()); //获取第二层的字符串数组 JSONArray array = jsonObject.getJSONArray("result"); for (int i = 0; i < array.length(); i++) { JSONObject jsonObj = array.getJSONObject(i); String title = jsonObj.getString("title"); String src = "国内新闻"; String pdate_src = jsonObj.getString("ctime"); String content = jsonObj.getString("description"); String img = jsonObj.getString("picUrl"); String url = jsonObj.getString("url"); Bitmap bitmap = null; if(img != null && img != ""){ //调用方法将网络图片转化成bitmap bitmap = CreateBitmapFromUrl.CreateBitmap(img); } list.add(new NewsContent(title,content,src,url,pdate_src,bitmap)); } } } catch (JSONException e) { e.printStackTrace(); } return list; } }最后附加一个Activity的xml代码
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" tools:context="com.plane.people.planebattle.NewsShowActivity"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar_news_show" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/darkturquoise" app:popupTheme="@style/OverflowMenuStyle"/> <include layout="@layout/layout_searchline_summer" android:layout_width="match_parent" android:layout_height="wrap_content" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" > <android.support.v7.widget.RecyclerView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:id="@+id/rv_nsa"> </android.support.v7.widget.RecyclerView> <ProgressBar android:layout_width="100dp" android:layout_height="100dp" android:layout_centerInParent="true" style="@style/Widget.AppCompat.ProgressBar" android:id="@+id/pb_nsa" /> </RelativeLayout> </LinearLayout>
Aapter代码:
import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.plane.people.planebattle.R; import com.plane.people.planebattle.base.RecylerItemClickListener; import com.plane.people.planebattle.obj.NewsContent; import java.util.List; /** * Created by Administrator on 2016/9/11. */ public class NewsShowRecyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{ private List<NewsContent> list; /** * 设置监听Recyler列表项的监听事件 * (自定的一个接口,就一个方法:void onRecylerItemClick(View v,int position)) */ public void setRecylerItemClickListener(RecylerItemClickListener recylerItemClickListener) { this.recylerItemClickListener = recylerItemClickListener; } private RecylerItemClickListener recylerItemClickListener; public NewsShowRecyAdapter(List<NewsContent> list) { this.list = list; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_newscontent,parent,false); ViewHolder_newsContent holder_newsContent = new ViewHolder_newsContent(view); return holder_newsContent; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder,final int position) { ViewHolder_newsContent myHolder = (ViewHolder_newsContent)holder; if(list.get(position).getBitmap()!=null){ myHolder.imageView.setImageBitmap(list.get(position).getBitmap()); }else{ myHolder.imageView.setVisibility(View.GONE); } myHolder.tvTitle.setText(list.get(position).getTitle()); myHolder.tvSrcTime.setText("来源:" + list.get(position).getSrc() + " 发布时间:" + list.get(position).getPdate_src()); myHolder.tvContent.setText(list.get(position).getContent()); myHolder.linearLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //点击列表项调用自定义接口中的回调方法(activity中实现) recylerItemClickListener.onRecylerItemClick(v,position); } }); } @Override public int getItemCount() { return list.size(); } class ViewHolder_newsContent extends RecyclerView.ViewHolder{ TextView tvTitle,tvSrcTime,tvContent; ImageView imageView; LinearLayout linearLayout; public ViewHolder_newsContent(View itemView) { super(itemView); imageView = (ImageView)itemView.findViewById(R.id.iv_item_newscontent); tvTitle = (TextView)itemView.findViewById(R.id.tv_title_item_newscontent); tvSrcTime = (TextView)itemView.findViewById(R.id.tv_src_time_item_newscontent); tvContent = (TextView)itemView.findViewById(R.id.tv_content_item_newscontent); linearLayout = (LinearLayout)itemView.findViewById(R.id.linear_item_newscontent); } } }
网络图片转换成Bitmap代码:
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; /** * Created by Administrator on 2016/9/9. */ public class CreateBitmapFromUrl { private CreateBitmapFromUrl(){}//不允许生成对象 /** * 将图片资源转换为bitmap * @param imageUrl * @return */ public static Bitmap CreateBitmap(String imageUrl){ Bitmap bitmap = null; try { URL url = new URL(imageUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setReadTimeout(5000); connection.setDoInput(true); connection.connect(); bitmap = BitmapFactory.decodeStream(connection.getInputStream()); connection.disconnect(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return bitmap; } }
显示效果:(获取到图片则显示出来,没图片则)让ImageView的可见性=gone