Search code examples
androidandroid-intentserviceintentfilterintentservice

My IntentService doesn't seem to return an answer, or it isn't called at all?


I've got a problem with my IntentService - my intention is to outsource the networking and processing from the activity (I previously used an AsyncTask which worked excellent, however I also want to extend it to a widget).

The thing is, I don't get any result from the service - it almost seems like it never gets called (or something is wrong in the code that's supposed to retreive the data)...

Can someone with more experience in using services than me take a look and spot the obvious (or hidden) errors I've made? Would be greatly appreciated!

Contents of the service:

public class StateCheckerService extends IntentService {
public StateCheckerService() {
    super("StateCheckerService");
    // TODO Auto-generated constructor stub
}


String pageContent;
public static final String API_URL = "http://omegav.no/api/dooropen.php", INTENT_ACTION="omegavdoor.FETCH_COMPLETE", EXTRA_STATUS="status", EXTRA_TIME="time", KEY_STATUS="";
SharedPreferences settings;
private int timeMins = 0, timeoutMillis = 5000, resultCode;
int status_code = 0;

public void onCreate() {
    super.onCreate();
    // Declares the SharedPreferences object to use
    settings = PreferenceManager.getDefaultSharedPreferences(getBaseContext());

}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(null, resultCode, resultCode);

    return START_FLAG_RETRY;
}

@Override
protected void onHandleIntent(Intent intent) {
    // TODO Auto-generated method stub
    if (checkConnection()) {
        // Start process of retrieving status
        try {
            getData();
        } catch (IOException e) {
            returnResult(11);
        } finally {
            returnResult(resultCode);
        }
    } else {
        // Notify the user of missing connection
        returnResult(0); // Error: connection unavailable
    }
}


private boolean checkConnection() {
    // Declare connection manager and NetworkInfo objects
    ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();

    // Check network connection
    if (activeInfo != null && activeInfo.isConnected()) {
        return true;
    } else {
        return false;
    }
}


    /** Function to get data from the remote server */
    public void getData() throws IOException {
        // Create URL object to connect to
        URL url = new URL(API_URL);
        // Open new HTTP connection
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        // Set a connection timeout to prevent app lockup if it can't reach the server
        urlConnection.setConnectTimeout(timeoutMillis);

        // Attempt to connect and retrieve data
        try {   // Return exception if the stream is unreachable
            InputStream in = new BufferedInputStream(urlConnection.getInputStream());
            // Process the contents of the stream
            readStream(in);
        }
        finally {
            // Disconnect after retrieving data
            urlConnection.disconnect();
        }
    }

    public void readStream(InputStream input) throws IOException {
        // Reads the content of the page
        try {
            // String length varies with the time value - read some extra to avoid missing the end
            pageContent = readIt(input, 40);
            // Remove the extra white spaces at the end

        } catch (UnsupportedEncodingException e) {
            resultCode = 10;
        }
        if (pageContent == null) {
            // Stop further processing (and cause the UI to report error)
            resultCode = 13;
        } else {
            // Checks to see whether the "open" flag exists 
            if (pageContent.charAt(9) == '1') {
                // Find out how long it's been open
                int openTime = Integer.parseInt(pageContent.substring(20, pageContent.lastIndexOf("}")));
                // Convert from seconds to minutes
                timeMins = openTime / 60;
                if (timeMins > 0) {
                    resultCode = 1; // Display how long it's been open
                } else { 
                    resultCode = 2; // If it just opened
                    }                   
            } else {
                // Find out how long it's been closed
                int closedTime = Integer.parseInt(pageContent.substring(19, pageContent.lastIndexOf("}"))); // TODO: change 19 to 20 to support the API change
                // Convert from seconds to minutes
                timeMins = closedTime / 60;
                if (timeMins > 0) {
                    resultCode = 3; // Display how long it's been open
                } else {
                    resultCode = 4; // If it just closed
                }
            }
        }
    }


    // Reads an InputStream and converts it to a String.
    public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
        // Initialize reader object
        Reader reader = null;

        // Decode the input stream
        reader = new InputStreamReader(stream, "UTF-8");        
        char[] buffer = new char[len];
        reader.read(buffer);
        return new String(buffer);
    }


private void returnResult(int resultCode) {
    Intent resultIntent = new Intent();
    resultIntent.setAction(INTENT_ACTION);
    resultIntent.putExtra(EXTRA_STATUS, resultCode)
    .putExtra(EXTRA_TIME, timeMins);

}


@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    return null;
}
}

Contents of the calling activity:

public class StateChecker extends Activity {
String pageContent;
boolean doorIsOpen = false, notFirstRun = false, error = false;
private static final int transitionDuration = 250;
private ResponseReceiver receiver;
TransitionDrawable transition;
TextView text_doorState;
Button button_getState;
ProgressBar door_progress;
LinearLayout background;
int timeMins;


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // Inflate the XML layout
    setContentView(R.layout.state_checker);

    // Declare the views to be adressed
    text_doorState = (TextView) findViewById(R.id.tv_doorState);
    button_getState = (Button) findViewById(R.id.button_refreshState);
    door_progress = (ProgressBar) findViewById(R.id.doorState_progressBar);
    background = (LinearLayout) findViewById(R.id.doorStateView);


    IntentFilter filter = new IntentFilter(ResponseReceiver.ACTION_RESP);
    filter.addCategory(Intent.CATEGORY_DEFAULT);
    receiver = new ResponseReceiver();
    registerReceiver(receiver, filter);

}

/** Receiver class to listen to and handle result from checker service */
public class ResponseReceiver extends BroadcastReceiver {
    public static final String ACTION_RESP = StateCheckerService.INTENT_ACTION;
    @Override
    public void onReceive(Context context, Intent intent) {
        int result = intent.getIntExtra(StateCheckerService.EXTRA_STATUS, 0);
        timeMins = intent.getIntExtra(StateCheckerService.EXTRA_TIME, 0);
        Toast.makeText(context, "Result received", Toast.LENGTH_SHORT).show();
        processResult(result);
    }
}

public void onStart() {
    super.onStart();
    // Checks the door status on app launch
    go();
}

public void onStop() {
    super.onStop();
    unregisterReceiver(receiver);
}

private void go() {
    // Update text and progress bar to indicate it's working
    text_doorState.setText(R.string.text_stateUpdating);
    door_progress.setVisibility(View.VISIBLE);
    // Fade the color back to grey if it is something else
    if (notFirstRun) {
        transition.reverseTransition(transitionDuration);
    }
    if (checkConnection()) {
        Intent intent = new Intent(this, StateCheckerService.class);
        startService(intent);
        notify("service started");
    } else {
        // Notify the user of missing connection
        notify(getString(R.string.error_connection_unavailable));
    }

}
private boolean checkConnection() {
    // Declare connection manager and NetworkInfo objects
    ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();

    // Check network connection
    if (activeInfo != null && activeInfo.isConnected()) {
        return true;
    } else {
        return false;
    }
}


protected void processResult(Integer resultCode) {
    switch (resultCode) {
    case 1:
        if (timeMins < 60) {
            // Notify of open door and display minutes
            notify(getString(R.string.text_stateOpenMins, timeMins));
        } else {
            // If it's been more than an hour, display the time in hours
            int openTimeHours = timeMins / 60;
            int remainder = timeMins - (openTimeHours * 60);
            notify(getString(R.string.text_stateOpenHours, openTimeHours, remainder));
        }
        break;
    case 2:
        // Notify of open door (just opened)
        notify(getString(R.string.text_stateOpenNow));
        break;
    case 3:
        if (timeMins < 60) {
            // Notify of closed door and display minutes
            notify(getString(R.string.text_stateClosedMins, timeMins));
        } else {
            // If it's been more than an hour, display the time in hours
            int closedTimeHours = timeMins / 60;
            int remainder = timeMins - (closedTimeHours * 60);
            notify(getString(R.string.text_stateClosedHours, closedTimeHours, remainder));
        }
        break;
    case 4:
        // Notify of closed door (just closed
        notify(getString(R.string.text_stateClosedNow));
        break;
    case 10:
        // Error message: unsupported stream format
        notify(getString(R.string.error_stream_unsupported));
        break;
    case 11:
        // Error message: connection failed
        notify(getString(R.string.error_connection_failed));
        break;
    // Case 12 reserved
    case 13:
        // Error message: null data stream
        notify(getString(R.string.error_stream_retrieve));
        break;
    }
    if (resultCode >= 10) {
        error = true;
    } else {
        error = false;
    }
    updateDisplay();
}

protected void updateDisplay() {
    door_progress.setVisibility(View.GONE);
    if (!error) {
        /** Update the UI to reflect the door state */
        if(doorIsOpen) {
            // Update the text view to display an open door state
            text_doorState.setText(getString(R.string.text_stateOpen));
            // Change the background color
            background.setBackgroundResource(R.drawable.trans_open);
            transition = (TransitionDrawable) background.getBackground();
            transition.startTransition(transitionDuration);
        } else {
            // Update the text view to display a closed door state
            text_doorState.setText(getString(R.string.text_stateClosed));
            // Change the background color
            background.setBackgroundResource(R.drawable.trans_close);
            transition = (TransitionDrawable) background.getBackground();
            transition.startTransition(transitionDuration);
        }
        // Indicates that the app has gone through a successful execution
        notFirstRun = true; 
    } else {
        // If it failed to execute, display error message
        text_doorState.setText(R.string.text_stateFailed);
        // Revert to grey background
        background.setBackgroundResource(R.drawable.background);
    }

}


/** Helper class used to display toast notifications */
private void notify(String message) {
    Toast.makeText(this, message, Toast.LENGTH_LONG).show();        
}

}

Edit (AndroidManifest):

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tovine.omegavdoor.widget"
android:versionCode="5"
android:versionName="1.0.1" >

<uses-sdk
    android:minSdkVersion="7"
    android:targetSdkVersion="14" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />


<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >
    <activity
        android:name=".Settings"
        android:label="@string/title_activity_settings" >
    </activity>
    <activity
        android:name=".StateChecker"
        android:configChanges="orientation|screenSize"
        android:title="@string/app_name"
        android:windowSoftInputMode="stateAlwaysHidden" >

        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <activity
        android:name="com.google.ads.AdActivity"
        android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />

    <receiver
        android:name=".WidgetStateProvider" >
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            <action android:name="omegavdoor.FETCH_COMPLETE" />
        </intent-filter>

        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/doorwidget" />
    </receiver>

    <service android:name="tovine.omegavdoor.widget.WidgetUpdateService">
        <intent-filter>
            <action android:name="omegavdoor.FETCH_COMPLETE" />
        </intent-filter>
    </service>

    <service android:name="tovine.omegavdoor.widget.StateCheckerService"
        android:process=":checker_process">

    </service>

    -->
   <!-- <activity
        android:name="Probability"
        android:label="@string/title_activity_probability" >
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="StateChecker" />
    </activity>
    <activity
        android:name=".LoadWebImg"
        android:label="TestClass" /> -->
</application>

</manifest>

Solution

  • I can be wrong but it seems your returnResult() function doesn't send anything. Maybe you forgot to add sendBroadcst(resultIntent); call to it?