1, Initializing the interface in Java code
Initialize the ViewPager interface in MainActivity
private void initPager() { //Create a Fragment object and add it to the ViewPager data source for (int i=0;i<cityList.size();i++){ //Use the for loop to add the contents of the city collection to the fragment collection WeatherFragment weatherFragment = new WeatherFragment(); Bundle bundle = new Bundle(); bundle.putString("city",cityList.get(i)); //Use the bundle to store the city name and transfer it to the fragment weatherFragment.setArguments(bundle); fragmentList.add(weatherFragment); } //Pass the fragment collection into the fragment adapter FragmentPagerAdapter fragmentPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager(),fragmentList); showVp.setAdapter(fragmentPagerAdapter); }
Get the city passed in from MainActivity in WeatherFragment
//Get the weather conditions of the place where the current fragment is loaded by passing the value of the activity Bundle arguments = getArguments(); String city=arguments.getString("city"); getWeatherCity(city);
Write FragmentPagerAdapter to display fragments
public class FragmentPagerAdapter extends FragmentStatePagerAdapter { List<Fragment> fragmentList; //The collection of fragenr passed in from the main interface public FragmentPagerAdapter(FragmentManager fragmentManager,List<Fragment> fragments) { super(fragmentManager); this.fragmentList=fragments; } @NonNull @Override public Fragment getItem(int position) { //Get collection entry content based on location return fragmentList.get(position); } @Override public int getCount() { //Get the number of collection entries return fragmentList.size(); } }
2, Open network request in child thread
Write the NetUtil class, and write two static methods doGet and getWeatherOfCity in the class
The doGet method is used to get data from the network. After the getWeatherOfCity method is used to splice url, the doGet method is called into the url to get weather information.
public static final String URL_WEATHER="https://tianqiapi.com/api?unescape=1&version=v1&appid=22444194&appsecret=EG7XHDop"; public static String doGet(String urlString){ String result=""; String line; StringBuilder stringBuilder=null; BufferedReader bufferedReader=null; //Connect network HttpURLConnection connection=null; InputStreamReader isr=null; try { URL url=new URL(urlString); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); //Link mode connection.setConnectTimeout(5000); //Timeout //Read data from connection (binary) InputStream inputStream=connection.getInputStream(); //Process data flow isr=new InputStreamReader(inputStream); //Create buffer to send binary stream to bufferedReader=new BufferedReader(isr); //Read the string line by line from the buffer stringBuilder=new StringBuilder(); while ((line=bufferedReader.readLine())!=null){ stringBuilder.append(line); //Splice } result=stringBuilder.toString(); } catch (Exception e) { e.printStackTrace(); }finally { try { //Close flow connection.disconnect(); bufferedReader.close(); isr.close(); } catch (IOException e) { e.printStackTrace(); } } return result; } //Splice it to get the url of the weather public static String getWeatherOfCity(String city){ String url=URL_WEATHER+"&city="+city; Log.i("Aye","URL:"+url); Log.i("Aye","URLResult:"+doGet(url)); return doGet(url); }
Write the getWeatherCity method, start the sub thread, call the static method getWeatherOfCity in the NetUtil class to obtain the weather data, and pass the data to the main thread through the handler
private void getWeatherCity(String selectCity) { //Start the sub thread and request the network new Thread(new Runnable() { @Override public void run() { //Request network String weatherOfCity=NetUtil.getWeatherOfCity(selectCity); //Use the handler to pass data to the main thread Message message=Message.obtain(); message.what=0; message.obj=weatherOfCity; handler.sendMessage(message); } }).start(); }
3, Analysis of Json data returned from network request
Use online tools to parse Json data and generate JavaBean import package
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-zejn14mr-1632214033044) (C: \ users \ paranoia \ appdata \ roaming \ typora user images \ image-20210915094807564. PNG)]
Receive the data passed by the child thread and parse it using gson
private Handler handler=new Handler(Looper.myLooper()){ @Override public void handleMessage(@NonNull Message msg) { super.handleMessage(msg); if (msg.what==0){ //Weather data received by the main thread String weather= (String) msg.obj; Log.i("Aye","Weather data received by the main thread:"+weather); //Parsing using gson Gson gson=new Gson(); JsonRootBean jsonRootBean=gson.fromJson(weather, JsonRootBean.class); updateWeather(jsonRootBean); //Update weather data and display } } };
4, Interface presentation
1. Obtain and display weather data
Write the updateWeather method to get the data and display it on the interface
//data display private void updateWeather(JsonRootBean jsonRootBean) { if (jsonRootBean!=null){ List<Data> dayWeather = jsonRootBean.getData(); //Get data for each day Data todayWeather = dayWeather.get(0);//Get today's data //If it is not empty, today's weather data will be displayed if (todayWeather!=null){ tempTv.setText(todayWeather.getTem1()); mainWeatherTv.setText(todayWeather.getWea());; todayTv.setText("today:"+todayWeather.getWea()); todayAirTv.setText("Air:"+todayWeather.getAir_level()); todayTempTv.setText(todayWeather.getTem()+"~"+todayWeather.getTem2()); todayIconIv.setImageResource(getImg(todayWeather.getWea_img())); windTv.setText(todayWeather.getWin_speed()); humidityTv.setText(todayWeather.getHumidity()); pressureTv.setText(todayWeather.getPressure()+"hPa"); windTv1.setText(todayWeather.getWin().get(0)); sunriseTv.setText("Sunrise:"+todayWeather.getSunrise()); sunsetTv.setText("Sunset:"+todayWeather.getSunset()); } //Get tomorrow's data Data tomorrowWeather = dayWeather.get(1); //If it is not empty, tomorrow's data will be displayed if (tomorrowWeather!=null){ tomorrowTv.setText("tomorrow:"+tomorrowWeather.getWea()); tomorrowAirTv.setText("Air:"+tomorrowWeather.getAir_level()); tomorrowTempTv.setText(tomorrowWeather.getTem()+"~"+tomorrowWeather.getTem2()); tomorrowIconIv.setImageResource(getImg(tomorrowWeather.getWea_img())); } //Get the data the day after tomorrow Data afterWeather = dayWeather.get(2); //If it is not blank, the weather data of the day after tomorrow will be displayed if (afterWeather!=null){ afterTv.setText("the day after tomorrow:"+afterWeather.getWea()); afterAirTv.setText("Air:"+afterWeather.getAir_level()); afterTempTv.setText(afterWeather.getTem()+"~"+afterWeather.getTem2()); afterIconIv.setImageResource(getImg(afterWeather.getWea_img())); } //Get index information List<Index> index = todayWeather.getIndex(); //If it is not empty, it will be displayed if (index!=null) { //UV index UVTitle = index.get(0).getTitle(); UVLevel = index.get(0).getLevel(); UVDesc = index.get(0).getDesc(); //Dressing index clotheTitle = index.get(3).getTitle(); clotheLevel = index.get(3).getLevel(); clotheDesc = index.get(3).getDesc(); //Motion index sportTitle=index.get(1).getTitle(); sportLevel=index.get(1).getLevel(); sportDesc=index.get(1).getDesc(); //Car washing index carTitle=index.get(4).getTitle(); carLevel=index.get(4).getLevel(); carDesc=index.get(4).getDesc(); //Glycemic index sickTitle=index.get(2).getTitle(); sickLevel=index.get(2).getLevel(); sickDesc=index.get(2).getDesc(); //Air pollution index airTitle=index.get(5).getTitle(); airLevel=index.get(5).getLevel(); airDesc=index.get(5).getDesc(); } //Get hourly weather conditions and pass them to the Adapter for display List<Hours> timeBean = todayWeather.getHours(); weatherAdapter=new WeatherAdapter(getActivity(),timeBean); LinearLayoutManager manager=new LinearLayoutManager(getActivity(), RecyclerView.HORIZONTAL,false); hoursRv.setAdapter(weatherAdapter); hoursRv.setLayoutManager(manager); } }
2. Display corresponding pictures according to weather conditions
Write the getImg method to display pictures according to weather conditions
private int getImg(String wea_img) { int result = 0; switch (wea_img) { case "qing": //a sunny day result=R.mipmap.sun; break; case "yin": //overcast result=R.mipmap.yin; break; case "yu": //rain result=R.mipmap.yu; break; case "yun": //cloudy result=R.mipmap.yun; break; case "bingbao": //hail result=R.mipmap.bingbao; break; case "wu": //fog result=R.mipmap.wu; break; case "shachen": //sand storm result=R.mipmap.shachen; break; case "lei": //thunder result=R.mipmap.lei; break; case "xue": //snow result=R.mipmap.xue; break; default: //If none, the display is clear result=R.mipmap.sun; break; } return result; }
3. Display hourly weather conditions
Write a WeatherAdapter to display hourly weather conditions
public class WeatherAdapter extends RecyclerView.Adapter<WeatherAdapter.WeatherViewHolder> { private Context context; //context private List<Hours> timeBean; //Weather information public WeatherAdapter(Context context, List<Hours> timeBean) { this.context = context; this.timeBean = timeBean; } @NonNull @Override //Create ViewHolder public WeatherViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view= LayoutInflater.from(context).inflate(R.layout.recylerview_item,parent,false); WeatherViewHolder weatherViewHolder=new WeatherViewHolder(view); return weatherViewHolder; } @Override //Bind ViewHolder to display data public void onBindViewHolder(@NonNull WeatherViewHolder holder, int position) { Hours hoursBean = timeBean.get(position); //Obtain and display the weather information of the hour according to the location holder.timeTv.setText(hoursBean.getHours()); holder.timeWeatherTv.setText(hoursBean.getWea()); holder.timeTempTv.setText(hoursBean.getTem()); holder.timeWindTv.setText(hoursBean.getWin()+" "+hoursBean.getWin_speed()); } @Override //Get the number of entries public int getItemCount() { return timeBean.size(); } //ViewHolder class WeatherViewHolder extends RecyclerView.ViewHolder { TextView timeTv; TextView timeTempTv; TextView timeWeatherTv; TextView timeWindTv; public WeatherViewHolder(@NonNull View itemView) { //Object and control binding super(itemView); timeTv = itemView.findViewById(R.id.timeTv); timeTempTv = itemView.findViewById(R.id.timeTempTv); timeWeatherTv = itemView.findViewById(R.id.timeWeatherTv); timeWindTv = itemView.findViewById(R.id.timeWindTv); } } }
4. Click event listener
Set click events to display the details of various indexes and jump to the browser to see more weather
@Override public void onClick(View v) { switch (v.getId()){ case R.id.webTv: //Click "view more weather" to jump to the browser interface Uri uri=Uri.parse("https://tianqi.qq.com/index.htm"); Intent intent=new Intent(); intent.setAction("android.intent.action.VIEW"); intent.setData(uri); startActivity(intent); break; case R.id.clotheIv: //Click the dressing index to pop up the dialog box showAlertDialog(clotheTitle,clotheLevel,clotheDesc); break; case R.id.UVIv: //Click UV index showAlertDialog(UVTitle,UVLevel,UVDesc); break; case R.id.sportIv: //Click motion index showAlertDialog(sportTitle,sportLevel,sportDesc); break; case R.id.carIv: //Click car wash index showAlertDialog(carTitle,carLevel,carDesc); break; case R.id.airPollutionIv: //Click air pollution index showAlertDialog(airTitle,airLevel,airDesc); break; case R.id.sickIv: //Click glycemic index showAlertDialog(sickTitle,sickLevel,sickDesc); break; } }
Write the showAlertDialog method to display the dialog box
private void showAlertDialog(String title, String level, String desc) { AlertDialog.Builder builder= new AlertDialog.Builder(MainActivity.this); builder.setTitle(title).setMessage("\n"+level+"\n\n"+desc).create().show(); }
5, Database creation and function implementation
Write CityDBHelper, inherit SQLiteOpenHelper and rewrite methods
private static SQLiteDatabase db; ContentValues values=new ContentValues(); private long flag=0; public CityDBHelper(@Nullable Context context) { super(context, "city.db", null, 1); db=this.getWritableDatabase(); } @Override public void onCreate(SQLiteDatabase db) { //Create table String sql = "create table city(id integer primary key autoincrement,city varchar(20) unique not null)"; db.execSQL(sql); } //Add data public boolean addCity(String city){ values.put("city",city); flag=db.insert("city",null,values); return flag>0?true:false; } //Delete data by city name public boolean deleteCity(String city){ flag=db.delete("city","city=?",new String[]{city}); return flag>0?true:false; } //Query all data public List<String> queryCity(){ List<String> cityList=new ArrayList<>(); Cursor cursor=db.query("city",null,null,null,null,null,null); if (cursor!=null){ while (cursor.moveToNext()){ String city=cursor.getString(1); cityList.add(city); } } return cityList; } //Query data by city name public boolean findCity(String city) { Cursor cursor = db.query("city", null, "city=?", new String[]{city}, null, null, null); if (cursor != null) { while (cursor.moveToNext()) { String findCity = cursor.getString(1); Log.i("Aye",findCity+"findCity"); if (findCity != null) { return false; } else { return true; } } } return true; } @Override //Update database public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }
6, Function realization of urban management interface
1. listView Adapter Configuration
Write a CityAdapter that inherits from BaseAdapter and is a listView adapter
private Context context; private List<String> cityList; public CityAdapter(Context context, List<String> cityList) { this.context = context; this.cityList = cityList; } @Override public int getCount() { //Number of collection entries return cityList.size(); } @Override public Object getItem(int position) { //Get entry information based on location return cityList.get(position); } @Override public long getItemId(int position) { //Get location return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder=null; if (convertView==null){ //If convertView is empty, initialize and bind viewHolder=new ViewHolder(); convertView=View.inflate(context, R.layout.city_listview_item,null); viewHolder.cityNameTv=convertView.findViewById(R.id.cityNameTv); convertView.setTag(viewHolder); }else { viewHolder=(ViewHolder)convertView.getTag(); } //Get data and display viewHolder.cityNameTv.setText(cityList.get(position)); return convertView; } class ViewHolder{ TextView cityNameTv; }
4. Control listening events
Add listening events for interface controls, which are used to jump to the add city interface and delete cities
//Add city, jump to the add city interface findTv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(CityActivity.this,AddActivity.class)); } }); //Long press to delete the city showLv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { String deleteCity=cityList.get(position); //Obtain the content according to the long click position //Pop up dialog box AlertDialog.Builder builder= new AlertDialog.Builder(CityActivity.this); builder.setTitle("Tips").setMessage("Delete the weather information of this city?") .setNegativeButton("cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { } }) .setPositiveButton("delete", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //Call the database method to delete the entry flag=cityDBHelper.deleteCity(deleteCity); if (flag){ Toast.makeText(CityActivity.this,"Delete succeeded",Toast.LENGTH_SHORT).show(); initView(); //Send broadcast to update weather data Intent intent=new Intent("UPDATE1"); sendBroadcast(intent); }else { Toast.makeText(CityActivity.this,"Deletion failed",Toast.LENGTH_SHORT).show(); } } }) .create().show(); return true; } });
7, Add city interface function implementation
1. The adapter configuration is realized through the function of adding cities to the provincial capital
private Context context; private List<String> cityList; private CityDBHelper cityDBHelper; public AddAdapter(Context context, List<String> cityList,CityDBHelper cityDBHelper) { this.context = context; this.cityList = cityList; this.cityDBHelper=cityDBHelper; } @NonNull @Override //Create ViewHolder public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view=View.inflate(context,R.layout.add_recylerview_item,null); ViewHolder viewHolder = new ViewHolder(view); return viewHolder; } @Override //Bind ViewHolder, display data and add data public void onBindViewHolder(@NonNull ViewHolder holder, int position) { holder.cityTv.setText(cityList.get(position)); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String clickCity=cityList.get(position); //Get click entry information //Judge whether the clicked item is empty, then judge whether the city has been added to the database, and finally judge whether the addition is successful if (clickCity!=null){ if (cityDBHelper.findCity(clickCity)) { if (cityDBHelper.addCity(clickCity)) { Toast.makeText(context,"Added successfully",Toast.LENGTH_SHORT).show(); //Send broadcast to update weather data Intent intent=new Intent("UPDATE"); context.sendBroadcast(intent); }else { Toast.makeText(context,"Add failed",Toast.LENGTH_SHORT).show(); } }else { Toast.makeText(context,"The city already exists",Toast.LENGTH_SHORT).show(); } } } }); } @Override public int getItemCount() { //Gets the number of collections return cityList.size(); } //ViewHolder class ViewHolder extends RecyclerView.ViewHolder { TextView cityTv; public ViewHolder(@NonNull View itemView) { super(itemView); cityTv=ite mView.findViewById(R.id.itemCityTv); } }
Adapter binding, data transfer
private String[] cityStrings=new String[]{"Beijing","Tianjin","Harbin","Shenyang","Shijiazhuang", "Lanzhou", "Xi'an", "Zhengzhou", "Taiyuan", "Changsha", "Nanjing", "Guiyang", "Hangzhou", "Guangzhou", "Taipei", "Shanghai" , "Chongqing", "Changchun", "Hohhot", "Urumqi", "Xining", "Yinchuan", "Jinan", "Hefei", "Wuhan", "Chengdu", "Lhasa", "Kunming", "Nanchang", "Fuzhou", "Haikou", "Macao"}; cityList=new ArrayList<>(); for (int i=0;i<cityStrings.length;i++){ //Use the for collection to pass array data into the collection cityList.add(cityStrings[i]); } addAdapter=new AddAdapter(this,cityList,cityDBHelper); cityRv.setLayoutManager(new GridLayoutManager(this,3)); //Adapter layout GridLayout, three controls in a row cityRv.setAdapter(addAdapter);
4. Add city function through search
Search key listening event findTv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String findCity=findEt.getText().toString(); //Gets the contents of the input box //Judge whether the input content is empty, then judge whether the city already exists in the database, and finally judge whether it is successfully added if (findCity!=null){ if(cityDBHelper.findCity(findCity)){ if (cityDBHelper.addCity(findCity)) { Toast.makeText(AddActivity.this,"Added successfully",Toast.LENGTH_SHORT).show(); //Use the radio to notify weather updates Intent intent=new Intent("UPDATE"); sendBroadcast(intent); }else { Toast.makeText(AddActivity.this,"Add failed",Toast.LENGTH_SHORT).show(); } }else { Toast.makeText(AddActivity.this,"The city already exists",Toast.LENGTH_SHORT).show(); } }else { Toast.makeText(AddActivity.this,"The input city is empty",Toast.LENGTH_SHORT).show(); } } });
5. Receive the city information update message through broadcasting
Create a broadcast recipient in the CityActivity file
@Override protected void onCreate(Bundle savedInstanceState) { myReceiver=new MyReceiver(); //Instantiate the filter and set the filtered broadcast IntentFilter intentFilter=new IntentFilter(); intentFilter.addAction("UPDATE"); registerReceiver(myReceiver,intentFilter); //Register broadcast } private class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { initView(); //After receiving the broadcast information, update the interface } }
Broadcast recipients are also created in MainActivity
@Override protected void onCreate(Bundle savedInstanceState) { myReceiver=new MyReceiver(); //Instantiate the filter and set the filtered broadcast IntentFilter intentFilter=new IntentFilter(); intentFilter.addAction("UPDATE"); intentFilter.addAction("UPDATE1"); registerReceiver(myReceiver,intentFilter); //Register broadcast } private class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { initPager();/After receiving the broadcast information, update the interface } }