Search code examples
androidconnectionksoap2android-appwidget

Android ksoap2 communication doesn't work with slow internet connection


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();
}
}

Solution

  • 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. ;-)