0

我的 IntentService 有问题 - 我的目的是从活动中外包网络和处理(我之前使用了一个效果很好的 AsyncTask,但我也想将它扩展到一个小部件)。

问题是,我没有从服务中得到任何结果——它几乎似乎永远不会被调用(或者应该检索数据的代码中有问题)......

在使用服务方面比我更有经验的人可以看看并发现我犯的明显(或隐藏)错误吗?将不胜感激!

服务内容:

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

调用活动的内容:

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

}

编辑(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>
4

2 回答 2

0


对于意图服务,我们不需要实现/覆盖方法onStartCommand
所以删除以下代码

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

    return START_FLAG_RETRY;
}


“服务内容”中
再试一试。

于 2012-12-13T14:32:34.763 回答
0

我可能是错的,但您的 returnResult() 函数似乎没有发送任何内容。也许您忘记添加 sendBroadcst(resultIntent); 打电话给它?

于 2012-12-21T04:48:16.657 回答