安卓盒子launcher界面开发之添加自动定位,获取当地天气
Posted yun382657988
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓盒子launcher界面开发之添加自动定位,获取当地天气相关的知识,希望对你有一定的参考价值。
最近老板要求在launcher界面做个自动定位,并获取当地天气的功能,中间走了不少弯路,我在这里都写下来,希望看到这篇文章的人,能少走点弯路。(先上图,嘿嘿)
1、接到任务后,我首先想的是,先把天气获取到(比如获取深圳本地的),然后再做定位的功能
有了大致的思路后,就着手开始做了,因为公司是做国外的生意,所以用的是雅虎的api,说起来雅虎,年前自己搞个天气玩了下,用的就是雅虎的,是解析woeid的,当时是可以用的,不清楚从什么时候用不了
就变成了如下这样
然后就到雅虎的官网上找别的方法https://developer.yahoo.com/weather/,因为之前参考网上的例子,原作者是用sax解析xml,我也就依葫芦画瓢想用sax解析,xml是这样的
ok,但是后来发现,遇到了困难,用的方法不对。想了下,还是用json的解析,比较熟悉些。然后访问雅虎返回的json数据是这样的
是不是看着头都大了,本菜菜当时一看顿时吓尿,这里推荐一个在线转换json格式(http://json.cn/)
效果图是这样的
是不是感觉清晰了很多?
这里返回的数据,需要层层递取的,下面贴代码,
这里我用了voelly框架,封装好的方法,用起来就是爽,话说还没用过的请自行百度,真的很好用(哈哈,这里感谢基友浩的鼎力帮助)
private RequestQueue mQueue;
mQueue = Volley.newRequestQueue(this);
需要导包的
private void getData(String url) {//解析的方法
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
try {
// JSONObject 解析”query“数组
JSONObject queryJSONObject = (JSONObject) response.getJSONObject("query");
JSONObject channelJSONObject = queryJSONObject.getJSONObject("results").getJSONObject("channel");//逐层取.....
//下面就是要获得的东西咯
JSONObject locationJSONObject = channelJSONObject.getJSONObject("location");
//国家、省份、城市
tx_city.setText(locationJSONObject.getString("city")+" "+locationJSONObject.getString("region")
+ " "+ locationJSONObject.getString("country"));
JSONObject itemJSONObject = channelJSONObject.getJSONObject("item");
//天气情况
JSONArray forecastJSONArray = itemJSONObject.getJSONArray("forecast");
String descriptionString = itemJSONObject.getString("description");
StringBuilder descriptionSB = new StringBuilder(descriptionString);
//获取雅虎的天气图像(蛮丑的,(⊙o⊙)…)
String imgUrl = descriptionSB.substring(
descriptionString.indexOf("<img src=\\"") + "<img src=\\"".length(),
descriptionString.lastIndexOf("\\"/>"));
//Log.d(TAG,"imgUrl++++is"+imgUrl);
for (int i = 0; i < forecastJSONArray.length(); i++) {
//这里我只要当天的天气,取的是“0”
JSONObject dayWeatherJSONObject = forecastJSONArray.getJSONObject(0);
((TextView) findViewById(R.id.tx_condition)).setText(dayWeatherJSONObject.getString("text"));
//得到的是华摄氏度转化为摄氏度
tx_temp.setText("" + (int) (((Integer.parseInt(dayWeatherJSONObject.getString("low")))-32)/1.8) + "/"+ (int)(((Integer.parseInt(dayWeatherJSONObject.getString("high")))-32)/1.8)+ getResources().getString(R.string.str_temp));
//这里取字符串加了个判断
if(imgUrl.length()==37){
String pic=imgUrl.substring(31, 37);
img_weather.setImageResource(parseIcon2(pic));//替换雅虎图片的方法
}else if(imgUrl.length()==36){
String pic=imgUrl.substring(31, 36);
img_weather.setImageResource(parseIcon2(pic));
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new ErrorListener() {
@Override
public void onErrorResponse(VolleyError arg0) {
}
});
mQueue.add(jsonObjectRequest);
}
private int parseIcon2(String strIcon) {
if (strIcon == null)
return -1;
if ("31.gif".equals(strIcon)||"32.gif".equals(strIcon)||
"33.gif".equals(strIcon)||"34.gif".equals(strIcon)||"36.gif".equals(strIcon))
return R.drawable.sunny03;
if ("23.gif".equals(strIcon)||"24.gif".equals(strIcon)||"26.gif".equals(strIcon)||"27.gif".equals(strIcon)||"28.gif".equals(strIcon)
||"30.gif".equals(strIcon)||"44.gif".equals(strIcon))
return R.drawable.cloudy03;
if ("29.gif".equals(strIcon))
return R.drawable.shade03;
if ("40.gif".equals(strIcon))
return R.drawable.shower01;
if ("4.gif".equals(strIcon))
return R.drawable.thunder_shower03;
if ("13.gif".equals(strIcon))
return R.drawable.snow_shower03;
if ("25.gif".equals(strIcon))
return R.drawable.s_snow03;
if ("14.gif".equals(strIcon)||"15.gif".equals(strIcon))
return R.drawable.m_snow03;
if ("16.gif".equals(strIcon)||"42.gif".equals(strIcon))
return R.drawable.l_snow03;
if ("43.gif".equals(strIcon)||"41.gif".equals(strIcon))
return R.drawable.h_snow03;
if ("20.gif".equals(strIcon)||"21.gif".equals(strIcon)||"22.gif".equals(strIcon))
return R.drawable.fog03;
if ("6.gif".equals(strIcon))
return R.drawable.ics_rain;
if ("7.gif".equals(strIcon)||"17.gif".equals(strIcon)||"35.gif".equals(strIcon))
return R.drawable.rain_and_hail;
if ("5.gif".equals(strIcon)||"18.gif".equals(strIcon))
return R.drawable.rain_and_snow;
//--
if ("8.gif".equals(strIcon)||"9.gif".equals(strIcon))
return R.drawable.s_rain03;
//--
if ("10.gif".equals(strIcon))
return R.drawable.m_rain03;
if ("11.gif".equals(strIcon)||"12.gif".equals(strIcon))
return R.drawable.l_rain03;
if ("45.gif".equals(strIcon)||"47.gif".equals(strIcon)||"39.gif".equals(strIcon))
return R.drawable.h_rain03;
if ("38.gif".equals(strIcon))
return R.drawable.hh_rain03;
if ("3.gif".equals(strIcon)||"37.gif".equals(strIcon))
return R.drawable.hhh_rain03;
if ("29.gif".equals(strIcon))
return R.drawable.smoke03;
if ("2.gif".equals(strIcon)||"19.gif".equals(strIcon))
return R.drawable.sand_blowing03;
if ("1.gif".equals(strIcon))
return R.drawable.sand_storm02;
if ("0.gif".equals(strIcon))
return R.drawable.sand_storm03;
return R.drawable.sunny03;
}
上面的这些,已经可以解析出深圳当地的天气啦,在盒子里运行,果断可以显示了,当时是在launcher代码里,用动态广播做了监听,如果有网络,就显示在主页上。
2、下面就是实现定位的功能了(话说也折腾了我很久,且听我详细道来,以后大家开发东西的时候一定要想好,用哪些方法,调用什么,一定要想好,最好写下来,再去实施)
上面说了,公司做的是国外的生意,所以,高德pass了,我们的盒子上没gps,pass,wifi定位的是我后来才想到了,这里,说下,网上资料的一个坑,大家如果用到了这个方法,还是立马停止的好
这里访问google,一是需要翻墙,这个对我们公司倒是没有压力。把现成的方法copy进去,就发现了问题
这里一直得到的是null值,跟了代码,不是很明白,一直走不到下一步,在网上查了下,说是这个google的服务器停了(欲哭无泪),有点怀疑,因为打印,取到的是乱码,我也无从考察,因为时间很紧,果断换了方法了。
然后说下能全球定位的其他两个方法,google和百度,如果单从我们公司出发,肯定google定位是首先,为此我还申请了key。但goolge定位的,需要些services,还有些其他的原因,搞了一天没搞出来,果断换了。
去看了百度这地图的官方文档,上面也有现成的demo可以参考,下载下来过后,运行,定位ok。把需要的code放到源码环境下编译,需要倒入jar包和.so文件。android.mk配置
mm 该工程,编译通过,out目录该工程目录下成功生成了lib文件.so自然在其中了,需要手动把你的.so放到system/lib下,在盒子上测试,你需要把.so放到system/lib下,修改权限,把out目录下生成该工程的apk,push到盒子里,替换,当联网的时候,盒子一直闪屏,查看logcat打印的报错信息,如下:
不可用?!因为之前参考的demo不是最新的.so和jar包,更换了百度最新的.so和jar包,重复上面的过程,还是报同样的错误,在网上搜了一下,说是可能不兼容的处理器,问了下硬件,我们是64位的处理器,但是软件是32的,什么鬼?ok,用笨方法,一个试总可以吧
试完以上的所有.so还是闪屏不断,崩溃了快,这样编译百度.so,jar到系统中,反复测试,耽误了不少时间。一时陷入僵局(这个问题是兼容的问题,还是so文件配置出了问题,到现在也没头绪,如果有大神读到小弟的这篇文章,还请不吝赐教,感谢感谢)。和基友浩交流,决定用强大的SP(SharedPreference)把获得的定位城市数据传递到 launcher APK,可以将apk的数据传递到apk2
打印,得到的"lucy",可是后来遇到个问题,需要传递的是city = res.addressComponents.city;百度定位获得的city,却传不过去了。想了下,用广播的方式传值,有个方法
Intent i = new Intent();
i.setAction("com.example.perference.shared_id");
i.putExtra("city",city);
sendBroadcast(i);
3、城市定位apk与launcher APK的数据传送
连上wifi发送此广播
if((action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION))||action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)||
action.equals(ConnectivityManager.CONNECTIVITY_ACTION)){
Intent send = new Intent();
send.setAction("com.weather.broadcast");
send.putExtra("launcher", "weather");
Launcher.this.sendBroadcast(send);
Log.d(TAG,"send BroadcastReceiver++++++++=");
}
定位apk监听此广播
public class MyBroadcast extends BroadcastReceiver{
private static final String TAG = "MyBroadcast";
public final String weather_broadcat = "com.weather.broadcast";//接收到此广播
@Override
public void onReceive(Context content, Intent intent)
{
if(intent.getAction().equals(weather_broadcat)){
String str = intent.getExtras().getString("launcher");
//Log.d(TAG, "+++++"+str);
intent =new Intent(content,MyService.class);
content.startService(intent); //启动后台service服务
//Log.d(TAG, "intent++++++++over");
}
}
}
启动service,开启定位,获取当地城市
public class MyService extends Service{
private static final String TAG = "MyService";
private BMapManager mBMapMan = null;
private LocationListener mLocationListener = null;
private MKSearch mSearch = null;
private final String weather_receive_action = "com.example.perference.shared_id";
static String city;
private Handler handler = new Handler();
@Override
public IBinder onBind(Intent intent)/*noted*/
{
return null;
}
@Override
public void onCreate() {
//Log.d(TAG, "onCreate()+++++++");
initBaiDuMap();
mBMapMan.getLocationManager().requestLocationUpdates(mLocationListener);
mBMapMan.getLocationManager().enableProvider(MKLocationManager.MK_GPS_PROVIDER);
mBMapMan.start();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Log.d(TAG, "onStartCommand++++++++");
initBaiDuMap();
mBMapMan.getLocationManager().requestLocationUpdates(mLocationListener);
mBMapMan.getLocationManager().enableProvider(MKLocationManager.MK_GPS_PROVIDER);
mBMapMan.start();
return super.onStartCommand(intent, flags, startId);
}
public void initBaiDuMap(){
mBMapMan = new BMapManager(getApplication());
mBMapMan.init("14A97FC2DDF678193F61C19C0A20EA29C49DEF5C", null);
mBMapMan.start();
initMyLocation();
//Log.d(TAG, "initMyLocation()+++++++");
}
private void initMyLocation(){
mLocationListener = new LocationListener(){
@Override
public void onLocationChanged(Location location) {
if(location != null){
GeoPoint myPt = new GeoPoint((int)(location.getLatitude()*1e6),
(int)(location.getLongitude()*1e6));
initMapSerach();
mSearch.reverseGeocode(myPt);
}else{
}
}
};
}
private void initMapSerach(){
//Log.d(TAG, "the first1+++++");
mSearch = new MKSearch();
mSearch.init(mBMapMan, new MKSearchListener(){
public void onGetPoiResult(MKPoiResult res, int type, int error) {
}
public void onGetDrivingRouteResult(MKDrivingRouteResult res,
int error) {
}
public void onGetTransitRouteResult(MKTransitRouteResult res,
int error) {
}
public void onGetWalkingRouteResult(MKWalkingRouteResult res,
int error) {
}
public void onGetAddrResult(MKAddrInfo res, int error) {
if (error != 0 || res == null) {
//Log.d(TAG, "is not error");
}else{
//获取到城市和省份
city = res.addressComponents.city;
String pro = res.addressComponents.province;
new Thread(){
public void run(){
Intent i = new Intent();
i.setAction("com.example.perference.shared_id");
i.putExtra("city",city);
//Log.d(TAG, "city====="+city);
sendBroadcast(i);
handler.postDelayed(this, 600000); //隔十分钟更新一次
}
}.start();
}
}
@Override
public void onGetBusDetailResult(MKBusLineResult arg0, int arg1) {
}
});
}
}
launcher APK 接收到广播,调用解析方法,JSONObject解析,在主界面更新显示
private BroadcastReceiver netReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action == null)
return;
Log.d(TAG, "netReceiver action = " + action);
if(action.equals(outputmode_change_action)){
setHeight();
}
if (action.equals(Intent.ACTION_TIME_TICK)){
displayDate();
time_count++;
if(time_count >= time_freq){
sendWeatherBroadcast();
time_count = 0;
}
}if((action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION))||action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)||
action.equals(ConnectivityManager.CONNECTIVITY_ACTION)){
Intent send = new Intent();
send.setAction("com.weather.broadcast");
send.putExtra("launcher", "weather");
Launcher.this.sendBroadcast(send);
Log.d(TAG,"send BroadcastReceiver++++++++=");
}
if(action.equals(net_change_action)){
}
else if (action.equals(weather_receive_action)) { //接收service发送的广播,然后调用方法解析
String weatherInfo = intent.getExtras().getString("weather_today");
setWeatherView(weatherInfo);
String weatherCity = intent.getExtras().getString("city"); //得到定位到的城市
urlcity="https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D'"+weatherCity+"')&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"; //雅虎json查询天气语句
getData(urlcity); //调用解析方法
} else if(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)
|| Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)){
updateAppList(intent);
}else {
updateWifiLevel();
displayStatus();
updateStatus();
}
}
};
最后说一下,因为定位只在移动网络上有效,query 这个button按钮是为了客户连接以太网,手动输入城市,获取天气儿准备的
query_button.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v){
/**因为开机EditText会自动获取焦点,从而调系统的软键盘,所以在xml设置成了 android:visibility="gone"
这里,点击EditText才会显示软键盘*/
etCity.setVisibility(View.VISIBLE);
final String mCityStr = etCity.getText().toString();
String CityCodeUrl = "";
if(!mCityStr.isEmpty()){
tx_city.setVisibility(View.GONE);
CityCodeUrl = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D'"+mCityStr+"')&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys";
getData(CityCodeUrl);
//Log.d(TAG, "query on click+++");
}else{
Toast.makeText(Launcher.this,"Please enter a city name" , Toast.LENGTH_SHORT).show();
}
}
});
}
希望可以帮到大家,如有错误,请帮忙指正。谢谢!
发下我定位天气apk的百度云链接
http://pan.baidu.com/s/1o8vk2Bg
以上是关于安卓盒子launcher界面开发之添加自动定位,获取当地天气的主要内容,如果未能解决你的问题,请参考以下文章
安卓Launcher之获取手机安装的应用列表,安卓launcher
python 之 前端开发(盒子模型页面布局浮动定位z-indexoverflow溢出)
系统方向学习总结6 --Launcher3拖拽分析之Workspace
系统方向学习总结6 --Launcher3拖拽分析之Workspace