I created an Android app widget that displays some text. By pressing on the widget the text updates by calling a web service using ksoap2. Everything works fine when my device has a fast internet connection (Wlan, HSDPA, 3G). It takes just one sec. But when it only has a slow connection (G or E) it doesn't work any more.
Each communication process takes about 20kb, so that's not that much data (I guess).
I was wondering if I do something wrong here. Should I use a service instead? I tried that but didn't know how to handle multiple intents. All examples I could find are using just 1 intent and no onReceive-method, so I didn't know rearrange my code.
This is what my AppWidgetProvider class looks like.
{
private static String UPDATE_WIDGET = "UpdateWidget";
private static String COUNT_DOWN = "CountDown";
private static String COUNT_UP = "CountUp";
// HARDCODED !!!
private static String currentLeague = "bl1";
private final static String saison = "2011";
private int maxNoOfGroups = 34;
// For all Soap methods
private static Soap soap = new Soap();
// Current group
private static int currentGroupOrderID = soap.getCurrentGroupOrderID(currentLeague);
// Singleton for counting up and down
private static Singleton singleton = Singleton.getInstance();
@Override
public void onDeleted(Context context, int[] appWidgetIds)
{
// TODO Auto-generated method stub
super.onDeleted(context, appWidgetIds);
}
@Override
public void onDisabled(Context context)
{
// TODO Auto-generated method stub
super.onDisabled(context);
}
@Override
public void onEnabled(Context context)
{
// TODO Auto-generated method stub
super.onEnabled(context);
}
@Override
public void onReceive(Context context, Intent intent)
{
// Name of the action of the intent
final String action = intent.getAction();
// Count down group by 1
if(COUNT_DOWN.equals(action))
{
if(currentGroupOrderID + singleton.getCount() == 1)
{
Toast.makeText(context, "Kein vorheriger Spieltag in dieser Saison vorhanden.", Toast.LENGTH_SHORT).show();
}
else
{
singleton.setCount(singleton.getCount()-1);
updateWidgetData(context, intent);
}
}
// Count up group by 1
if(COUNT_UP.equals(action))
{
if(currentGroupOrderID + singleton.getCount() == maxNoOfGroups)
{
Toast.makeText(context, "Kein weiterer Spieltag in dieser Saison vorhanden.", Toast.LENGTH_SHORT).show();
}
else
{
singleton.setCount(singleton.getCount()+1);
updateWidgetData(context, intent);
}
}
// Update current group
if(UPDATE_WIDGET.equals(action))
{
updateWidgetData(context, intent);
}
super.onReceive(context, intent);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++)
{
int appWidgetId = appWidgetIds[i];
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout_simple);
attachIntents(context,remoteViews,appWidgetId);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
/**
* Attaches the intents that are used by the widget.
*
* @param context
* @param remoteViews
* @param appWidgetId
*/
protected void attachIntents(Context context, RemoteViews remoteViews, int appWidgetId)
{
// Creating the intents
Intent updateIntent = new Intent(context, SoccerWidgetProvider.class);
Intent countDownIntent = new Intent(context, SoccerWidgetProvider.class);
Intent countUpIntent = new Intent(context, SoccerWidgetProvider.class);
// Setting the actions
updateIntent.setAction(UPDATE_WIDGET);
countDownIntent.setAction(COUNT_DOWN);
countUpIntent.setAction(COUNT_UP);
// Putting the appWidgetIds as extra for constant reaction of the wigdet
updateIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
updateIntent.setData(Uri.parse(updateIntent.toUri(Intent.URI_INTENT_SCHEME)));
countDownIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
countDownIntent.setData(Uri.parse(countDownIntent.toUri(Intent.URI_INTENT_SCHEME)));
countUpIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
countUpIntent.setData(Uri.parse(countUpIntent.toUri(Intent.URI_INTENT_SCHEME)));
// Creating the pendingIntents
PendingIntent updatePendingIntent = PendingIntent.getBroadcast(context, 0, updateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent countDownPendingIntent = PendingIntent.getBroadcast(context, 0, countDownIntent, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent countUpPendingIntent = PendingIntent.getBroadcast(context, 0, countUpIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// Setting the "onClick-listener"
remoteViews.setOnClickPendingIntent(R.id.widget_layout_root_elem, updatePendingIntent);
remoteViews.setOnClickPendingIntent(R.id.back_imageView, countDownPendingIntent);
remoteViews.setOnClickPendingIntent(R.id.forward_imageView, countUpPendingIntent);
// Update the widget
AppWidgetManager.getInstance(context).updateAppWidget(appWidgetId, remoteViews);
}
/**
* Updates the widget's content by calling the web service.
*
* @param context
* @param intent
* @param groupOrderID
*/
public void updateWidgetData(Context context, Intent intent)
{
// Calling the web service and parsing the response
Group theGroup = soap.getGroup(currentGroupOrderID + singleton.getCount(), currentLeague, saison);
if(theGroup == null)
{
Toast.makeText(context, "Soap result is null", Toast.LENGTH_SHORT).show();
}
// Current group name
String currentGroupName = theGroup.getGroupName();
// Creating the strings for the textViews
String teams1 = theGroup.returnAllTeams1AsString();
String teams2 = theGroup.returnAllTeams2AsString();
String scores = theGroup.returnAllScoresAsString();
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout_simple);
// Setting the text of the textViews
remoteViews.setTextViewText(R.id.widget_header_textView, currentGroupName);
remoteViews.setTextViewText(R.id.widget_team1_textView, teams1);
remoteViews.setTextViewText(R.id.widget_scores_textView, scores);
remoteViews.setTextViewText(R.id.widget_team2_textView, teams2);
ComponentName widget = new ComponentName(context, SoccerWidgetProvider.class);
AppWidgetManager awm = AppWidgetManager.getInstance(context);
awm.updateAppWidget(widget, remoteViews);
final int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
// This way the widget doesn't stop reacting after some time
if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID)
{
attachIntents(context, remoteViews, appWidgetId);
}
// In case of success make a toast
Toast.makeText(context, "Update complete", Toast.LENGTH_SHORT).show();
}
}
I solved it myself. Actually I just wanted to check for internet connection by implementing this method:
public boolean isOnline(Context context)
{
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting())
{
return true;
}
else
{
return false;
}
}
But as it turns out this also solves my problem of getting no answer with a slow connection. I use it in the onReceive() like this:
@Override
public void onReceive(Context context, Intent intent)
{
// Name of the action of the intent
final String action = intent.getAction();
// Check for internet connection. Also solves problem of slow internet connection!!!
if(isOnline(context) == true)
{
// Count down group by 1
if(COUNT_DOWN.equals(action))
{
if(currentGroupOrderID + singleton.getCount() == 1)
{
Toast.makeText(context, "Kein vorheriger Spieltag in dieser Saison vorhanden.", Toast.LENGTH_SHORT).show();
}
else
{
singleton.setCount(singleton.getCount()-1);
updateWidgetData(context, intent);
}
}
// Count up group by 1
if(COUNT_UP.equals(action))
{
if(currentGroupOrderID + singleton.getCount() == maxNoOfGroups)
{
Toast.makeText(context, "Kein weiterer Spieltag in dieser Saison vorhanden.", Toast.LENGTH_SHORT).show();
}
else
{
singleton.setCount(singleton.getCount()+1);
updateWidgetData(context, intent);
}
}
// Update current group
if(UPDATE_WIDGET.equals(action))
{
updateWidgetData(context, intent);
}
}
else
{
Toast.makeText(context, "No internet connection", Toast.LENGTH_SHORT).show();
}
super.onReceive(context, intent);
}
Maybe this will help someone else. ;-)