Weather app

Keywords: Android Andriod

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
        }
    }
   

Posted by yzerman on Tue, 21 Sep 2021 16:03:58 -0700