最近在看郭霖大神的《第一行代码》,在第十一章的时候,第一个Demo就出现了问题,书里面用的工具是ecplise+ADT,而现在的趋势是AS。当然这不是关键,随着Android的更新换代,其中相关的技术也有了很多改变,拥抱变化才是我应该做的,当然,作为刚刚入门的菜鸟,打好基础才是关键,成长就是在发现问题和解决问题的过程中。
这个例子的目的是确定自己的位置。废话不多说,上代码:
activity_main:
<TextView
android:id="@+id/position_test_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
MainActivity:
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
public class MainActivity extends AppCompatActivity {
public static final int SHOW_LOCATION = 0;
private TextView positionTextView;
private LocationManager locationManager;
private String provider;
private Location location;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
positionTextView = (TextView) findViewById(R.id.position_test_view);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
// 获取所有可用的位置提供器
List<String> providerList = locationManager.getProviders(true);
if (providerList.contains(LocationManager.GPS_PROVIDER)) {
provider = LocationManager.GPS_PROVIDER;
} else if (providerList.contains(LocationManager.NETWORK_PROVIDER)) {
provider = LocationManager.NETWORK_PROVIDER;
} else {
// 当没有可用的位置提供器时,弹出Toast提示用户
Toast.makeText(this, "No location provider to use",
Toast.LENGTH_SHORT).show();
return;
}
try {//try和catch我在这里卡了好久,说明我对Java的这部分知识并没有掌握
location = locationManager.getLastKnownLocation(provider);
//将选择好的位置提供器传入到getLastKnownLocation方法中
} catch (SecurityException e) {//这里为什么要用SecurityException呢?
e.printStackTrace();
}
if (location != null) {
// 显示当前设备的位置信息
showLocation(location);
}
try {
//实时更新地理信息
locationManager.requestLocationUpdates(provider, 5000, 1, locationListener);
//调用了requestLocationUpdates()方法来添加一个位置监听器,设置时间间隔是5秒,距离间隔是1米
} catch (SecurityException e) {
e.printStackTrace();
}
}
protected void onDestroy() {
super.onDestroy();
if (locationManager != null) {
// 关闭程序时将监听器移除
try {
locationManager.removeUpdates(locationListener);
}catch(SecurityException e){
e.printStackTrace();
}
}
}
LocationListener locationListener = new LocationListener() {
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onLocationChanged(Location location) {
// 更新当前设备的位置信息
showLocation(location);
}
};
private void showLocation(final Location location) {
new Thread(new Runnable() {
@Override
public void run() {//要在这里发起网络请求,所以开启一个子线程
try {
// 组装反向地理编码的接口地址
StringBuilder url = new StringBuilder();
url.append("http://maps.googleapis.com/maps/api/geocode/json?latlng=");
url.append(location.getLatitude()).append(",").append(location.getLongitude());
url.append("&sensor=false");
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url.toString());
// 在请求消息头中指定语言,保证服务器会返回中文数据
httpGet.addHeader("Accept-Language", "zh-CN");
HttpResponse httpResponse = httpClient.execute(httpGet);
if (httpResponse.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = httpResponse.getEntity();
String response = EntityUtils.toString(entity, "utf-8");
JSONObject jsonObject = new JSONObject(response);
// 获取results节点下的位置信息
JSONArray resultArray = jsonObject.getJSONArray("results");
if (resultArray.length() > 0) {
JSONObject subObject = resultArray.getJSONObject(0);
// 取出格式化后的位置信息
String address = subObject.getString("formatted_address");
Message message = new Message();
message.what = SHOW_LOCATION;
message.obj = address;
handler.sendMessage(message);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case SHOW_LOCATION:
String currentPosition = (String) msg.obj;
positionTextView.setText(currentPosition);
break;
default:
break;
}
}
};
}
例子比较长,需要耐心看一下。一开始,我照着书上的代码敲了一遍,好多的问题,最后locationManager
三处的错误怎么也消不掉,我把错误信息搜了一下,知道要加try,catch块,可是我并不知道怎么加,后来好不用容易找到了代码,才改正过来
try {
要添加的代码块
}catch(SecurityException e){
e.printStackTrace();
}
其实就是这么简单,可是我没发现。
还有一个问题HttpClient
等一系列函数会发现是错的,其实是Android 6.0版本已经已经基本将Apahce Http Client
移除出SDK。来看看官方怎么说的:
Apache HTTP Client Removal
Android 6.0 release removes support for the Apache HTTP client. If your app is using this client and targets Android 2.3 (API level 9) or higher, use the HttpURLConnection class instead. This API is more efficient because it reduces network use through transparent compression and response caching, and minimizes power consumption. To continue using the Apache HTTP APIs, you must first declare the following compile-time dependency in your build.gradle file:
android {
useLibrary 'org.apache.http.legacy'
}
所以在build.gradle中加入上面的配置就行了。
最后不要忘记设置权限(AndroidManifest.xml):
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>