improve performance of scrollview in main screen #39

Closed
marc.nause wants to merge 5 commits from marc.nause/TinyWeatherForecastGermany:fixjerkylist into master
  1. 351
      app/src/main/java/de/kaffeemitkoffein/tinyweatherforecastgermany/ForecastAdapter.java
  2. 67
      app/src/main/java/de/kaffeemitkoffein/tinyweatherforecastgermany/ForecastBitmap.java
  3. 21
      app/src/main/java/de/kaffeemitkoffein/tinyweatherforecastgermany/MainActivity.java

351
app/src/main/java/de/kaffeemitkoffein/tinyweatherforecastgermany/ForecastAdapter.java

@ -23,10 +23,16 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.astronomie.info.Astronomy;
import java.text.DecimalFormat;
@ -34,6 +40,7 @@
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
public class ForecastAdapter extends BaseAdapter {
@ -51,7 +58,13 @@
private int display_wind_type;
private int display_wind_unit;
private int display_distance_unit;
LayoutInflater layoutInflater;
private LayoutInflater layoutInflater;
private final String labelSunrise;
private final String labelSunset;
private final String labelTwilight;
private final SparseArray<Bitmap> bitmapCache = new SparseArray<>();
public ForecastAdapter(Context context, ArrayList<Weather.WeatherInfo> weatherForecasts, ArrayList<Weather.WeatherInfo> weatherForecasts_hourly, Weather.WeatherLocation weatherLocation) {
this.context = context;
@ -70,14 +83,50 @@
this.display_distance_unit = weatherSettings.getDistanceDisplayUnit();
this.display_layout = weatherSettings.getDisplayLayout();
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.labelSunrise = context.getResources().getString(R.string.sunrise);
this.labelSunset = context.getResources().getString(R.string.sunset);
this.labelTwilight = context.getResources().getString(R.string.twilight);
}
private final static int SCALE_CONDITION_ICON = 2;
private final static int SCALE_MINI_ICON = 8;
private Bitmap loadScaledIcon(int id, int scale){
final Bitmap result = BitmapFactory.decodeResource(context.getResources(),id,null);
return result;
private void loadScaledIcon(final ImageView imageView, final int id, final int scale) {
final Integer key = Objects.hash(id, scale);
final boolean changed = !key.equals((Integer) imageView.getTag());
// only change if new image does not match existing image
if (changed) {
imageView.setTag(key);
imageView.post(new Runnable() {
@Override
public void run() {
// only set new image if image has not been changed until Runnable is executed
if (key.equals((Integer) imageView.getTag())) {
imageView.setTag(key);
Bitmap bitmap = bitmapCache.get(key);
if (bitmap == null) {
bitmap = BitmapFactory.decodeResource(context.getResources(), id, null);
bitmapCache.put(key, bitmap);
}
imageView.setImageBitmap(bitmap);
}
}
});
}
}
public void clearBitmapCache() {
bitmapCache.clear();
ForecastBitmap.clearBitmapCache();
}
private static void setVisibility(final View view, final int visibility) {
if (view.getVisibility() != visibility) {
view.setVisibility(visibility);
}
}
static class ViewHolder {
@ -104,7 +153,7 @@
ImageView sunset2;
View endofday_bar;
public ViewHolder(){
public ViewHolder() {
symbols = new ImageView[6];
labels = new TextView[6];
}
@ -151,10 +200,10 @@
ImageView sunset1 = null;
ImageView sunset2 = null;
View endofday_bar = null;
if (view == null){
if (view == null) {
// view is not available from cache
newView = true;
view = this.layoutInflater.inflate(R.layout.forecastitem,viewGroup,false);
view = this.layoutInflater.inflate(R.layout.forecastitem, viewGroup, false);
} else {
// recycle view information
viewHolder = (ViewHolder) view.getTag();
@ -208,7 +257,7 @@
viewHolder.condition_text = textView_weathercondition;
}
if (weatherInfo.hasCondition()){
Integer weathercondition = weatherInfo.getCondition();
int weathercondition = weatherInfo.getCondition();
textView_weathercondition.setText(WeatherCodeContract.getWeatherConditionText(context,weathercondition));
}
String precipitation_string = "";
@ -223,7 +272,7 @@
iconbar1_view = view.findViewById(R.id.fcitem_iconbar1);
viewHolder.iconbar1_view = iconbar1_view;
}
iconbar1_view.setVisibility(View.INVISIBLE);
setVisibility(iconbar1_view, View.INVISIBLE);
} else {
if (precipitation_textview == null){
precipitation_textview = (TextView) view.findViewById(R.id.fcitem_precipitation_text);
@ -236,42 +285,42 @@
int index = 0;
if (weatherInfo.hasClouds()){
ImageView clouds_view = getSymbolView(view,index,symbols,viewHolder);
clouds_view.setImageBitmap(loadScaledIcon(R.mipmap.symbol_cloud,SCALE_MINI_ICON));
loadScaledIcon(clouds_view, R.mipmap.symbol_cloud, SCALE_MINI_ICON);
TextView clouds_text = getTextView(view,index,labels,viewHolder);
clouds_text.setText(weatherInfo.getClouds()+"%");
index ++;
}
if (weatherInfo.hasProbThunderstorms()){
ImageView lightning_view = getSymbolView(view,index,symbols,viewHolder);
lightning_view.setImageBitmap(loadScaledIcon(R.mipmap.symbol_lightning,SCALE_MINI_ICON));
loadScaledIcon(lightning_view, R.mipmap.symbol_lightning, SCALE_MINI_ICON);
TextView lightning_text = getTextView(view,index,labels,viewHolder);
lightning_text.setText(weatherInfo.getProbThunderStorms()+"%");
index ++;
}
if (weatherInfo.hasProbSolidPrecipitation()){
ImageView solid_view = getSymbolView(view,index,symbols,viewHolder);
solid_view.setImageBitmap(loadScaledIcon(R.mipmap.symbol_hail,SCALE_MINI_ICON));
loadScaledIcon(solid_view, R.mipmap.symbol_hail, SCALE_MINI_ICON);
TextView solid_text = getTextView(view,index,labels,viewHolder);
solid_text.setText(weatherInfo.getProbSolidPrecipitation()+"%");
index ++;
}
if (weatherInfo.hasProbFreezingRain()){
ImageView freezingrain_view = getSymbolView(view,index,symbols,viewHolder);
freezingrain_view.setImageBitmap(loadScaledIcon(R.mipmap.symbol_freezing_rain,SCALE_MINI_ICON));
loadScaledIcon(freezingrain_view, R.mipmap.symbol_freezing_rain, SCALE_MINI_ICON);
TextView freezingrain_text = getTextView(view,index,labels,viewHolder);
freezingrain_text.setText(weatherInfo.getProbFreezingRain()+"%");
index ++;
}
if (weatherInfo.hasProbFog()){
ImageView fog_view = getSymbolView(view,index,symbols,viewHolder);
fog_view.setImageBitmap(loadScaledIcon(R.mipmap.symbol_fog,SCALE_MINI_ICON));
loadScaledIcon(fog_view, R.mipmap.symbol_fog, SCALE_MINI_ICON);
TextView fog_text = getTextView(view,index,labels,viewHolder);
fog_text.setText(weatherInfo.getProbFog()+"%");
index ++;
}
if (weatherInfo.hasProbDrizzle()){
ImageView drizzle_view = getSymbolView(view,index,symbols,viewHolder);
drizzle_view.setImageBitmap(loadScaledIcon(R.mipmap.symbol_drizzle,SCALE_MINI_ICON));
loadScaledIcon(drizzle_view, R.mipmap.symbol_drizzle, SCALE_MINI_ICON);
TextView drizzle_text = getTextView(view,index,labels,viewHolder);
drizzle_text.setText(weatherInfo.getProbDrizzle()+"%");
index ++;
@ -279,9 +328,9 @@
// make remaining icons invisible
while (index<6){
ImageView iv = getSymbolView(view,index,symbols,viewHolder);
iv.setVisibility(View.INVISIBLE);
setVisibility(iv, View.INVISIBLE);
TextView tv = getTextView(view,index,labels,viewHolder);
tv.setVisibility(View.INVISIBLE);
setVisibility(tv, View.INVISIBLE);
index++;
}
// weather icon
@ -291,7 +340,7 @@
}
if (weatherInfo.hasCondition()){
int weathercondition = weatherInfo.getCondition();
weather_icon.setImageBitmap(loadScaledIcon(WeatherCodeContract.getWeatherConditionDrawableResource(weathercondition,weatherInfo.isDaytime(weatherLocation)),SCALE_CONDITION_ICON));
loadScaledIcon(weather_icon, WeatherCodeContract.getWeatherConditionDrawableResource(weathercondition, weatherInfo.isDaytime(weatherLocation)), SCALE_CONDITION_ICON);
}
// right column
if (textView_temp == null){
@ -299,7 +348,7 @@
viewHolder.textView_temp = textView_temp;
}
if (weatherInfo.hasTemperature()){
textView_temp.setText(String.valueOf(weatherInfo.getTemperatureInCelsiusInt()+"°"));
textView_temp.setText(weatherInfo.getTemperatureInCelsiusInt()+"°");
}
if (textView_temphigh == null){
textView_temphigh = (TextView) view.findViewById(R.id.fcitem_temperature_high);
@ -326,19 +375,21 @@
imageView_windarrow = (ImageView) view.findViewById(R.id.fcitem_windarrow);
viewHolder.imageView_windarrow = imageView_windarrow;
}
String windstring="";
final StringBuilder windstring = new StringBuilder();
if (weatherInfo.hasWindDirection()){
if (display_wind_type==Weather.WindDisplayType.ARROW){
imageView_windarrow.setVisibility(View.VISIBLE);
imageView_windarrow.setImageBitmap(weatherInfo.getArrowBitmap(context));
}
if (display_wind_type==Weather.WindDisplayType.BEAUFORT){
imageView_windarrow.setVisibility(View.VISIBLE);
imageView_windarrow.setImageBitmap(weatherInfo.getBeaufortBitmap(context));
}
if (display_wind_type==Weather.WindDisplayType.TEXT){
imageView_windarrow.setVisibility(View.GONE);
windstring=weatherInfo.getWindDirectionString(context)+" ";
switch (display_wind_type) {
case Weather.WindDisplayType.ARROW:
setVisibility(imageView_windarrow, View.VISIBLE);
imageView_windarrow.setImageBitmap(weatherInfo.getArrowBitmap(context));
break;
case Weather.WindDisplayType.BEAUFORT:
setVisibility(imageView_windarrow, View.VISIBLE);
imageView_windarrow.setImageBitmap(weatherInfo.getBeaufortBitmap(context));
break;
case Weather.WindDisplayType.TEXT:
setVisibility(imageView_windarrow, View.GONE);
windstring.append(weatherInfo.getWindDirectionString(context)).append(' ');
break;
}
}
if (textView_wind == null){
@ -346,20 +397,24 @@
viewHolder.textView_wind = textView_wind;
}
if (weatherInfo.hasWindSpeed()){
String windspeed = "";
if (display_wind_unit==Weather.WindDisplayUnit.METERS_PER_SECOND){
windspeed = String.valueOf(weatherInfo.getWindSpeedInMsInt())+" ";
}
if (display_wind_unit==Weather.WindDisplayUnit.BEAUFORT){
windspeed = String.valueOf(weatherInfo.getWindSpeedInBeaufortInt())+" ";
final String windspeed;
switch (display_wind_unit) {
case Weather.WindDisplayUnit.METERS_PER_SECOND:
windspeed = String.valueOf(weatherInfo.getWindSpeedInMsInt()) + ' ';
break;
case Weather.WindDisplayUnit.BEAUFORT:
windspeed = String.valueOf(weatherInfo.getWindSpeedInBeaufortInt()) + ' ';
break;
case Weather.WindDisplayUnit.KILOMETERS_PER_HOUR:
windspeed = String.valueOf(weatherInfo.getWindSpeedInKmhInt()) + ' ';
break;
case Weather.WindDisplayUnit.KNOTS:
windspeed = String.valueOf(weatherInfo.getWindSpeedInKnotsInt()) + ' ';
break;
default:
windspeed = "";
}
if (display_wind_unit==Weather.WindDisplayUnit.KILOMETERS_PER_HOUR){
windspeed = String.valueOf(weatherInfo.getWindSpeedInKmhInt())+" ";
}
if (display_wind_unit==Weather.WindDisplayUnit.KNOTS){
windspeed = String.valueOf(weatherInfo.getWindSpeedInKnotsInt())+" ";
}
windstring = windstring + windspeed + Weather.getWindUnitString(display_wind_unit);
windstring.append(windspeed).append(Weather.getWindUnitString(display_wind_unit));
}
if (weatherInfo.hasFlurries()){
String flurries="";
@ -369,7 +424,7 @@
case Weather.WindDisplayUnit.KILOMETERS_PER_HOUR: flurries=String.valueOf(weatherInfo.getFlurriesInKmhInt()); break;
case Weather.WindDisplayUnit.KNOTS: flurries=String.valueOf(weatherInfo.getFlurriesInKnotsInt());
}
windstring = windstring + " ("+flurries+") ";
windstring.append(" (").append(flurries).append(") ");
}
textView_wind.setText(windstring);
if (linearLayout_visibility == null){
@ -381,18 +436,18 @@
viewHolder.textview_visibility = textview_visibility;
}
if (display_visibility){
String visibility = getVisibilityString(weatherInfo,display_distance_unit);
CharSequence visibility = getVisibilityString(weatherInfo, display_distance_unit);
if (visibility!=null){
linearLayout_visibility.setVisibility(View.VISIBLE);
textview_visibility.setVisibility(View.VISIBLE);
setVisibility(linearLayout_visibility, View.VISIBLE);
setVisibility(textview_visibility, View.VISIBLE);
textview_visibility.setText(visibility);
} else {
linearLayout_visibility.setVisibility(View.GONE);
textview_visibility.setVisibility(View.GONE);
setVisibility(linearLayout_visibility, View.GONE);
setVisibility(textview_visibility, View.GONE);
}
} else {
linearLayout_visibility.setVisibility(View.GONE);
textview_visibility.setVisibility(View.GONE);
setVisibility(linearLayout_visibility, View.GONE);
setVisibility(textview_visibility, View.GONE);
}
if (imageView_forecastBar == null){
imageView_forecastBar = (ImageView) view.findViewById(R.id.fcitem_forecastbar);
@ -400,7 +455,7 @@
}
// hourly forecast bar, display only if forecast is 6h
if ((weatherInfo.getForecastType() == Weather.WeatherInfo.ForecastType.HOURS_6) && (display_bar)){
imageView_forecastBar.setVisibility(View.VISIBLE);
setVisibility(imageView_forecastBar, View.VISIBLE);
// calculate offset
int start = getLastHourlyForecast();
int offset = getHourlyOffset(start,i);
@ -410,19 +465,31 @@
offset = start;
}
// construct arraylist with 0-6 items
ArrayList<Weather.WeatherInfo> baritems = new ArrayList<Weather.WeatherInfo>();
ArrayList<Weather.WeatherInfo> baritems = new ArrayList<>();
for (int j=offset; j<=offset+count; j++){
baritems.add(weatherForecasts_hourly.get(j));
}
ForecastBitmap forecastBitmap = new ForecastBitmap.Builder()
final ForecastBitmap forecastBitmap = new ForecastBitmap.Builder()
.setWetherInfos(baritems)
.setAnticipatedWidth(6)
.setWeatherLocation(weatherLocation)
.create(context);
imageView_forecastBar.setImageBitmap(forecastBitmap.getForecastBitmap());
final ImageView v = imageView_forecastBar;
final Long timestamp = System.currentTimeMillis();
v.setTag(timestamp);
v.post(new Runnable() {
@Override
public void run() {
if (timestamp.equals((Long) v.getTag())) {
v.setImageBitmap(forecastBitmap.getForecastBitmap());
}
}
});
} else {
// hide forecast bar when not needed
imageView_forecastBar.setVisibility(View.GONE);
setVisibility(imageView_forecastBar, View.GONE);
}
if (rise1 == null){
rise1 = (TextView) view.findViewById(R.id.fcitem_rise1);
@ -446,71 +513,65 @@
if (weatherInfo.getForecastType() == Weather.WeatherInfo.ForecastType.HOURS_6){
time_interval_start = weatherInfo.getTimestamp()-Weather.MILLIS_IN_HOUR*6;
}
if (Weather.isSunriseInIntervalUTC(riseset,time_interval_start,weatherInfo.getTimestamp()) && (Weather.isSunsetInIntervalUTC(riseset,time_interval_start,weatherInfo.getTimestamp()))){
boolean sunriseInIntervalUTC = Weather.isSunriseInIntervalUTC(riseset, time_interval_start, weatherInfo.getTimestamp());
boolean sunsetInIntervalUTC = Weather.isSunsetInIntervalUTC(riseset, time_interval_start, weatherInfo.getTimestamp());
if (sunriseInIntervalUTC && sunsetInIntervalUTC) {
// handle rare case that sunrise & sunset are in the same interval, then display sundrise & sunset
rise1.setVisibility(View.VISIBLE);
rise2.setVisibility(View.VISIBLE);
sunset1.setVisibility(View.VISIBLE);
setVisibility(rise1, View.VISIBLE);
setVisibility(rise2, View.VISIBLE);
setVisibility(sunset1, View.VISIBLE);
// in this case, display no arrow
sunset2.setVisibility(View.INVISIBLE);
String string_sunrise = context.getResources().getString(R.string.sunrise);
String string_sunset = context.getResources().getString(R.string.sunset);
string_sunrise = string_sunrise+": "+Weather.toHourMinuteString(Weather.getSunriseInUTC(riseset,weatherInfo.getTimestamp()));
string_sunset = string_sunset+": "+Weather.toHourMinuteString(Weather.getSunsetInUTC(riseset,weatherInfo.getTimestamp()));
setVisibility(sunset2, View.INVISIBLE);
String string_sunrise = labelSunrise + ": " + Weather.toHourMinuteString(Weather.getSunriseInUTC(riseset, weatherInfo.getTimestamp()));
String string_sunset = labelSunset + ": " + Weather.toHourMinuteString(Weather.getSunsetInUTC(riseset, weatherInfo.getTimestamp()));
rise1.setText(string_sunrise);
rise2.setText(string_sunset);
} else
if (Weather.isSunriseInIntervalUTC(riseset,time_interval_start,weatherInfo.getTimestamp())){
} else if (sunriseInIntervalUTC) {
// when runrise is in the interval, display twilight & sunrise
rise1.setVisibility(View.VISIBLE);
rise2.setVisibility(View.VISIBLE);
sunset1.setVisibility(View.VISIBLE);
sunset2.setVisibility(View.VISIBLE);
sunset1.setImageBitmap(loadScaledIcon(R.mipmap.arrow_up,SCALE_MINI_ICON));
sunset2.setImageBitmap(loadScaledIcon(R.mipmap.sunset,SCALE_MINI_ICON));
String string_sunrise = context.getResources().getString(R.string.sunrise);
String string_twilight = context.getResources().getString(R.string.twilight);
string_sunrise = string_sunrise+": "+Weather.toHourMinuteString(Weather.getSunriseInUTC(riseset,weatherInfo.getTimestamp()));
string_twilight = string_twilight+": "+Weather.toHourMinuteString(Weather.getCivilTwilightMorning(riseset, weatherInfo.getTimestamp()));
setVisibility(rise1, View.VISIBLE);
setVisibility(rise2, View.VISIBLE);
setVisibility(sunset1, View.VISIBLE);
setVisibility(sunset2, View.VISIBLE);
loadScaledIcon(sunset1, R.mipmap.arrow_up, SCALE_MINI_ICON);
loadScaledIcon(sunset2, R.mipmap.sunset, SCALE_MINI_ICON);
String string_sunrise = labelSunrise + ": " + Weather.toHourMinuteString(Weather.getSunriseInUTC(riseset, weatherInfo.getTimestamp()));
String string_twilight = labelTwilight + ": " + Weather.toHourMinuteString(Weather.getCivilTwilightMorning(riseset, weatherInfo.getTimestamp()));
rise1.setText(string_twilight);
rise2.setText(string_sunrise);
} else
if (Weather.isSunsetInIntervalUTC(riseset,time_interval_start,weatherInfo.getTimestamp())){
} else if (sunsetInIntervalUTC) {
// when sunset is in the interval, display sunset and twilight
rise1.setVisibility(View.VISIBLE);
rise2.setVisibility(View.VISIBLE);
sunset1.setVisibility(View.VISIBLE);
sunset2.setVisibility(View.VISIBLE);
sunset1.setImageBitmap(loadScaledIcon(R.mipmap.sunset,SCALE_MINI_ICON));
sunset2.setImageBitmap(loadScaledIcon(R.mipmap.arrow_down,SCALE_MINI_ICON));
String string_sunset = context.getResources().getString(R.string.sunset);
string_sunset = string_sunset+": "+Weather.toHourMinuteString(Weather.getSunsetInUTC(riseset,weatherInfo.getTimestamp()));
String string_twilight = context.getResources().getString(R.string.twilight);
string_twilight = string_twilight+": "+Weather.toHourMinuteString(Weather.getCivilTwilightEvening(riseset, weatherInfo.getTimestamp()));
setVisibility(rise1, View.VISIBLE);
setVisibility(rise2, View.VISIBLE);
setVisibility(sunset1, View.VISIBLE);
setVisibility(sunset2, View.VISIBLE);
loadScaledIcon(sunset1, R.mipmap.sunset, SCALE_MINI_ICON);
loadScaledIcon(sunset2, R.mipmap.arrow_down, SCALE_MINI_ICON);
String string_sunset = labelSunset + ": " + Weather.toHourMinuteString(Weather.getSunsetInUTC(riseset, weatherInfo.getTimestamp()));
String string_twilight = labelTwilight + ": " + Weather.toHourMinuteString(Weather.getCivilTwilightEvening(riseset, weatherInfo.getTimestamp()));
rise1.setText(string_sunset);
rise2.setText(string_twilight);
} else {
rise1.setVisibility(View.INVISIBLE);
rise2.setVisibility(View.INVISIBLE);
sunset1.setVisibility(View.INVISIBLE);
sunset2.setVisibility(View.INVISIBLE);
setVisibility(rise1, View.INVISIBLE);
setVisibility(rise2, View.INVISIBLE);
setVisibility(sunset1, View.INVISIBLE);
setVisibility(sunset2, View.INVISIBLE);
}
} else {
// hide if sunrise & sunset cannot be calculated (too far north or south)
rise1.setVisibility(View.INVISIBLE);
rise2.setVisibility(View.INVISIBLE);
sunset1.setVisibility(View.INVISIBLE);
sunset2.setVisibility(View.INVISIBLE);
setVisibility(rise1, View.INVISIBLE);
setVisibility(rise2, View.INVISIBLE);
setVisibility(sunset1, View.INVISIBLE);
setVisibility(sunset2, View.INVISIBLE);
}
if (endofday_bar == null){
endofday_bar = (View) view.findViewById(R.id.fcitem_endofday_bar);
endofday_bar = view.findViewById(R.id.fcitem_endofday_bar);
viewHolder.endofday_bar = endofday_bar;
}
if (isEndOfDay(weatherInfo) && (display_endofday_bar)){
endofday_bar.setVisibility(View.VISIBLE);
setVisibility(endofday_bar, View.VISIBLE);
} else {
endofday_bar.setVisibility(View.GONE);
setVisibility(endofday_bar, View.GONE);
}
if (newView){
view.setTag(viewHolder);
@ -518,32 +579,56 @@
return view;
}
private ImageView getSymbolView(View view, int pos, ImageView[] symbols, ViewHolder viewHolder){
private static ImageView getSymbolView(View view, int pos, ImageView[] symbols, ViewHolder viewHolder) {
int result = 0;
switch (pos){
case 0: result = R.id.fcitem_var1_symbol; break;
case 1: result = R.id.fcitem_var2_symbol; break;
case 2: result = R.id.fcitem_var3_symbol; break;
case 3: result = R.id.fcitem_var4_symbol; break;
case 4: result = R.id.fcitem_var5_symbol; break;
case 5: result = R.id.fcitem_var6_symbol; break;
}
if (symbols[pos]==null){
case 0:
result = R.id.fcitem_var1_symbol;
break;
case 1:
result = R.id.fcitem_var2_symbol;
break;
case 2:
result = R.id.fcitem_var3_symbol;
break;
case 3:
result = R.id.fcitem_var4_symbol;
break;
case 4:
result = R.id.fcitem_var5_symbol;
break;
case 5:
result = R.id.fcitem_var6_symbol;
break;
}
if (symbols[pos] == null){
symbols[pos] = (ImageView) view.findViewById(result);
viewHolder.symbols[pos] = symbols[pos];
}
return symbols[pos];
}
private TextView getTextView(View view, int pos, TextView[] labels, ViewHolder viewHolder){
private static TextView getTextView(View view, int pos, TextView[] labels, ViewHolder viewHolder) {
int result = 0;
switch (pos){
case 0: result = R.id.fcitem_var1_text; break;
case 1: result = R.id.fcitem_var2_text; break;
case 2: result = R.id.fcitem_var3_text; break;
case 3: result = R.id.fcitem_var4_text; break;
case 4: result = R.id.fcitem_var5_text; break;
case 5: result = R.id.fcitem_var6_text; break;
case 0:
result = R.id.fcitem_var1_text;
break;
case 1:
result = R.id.fcitem_var2_text;
break;
case 2:
result = R.id.fcitem_var3_text;
break;
case 3:
result = R.id.fcitem_var4_text;
break;
case 4:
result = R.id.fcitem_var5_text;
break;
case 5:
result = R.id.fcitem_var6_text;
break;
}
if (labels[pos] == null){
labels[pos] = (TextView) view.findViewById(result);
@ -577,44 +662,46 @@
return r;
}
public static String getVisibilityString(Weather.WeatherInfo weatherInfo, int display_distance_unit) {
public static CharSequence getVisibilityString(Weather.WeatherInfo weatherInfo, int display_distance_unit) {
if (!weatherInfo.hasVisibility() && !weatherInfo.hasProbVisibilityBelow1km()) {
return null;
} else {
String s = "";
StringBuilder s = new StringBuilder();
if (weatherInfo.hasVisibility()) {
if (display_distance_unit==Weather.DistanceDisplayUnit.METRIC){
int v = weatherInfo.getVisibilityInMetres();
if (v >= 10000) {
s = s + v / 1000 + " km";
s.append((v / 1000)).append(" km");
} else {
s = s + v + " m";
s.append(v).append(" m");
}
}
if (display_distance_unit==Weather.DistanceDisplayUnit.NAUTIC){
} else if (display_distance_unit == Weather.DistanceDisplayUnit.NAUTIC) {
Double v = weatherInfo.getVisibilityInNauticMiles();
String result = String.valueOf(v.intValue());
final String result;
if (v<1) {
result = formatDistanceNumberToString(v);
} else {
result = String.valueOf(v.intValue());
}
s = s + result + " nm";
}
if (display_distance_unit==Weather.DistanceDisplayUnit.IMPERIAL) {
s.append(result).append(" nm");
} else if (display_distance_unit == Weather.DistanceDisplayUnit.IMPERIAL) {
Double v = weatherInfo.getVisibilityInMiles();
String result = String.valueOf(v.intValue() + " mi");
final String result;
if (v < 1) {
Double yd = weatherInfo.getVisibilityInYards();
result = String.valueOf(yd.intValue()) + " yd";
} else {
result = String.valueOf(v.intValue() + " mi");
}
s = s + result;
s.append(result);
}
}
if (weatherInfo.hasVisibility() && weatherInfo.hasProbVisibilityBelow1km()) {
s = s + ", ";
s.append(", ");
}
if (weatherInfo.hasProbVisibilityBelow1km()) {
s = s + "<1km: " + weatherInfo.getProbVisibilityBelow1km() + "%";
s.append("<1km: ").append(weatherInfo.getProbVisibilityBelow1km()).append("%");
}
return s;
}

67
app/src/main/java/de/kaffeemitkoffein/tinyweatherforecastgermany/ForecastBitmap.java

@ -1,14 +1,20 @@
package de.kaffeemitkoffein.tinyweatherforecastgermany;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.*;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.SparseArray;
import android.view.WindowManager;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Objects;
public class ForecastBitmap{
@ -25,6 +31,18 @@ public class ForecastBitmap{
private float fontSize_medium;
private boolean displayWind = false;
private static final Paint POLY_PAINT = new Paint();
static {
POLY_PAINT.setStyle(Paint.Style.FILL_AND_STROKE);
}
private static final Paint TEXT_PAINT = new Paint();
static {
TEXT_PAINT.setAlpha(255);
}
private static final SparseArray<Bitmap> BITMAP_CACHE = new SparseArray<>();
static class Builder{
private ArrayList<Weather.WeatherInfo> weatherInfos;
private Weather.WeatherLocation weatherLocation;
@ -102,6 +120,8 @@ public class ForecastBitmap{
}
}
}
TEXT_PAINT.setColor(getColorFromResource(R.color.textColor));
}
private Bitmap getIconBitmap(Context context, Weather.WeatherInfo weatherInfo, int bitmapWidth, int bitmapHeight){
@ -115,24 +135,34 @@ public class ForecastBitmap{
resource = WeatherCodeContract.getWeatherConditionDrawableResource(weatherInfo.getCondition(), weatherInfo.isDaytime(this.weatherLocation));
}
}
Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(context.getResources(),resource),
bitmapWidth,
bitmapHeight,
true);
final int key = Objects.hash(resource, bitmapHeight, bitmapWidth);
Bitmap bitmap = BITMAP_CACHE.get(key);
if (bitmap == null) {
bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(context.getResources(),resource),
bitmapWidth,
bitmapHeight,
true);
BITMAP_CACHE.put(key, bitmap);
}
return bitmap;
}
public static void clearBitmapCache() {
BITMAP_CACHE.clear();
}
private void drawPolygon(Canvas canvas, float[] poly_x, float[] poly_y, int color, int alpha){
Paint poly_paint = new Paint();
poly_paint.setColor(color);
poly_paint.setAlpha(alpha);
poly_paint.setStyle(Paint.Style.FILL_AND_STROKE);
POLY_PAINT.setColor(color);
POLY_PAINT.setAlpha(alpha);
Path path = new Path();
path.moveTo(0,poly_y[0]);
for (int i=0; i<poly_x.length; i++){
path.lineTo(poly_x[i],poly_y[i]);
}
canvas.drawPath(path,poly_paint);
canvas.drawPath(path, POLY_PAINT);
}
public Bitmap getForecastBitmap(){
@ -150,9 +180,7 @@ public class ForecastBitmap{
itemWidth = (float) (bitmapWidth / anticipatedWidth);
fontSize_medium = (float) (bitmapHeight/2.2);
fontSize_small = (float) (bitmapHeight/3.3);
Paint paint = new Paint();
paint.setColor(getColorFromResource(R.color.textColor));
paint.setTextSize(fontSize_medium);
TEXT_PAINT.setTextSize(fontSize_medium);
float x_offset = (bitmapWidth - itemWidth);
// draw polygons for rain and clouds
float[] x_polygon = new float[weatherInfos.size()+4];
@ -200,19 +228,18 @@ public class ForecastBitmap{
Date date = new Date();
date.setTime(weatherInfos.get(position).getTimestamp());
String timetext = format.format(date);
paint.setTextSize(fontSize_small);
paint.setAlpha(255);
canvas.drawText(timetext,x_offset,fontSize_small,paint);
TEXT_PAINT.setTextSize(fontSize_small);
canvas.drawText(timetext,x_offset,fontSize_small,TEXT_PAINT);
// draw icon
Weather.WeatherInfo wi = weatherInfos.get(position);
float iconsize = itemWidth*iconRatio;
if (iconsize>bitmapHeight-fontSize_small-1){
iconsize = bitmapHeight-fontSize_small-1;
}
canvas.drawBitmap(getIconBitmap(context, wi,(int) iconsize,(int) iconsize),x_offset, fontSize_small+1,paint);
canvas.drawBitmap(getIconBitmap(context, wi,(int) iconsize,(int) iconsize),x_offset, fontSize_small+1,TEXT_PAINT);
// place temperature
paint.setTextSize(fontSize_medium);
canvas.drawText(weatherInfos.get(position).getTemperatureInCelsiusInt()+"°",x_offset+itemWidth*iconRatio,(float) (bitmapHeight/2)+fontSize_medium/2,paint);
TEXT_PAINT.setTextSize(fontSize_medium);
canvas.drawText(weatherInfos.get(position).getTemperatureInCelsiusInt()+"°",x_offset+itemWidth*iconRatio,(float) (bitmapHeight/2)+fontSize_medium/2,TEXT_PAINT);
x_offset = x_offset - itemWidth;
position--;
}

21
app/src/main/java/de/kaffeemitkoffein/tinyweatherforecastgermany/MainActivity.java

@ -57,6 +57,8 @@ public class MainActivity extends Activity {
public final static boolean API_TESTING_ENABLED = false;
private int test_position = 0; //last: 1916
private ForecastAdapter forecastAdapter;
StationsManager stationsManager;
ArrayList<String> spinnerItems;
@ -622,7 +624,7 @@ public class MainActivity extends Activity {
displayUpdateTime(weatherCard);
PrivateLog.log(getApplicationContext(),Tag.MAIN,"displaying: "+weatherCard.getCity()+" sensor: "+weatherCard.weatherLocation.name);
ListView weatherList = (ListView) findViewById(R.id.main_listview);
ForecastAdapter forecastAdapter = new ForecastAdapter(getApplicationContext(),getCustomForecastWeatherInfoArray(weatherCard),weatherCard.forecast1hourly,weatherCard.weatherLocation);
forecastAdapter = new ForecastAdapter(getApplicationContext(),getCustomForecastWeatherInfoArray(weatherCard),weatherCard.forecast1hourly,weatherCard.weatherLocation);
weatherList.setAdapter(forecastAdapter);
UpdateAlarmManager.updateAndSetAlarmsIfAppropriate(getApplicationContext(),UpdateAlarmManager.CHECK_FOR_UPDATE);
}
@ -1053,6 +1055,23 @@ public class MainActivity extends Activity {
}
}
@Override
public void onTrimMemory(final int level) {
switch (level) {
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
if (forecastAdapter != null) {
forecastAdapter.clearBitmapCache();
}
break;
}
}
private void showSimpleLocationAlert(String text){
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getApplicationContext().getResources().getString(R.string.geoinput_title));

Loading…
Cancel
Save