Bootstrap

基于Android平台开发,天气预报APP

1.项目功能思维导图

在这里插入图片描述

2. 项目涉及到的技术点

  1. 数据来源:和风天气API
  2. 使用okhttp网络请求框架获取api数据
  3. 使用gson库解析json数据
  4. 使用RecyclerView+adapter实现未来7天列表展示和天气指数
  5. 使用PopupMenu 实现弹出选项框
  6. 使用动画+定时器实现欢迎页倒计时和logo动画
  7. 使用TextToSpeech 实现语音播报

3.项目截图

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

4.部分代码功能实现

  1. 欢迎页实现
public class WelcomeActivity extends AppCompatActivity {

    private TextView tvCountdown;
    private CardView card_logo;
    private CountDownTimer countDownTimer;
    private long timeLeftInMillis = 1000; // 设置倒计时时长,单位为毫秒



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        //初始化控件
        tvCountdown = findViewById(R.id.tv_countdown);
        card_logo = findViewById(R.id.card_logo);
        // 启动倒计时
        startCountdown();

        //实现logo缩放动画
        startAnim();

    }

    private void startAnim() {
        ViewCompat.animate(card_logo)
                .scaleX(1.0f)
                .scaleY(1.0f)
                .setDuration(1000)
                .setListener(new ViewPropertyAnimatorListener() {
                    @Override
                    public void onAnimationStart(View view) {

                    }

                    @Override
                    public void onAnimationEnd(View view) {

                    }

                    @Override
                    public void onAnimationCancel(View view) {

                    }
                })
                .start();
    }


    private void startCountdown() {
        countDownTimer = new CountDownTimer(timeLeftInMillis, 1000) {
            @Override
            public void onTick(long millisUntilFinished) {
                timeLeftInMillis = millisUntilFinished;
                int secondsRemaining = (int) (millisUntilFinished / 1000);
                tvCountdown.setText(secondsRemaining + "s | 跳转");
            }

            @Override
            public void onFinish() {
                //跳转到登录页面(看自己逻辑想跳转哪个页面)
                startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                // 倒计时结束后的操作,例如跳转到主页面
                finish();

            }
        }.start();

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (countDownTimer != null) {
            countDownTimer.cancel();
        }
    }
}
  1. 天气指数
public class IndicesActivity extends AppCompatActivity {
    private String city_id;

    private RecyclerView recyclerView;
    private IndicesListAdapter mIndicesListAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_indices);
        //获取跳转传值
        city_id = getIntent().getStringExtra("city_id");
        //获取生活指数
        getWeatherIndices(city_id);
        //初始化控件
        initViews();
        //初始化适配器
        mIndicesListAdapter = new IndicesListAdapter();
        //设置适配器
        recyclerView.setAdapter(mIndicesListAdapter);
        //设置监听器
        setListener();
    }


    /**
     * 初始化控件
     */
    private void initViews() {
        recyclerView = findViewById(R.id.recyclerView);

    }

    /**
     * 设置监听器
     */
    private void setListener() {

        findViewById(R.id.toolbar).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });
    }


    /**
     * 获取生活指数
     */
    private void getWeatherIndices(String city_id) {
        OkGo.<String>get("https://devapi.qweather.com/v7/indices/1d")
                .params("location", city_id)
                .params("key", ApiConstants.APP_KEY)
                .params("type", "0")
                .execute(new StringCallback() {
                    @Override
                    public void onStart(Request<String, ? extends Request> request) {
                        super.onStart(request);
                        ProgressDialogUtils.showProgressDialog(IndicesActivity.this);
                    }

                    @Override
                    public void onSuccess(Response<String> response) {
                        IndicesInfo indicesInfo = new Gson().fromJson(response.body(), IndicesInfo.class);
                        if (null != indicesInfo && indicesInfo.getCode().equals("200")) {
                            mIndicesListAdapter.setIndicesInfoList(indicesInfo.getDaily());
                        }
                    }

                    @Override
                    public void onFinish() {
                        super.onFinish();
                        ProgressDialogUtils.hideProgressDialog();
                    }
                });
    }
}
  1. 城市搜索
public class SearchActivity extends AppCompatActivity {
    private EditText et_search_city;
    private RecyclerView recyclerView;
    private LinearLayoutCompat ll_empty;

    private SearchListAdapter mSearchListAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search);

        // 1. 初始化控件
        initViews();
        //创建适配器
        mSearchListAdapter = new SearchListAdapter();
        //设置适配器
        recyclerView.setAdapter(mSearchListAdapter);
        // 2. 点击事件
        setListener();


    }

    /**
     * 初始化控件
     */
    private void initViews() {
        et_search_city = findViewById(R.id.et_search_city);
        recyclerView = findViewById(R.id.recyclerView);
        ll_empty = findViewById(R.id.ll_empty);
    }

    /**
     * 点击事件
     */
    private void setListener() {
        findViewById(R.id.btn_search).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 1. 获取输入框的值
                String cityName = et_search_city.getText().toString().trim();
                // 2. 判断是否为空
                if (cityName.isEmpty()) {
                    // 提示用户
                    Toast.makeText(SearchActivity.this, "城市名不能为空", Toast.LENGTH_SHORT).show();
                } else {
                    searchCity(cityName);
                }
            }
        });


        //返回
        findViewById(R.id.toolbar).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                finish();
            }
        });


        //recyclerView点击事件
        mSearchListAdapter.setOnItemClickListener(new SearchListAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(CityLocationInfo.LocationDTO locationDTO) {
                // 1. 获取城市名
                String cityName = locationDTO.getName();
                Intent intent = new Intent();
                intent.putExtra("cityName", cityName);
                intent.putExtra("id", locationDTO.getId());
                //设置跳转回传的值
                setResult(1000, intent);
                // 3. 关闭当前界面
                finish();
            }
        });
    }


    /**
     * 城市搜索
     */
    private void searchCity(String cityName) {

        OkGo.<String>get("https://geoapi.qweather.com/v2/city/lookup").params("location", cityName).params("key", ApiConstants.APP_KEY).execute(new StringCallback() {
            @Override
            public void onStart(Request<String, ? extends Request> request) {
                super.onStart(request);
                ProgressDialogUtils.showProgressDialog(SearchActivity.this);
            }

            @Override
            public void onSuccess(Response<String> response) {
                CityLocationInfo cityLocationInfo = new Gson().fromJson(response.body(), CityLocationInfo.class);
                if (null != cityLocationInfo && cityLocationInfo.getCode().equals("200")) {
                    if (null != mSearchListAdapter) {
                        mSearchListAdapter.setCityLocationInfoList(cityLocationInfo.getLocation());
                    }
                    //判断是否显示空布局
                    if (mSearchListAdapter.getItemCount() > 0) {
                        ll_empty.setVisibility(View.GONE);
                    } else {
                        ll_empty.setVisibility(View.VISIBLE);
                    }
                } else {
                    Toast.makeText(SearchActivity.this, "未查询到该城市", Toast.LENGTH_SHORT).show();
                }
            }

            @Override
            public void onError(Response<String> response) {
                super.onError(response);
            }

            @Override
            public void onFinish() {
                super.onFinish();
                ProgressDialogUtils.hideProgressDialog();
            }
        });


    }
}
;