1 参考资料
1.知心天气接口实现传送门
2.对于获取的JSON数据的解析传送门
3.@BindView的用法的用法,(通过直接导入包即可实现,不需要下载重启软件)传送门
4.OKhttp的教程传送门
5.腾讯集成的webView的使用传送门
6.安卓自带的LocationManager实现定位功能(通过经纬度来获取详细信息)传送门
2 项目备注
1 contains方法是字符串addUrl存在在url中,(不仅仅是一个字符,一串字符串也可以),即字符串的包含
2 res.getStringArray(R.array.adUrls);获取资源中的文件信息.
Resources res = MainActivity.this.getResources();
String[] filterUrls = res.getStringArray(R.array.adUrls);
for (String adUrl : filterUrls) {
if (url.contains(adUrl)) {
return true;
}
}
3 OKhttp的异步请求结果回调
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("数据:", "请求失败");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d("数据:", "请求成功");
String responseData = response.body().string();
Log.d("原数据", responseData);//显示原始数据和解析后的数据
//解析SSON数据
try {
JSONObject jsonObject = new JSONObject(responseData);
JSONArray results = jsonObject.getJSONArray("results"); //得到键为results的JSONArray
JSONObject now = results.getJSONObject(0).getJSONObject("now");//得到键值为"now"的JSONObject
JSONObject location = results.getJSONObject(0).getJSONObject("location"); //得到键值为location的JSONObject
city.setText(location.getString("name"));
wear.setText(now.getString("text"));
tempe.setText(now.getString("temperature"));
} catch (JSONException e) {
e.printStackTrace();
}
}
});
4 webView对于请求的所有网址信息(可以通过过滤一部分网址信息,来实现对于广告的过滤功能)
webView.setWebViewClient(new WebViewClient() {
@Override//去除指定的广告库里面的链接
public WebResourceResponse shouldInterceptRequest(WebView webView, String url) {
Log.d("请求的链接", url);
//判断是否是广告相关的资源链接
if (!isAdTool(url)) {
//这里是不做处理的数据
return super.shouldInterceptRequest(webView, url);
} else {
//有广告的请求数据,我们直接返回空数据,注:不能直接返回null
return new WebResourceResponse(null, null, null);
}
}
});
5 webView访问的时候加入进度条的实现(通过布局的方式实现)
布局代码实现
<FrameLayout
android:id="@+id/web_frame"
android:layout_width="match_parent"
android:visibility="gone"
android:layout_height="match_parent">
<com.tencent.smtt.sdk.WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ProgressBar
android:id="@+id/pb"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:progressDrawable="@drawable/barcolor"
android:layout_height="1dp"
/>
</FrameLayout>
********实现代码***********
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
//进度条使用
if (newProgress == 100) {
pb.setVisibility(View.GONE);
} else {
if (View.GONE == pb.getVisibility()) {
pb.setVisibility(View.VISIBLE);
}
pb.setProgress(newProgress);
}
super.onProgressChanged(view, newProgress);
}
});
- 动态申请权限方法
private String[] permissions = {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
};
private void requestPermission(int requestCode) {
ActivityCompat.requestPermissions(this,
permissions, requestCode);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (permissions == null || grantResults == null) {
return;
}
if (grantResults.length < 2 || grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) {
return;
}
if (requestCode == REQUEST_PERMISSION_CODE) {
getLocalAddress();//权限申请成功后返回执行的方法
}
}
7 .系统返回键连续点击2次后退出实现
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
if ((System.currentTimeMillis() - exitTime) > 2000) //System.currentTimeMillis()无论何时调用,肯定大于2000
{
//返回上一个界面
if(linearMain.getVisibility()==View.GONE){
linearMain.setVisibility(View.VISIBLE);
OkLinear.setVisibility(View.GONE);
webFrame.setVisibility(View.GONE);
}else{
Toast.makeText(getApplicationContext(), "再按一次退出程序", Toast.LENGTH_SHORT).show();
exitTime = System.currentTimeMillis();
}
} else {
finish();
System.exit(0);
}
return true;
}
return super.onKeyDown(keyCode, event); //默认返回true,true的时候退出,flash的时候不退出.
}
3.代码实现
package com.example.weatherdemo;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import com.tencent.smtt.export.external.interfaces.WebResourceResponse;
import com.tencent.smtt.sdk.WebChromeClient;
import com.tencent.smtt.sdk.WebSettings;
import com.tencent.smtt.sdk.WebView;
import com.tencent.smtt.sdk.WebViewClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MainActivity extends AppCompatActivity {
@BindView(R.id.webInfo)
Button webInfo;
@BindView(R.id.OKInfo)
Button OKInfo;
@BindView(R.id.linearMain)
LinearLayout linearMain;
@BindView(R.id.cityinput)
EditText cityinput;
@BindView(R.id.search)
Button search;
@BindView(R.id.local)
Button local;
@BindView(R.id.city)
TextView city;
@BindView(R.id.wear)
TextView wear;
@BindView(R.id.tempe)
TextView tempe;
@BindView(R.id.OkLinear)
LinearLayout OkLinear;
@BindView(R.id.webView)
WebView webView;
@BindView(R.id.pb)
ProgressBar pb;
@BindView(R.id.web_frame)
FrameLayout webFrame;
/*天气软件
1.获取当前的位置
2.通过位置信息获取当前信息
3.通过腾讯封装的webView实现天气信息
*/
private String[] permissions = {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
};
private static final int REQUEST_PERMISSION_CODE = 12;
private LocationManager locationManager;
private LinkedHashMap<String, String> infoMap = new LinkedHashMap<>();
private String cityName;
private String urlRoot="https://api.seniverse.com/v3/weather/now.json?key=S6QNx9n_ieuY_dtH_&location=";
private boolean isExit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
webInfo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
linearMain.setVisibility(View.GONE);
webFrame.setVisibility(View.VISIBLE);
OkLinear.setVisibility(View.GONE);
//webView的链接
String url="https://m.weather.com.cn/mweather/101010100.shtml";
webLoadUrl(url);
}
});
OKInfo.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
linearMain.setVisibility(View.GONE);
webFrame.setVisibility(View.GONE);
OkLinear.setVisibility(View.VISIBLE);
okHttpRequest(urlRoot+"北京");
}
});
search.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
cityName=cityinput.getText().toString().trim();
if(cityName!=null&&!cityName.equals("")){
okHttpRequest(urlRoot+cityName);
}else{
Toast.makeText(MainActivity.this,"请输入城市名称",Toast.LENGTH_LONG).show();
}
}
});
local.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//打开权限,开始运行获取当前位置
requestPermission(REQUEST_PERMISSION_CODE);
//显示天气信息
}
});
}
//okhttp请求网络数据
public void okHttpRequest(String url) {
OkHttpClient okHttpClient = new OkHttpClient();
//创建Request对象
final Request request = new Request.Builder()
.url(url)
//.addHeader("key","value")
.get()
.build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Log.d("数据:", "请求失败");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d("数据:", "请求成功");
String responseData = response.body().string();
Log.d("原数据", responseData);//显示原始数据和解析后的数据
//解析SSON数据
try {
JSONObject jsonObject = new JSONObject(responseData);
JSONArray results = jsonObject.getJSONArray("results"); //得到键为results的JSONArray
JSONObject now = results.getJSONObject(0).getJSONObject("now");//得到键值为"now"的JSONObject
JSONObject location = results.getJSONObject(0).getJSONObject("location"); //得到键值为location的JSONObject
city.setText(location.getString("name"));
wear.setText(now.getString("text"));
tempe.setText(now.getString("temperature"));
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
private void webLoadUrl(String url) {
// 支持javascript
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebContentsDebuggingEnabled(true);
// 自适应屏幕大小
webView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
webView.loadUrl(url);
webView.setWebViewClient(new WebViewClient() {
@Override//去除指定的广告库里面的链接
public WebResourceResponse shouldInterceptRequest(WebView webView, String url) {
Log.d("请求的链接", url);
//判断是否是广告相关的资源链接
if (!isAdTool(url)) {
//这里是不做处理的数据
return super.shouldInterceptRequest(webView, url);
} else {
//有广告的请求数据,我们直接返回空数据,注:不能直接返回null
return new WebResourceResponse(null, null, null);
}
}
});
webView.setWebChromeClient(new WebChromeClient() {
@Override
public void onProgressChanged(WebView view, int newProgress) {
//进度条使用
if (newProgress == 100) {
pb.setVisibility(View.GONE);
} else {
if (View.GONE == pb.getVisibility()) {
pb.setVisibility(View.VISIBLE);
}
pb.setProgress(newProgress);
}
super.onProgressChanged(view, newProgress);
}
});
}
//判断是否为广告(指定的广告库)
private boolean isAdTool(String url) {
Resources res = MainActivity.this.getResources();
String[] filterUrls = res.getStringArray(R.array.adUrls);
for (String adUrl : filterUrls) {
if (url.contains(adUrl)) {
return true;
}
}
return false;
}
private void getLocalAddress() {
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
boolean providerEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (providerEnabled) {//GPS已经开启
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
/**
* 绑定监听
* 参数1,设备:有GPS_PROVIDER和NETWORK_PROVIDER两种,前者是GPS,后者是GPRS以及WIFI定位
* 参数2,位置信息更新周期.单位是毫秒
* 参数3,位置变化最小距离:当位置距离变化超过此值时,将更新位置信息
* 参数4,监听
* 备注:参数2和3,如果参数3不为0,则以参数3为准;参数3为0,则通过时间来定时更新;两者为0,则随时刷新
*/
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 1, locationListener);
} else {
Toast.makeText(this, "请打开GPS", Toast.LENGTH_SHORT).show();
}
}
private LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(@NonNull Location location) {
cityName=getLocality(MainActivity.this,
location.getLatitude(), location.getLongitude());
if(cityName!=null&&!cityName.equals("")&&!cityName.equals("unknown")){
okHttpRequest(urlRoot+cityName);
Log.d("城市",cityName);
}else {
Log.d("城市","定位失败");
}
// //位置信息变化时触发
// infoMap.put("纬度", location.getLatitude() + "");
// infoMap.put("经度", location.getLongitude() + "");
// infoMap.put("海拔", location.getAltitude() + "");
// infoMap.put("国家", getCountryName(MainActivity.this,
// location.getLatitude(), location.getLongitude()) + "");
// infoMap.put("城市", getLocality(MainActivity.this,
// location.getLatitude(), location.getLongitude()) + "");
// infoMap.put("街道", getStreet(MainActivity.this,
// location.getLatitude(), location.getLongitude()) + "");
// StringBuffer stringBuffer = new StringBuffer();
// for (String key : infoMap.keySet()) {
// stringBuffer.append(key + ":" + infoMap.get(key));
// }
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
//GPS状态变化时触发
switch (status) {
case LocationProvider.AVAILABLE:
Log.e("onStatusChanged", "当前GPS状态为可见状态");
break;
case LocationProvider.OUT_OF_SERVICE:
Log.e("onStatusChanged", "当前GPS状态为服务区外状态");
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE:
Log.e("onStatusChanged", "当前GPS状态为暂停服务状态");
break;
}
}
@Override
public void onProviderEnabled(String provider) {
//GPS开启时触发
Log.e("xyh", "GPS开启: ");
}
@Override
public void onProviderDisabled(String provider) {
//GPS禁用时触发
Log.e("xyh", "GPS禁用: ");
}
};
private void requestPermission(int requestCode) {
ActivityCompat.requestPermissions(this,
permissions, requestCode);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (permissions == null || grantResults == null) {
return;
}
if (grantResults.length < 2 || grantResults[0] != PackageManager.PERMISSION_GRANTED || grantResults[1] != PackageManager.PERMISSION_GRANTED) {
return;
}
if (requestCode == REQUEST_PERMISSION_CODE) {
getLocalAddress();
}
}
/**
* 根据经纬度获取地理位置
*
* @param context 上下文
* @param latitude 纬度
* @param longitude 经度
* @return {@link Address}
*/
public static Address getAddress(Context context, double latitude, double longitude) {
Geocoder geocoder = new Geocoder(context, Locale.getDefault());
try {
List<Address> addresses = geocoder.getFromLocation(latitude, longitude, 1);
if (addresses.size() > 0)
return addresses.get(0);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 根据经纬度获取所在国家
*
* @param context 上下文
* @param latitude 纬度
* @param longitude 经度
* @return 所在国家
*/
public static String getCountryName(Context context, double latitude, double longitude) {
Address address = getAddress(context, latitude, longitude);
return address == null ? "unknown" : address.getCountryName();
}
/**
* 根据经纬度获取所在地
*
* @param context 上下文
* @param latitude 纬度
* @param longitude 经度
* @return 所在地
*/
public static String getLocality(Context context, double latitude, double longitude) {
Address address = getAddress(context, latitude, longitude);
return address == null ? "unknown" : address.getAdminArea();
}
/**
* 根据经纬度获取所在街道
*
* @param context 上下文
* @param latitude 纬度
* @param longitude 经度
* @return 所在街道
*/
public static String getStreet(Context context, double latitude, double longitude) {
Address address = getAddress(context, latitude, longitude);
return address == null ? "unknown" : address.getFeatureName();
}
@Override
protected void onDestroy() {
super.onDestroy();
removeListener();
}
public void removeListener() {
if (locationManager != null) {
locationManager.removeUpdates(locationListener);
}
}
long exitTime=0;
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) {
if ((System.currentTimeMillis() - exitTime) > 2000) //System.currentTimeMillis()无论何时调用,肯定大于2000
{
//返回上一个界面
if(linearMain.getVisibility()==View.GONE){
linearMain.setVisibility(View.VISIBLE);
OkLinear.setVisibility(View.GONE);
webFrame.setVisibility(View.GONE);
}else{
Toast.makeText(getApplicationContext(), "再按一次退出程序", Toast.LENGTH_SHORT).show();
exitTime = System.currentTimeMillis();
}
} else {
finish();
System.exit(0);
}
return true;
}
return super.onKeyDown(keyCode, event);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:id="@+id/linearMain"
android:orientation="horizontal"
android:paddingTop="100dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/webInfo"
android:text="webView获取天气"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/OKInfo"
android:text="OKhttp获取天气"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:id="@+id/OkLinear"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="100dp"
android:visibility="gone">
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
<EditText
android:id="@+id/cityinput"
android:hint="请输入城市"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/search"
android:text="查询天气"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/local"
android:text="当地天气"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<TextView
android:id="@+id/city"
android:text="城市:"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/wear"
android:text="天气情况:"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tempe"
android:text="温度:"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<FrameLayout
android:id="@+id/web_frame"
android:layout_width="match_parent"
android:visibility="gone"
android:layout_height="match_parent">
<com.tencent.smtt.sdk.WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ProgressBar
android:id="@+id/pb"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:progressDrawable="@drawable/barcolor"
android:layout_height="1dp"
/>
</FrameLayout>
</LinearLayout>