Android之高仿墨迹天气桌面组件(AppWidgetProvider)

来源:互联网 发布:兄弟连python课程大纲 编辑:程序博客网 时间:2024/05/09 23:27

相信墨迹天气,大家都见过,他在时间显示和天气界面上,很吸引人,今天我就来模仿一下墨迹天气的桌面组件,但是由于谷歌在天朝频频被墙的缘故,所以我在今天测试的时候,解析xml文件的网页打不开,所以天气显示出了点问题,希望大家能理解,谢谢。(今天9月24日修改为解析中国天气网获取天气了,而且修改组件在桌面居中显示)。

        老规矩,先分享源代码:Weather.zip(2.38 MB, 下载次数: 229)

        好了,废话不多说,先上效果图:

  

再来看一下整个小项目的主体结构:

首先先声明一个桌面布局的xml文件,即app.xml:

    <?xml version="1.0" encoding="utf-8"?>    <!--             指定该桌面组件的基本配置信息:            initialLayout:初始时显示的布局            minWidth:桌面小控件的最小高度。            minWidth:桌面小控件的最小宽度。            updatePeriodMillis:更新频率    -->    <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"        android:initialLayout="@layout/main"        android:minHeight="150dp"        android:minWidth="200dp"        android:updatePeriodMillis="0" >    </appwidget-provider>

复制代码
然后要在manifest文件中声明:
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"        package="com.way.apptest"        android:versionCode="1"        android:versionName="1.0" >        <uses-sdk            android:minSdkVersion="8"            android:targetSdkVersion="15" />        <uses-permission android:name="android.permission.INTERNET" />        <application            android:icon="@drawable/ic_launcher"            android:label="@string/app_name"            android:theme="@style/AppTheme" >            <activity android:name="com.way.apptest.MainActivity" >            </activity>            <receiver android:name="com.way.apptest.App" >                <!-- 指定桌面小控件的meta-data -->                <meta-data                    android:name="android.appwidget.provider"                    android:resource="@xml/app" />                <!-- 将该BroadcastReceiver当成桌面小控件 -->                <intent-filter>                    <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />                </intent-filter>            </receiver>            <service android:name=".UpdateService" >            </service>        </application>    </manifest>

复制代码
主要代码:一:定义一个App类继承AppWidgetProvider,然后再onUpdate方法中启动一个服务去更新时间和天气。
    /**    * @author way    */    public class App extends AppWidgetProvider {            private Intent intent;            @Override            public void onUpdate(Context context, AppWidgetManager appWidgetManager,                            int[] appWidgetIds) {                    intent = new Intent(context, UpdateService.class);                    context.startService(intent);                    super.onUpdate(context, appWidgetManager, appWidgetIds);            }            @Override            public void onDeleted(Context context, int[] appWidgetIds) {                    context.stopService(intent);                    super.onDeleted(context, appWidgetIds);            }    }


二:本项目中最重要的部分,在这个服务中,我们注册一个广播接收者去接受系统每分钟时间时间变化的广播,从而来更新桌面时间,这样更省电哦,需要注意的是:这个广播接收者必须在代码中注册,在Manifest文件中注册是没有效果的。更新天气,我是通过定义一个定时器,由用户设置时间间隔来更新天气信息。
    package com.way.apptest;    import java.text.SimpleDateFormat;    import java.util.Date;    import java.util.Timer;    import java.util.TimerTask;    import android.app.AlertDialog;    import android.app.PendingIntent;    import android.app.Service;    import android.appwidget.AppWidgetManager;    import android.content.BroadcastReceiver;    import android.content.ComponentName;    import android.content.Context;    import android.content.DialogInterface;    import android.content.Intent;    import android.content.IntentFilter;    import android.net.ConnectivityManager;    import android.net.NetworkInfo;    import android.os.Handler;    import android.os.IBinder;    import android.os.Message;    import android.widget.RemoteViews;    import com.way.getWeather.MyWeather;    /**    * @author way    */    public class UpdateService extends Service {            private static final int UPDATE = 0x123;            private RemoteViews remoteViews;            // 数字时间图片资源数组            private int[] imgs = { R.drawable.n0, R.drawable.n1, R.drawable.n2,                            R.drawable.n3, R.drawable.n4, R.drawable.n5, R.drawable.n6,                            R.drawable.n7, R.drawable.n8, R.drawable.n9, };            // 将显示小时、分钟的ImageView定义成数组            private int[] dateViews = { R.id.h1, R.id.h2, R.id.m1, R.id.m2 };            // 按照中国天气网的天气图片顺序排列好本地资源图片,我这里是随意的~嘿嘿            private int[] weatherImg = { R.drawable.sunny, R.drawable.cloudy,                            R.drawable.chance_of_rain, R.drawable.chance_of_sleet,                            R.drawable.chance_of_snow, R.drawable.chance_of_storm,                            R.drawable.clock1, R.drawable.fog, R.drawable.haze,                            R.drawable.mist, R.drawable.mostly_sunny, R.drawable.mostly_cloudy,                            R.drawable.lower, R.drawable.middle };            private Handler handler = new Handler() {                    @Override                    public void handleMessage(Message msg) {                            switch (msg.what) {                            case UPDATE:                                    // 更新天气                                    updateTime();                                    updateWeather();                                    break;                            }                    }            };            // 广播接收者去接收系统每分钟的提示广播,来更新时间            private BroadcastReceiver mTimePickerBroadcast = new BroadcastReceiver() {                    @Override                    public void onReceive(Context context, Intent intent) {                            updateTime();                    }            };            private void updateWeather() {                    // Weather w = new GetWeather().googleWeather();                    // if (w != null) {                    // System.out.println("当前天气:" + w.getWeather() + ":" + w.getTemp_c()                    // + ":" + w.getIcon());                    remoteViews.setTextViewText(R.id.condition, MyWeather.weather1);                    remoteViews.setTextViewText(R.id.tem, (MyWeather.temp1));                    // 根据图片名,获取天气图片资源                    // remoteViews.setImageViewResource(                    // R.id.weather,                    // getApplicationContext().getResources().getIdentifier(                    // w.getIcon(), "drawable", "com.way.apptest"));                    if (MyWeather.img1 != null || !"".equals(MyWeather.img1))                            remoteViews.setImageViewResource(R.id.weather,                                            weatherImg[Integer.parseInt(MyWeather.img1)]);                    // 执行更新                    ComponentName componentName = new ComponentName(                                    getApplicationContext(), App.class);                    AppWidgetManager.getInstance(getApplicationContext()).updateAppWidget(                                    componentName, remoteViews);            }            @Override            public IBinder onBind(Intent intent) {                    return null;            }            @Override            public void onCreate() {                    super.onCreate();                    remoteViews = new RemoteViews(getApplication().getPackageName(),                                    R.layout.main);// 实例化RemoteViews                    if (isNetworkAvailable()) {                            MyWeather.getWeather();// json解析中国天气网天气                    } else {                            toast();                    }                    updateTime();// 第一次运行时先更新一下时间和天气                    updateWeather();                    // 点击天气图片,进入MainActivity                    Intent intent = new Intent(getApplicationContext(), MainActivity.class);                    PendingIntent pi = PendingIntent.getActivity(getApplicationContext(),                                    0, intent, 0);                    remoteViews.setOnClickPendingIntent(R.id.weather, pi);                    // 定义一个定时器去更新天气。实际开发中更新时间间隔可以由用户设置,                    new Timer().scheduleAtFixedRate(new TimerTask() {                            @Override                            public void run() {                                    Message msg = handler.obtainMessage();                                    msg.what = UPDATE;                                    handler.sendMessage(msg);                            }                    }, 1, 3600 * 1000);// 每小时更新一次天气            }            private void updateTime() {                    Date date = new Date();                    // 定义SimpleDateFormat对象                    SimpleDateFormat df = new SimpleDateFormat("HHmm");                    // 将当前时间格式化成HHmm的形式                    String timeStr = df.format(date);                    for (int i = 0; i < timeStr.length(); i++) {                            // 将第i个数字字符转换为对应的数字                            int num2 = Integer.parseInt(timeStr.substring(i, i + 1));                            // 将第i个图片的设为对应的数字图片                            remoteViews.setImageViewResource(dateViews[i], imgs[num2]);                    }                    remoteViews.setTextViewText(R.id.city, MyWeather.city);                    remoteViews.setTextViewText(R.id.date, "0" + (date.getMonth() + 1)                                    + "-" + date.getDate() + " 周" + date.getDay());                    ComponentName componentName = new ComponentName(getApplication(),                                    App.class);                    AppWidgetManager.getInstance(getApplication()).updateAppWidget(                                    componentName, remoteViews);            }            @Override            public void onStart(Intent intent, int startId) {                    // 注册系统每分钟提醒广播(注意:这个广播只能在代码中注册)                    IntentFilter updateIntent = new IntentFilter();                    updateIntent.addAction("android.intent.action.TIME_TICK");                    registerReceiver(mTimePickerBroadcast, updateIntent);                    super.onStart(intent, startId);            }            @Override            public void onDestroy() {                    // 注销系统的这个广播                    unregisterReceiver(mTimePickerBroadcast);                    //被系统干掉后,服务重启,做一次流氓软件,哈哈                    Intent intent = new Intent(getApplicationContext(), UpdateService.class);                    getApplication().startService(intent);                    super.onDestroy();            }            /**             * 判断手机网络是否可用             *             * @param context             * @return             */            private boolean isNetworkAvailable() {                    ConnectivityManager mgr = (ConnectivityManager) getApplicationContext()                                    .getSystemService(Context.CONNECTIVITY_SERVICE);                    NetworkInfo[] info = mgr.getAllNetworkInfo();                    if (info != null) {                            for (int i = 0; i < info.length; i++) {                                    if (info[i].getState() == NetworkInfo.State.CONNECTED) {                                            return true;                                    }                            }                    }                    return false;            }            <p>/**      * 在非Activity中弹出对话框      *      * @param context      */    private void showDialog(final Context context) {      // TODO Auto-generated method stub      /* create ui */      final AlertDialog dialog;      AlertDialog.Builder builder = new AlertDialog.Builder(context);      builder.setTitle("提示").setMessage("WiFi连接不可用");      builder.setPositiveButton("前往打开", new OnClickListener() {</p><p>   public void onClick(DialogInterface dialog, int which) {        Intent go2wifi = new Intent(          android.provider.Settings.ACTION_WIRELESS_SETTINGS);        go2wifi.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);        context.startActivity(go2wifi);</p><p>   }      }).setNegativeButton("下次再说", null);      dialog = builder.create();      dialog.getWindow()        .setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);      // d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY);      dialog.show();</p><p>  /* set size & pos */      WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();      WindowManager wm = (WindowManager) context        .getSystemService(Context.WINDOW_SERVICE);      Display display = wm.getDefaultDisplay();      if (display.getHeight() > display.getWidth()) {       // lp.height = (int) (display.getHeight() * 0.5);       lp.width = (int) (display.getWidth() * 1.0);      } else {       // lp.height = (int) (display.getHeight() * 0.75);       lp.width = (int) (display.getWidth() * 0.5);      }      dialog.getWindow().setAttributes(lp);    }    </p>//记得加上权限         <!-- 系统对话框权限 -->    //   <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>            }

三:这是桌面组件主要布局文件,如果大家有什么好的建议,欢迎提,本人对布局不是特别擅长。
    <?xml version="1.0" encoding="utf-8"?>    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"        android:id="@+id/bg"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center"        android:background="@drawable/ww_bg"        android:orientation="vertical" >        <LinearLayout            android:id="@+id/time"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="center"            android:orientation="horizontal" >            <LinearLayout                android:id="@+id/linearLayout1"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:background="@drawable/wd_bg"                android:orientation="horizontal" >                <ImageView                    android:id="@+id/h1"                    android:layout_width="wrap_content"                    android:layout_height="fill_parent"                    android:paddingLeft="10dip"                    android:src="@drawable/n0" />                <ImageView                    android:id="@+id/h2"                    android:layout_width="wrap_content"                    android:layout_height="fill_parent"                    android:src="@drawable/n0" />            </LinearLayout>            <TextView                android:layout_width="30dip"                android:layout_height="wrap_content" />            <LinearLayout                android:id="@+id/linearLayout2"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:background="@drawable/wd_bg"                android:orientation="horizontal" >                <ImageView                    android:id="@+id/m1"                    android:layout_width="wrap_content"                    android:layout_height="match_parent"                    android:paddingLeft="10dip"                    android:src="@drawable/n0" />                <ImageView                    android:id="@+id/m2"                    android:layout_width="wrap_content"                    android:layout_height="match_parent"                    android:src="@drawable/n0" />            </LinearLayout>        </LinearLayout>        <LinearLayout            android:id="@+id/linearLayout3"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="center_horizontal"            android:gravity="center"            android:orientation="horizontal" >            <LinearLayout                android:layout_width="100dip"                android:layout_height="wrap_content"                android:orientation="vertical"                android:paddingLeft="10dip" >                <TextView                    android:id="@+id/city"                    android:layout_width="wrap_content"                    android:layout_height="wrap_content"                    android:textColor="#000000"                    android:textSize="20sp" />                <TextView                    android:id="@+id/condition"                    android:layout_width="wrap_content"                    android:layout_height="wrap_content"                    android:text="@string/neterror"                    android:textColor="#000000"                    android:textSize="18sp" />            </LinearLayout>            <ImageView                android:id="@+id/weather"                android:layout_width="wrap_content"                android:layout_height="wrap_content"                android:layout_gravity="center_horizontal|top"                android:src="@drawable/sunny" />            <LinearLayout                android:layout_width="100dip"                android:layout_height="wrap_content"                android:gravity="right"                android:orientation="vertical"                android:paddingRight="10dip" >                <TextView                    android:id="@+id/date"                    android:layout_width="wrap_content"                    android:layout_height="wrap_content"                    android:textColor="#000000"                    android:textSize="18sp" />                <TextView                    android:id="@+id/tem"                    android:layout_width="wrap_content"                    android:layout_height="wrap_content"                    android:text="@string/neterror"                    android:textColor="#000000"                    android:textSize="18sp" />            </LinearLayout>        </LinearLayout>    </LinearLayout>


四:谷歌天气不给力,所以我就简单的给出获取天气的核心代码。这里简单的做了一下乱码处理。
     * @author way    *    */    public class GetWeather {            /**             *             * @return 天气对象             */            public Weather googleWeather() {                    String str = "http://www.google.com/ig/api?hl=zh_cn&weather=shenzhen";                    try {                            URL url = new URL(str);                            InputStream in = url.openStream();                            ByteArrayOutputStream bos = new ByteArrayOutputStream();                            int len = -1;                            while ((len = in.read()) != -1) {                                    bos.write(len);                            }                            InputStream is = new ByteArrayInputStream(bos.toString("GBK")                                            .getBytes("utf-8"));                            // 从流中获取文档到本地内存                            Document doc = DocumentBuilderFactory.newInstance()                                            .newDocumentBuilder().parse(is);                            // 从文档中得到名字为current_conditions的第一个节点下的所有子节点(一个集合)                            NodeList nodeList = doc.getElementsByTagName("current_conditions")                                            .item(0).getChildNodes();                            // 得到nodeList下第一个节点的第一个元素内容(即当前天气)                            String condition = nodeList.item(0).getAttributes().item(0)                                            .getNodeValue();                            // 当前温度                            String temp_c = nodeList.item(2).getAttributes().item(0)                                            .getNodeValue();                            // 当前湿度    //                        String humidity = nodeList.item(3).getAttributes().item(0)    //                                        .getNodeValue();                            // 当前图片路径                            String iconPath = nodeList.item(4).getAttributes().item(0)                                            .getNodeValue();                            // 当前风向    //                        String wind_condition = nodeList.item(5).getAttributes().item(0)    //                                        .getNodeValue();                            Weather w = new Weather();                            w.setWeather(condition);                            w.setTemp_c(temp_c);                            // 从图片路径中获取图片的名字                            String icon = iconPath.substring(iconPath.lastIndexOf("/") + 1,                                            iconPath.indexOf("."));                            w.setIcon(icon);                            return w;                    } catch (MalformedURLException e) {                            e.printStackTrace();                    } catch (IOException e) {                            e.printStackTrace();                    } catch (SAXException e) {                            e.printStackTrace();                    } catch (ParserConfigurationException e) {                            e.printStackTrace();                    }                    return null;            }    }



今天再修改解析中国天气网的json代码:
    public class MyWeather {            public static String city;            public static String temp1;            public static String weather1;            public static String img1;            public static void getWeather() {                    try {                            URL url = new URL("http://m.weather.com.cn/data/101250101.html");                            InputStream is = url.openStream();                            ByteArrayOutputStream bos = new ByteArrayOutputStream();                            int len = -1;                            byte[] buffer = new byte[1024];                            while ((len = is.read(buffer)) != -1) {                                    bos.write(buffer, 0, len);                            }                            String info = bos.toString("utf-8");                            JSONObject dataJson = new JSONObject(info);                            JSONObject json = dataJson.getJSONObject("weatherinfo");                            city = json.getString("city");                            temp1 = json.getString("temp1");                            weather1 = json.getString("weather1");                            img1 = json.getString("img1");                            System.out.println(city);is.close();bos.close();                    } catch (MalformedURLException e) {                            e.printStackTrace();                    } catch (IOException e) {                            e.printStackTrace();                    } catch (JSONException e) {                            e.printStackTrace();                    }            }    }



转载: http://www.apkbus.com/android-130431-1-1.html
原创粉丝点击