主要功能:
- 登录、注册(需要有Web端):这个很好写,我使用SpringBoot搭建的Web端,配置好Mybatis,编写Dao层、Service层和Controller层就基本完成了。
- 首页显示所在地天气信息:通过网络定位获取所在位置的经纬度,然后调用高德的逆地理编码API将经纬度作为参数传入,解析返回结果,获取adcode(行政区编码),再调用高德天气查询API将adcode作为参数传入,解析返回的结果得到今天、明天、后天的天气信息,通过ListVIew将其显示出来。
- 查询其他城市天气信息:在输入框中输入要查询的城市、省份等位置信息,点击查询按钮,调用高德的地理编码API将城市名、省份或其他位置作为参数传入,解析返回结果,获取adcode,剩下的操作同上。
效果图:
Web端主要代码实现:
@RestController
public class UserController {
@Autowired
UserService userService;
/**
* 负责Android端登录请求
*
* @param username
* @param password
* @return
*/
@PostMapping("/login")
public String login(@RequestParam("username") String username, @RequestParam("password") String password) {
// 根据用户名和密码查询该用户是否存在
User user = new User(null, username, password);
boolean canLogin = userService.checkLogin(user);
// 若该用户存在返回登录成功信息
if (canLogin) {
return "LOGIN_SUCCESS";
}
// 若该用户不存在返回登录失败信息
return "LOGIN_FAIL";
}
/**
* 负责Android端注册请求
*
* @param username
* @param password
* @return
*/
@PostMapping("/register")
public String register(@RequestParam("username") String username, @RequestParam("password") String password) {
// 查询该用户名是否存在,若存在返回用户已存在信息
if (userService.checkExistUserName(username)) {
return "USER_EXIST";
}
// 添加用户
User user = new User(null, username, password);
boolean canRegister = userService.checkRegister(user);
// 添加成功返回成功信息
if (canRegister) {
return "REG_SUCCESS";
}
// 添加失败返回失败信息
return "REG_FAIL";
}
}
Android端主要代码实现:
- 在manifest文件中声明权限、Service和apikey:(apikey需要在高德控制台申请,创建应用后,点击添加key,选择服务平台,使用定位服务选择Android平台,使用天气查询API服务和地理编码服务选择Web服务,不要弄混)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.youngpain.weatherf">
<!--用于访问网络,网络定位需要上网-->
<uses-permission android:name="android.permission.INTERNET" />
<!--用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!--用于访问GPS定位-->
<!--<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />-->
<!--用于获取运营商信息,用于支持提供运营商信息相关的接口-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--用于访问wifi网络信息,wifi信息会用于进行网络定位-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!--用于获取wifi的获取权限,wifi信息会用来进行网络定位-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<application
android:allowBackup="true"
android:icon="@drawable/weather"
android:label="@string/app_name"
android:roundIcon="@drawable/weather"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".activity.Login">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--application标签中声明service组件,每个app拥有自己单独的定位service-->
<service android:name="com.amap.api.location.APSService" />
<!--设置apikey-->
<meta-data
android:name="com.amap.api.v2.apikey"
android:value="你在高德控制台申请的Android平台服务的apikey" />
<activity android:name=".activity.ShowWeather" />
<activity android:name=".activity.SearchWeather" />
<activity android:name=".activity.Register" />
</application>
</manifest>
public class Login extends AppCompatActivity {
//控件
private EditText nameEdit;
private EditText pwdEdit;
private Button loginButton;
private Button notLoginButton;
private Button registerButton;
//定义状态码
private final int ERROR = 0;
private final int LOGIN_FAIL = 1;
private final int LOGIN_SUCCESS = 2;
//保存用户信息
private String username;
private String password;
//构建Web端登录请求URL
private final String url = "http://192.168.0.101:8080/user/login";
//使用OkHttpClient进行网络请求
private OkHttpClient httpClient = new OkHttpClient();
@SuppressLint("HandlerLeak")
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case ERROR:
//获取Message中的内容
String message0 = (String) msg.obj;
//Toast弹出错误
Toast.makeText(Login.this, message0, Toast.LENGTH_SHORT).show();
break;
case LOGIN_FAIL:
//获取Message中的内容
String message1 = (String) msg.obj;
//Toast弹出登录失败
Toast.makeText(Login.this, message1, Toast.LENGTH_SHORT).show();
break;
case LOGIN_SUCCESS:
//获取Message中的内容
String message2 = (String) msg.obj;
//Toast弹出登录成功
Toast.makeText(Login.this, message2, Toast.LENGTH_SHORT).show();
//登录成功跳转到个人信息页面
startActivity(new Intent(Login.this, ShowWeather.class));
finish();
break;
default:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//去除标题栏
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.login);
//初始化
init();
}
private void init() {
//获取控件
nameEdit = findViewById(R.id.login_et_user);
pwdEdit = findViewById(R.id.login_et_password);
loginButton = findViewById(R.id.bt_login);
//绑定监听事件
loginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//获取用户名和密码
username = nameEdit.getText().toString().trim();
password = pwdEdit.getText().toString().trim();
if ("".equals(username) || "".equals(password)) {
Toast.makeText(Login.this, "用户名或密码不能为空"
, Toast.LENGTH_SHORT).show();
} else {
//调用login()方法请求Web端
login(username, password);
}
}
});
notLoginButton = findViewById(R.id.not_login);
notLoginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(Login.this, ShowWeather.class));
}
});
registerButton = findViewById(R.id.register_user);
registerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(Login.this, Register.class));
}
});
}
/**
* 发送登录请求到Web端
*
* @param username
* @param password
*/
private void login(String username, String password) {
//创建请求表单
RequestBody body = new FormBody.Builder()
.add("username", username)//添加用户名
.add("password", password)//添加密码
.build();
//创建请求
final Request request = new Request.Builder().url(url).post(body).build();
//在子线程中获取服务器响应
new Thread(new Runnable() {
@Override
public void run() {
Response response = null;
try {
response = httpClient.newCall(request).execute();