Home>

Recently, people always come and tell me that a small app I wrote before can't get data normally ~ android weather forecast app

Run it again today to find the problem,It may be that the interface is limited,Cannot use the same apikey on multiple phones

Then, I found that the code I wrote was really messy,The interface is also really bad.Just rewritten again,I changed it a little bit,Development environment changed to android studio

The engineering drawing is as follows

1. Obtaining regional information

To make such a weather forecast app, we must first get a list of domestic regions

(Introduced in my other blog:Make a data request to any URL)

China Weather Network has a weather forecast interface,Visit "http://www.weather.com.cn/data/list3/city.xml" to get the list of domestic provinces and their codes

If i want to get a list of cities in Guangdong,As can be seen from the above figure, the code of Guangdong Province is 28, and the interface address is "http://www.weather.com.cn/data/list3/city28.xml". The obtained city list and code are as follows:

By analogy, you can get more detailed regional information.This completes the beginning

Acquisition of weather information

Baidu's apistore has a rich interface,Covers many aspects of life.For example, we can obtain json data containing weather information through an interface of apistore to achieve the weather forecast function

(Introduced in my other blog:Get json data with weather information)

First, the user must have a Baidu account.Then visit the following website:China and World Weather Forecast

The interface is free,But it ’s not stable enough,I often make mistakes when debugging

Then click "your own apikey" under the api option to view your own apikey. This value is a unique identifier for each developer and app.Need to be kept safe,With apikey, you can proceed to the next step

The weather information obtained is in json format and needs to be parsed in the program

Third, the design of the database

The list of regions is generally fixed.So we can store the data obtained from the first network connection into the database,Read from the database the next time you visit again

First of all, we need to set four models, including:province, city, county, hourly weather forecast,Used to carry data

Each model includes several properties and corresponding get and set methods

For example, the province province design is shown below,The design of city and county is similar

/**
 * Province
 * /
public class province {
 //Province name
 private string provincename;
 //Province id
 private string provinceid;
 public string getprovinceid () {
  return provinceid;
 }
 public string getprovincename () {
  return provincename;
 }
 public void setprovinceid (string provinceid) {
  this.provinceid=provinceid;
 }
 public void setprovincename (string provincename) {
  this.provincename=provincename;
 }
}

The hourlyweather forecast is designed as follows:

/**
 * created by zy on 2016/7/21.
 * /
public class hourlyweather {
 //prediction time
 private string time;
 //temperature
 private string temp;
 //Precipitation probability
 private string pop;
 //Wind
 private string wind;
 public hourlyweather (string time, string temp, string pop, string wind) {
  this.time=time;
  this.temp=temp;
  this.pop=pop;
  this.wind=wind;
 }
 public string gettime () {
  return time;
 }
 public string gettemp () {
  return temp;
 }
 public string getpop () {
  return pop;
 }
 public string getwind () {
  return wind;
 }
}

Then, create a new databasehelper class inherited from sqliteopenhelper to create three database tables

public class databasehelper extends sqliteopenhelper {
 private final string create_province="create table province ("
   + "provincename text," + "provinceid text)";
 private final string create_city="create table city ("
   + "cityname text," + "cityid text," + "provinceid text)";
 private final string create_county="create table county ("
   + "countyname text," + "countyid text," + "cityid text)";
 public databasehelper (context context, string dbname,       cursorfactory factory, int version) {
  super (context, dbname, factory, version);
 }
 @override
 public void oncreate (sqlitedatabase db) {
  db.execsql (create_province);
  db.execsql (create_city);
  db.execsql (create_county);
 }
 @override
 public void onupgrade (sqlitedatabase db, int oldversion, int newversion) {
 }
}

Then, create a weatherdb class for actual database operations.Including access to province information, city information, county information, etc.

have to be aware of is,Because every city is included in a certain province,So query the list of all cities in a province,The province id needs to be passed in as a unique identifier

public class weatherdb {
 private final string databasename="zyweather";
 private final int version=1;
 private sqlitedatabase database;
 private static weatherdb weatherdb;
 private weatherdb (context context) {
  databasehelper databasehelper=new databasehelper (context,    databasename, null, version);
  database=databasehelper.getwritabledatabase ();
 }
 //Get instance
 public static weatherdb getinstance (context context) {
  if (weatherdb == null) {
   weatherdb=new weatherdb (context);
  }
  return weatherdb;
 }
 //Save province information
 public void saveprovinces (list<province>provincelist) {
  if (provincelist!=null&&provincelist.size ()>0) {
   contentvalues ​​values ​​= new contentvalues ​​();
   for (int i=0;i<provincelist.size ();i ++) {
    values.put ("provincename", provincelist.get (i) .getprovincename ());
    values.put ("provinceid", provincelist.get (i) .getprovinceid ());
    database.insert ("province", null, values);
    values.clear ();
   }
  }
 }
 //Save city information
 public void savecities (list<city>citylist) {
  if (citylist!=null&&citylist.size ()>0) {
   contentvalues ​​values ​​= new contentvalues ​​();
   for (int i=0;i<citylist.size ();i ++) {
    values.put ("cityname", citylist.get (i) .getcityname ());
    values.put ("cityid", citylist.get (i) .getcityid ());
    values.put ("provinceid", citylist.get (i) .getprovinceid ());
    database.insert ("city", null, values);
    values.clear ();
   }
  }
 }
 //Save village information
 public void savecounties (list<county>countylist) {
  if (countylist!=null&&countylist.size ()>0) {
   contentvalues ​​values ​​= new contentvalues ​​();
   for (int i=0;i<countylist.size ();i ++) {
    values.put ("countyname", countylist.get (i) .getcountyname ());
    values.put ("countyid", countylist.get (i) .getcountyid ());
    values.put ("cityid", countylist.get (i) .getcityid ());
    database.insert ("county", null, values);
    values.clear ();
   }
  }
 }
 //Return all province information
 public list<province>getallprovince () {
  cursor cursor=database.query ("province", null, null, null, null, null, null);
  list<province>list=new arraylist<>();
  province province;
  if (cursor.movetofirst ()) {
   do {
    province=new province ();
    province.setprovincename (cursor.getstring (cursor.getcolumnindex ("provincename")));
    province.setprovinceid (cursor.getstring (cursor.getcolumnindex ("provinceid")));
    list.add (province);
   } while (cursor.movetonext ());
  }
  return list;
 }
 //return all cities in the specified province
 public list<city>getallcity (string provinceid) {
  list<city>list=new arraylist<>();
  city ​​city;
  cursor cursor=database.query ("city", null, "provinceid =?", new string [] {provinceid}, null, null, null);
  if (cursor.movetofirst ()) {
   do {
    city ​​= new city ();
    city.setcityname (cursor.getstring (cursor.getcolumnindex ("cityname")));
    city.setcityid (cursor.getstring (cursor.getcolumnindex ("cityid")));
    city.setprovinceid (provinceid);
    list.add (city);
   } while (cursor.movetonext ());
  }
  return list;
 }
 //Return all villages under the specified city
 public list<county>getallcountry (string cityid) {
  list<county>list=new arraylist<>();
  cursor cursor=database.query ("county", null, "cityid =?", new string [] {cityid}, null, null, null);
  county county;
  if (cursor.movetofirst ()) {
   do {
    county=new county ();
    county.setcountyname (cursor.getstring (cursor.getcolumnindex ("countyname")));
    county.setcountyid (cursor.getstring (cursor.getcolumnindex ("countyid")));
    county.setcityid (cityid);
    list.add (county);
   } while (cursor.movetonext ());
  }
  return list;
 }
}

Fourth, network operation

The entire app uses the same function to complete various data operations.This function is included in the httputil class and is a static function

You need to fill in the apikey you applied for. This key is only useful for obtaining weather information.It is not needed when obtaining regional information.This is just for simplicity,So I wrote it together

public class httputil {
 public static void sendhttprequest (final string address, final httpcallbacklistener listener) {
  new thread (new runnable () {
   public void run () {
    httpurlconnection connection=null;
    try {
     url url=new url (address);
     connection=(httpurlconnection) url.openconnection ();
     connection.setrequestmethod ("get");
     connection.setconnecttimeout (8000);
     connection.setreadtimeout (8000);
     connection.setrequestproperty ("apikey", "Fill in your own APIkey");
     connection.connect ();
     inputstream inputstream=connection.getinputstream ();
     inputstreamreader inputstreamreader=new inputstreamreader (inputstream, "utf-8");
     bufferedreader bufferedreader=new bufferedreader (inputstreamreader);
     stringbuilder response=new stringbuilder ();
     string line;
     while ((line=bufferedreader.readline ())!=null) {
      response.append (line);
     }
     if (listener!=null) {
      listener.onfinish (response.tostring ());
     }
    } catch (exception e) {
     if (listener!=null) {
      listener.onerror (e);
     }
    } finally {
     if (connection!=null) {
      connection.disconnect ();
     }
    }
   }
  }). start ();
 }
}

Five, tools

After networked access to data succeeds or fails,All need to process data through callback methods,So you need to set an interface httpcallbacklistener

public interface httpcallbacklistener {
 void onfinish (string response);
 void onerror (exception e);
}

In addition, after using the httputil class to obtain region information,Because the data contains some delimiters,Can't be saved directly into the database,Moreover, the weather information obtained is also in json format, and data analysis is also required.So you also need a utility class for data processing

public class utility {
 //Save the provincial data returned by the server
 public static boolean saveprovincesresponse (weatherdb weatherdb, string response) {
  if (! textutils.isempty (response)) {
   string [] allprovinces=response.split (",");
   if (allprovinces!=null&&allprovinces.length>0) {
    province province;
    list<province>provincelist=new arraylist<>();
    for (string p:allprovinces) {
     string [] array=p.split ("\\ |");
     province=new province ();
     province.setprovinceid (array [0]);
     province.setprovincename (array [1]);
     provincelist.add (province);
    }
    weatherdb.saveprovinces (provincelist);
    return true;
   }
  }
  return false;
 }
 //Save the city-level data returned by the server
 public static boolean savecitiesresponse (weatherdb weatherdb, string response, string provinceid) {
  if (! textutils.isempty (response)) {
   string [] allcities=response.split (",");
   if (allcities!=null&&allcities.length>0) {
    city ​​city;
    list<city>citylist=new arraylist<>();
    for (string c:allcities) {
     string [] array=c.split ("\\ |");
     city ​​= new city ();
     city.setcityid (array [0]);
     city.setcityname (array [1]);
     city.setprovinceid (provinceid);
     citylist.add (city);
    }
    weatherdb.savecities (citylist);
    return true;
   }
  }
  return false;
 }
 //Save the county-level data returned by the server
 public static boolean savecountiesresponse (weatherdb weatherdb, string response, string cityid) {
  if (! textutils.isempty (response)) {
   string [] allcounties=response.split (",");
   if (allcounties!=null&&allcounties.length>0) {
    county county;
    list<county>countylist=new arraylist<();
    for (string c:allcounties) {
     string [] array=c.split ("\\ |");
     county=new county ();
     county.setcountyid (array [0]);
     county.setcountyname (array [1]);
     county.setcityid (cityid);
     countylist.add (county);
    }
    weatherdb.savecounties (countylist);
    return true;
   }
  }
  return false;
 }
 //Process the json data returned by the server
 public static void handleweatherresponse (context context, string response) {
  try {
   jsonobject jsonobject=new jsonobject (response);
   jsonarray title=jsonobject.getjsonarray ("heweather data service 3.0");
   jsonobject first_object=(jsonobject) title.get (0);
   jsonobject basic=(jsonobject) first_object.get ("basic");
   //Update time
   jsonobject update=(jsonobject) basic.get ("update");
   jsonarray daily_forecast=(jsonarray) first_object.get ("daily_forecast");
   jsonobject daily_forecast_first=(jsonobject) daily_forecast.get (0);
   jsonobject cond=(jsonobject) daily_forecast_first.get ("cond");
   //temperature
   jsonobject temp=(jsonobject) daily_forecast_first.get ("tmp");
   jsonobject astro=(jsonobject) daily_forecast_first.get ("astro");
   jsonobject wind=(jsonobject) daily_forecast_first.get ("wind");
   jsonarray hourly_forecast=(jsonarray) first_object.get ("hourly_forecast");
   weatheractivity.weatherlist.clear ();
   for (int i=0;i<hourly_forecast.length ();i ++) {
    jsonobject json=hourly_forecast.getjsonobject (i);
    jsonobject json_wind=(jsonobject) json.get ("wind");
    string date=json.getstring ("date");
    string [] array=date.split ("");
    string dir=json_wind.getstring ("dir");
    string sc=json_wind.getstring ("sc");
    string hourly_clock=array [1];
    string hourly_temp="Temperature:" + json.getstring ("tmp") + "℃";
    string hourly_pop="Precipitation probability:" + json.getstring ("pop");
    string hourly_wind="Wind:" + dir + "" + sc+ "level";
    hourlyweather weather=new hourlyweather (hourly_clock, hourly_temp, hourly_pop, hourly_wind);
    weatheractivity.weatherlist.add (weather);
   }
   //sunrise
   string sunrisetime=astro.getstring ("sr");
   //sunset
   string sunsettime=astro.getstring ("ss");
   //day weather
   string dayweather=cond.getstring ("txt_d");
   //night weather
   string nightweather=cond.getstring ("txt_n");
   //Wind
   string windtext=wind.getstring ("dir") + "" + wind.getstring ("sc") + "level";
   //Precipitation probability
   string pop=daily_forecast_first.getstring ("pop");
   //temperature
   string temptext=temp.getstring ("min") + "℃ ~" + temp.getstring ("max") + "℃";
   //Update time
   string updatetime=update.getstring ("loc");
   //city name
   string cityname=basic.getstring ("city");
   saveweatherinfo (context, cityname, sunrisetime, sunsettime, dayweather, nightweather, windtext, pop, temptext, updatetime);
  } catch (exception e) {
   e.printstacktrace ();
  }
 }
 private static void saveweatherinfo (context context, string cityname,          string sunrisetime, string sunsettime, string dayweather, string nightweather,          string windtext, string pop, string temptext, string updatetime) {
  sharedpreferences.editor editor=context.getsharedpreferences ("weather", context.mode_private) .edit ();
  editor.putstring ("cityname", cityname);
  editor.putstring ("sunrisetime", sunrisetime);
  editor.putstring ("sunsettime", sunsettime);
  editor.putstring ("dayweather", dayweather);
  editor.putstring ("nightweather", nightweather);
  editor.putstring ("wind", windtext);
  editor.putstring ("pop", pop);
  editor.putstring ("temp", temptext);
  editor.putstring ("updatetime", updatetime);
  editor.commit ();
 }
}

Six, adapterYou can see hourly weather forecast information from the dynamic graph above.That's rendered using listview, which is to provide an adapter for it

The layout files used by listview are as follows:

<?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="match_parent"
 android:orientation="horizontal">
 <!-Time->
 <textview
  android:id="@ + id/forecasttime"
  android:layout_width="0dp"
  android:layout_height="match_parent"
  android:layout_weight="2"
  android:gravity="center"
  android:textsize="20sp"
  android:textstyle="bold" />
 <linearlayout
  android:layout_width="0dp"
  android:layout_height="match_parent"
  android:layout_weight="5"
  android:orientation="vertical">
  <!-Temperature precipitation probability->
  <linearlayout
   android:layout_width="match_parent"
   android:layout_height="0dp"
   android:layout_weight="1"
   android:gravity="center"
   android:orientation="horizontal">
   <!-Temperature->
   <textview
    android:id="@ + id/forecasttemp"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:gravity="center" />
   <!-Rain probability->
   <textview
    android:id="@ + id/forecastpop"
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:gravity="center" />
  </linearlayout>
  <!-Wind->
  <textview
   android:id="@ + id/forecastwind"
   android:layout_width="match_parent"
   android:layout_height="0dp"
   android:layout_weight="1"
   android:gravity="center" />
 </linearlayout>
</linearlayout>

Then create a new weatheradapter inherited from arrayadapter<hourlyweather>

Just override the getview (int position, view convertview, viewgroup parent) method

public class weatheradapter extends arrayadapter<hourlyweather>{
 private int resourceid;
 private context context;
 public weatheradapter (context context, int textviewresourceid, list<hourlyweather>objects) {
  super (context, textviewresourceid, objects);
  this.context=context;
  this.resourceid=textviewresourceid;
 }
 public view getview (int position, view convertview, viewgroup parent) {
  hourlyweather weather=getitem (position);
  view view=layoutinflater.from (context) .inflate (resourceid, null);
  textview forecasttime=(textview) view.findviewbyid (r.id.forecasttime);
  textview forecasttemp=(textview) view.findviewbyid (r.id.forecasttemp);
  textview forecastpop=(textview) view.findviewbyid (r.id.forecastpop);
  textview forecastwind=(textview) view.findviewbyid (r.id.forecastwind);
  forecasttime.settext (weather.gettime ());
  forecasttemp.settext (weather.gettemp ());
  forecastpop.settext (weather.getpop ());
  forecastwind.settext (weather.getwind ());
  return view;
 }
}

Preparation of activityFirst, complete the area selection interface chooseareaactivity

The chooseareaactivity interface only includes a centered textview and a listview

The layout file is as follows:

<?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="match_parent"
 android:orientation="vertical">
 <relativelayout
  android:layout_width="match_parent"
  android:layout_height="50dp">
  <textview
   android:id="@ + id/title"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_centerinparent="true"
   android:textsize="24sp" />
 </relativelayout>
 <listview
  android:id="@ + id/listview"
  android:layout_width="match_parent"
  android:layout_height="match_parent" />
</linearlayout>

Chooseareaactivity needs to complete the operations:complete the loading of the region list, pass the selected county name to weatheractivity

In addition, showprogressdialog () is used to render a progress dialog,It is also set to not be closed by the back button.And I have not debugged in a weak network environment,Every load is fast,I haven't seen the dialog box come out,So I don't know if there is any bug in showprogressdialog () ~

public class chooseareaactivity extends appcompatactivity {
 //mark the current list as a province
 public static final int level_province=0;
 //mark the current list as a city
 public static final int level_city=1;
 //mark the current list as a county
 public static final int level_county=2;
 //progress dialog
 private progressdialog progressdialog;
 //title
 private textview titletext;
 //Datasheets
 private listview listview;
 //list data
 private arrayadapter<string>adapter;
 //database
 private weatherdb weatherdb;
 private list<string>datalist;
 private list<province>provincelist;
 private list<city>citylist;
 private list<county>countylist;
 //Selected province
 private province selectedprovince;
 //Selected city
 private city selectedcity;
 //The currently selected list type
 private int currentlevel;
 //Mark whether jump from weatheractivity
 private boolean isfromweatheractivity;
 @override
 protected void oncreate (bundle savedinstancestate) {
  super.oncreate (savedinstancestate);
  isfromweatheractivity=getintent (). getbooleanextra ("choosearea", false);
  sharedpreferences sharedpreferences=getsharedpreferences ("weather", context.mode_private);
  //If country is selected and this activity is not launched from the weather interface,Jump directly to weatheractivity
  if (! textutils.isempty (sharedpreferences.getstring ("countyname", ""))&&! isfromweatheractivity) {
   intent intent=new intent (this, weatheractivity.class);
   startactivity (intent);
   finish ();
   return;
  }
  setcontentview (r.layout.activity_choose_area);
  if (getsupportactionbar ()!=null) {
   getsupportactionbar (). hide ();
  }
  listview=(listview) findviewbyid (r.id.listview);
  titletext=(textview) findviewbyid (r.id.title);
  datalist=new arraylist<>();
  adapter=new arrayadapter<>(this, android.r.layout.simple_list_item_1, datalist);
  listview.setadapter (adapter);
  weatherdb=weatherdb.getinstance (this);
  listview.setonitemclicklistener (new adapterview.onitemclicklistener () {
   @override
   public void onitemclick (adapterview<?>arg0, view arg1, int index, long arg3) {
    if (currentlevel == level_province) {
     selectedprovince=provincelist.get (index);
     querycities ();
    } else if (currentlevel == level_city) {
     selectedcity=citylist.get (index);
     querycounties ();
    } else if (currentlevel == level_county) {
     //When clicked to the county list,Use intent to jump to the weather information interface
     string countyname=countylist.get (index) .getcountyname ();
     intent intent=new intent (chooseareaactivity.this, weatheractivity.class);
     intent.putextra ("countyname", countyname);
     startactivity (intent);
     finish ();
    }
   }
  });
  queryprovinces ();
 }
 private void queryprovinces () {
  showprogressdialog ();
  provincelist=weatherdb.getallprovince ();
  if (provincelist.size ()>0) {
   datalist.clear ();
   for (province province:provincelist) {
    datalist.add (province.getprovincename ());
   }
   adapter.notifydatasetchanged ();
   listview.setselection (0);
   titletext.settext ("China");
   currentlevel=level_province;
   closeprogressdialog ();
  } else {
   queryfromserver (null, "province");
  }
 }
 private void querycities () {
  showprogressdialog ();
  citylist=weatherdb.getallcity (selectedprovince.getprovinceid ());
  if (citylist.size ()>0) {
   datalist.clear ();
   for (city city:citylist) {
    datalist.add (city.getcityname ());
   }
   adapter.notifydatasetchanged ();
   listview.setselection (0);
   titletext.settext (selectedprovince.getprovincename ());
   currentlevel=level_city;
   closeprogressdialog ();
  } else {
   queryfromserver (selectedprovince.getprovinceid (), "city");
  }
 }
 private void querycounties () {
  showprogressdialog ();
  countylist=weatherdb.getallcountry (selectedcity.getcityid ());
  if (countylist.size ()>0) {
   datalist.clear ();
   for (county county:countylist) {
    datalist.add (county.getcountyname ());
   }
   adapter.notifydatasetchanged ();
   listview.setselection (0);
   titletext.settext (selectedcity.getcityname ());
   currentlevel=level_county;
   closeprogressdialog ();
  } else {
   queryfromserver (selectedcity.getcityid (), "county");
  }
 }
 private void queryfromserver (final string code, final string type) {
  string address;
  //code is not empty
  if (! textutils.isempty (code)) {
   address="http://www.weather.com.cn/data/list3/city" + code + ".xml";
  } else {
   address="http://www.weather.com.cn/data/list3/city.xml";
  }
  httputil.sendhttprequest (address, new httpcallbacklistener () {
   @override
   public void onfinish (string response) {
    boolean result=false;
    if ("province" .equals (type)) {
     result=utility.saveprovincesresponse (weatherdb, response);
    } else if ("city" .equals (type)) {
     result=utility.savecitiesresponse (weatherdb, response, selectedprovince.getprovinceid ());
    } else if ("county" .equals (type)) {
     result=utility.savecountiesresponse (weatherdb, response, selectedcity.getcityid ());
    }
    if (result) {
     runonuithread (new runnable () {
      @override
      public void run () {
       if ("province" .equals (type)) {
        queryprovinces ();
       } else if ("city" .equals (type)) {
        querycities ();
       } else if ("county" .equals (type)) {
        querycounties ();
       }
      }
     });
    }
   }
   @override
   public void onerror (exception e) {
    runonuithread (new runnable () {
     @override
     public void run () {
      toast.maketext (chooseareaactivity.this, "Load failed", toast.length_short) .show ();
     }
    });
   }
  });
  closeprogressdialog ();
 }
 private void showprogressdialog () {
  if (progressdialog == null) {
   progressdialog=new progressdialog (this);
   progressdialog.setmessage ("Loading ...");
   progressdialog.setcanceledontouchoutside (false);
  }
  progressdialog.show ();
 }
 private void closeprogressdialog () {
  if (progressdialog!=null) {
   progressdialog.dismiss ();
  }
 }
 @override
 public void onbackpressed () {
  if (currentlevel == level_county) {
   querycities ();
  } else if (currentlevel == level_city) {
   queryprovinces ();
  } else {
   if (isfromweatheractivity) {
    intent intent=new intent (this, weatheractivity.class);
    startactivity (intent);
   }
   finish ();
  }
 }
}

The layout of weatheractivity is relatively complicated,Contains many textviews, I just want to keep it simple,Simply present the data as text

//city switch button
 private button cityswitch;
 //refresh data button
 private button weatherrefresh;
 //city name
 private textview cityname;
 //day and night weather description
 private textview daynightweather;
 //temperature
 private textview temp;
 //sunrise time
 private textview sunrisetime;
 //sunset time
 private textview sunsettime;
 //wind
 private textview wind;
 //precipitation probability
 private textview pop;
 //release time
 private textview updatetime;
 //Today's weather forecast list
 private listview listview;
 public static list<hourlyweather>weatherlist=new arraylist<>();
 private sharedpreferences sharedpreferences;
 @override
 protected void oncreate (bundle savedinstancestate) {
  super.oncreate (savedinstancestate);
  setcontentview (r.layout.weather);
  if (getsupportactionbar ()!=null) {
   getsupportactionbar (). hide ();
  }
  init ();
 }
 private void init () {
  cityswitch=(button) findviewbyid (r.id.cityswitch);
  weatherrefresh=(button) findviewbyid (r.id.weatherrefresh);
  cityswitch.setonclicklistener (this);
  weatherrefresh.setonclicklistener (this);
  cityname=(textview) findviewbyid (r.id.cityname);
  daynightweather=(textview) findviewbyid (r.id.daynightweather);
  temp=(textview) findviewbyid (r.id.temp);
  sunrisetime=(textview) findviewbyid (r.id.sunrisetime);
  sunsettime=(textview) findviewbyid (r.id.sunsettime);
  wind=(textview) findviewbyid (r.id.wind);
  pop=(textview) findviewbyid (r.id.pop);
  updatetime=(textview) findviewbyid (r.id.updatetime);
  listview=(listview) findviewbyid (r.id.hourlyforecast);
  sharedpreferences=getsharedpreferences ("weather", context.mode_private);
  string countyname=getintent (). getstringextra ("countyname");
  //when countryname is not empty
  if (! textutils.isempty (countyname)) {
   sharedpreferences.editor editor=sharedpreferences.edit ();
   editor.putstring ("countyname", countyname);
   editor.commit ();
  } else {
   countyname=sharedpreferences.getstring ("countyname", "");
  }
  weatherrefresh.settext ("Syncing ...");
  queryfromserver (countyname);
 }
 @override
 public void onclick (view view) {
  switch (view.getid ()) {
   case r.id.cityswitch:
    intent intent=new intent (this, chooseareaactivity.class);
    intent.putextra ("choosearea", true);
    startactivity (intent);
    finish ();
    break;
   case r.id.weatherrefresh:
    weatherrefresh.settext ("Syncing ...");
    string countyname=sharedpreferences.getstring ("countyname", "");
    if (! textutils.isempty (countyname)) {
     queryfromserver (countyname);
    }
    break;
  }
 }
 private void queryfromserver (final string countyname) {
  try {
   string url="http://apis.google.com/heweather/weather/free?city=";
   string name=new string (countyname.getbytes ("utf-8"), "iso-8859-1");
   httputil.sendhttprequest (url + name, new httpcallbacklistener () {
    @override
    public void onfinish (string response) {
     utility.handleweatherresponse (weatheractivity.this, response);
     runonuithread (new runnable () {
      @override
      public void run () {
       showweather ();
      }
     });
    }
    @override
    public void onerror (exception e) {
     runonuithread (new runnable () {
      @override
      public void run () {
       toast.maketext (weatheractivity.this, "Synchronization failed", toast.length_long) .show ();
       weatherrefresh.settext ("Update data");
      }
     });
    }
   });
  } catch (exception e) {
   e.printstacktrace ();
  }
 }
 private void showweather () {
  cityname.settext (sharedpreferences.getstring ("cityname", "Unknown"));
  sunrisetime.settext ("Sunrise:" + sharedpreferences.getstring ("sunrisetime", "Unknown"));
  sunsettime.settext ("Sunset:" + sharedpreferences.getstring ("sunsettime", "Unknown"));
  daynightweather.settext ("Day:" + sharedpreferences.getstring ("dayweather", "Unknown") + "Night:" + sharedpreferences.getstring ("nightweather", "Unknown"));
  temp.settext ("Temperature:" + sharedpreferences.getstring ("temp", "Unknown"));
  wind.settext ("Wind:" + sharedpreferences.getstring ("wind", "Unknown"));
  pop.settext ("Precipitation probability:" + sharedpreferences.getstring ("pop", "Unknown"));
  updatetime.settext ("Release time:" + sharedpreferences.getstring ("updatetime", "Unknown"));
  weatheradapter adapter=new weatheradapter (this, r.layout.hourly_weather, weatherlist);
  listview.setadapter (adapter);
  toast.maketext (weatheractivity.this, "Already the latest data", toast.length_short) .show ();
  weatherrefresh.settext ("Update data");
 }
}

Explanation

It's strange thatThis little app runs without error on my 4.4 version of Xiaomi phone,I can not get data on the 5.1 system simulator and Huawei mobile phone.The returned json data indicates that the city is unknown,I haven't figured it out for a long time,Can only give up ~~

  • Previous Android uses Vitamio to build its own universal player (8)-details optimization
  • Next JavaScript package addLoadEvent method to implement multiple functions to load the page at the same time