Пишем термометр для Android

Предисловие




На написание данного материала меня сподвиг данный пост, так как месяцев 5 назад для себя писал почти такое-же приложение, но с немного другим функционалом, и столкнулся с различными трудностями.
Отличия от этого приложения:
  • Наличие виджета
  • Парсинг данных и обработка ошибок сайта bashkirenergo.ru/weather/ufa/index.asp (часто бывает, что с датчиков не приходит температура, и при отсутствии данных приложение может упасть) происходит на стороне сервера, за счет чего в разы уменьшается входящий трафик на телефоне
  • Цвет фона приложения меняется в зависимости от температуры
  • Подгрузка сторонних шрифтов



Принцип таков:
  • Класс — провайдер информации для самого приложения и виджета.
  • Два layout'а — для виджета и приложения.

Так как цикл разработки с нуля уже описан тут, то перейдем сразу к делу.

Класс провайдер информации


Создаем класс InetConn.java, который будет предоставлять информацию для виджета и приложения. Класс взят из поста.

<font color="black">package com.example.helloandroid;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.<font color="#0000ff">params</font>.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;

<font color="#0000ff">public</font> <font color="#0000ff">class</font> InetConn {
  <font color="#008000">//откуда получаем данные</font>
  <font color="#0000ff">public</font> <font color="#2B91AF">String</font> USER_URL = <font color="#A31515">"http://2sane.ru/weather/index.php"</font>;
  <font color="#0000ff">public</font> <font color="#2B91AF">String</font> RESULT_OK = <font color="#A31515">"ok"</font>;
  <font color="#0000ff">public</font> <font color="#2B91AF">String</font> RESULT_SERVER = <font color="#A31515">"server"</font>;
  <font color="#0000ff">public</font> <font color="#2B91AF">String</font> RESULT_USER_NOT_FOUND = <font color="#A31515">"not_found"</font>;
  <font color="#0000ff">public</font> <font color="#2B91AF">String</font> RESULT_NETWORK = <font color="#A31515">"network"</font>;
  
  
  <font color="#0000ff">public</font> <font color="#2B91AF">String</font> getInet()
  {
    <font color="#2B91AF">String</font> result = <font color="#A31515">""</font>;
    <font color="#2B91AF">String</font> url = USER_URL;
    <font color="#2B91AF">String</font> proxyHost = android.net.Proxy.getDefaultHost();
    <font color="#0000ff">int</font> proxyPort = android.net.Proxy.getDefaultPort();
    HttpClient httpClient = <font color="#0000ff">new</font> DefaultHttpClient();
    <font color="#0000ff">if</font> (proxyPort > 0)
    {
      HttpHost proxy = <font color="#0000ff">new</font> HttpHost(proxyHost, proxyPort);
      httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
    }
    HttpGet httpGet = <font color="#0000ff">new</font> HttpGet(url);
    <font color="#0000ff">try</font> {
      HttpResponse response = httpClient.execute(httpGet);
      <font color="#0000ff">if</font> (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
      {
        
        <font color="#008000">//BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), Charset.forName("CP1251")));</font>
        BufferedReader reader = <font color="#0000ff">new</font> BufferedReader(<font color="#0000ff">new</font> InputStreamReader(response.getEntity().getContent()));
        <font color="#2B91AF">StringBuilder</font> sb = <font color="#0000ff">new</font> <font color="#2B91AF">StringBuilder</font>();
        <font color="#2B91AF">String</font> line = <font color="#0000ff">null</font>;
        <font color="#0000ff">while</font> ((line = reader.readLine()) != <font color="#0000ff">null</font>) {
          sb.append(line);
        }
        sb.append(<font color="#A31515">'°'</font>);
        <font color="#2B91AF">String</font> answer = sb.toString();
        result = answer;
      }
    } <font color="#0000ff">catch</font> (Exception e)
    {
      
    }
    <font color="#0000ff">return</font> result;
  }
}
</font>
<font color="gray">* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx"><font color="gray">Source Code Highlighter</font></a>.</font>

Серверная часть на PHP

<font color="black">$url1 = <font color="#A31515">'http://www.bashkirenergo.ru/weather/ufa/index.asp'</font>;
$url2 = <font color="#A31515">'http://www.bashkirenergo.ru/weather/ufa/index.asp?delta=1'</font>;
<font color="#0000ff">if</font>(file_get_contents($url1)){
  $weather = file_get_contents($url1);
  $weather_utf = iconv(<font color="#A31515">"CP1251"</font>, <font color="#A31515">"UTF-8"</font>, $weather);
  $ind = stripos($weather_utf, <font color="#A31515">"Дом"</font>);
  $tempt = intval(substr($weather_utf, $ind-20, 3));
<font color="#008000">//если текущая температура недоступна, то пытаемся взять температуру часом ранее по этому адресу: <a href="http://www.bashkirenergo.ru/weather/ufa/index.asp?delta=1">www.bashkirenergo.ru/weather/ufa/index.asp?delta=1</a></font>

  <font color="#0000ff">if</font>(!isset($tempt)){
    $weather = file_get_contents($url2);
    $weather_utf = iconv(<font color="#A31515">"CP1251"</font>, <font color="#A31515">"UTF-8"</font>, $weather);
    $ind = stripos($weather_utf, <font color="#A31515">"Дом"</font>);
    $tempt = intval(substr($weather_utf, $ind-20, 3));
    <font color="#0000ff">if</font>(!isset($tempt)){$tempt = <font color="#A31515">"+0"</font>;}
  }
}
<font color="#0000ff">else</font>{
  $tempt = <font color="#A31515">"+0"</font>;
}
print $tempt;
</font>
<font color="gray">* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx"><font color="gray">Source Code Highlighter</font></a>.</font>

Код приложения


<font color="black">package com.example.helloandroid;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.<font color="#2B91AF">Uri</font>;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import android.view.View;
import android.view.View.OnClickListener;

<font color="#0000ff">public</font> <font color="#0000ff">class</font> HelloAndroid extends Activity {

  <font color="#0000ff">private</font> TextView txt;
  <font color="#0000ff">private</font> TextView txt2;
  <font color="#0000ff">private</font> ImageView logo;
  <font color="#0000ff">private</font> RelativeLayout mScreen;
  <font color="#0000ff">private</font> <font color="#0000ff">int</font> col = 0;
  <font color="#0000ff">private</font> <font color="#0000ff">int</font> num = 0;

<font color="#008000">//Массив цветов фона:</font>
  <font color="#0000ff">private</font> <font color="#2B91AF">String</font>[] colors = { <font color="#A31515">"#15ADFF"</font>, <font color="#A31515">"#1BAFF"</font>, <font color="#A31515">"#21B1FF"</font>, <font color="#A31515">"#27B3FF"</font>,
      <font color="#A31515">"#2DB5FF"</font>, <font color="#A31515">"#33B7FF"</font>, <font color="#A31515">"#39B9FF"</font>, <font color="#A31515">"#3FBBFF"</font>, <font color="#A31515">"#45BDFF"</font>, <font color="#A31515">"#4BBFFF"</font>,
      <font color="#A31515">"#51C1FF"</font>, <font color="#A31515">"#57C3FF"</font>, <font color="#A31515">"#5DC5FF"</font>, <font color="#A31515">"#63C7FF"</font>, <font color="#A31515">"#69C9FF"</font>, <font color="#A31515">"#6FCBFF"</font>,
      <font color="#A31515">"#75CDFF"</font>, <font color="#A31515">"#7BCFF"</font>, <font color="#A31515">"#81D1FF"</font>, <font color="#A31515">"#87D3FF"</font>, <font color="#A31515">"#8DD5FE"</font>, <font color="#A31515">"#93D7FE"</font>,
      <font color="#A31515">"#99D9FE"</font>, <font color="#A31515">"#9FDBFE"</font>, <font color="#A31515">"#A5DDFE"</font>, <font color="#A31515">"#ABDFFE"</font>, <font color="#A31515">"#B1E1FE"</font>, <font color="#A31515">"#B7F3FE"</font>,
      <font color="#A31515">"#BDF5FE"</font>, <font color="#A31515">"#C3E7FE"</font>, <font color="#A31515">"#C9E9FE"</font>, <font color="#A31515">"#CFEBFE"</font>, <font color="#A31515">"#D5EDFE"</font>, <font color="#A31515">"#DBEFFE"</font>,
      <font color="#A31515">"#E1F1FE"</font>, <font color="#A31515">"#E7F3FE"</font>, <font color="#A31515">"#EDF5FE"</font>, <font color="#A31515">"#F3F7FE"</font>, <font color="#A31515">"#F9F9FE"</font>, <font color="#A31515">"#FFFBFE"</font>,
      
      <font color="#A31515">"#FFFBFE"</font>,
      <font color="#A31515">"#FFF8F7"</font>, <font color="#A31515">"#FFF4F1"</font>, <font color="#A31515">"#FFF1EA"</font>, <font color="#A31515">"#FFEEE4"</font>, <font color="#A31515">"#FFEADD"</font>, <font color="#A31515">"#FFE7D7"</font>,
      <font color="#A31515">"#FFE4D0"</font>, <font color="#A31515">"#FFE0CA"</font>, <font color="#A31515">"#FFDDC3"</font>, <font color="#A31515">"#FFDABD"</font>, <font color="#A31515">"#FFD6B6"</font>, <font color="#A31515">"#FFD3B0"</font>,
      <font color="#A31515">"#FFD0A9"</font>, <font color="#A31515">"#FFCCA3"</font>, <font color="#A31515">"#FFC99C"</font>, <font color="#A31515">"#FFC696"</font>, <font color="#A31515">"#FFC28F"</font>, <font color="#A31515">"#FFBF89"</font>,
      <font color="#A31515">"#FFBC82"</font>, <font color="#A31515">"#FFB87C"</font>, <font color="#A31515">"#FFB575"</font>, <font color="#A31515">"#FFB26F"</font>, <font color="#A31515">"#FFAE68"</font>, <font color="#A31515">"#FFAB62"</font>,
      <font color="#A31515">"#FFA85B"</font>, <font color="#A31515">"#FFA455"</font>, <font color="#A31515">"#FFA14E"</font>, <font color="#A31515">"#FF9E48"</font>, <font color="#A31515">"#FF9A41"</font>, <font color="#A31515">"#FF973B"</font>,
      <font color="#A31515">"#FF9434"</font>, <font color="#A31515">"#FF902E"</font>, <font color="#A31515">"#FF8D27"</font>, <font color="#A31515">"#FF8A21"</font>, <font color="#A31515">"#FF861A"</font>, <font color="#A31515">"#FF8314"</font>,
      <font color="#A31515">"#FF800D"</font>, <font color="#A31515">"#FF7C07"</font>, <font color="#A31515">"#FF7900"</font>, <font color="#A31515">"#FF7900"</font>};

  @Override
  <font color="#0000ff">public</font> <font color="#0000ff">void</font> onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    txt = (TextView) findViewById(R.id.TextView01);
    txt2 = (TextView) findViewById(R.id.TextView02);
    logo = (ImageView) findViewById(R.id.ImageView01);
    
    <font color="#008000">//получаем данные от класса:</font>
    InetConn <font color="#0000ff">in</font> = <font color="#0000ff">new</font> InetConn();
    <font color="#2B91AF">String</font> tempt = <font color="#0000ff">in</font>.getInet();

<font color="#008000">//Преобразуем данные в число, для определения цвета фона:</font>
    <font color="#0000ff">if</font> (tempt.length() > 3)
      num = 3;
    <font color="#0000ff">else</font>
      num = 2;
    <font color="#0000ff">if</font> (tempt.substring(0, 1).equals(<font color="#A31515">"+"</font>)) {
      col = Integer.parseInt(tempt.substring(1, num));
    } <font color="#0000ff">else</font> {
      col = Integer.parseInt(tempt.substring(0, num));
    }

    mScreen = (RelativeLayout) findViewById(R.id.myScreen);
    mScreen.setBackgroundColor(Color.parseColor(colors[40+(col)]));
    
<font color="#008000">//Подгружаем наш шрифт</font>
    Typeface digitalFont = Typeface.createFromAsset(<font color="#0000ff">this</font>.getAssets(), <font color="#A31515">"fonts/HELVETCB.OTF"</font>);
    txt.setTypeface(digitalFont);
    txt2.setTypeface(digitalFont);
  
    txt.setText(tempt);
    
    logo.setOnClickListener(logoListener);
  }
  
<font color="#008000">//обработка клика по логотипу и открытие браузера:</font>
   <font color="#0000ff">private</font> OnClickListener logoListener = <font color="#0000ff">new</font> OnClickListener()
    {
      <font color="#0000ff">public</font> <font color="#0000ff">void</font> onClick(View arg0) {
        <font color="#008000">// TODO Auto-generated method stub</font>
        Intent intent = <font color="#0000ff">new</font> Intent(Intent.ACTION_VIEW, <font color="#2B91AF">Uri</font>.parse(<font color="#A31515">"http://www.atmateam.ru"</font>));
        startActivity(intent);
      }
    };  

}
</font>
<font color="gray">* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx"><font color="gray">Source Code Highlighter</font></a>.</font>

Layout виджета


<font color="black"><font color="#0000ff"><?</font><font color="#800000">xml</font> <font color="#ff0000">version</font><font color="#0000ff">="1.0"</font> <font color="#ff0000">encoding</font><font color="#0000ff">="utf-8"</font>?<font color="#0000ff">></font>
<font color="#0000ff"><</font><font color="#800000">LinearLayout</font> <font color="#ff0000">xmlns:android</font><font color="#0000ff">="http://schemas.android.com/apk/res/android"</font>
<font color="#ff0000">android:layout_width</font><font color="#0000ff">="fill_parent"</font>
<font color="#ff0000">android:orientation</font><font color="#0000ff">="vertical"</font>
<font color="#ff0000">android:layout_gravity</font><font color="#0000ff">="center"</font>
<font color="#ff0000">android:background</font><font color="#0000ff">="@drawable/widget_bg_normal"</font>
<font color="#ff0000">android:layout_height</font><font color="#0000ff">="wrap_content"</font><font color="#0000ff">></font>
<font color="#0000ff"><</font><font color="#800000">TextView</font> <font color="#ff0000">android:id</font><font color="#0000ff">="@+id/widget_textview"</font>
<font color="#ff0000">android:text</font><font color="#0000ff">="@string/widget_text"</font>
<font color="#ff0000">android:layout_height</font><font color="#0000ff">="wrap_content"</font>
<font color="#ff0000">android:layout_width</font><font color="#0000ff">="wrap_content"</font>
<font color="#ff0000">android:layout_gravity</font><font color="#0000ff">="center_horizontal|center"</font>
<font color="#ff0000">android:layout_marginTop</font><font color="#0000ff">="5dip"</font>
<font color="#ff0000">android:padding</font><font color="#0000ff">="15dip"</font>
<font color="#ff0000">android:textSize</font><font color="#0000ff">="16dip"</font>
<font color="#ff0000">android:textColor</font><font color="#0000ff">="@android:color/black"</font><font color="#0000ff">/></font>
<font color="#0000ff"></</font><font color="#800000">LinearLayout</font><font color="#0000ff">></font>
</font>
<font color="gray">* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx"><font color="gray">Source Code Highlighter</font></a>.</font>

Настройки виджета


<font color="black"><font color="#0000ff"><?</font><font color="#800000">xml</font> <font color="#ff0000">version</font><font color="#0000ff">="1.0"</font> <font color="#ff0000">encoding</font><font color="#0000ff">="utf-8"</font>?<font color="#0000ff">></font>
<font color="#0000ff"><</font><font color="#800000">appwidget-provider</font> <font color="#ff0000">xmlns:android</font><font color="#0000ff">="http://schemas.android.com/apk/res/android"</font>
<font color="#ff0000">android:minWidth</font><font color="#0000ff">="64dip"</font>
<font color="#ff0000">android:minHeight</font><font color="#0000ff">="64dip"</font>
<font color="#ff0000">android:updatePeriodMillis</font><font color="#0000ff">="1800000"</font>
<font color="#ff0000">android:initialLayout</font><font color="#0000ff">="@layout/widget"</font>
<font color="#0000ff">/></font>
</font>
<font color="gray">* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx"><font color="gray">Source Code Highlighter</font></a>.</font>

Код виджета


Больше всего проблем при написании виджета, я получил с его обновлением, стандартными методами ничего не выходило, сработало только с применением таймера.

<font color="black">package com.example.helloandroid;

import java.util.Timer;
import java.util.TimerTask;

import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.widget.RemoteViews;

<font color="#0000ff">public</font> <font color="#0000ff">class</font> HelloWidget extends AppWidgetProvider {

  @Override
  <font color="#0000ff">public</font> <font color="#0000ff">void</font> onReceive(Context context, Intent intent) {
  <font color="#008000">// v1.5 fix that doesn't call onDelete Action</font>
  final <font color="#2B91AF">String</font> action = intent.getAction();
  <font color="#0000ff">if</font> (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {
  final <font color="#0000ff">int</font> appWidgetId = intent.getExtras().getInt(
  AppWidgetManager.EXTRA_APPWIDGET_ID,
  AppWidgetManager.INVALID_APPWIDGET_ID);
  <font color="#0000ff">if</font> (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {
  <font color="#0000ff">this</font>.onDeleted(context, <font color="#0000ff">new</font> <font color="#0000ff">int</font>[] { appWidgetId });
  }
  } <font color="#0000ff">else</font> {
  super.onReceive(context, intent);
  }
  }
  
  
  @Override
  <font color="#0000ff">public</font> <font color="#0000ff">void</font> onUpdate(Context context, AppWidgetManager appWidgetManager,
      <font color="#0000ff">int</font>[] appWidgetIds) {
<font color="#008000">//Устанавливаем таймер обновления виджета, раз в 30 минут</font>
    Timer timer = <font color="#0000ff">new</font> Timer();
    timer.scheduleAtFixedRate(<font color="#0000ff">new</font> MyTime(context, appWidgetManager), 1,
        1800000);
  }
  
    
  <font color="#0000ff">private</font> <font color="#0000ff">class</font> MyTime extends TimerTask {
    RemoteViews remoteViews;
    AppWidgetManager appWidgetManager;
    ComponentName thisWidget;
    
    
    <font color="#0000ff">public</font> MyTime(Context context, AppWidgetManager appWidgetManager) {
      <font color="#0000ff">this</font>.appWidgetManager = appWidgetManager;
      remoteViews = <font color="#0000ff">new</font> RemoteViews(context.getPackageName(),
          R.layout.widget);
      thisWidget = <font color="#0000ff">new</font> ComponentName(context, HelloWidget.<font color="#0000ff">class</font>);
    }
    @Override
    <font color="#0000ff">public</font> <font color="#0000ff">void</font> run() {
      InetConn <font color="#0000ff">in</font> = <font color="#0000ff">new</font> InetConn();
      remoteViews.setTextViewText(R.id.widget_textview, <font color="#0000ff">in</font>.getInet());
      appWidgetManager.updateAppWidget(thisWidget, remoteViews);
    }
  }
  
  

}
</font>
<font color="gray">* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx"><font color="gray">Source Code Highlighter</font></a>.</font>

Финал


Правим AndroidManifest.xml

<font color="black"><?xml version=<font color="#A31515">"1.0"</font> encoding=<font color="#A31515">"utf-8"</font>?>
<manifest xmlns:android=<font color="#A31515">"http://schemas.android.com/apk/res/android"</font>
  package=<font color="#A31515">"com.example.helloandroid"</font> android:versionCode=<font color="#A31515">"1"</font>
  android:versionName=<font color="#A31515">"1.0"</font>>
  <application android:icon=<font color="#A31515">"@drawable/icon"</font> android:label=<font color="#A31515">"@string/app_name"</font>>
    <activity android:name=<font color="#A31515">".HelloAndroid"</font> android:label=<font color="#A31515">"@string/app_name"</font>>
      <intent-filter>
        <action android:name=<font color="#A31515">"android.intent.action.MAIN"</font> />
        <category android:name=<font color="#A31515">"android.intent.category.LAUNCHER"</font> />
      </intent-filter>
    </activity>

    <!-- Broadcast Receiver that will process AppWidget updates -->
    <receiver android:name=<font color="#A31515">".HelloWidget"</font> android:label=<font color="#A31515">"@string/app_name"</font>>
      <intent-filter>
        <action android:name=<font color="#A31515">"android.appwidget.action.APPWIDGET_UPDATE"</font> />
      </intent-filter>
      <meta-data android:name=<font color="#A31515">"android.appwidget.provider"</font>
        android:resource=<font color="#A31515">"@xml/hello_widget_provider"</font> />
    </receiver>
    
    <receiver android:name=<font color="#A31515">".HelloWidget"</font>
      android:label=<font color="#A31515">"@string/app_name"</font>>
        <intent-filter>
          <action android:name=<font color="#A31515">"android.appwidget.action.APPWIDGET_UPDATE"</font> />
          <data android:scheme=<font color="#A31515">"karma_widget"</font> />
        </intent-filter>  
        <meta-data android:name=<font color="#A31515">"android.appwidget.provider"</font> android:resource=<font color="#A31515">"@xml/hello_widget_provider"</font> />
    </receiver>

  </application>

  <uses-permission android:name=<font color="#A31515">"android.permission.INTERNET"</font>></uses-permission>
</manifest>
</font>
<font color="gray">* This source code was highlighted with <a href="http://virtser.net/blog/post/source-code-highlighter.aspx"><font color="gray">Source Code Highlighter</font></a>.</font>

Архив с исходным кодом и apk файлом.

Использованные материалы:

Так как это мой первый опыт разработки на Java и Android, в комментариях приветствуется критика и предложения.


0 комментариев

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.