2013-08-30 71 views
1

我正在使用新的位置API並嘗試ActivityRecognition。我使用了代碼庫,它在Google Developers Training上,一切都很順利,直到我想更新UI。 (我知道你不能直接在服務上更新用戶界面,這就是爲什麼我使用處理程序/界面/的東西。) 我試過的:使用帶有ActivityRecognition的IntentService更新UI

使用接口,但這是沒用的,因爲我沒有沒有找到從IntentService獲取Activity上下文的方法。

還試圖傳遞一個句柄到IntentService爲它用行動,但由於某種原因,發送消息時,它達到調用此:

// If the intent contains an update 
    if (ActivityRecognitionResult.hasResult(intent)) { 

這只是返回false因爲我傳遞信使與處理程序。如果我刪除添加包含該消息的額外行的工作就好,但我無法更新我的用戶界面。

我試圖在開始服務之前刪除額外的東西,但沒有成功。任何想法我應該如何解決這個問題?

這些都是我的代碼有:

活動:

public class MainActivity extends FragmentActivity implements ConnectionCallbacks, OnConnectionFailedListener { 

public static final int MILLISECONDS_PER_SECOND = 1000; 
public static final int DETECTION_INTERVAL_SECONDS = 20; 
public static final int DETECTION_INTERVAL_MILLISECONDS = MILLISECONDS_PER_SECOND * DETECTION_INTERVAL_SECONDS; 

private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000; 
private PendingIntent mActivityRecognitionPendingIntent; 
// Store the current activity recognition client 
private ActivityRecognitionClient mActivityRecognitionClient; 
private Context mContext; 
// Flag that indicates if a request is underway. 
private boolean mInProgress; 
private static final String TAG = "MainActivity"; 
public static final String KEY_ACTION = "user_action"; 

public enum REQUEST_TYPE {START, STOP} 
private REQUEST_TYPE mRequestType; 
private TextView tvAction; 


//FIXME I'm aware of this potential leak 
Handler handler = new Handler() { 
    @Override 
    public void handleMessage(Message msg) { 
     Bundle reply = msg.getData(); 
     final String userAction = reply.getString(KEY_ACTION); 
     tvAction.setText("You are now: "+userAction); 
     // do whatever with the bundle here 
    } 
}; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    mContext = this; 

    tvAction = (TextView)findViewById(R.id.tv_action); 
    // Start with the request flag set to false 
    mInProgress = false; 

    mActivityRecognitionClient = 
     new ActivityRecognitionClient(mContext, this, this); 

    Intent intent = new Intent(
      mContext, ActivityRecognitionIntentService.class); 
      //putting this will make return false. 
    intent.putExtra("messenger", new Messenger(handler)); 


    mActivityRecognitionPendingIntent = 
     PendingIntent.getService(mContext, 0, intent, 
     PendingIntent.FLAG_UPDATE_CURRENT); 
} 

private void startUpdates() { 

    mRequestType = REQUEST_TYPE.START; 

    // Check for Google Play services 

    if (!servicesConnected()) { 
     return; 
    } 
    // If a request is not already underway 
    if (!mInProgress) { 
     // Indicate that a request is in progress 
     mInProgress = true; 
     // Request a connection to Location Services 
     mActivityRecognitionClient.connect(); 
    // 
    } 
} 


private void stopUpdates() { 
    // Set the request type to STOP 
    mRequestType = REQUEST_TYPE.STOP; 
    /* 
    * Test for Google Play services after setting the request type. 
    * If Google Play services isn't present, the request can be 
    * restarted. 
    */ 
    if (!servicesConnected()) { 
     return; 
    } 
    // If a request is not already underway 
    if (!mInProgress) { 
     // Indicate that a request is in progress 
     mInProgress = true; 
     // Request a connection to Location Services 
     mActivityRecognitionClient.connect(); 
    // 
    } 
} 

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    // Decide what to do based on the original request code 
    switch (requestCode) { 
    case CONNECTION_FAILURE_RESOLUTION_REQUEST: 
     /* 
     * If the result code is Activity.RESULT_OK, try to connect again 
     */ 
     switch (resultCode) { 
     case Activity.RESULT_OK: 
      /* 
      * Try the request again 
      */ 
      break; 
     } 

    } 
} 

private boolean servicesConnected() { 
    // Check that Google Play services is available 
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); 
    // If Google Play services is available 
    if (ConnectionResult.SUCCESS == resultCode) { 
     // In debug mode, log the status 
     Log.d("Activity Recognition", "Google Play services is available."); 
     // Continue 
     return true; 
     // Google Play services was not available for some reason 
    } else { 
     // Get the error dialog from Google Play services 
     Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(resultCode, this, 
       CONNECTION_FAILURE_RESOLUTION_REQUEST); 

     // If Google Play services can provide an error dialog 
     if (errorDialog != null) { 
      // Create a new DialogFragment for the error dialog 
      ErrorDialogFragment errorFragment = new ErrorDialogFragment(); 
      // Set the dialog in the DialogFragment 
      errorFragment.setDialog(errorDialog); 
      // Show the error dialog in the DialogFragment 
      errorFragment.show(getSupportFragmentManager(), "Activity Recognition"); 
     } 
     return false; 
    } 
} 

// Define a DialogFragment that displays the error dialog 
public static class ErrorDialogFragment extends DialogFragment { 
    // Global field to contain the error dialog 
    private Dialog mDialog; 

    // Default constructor. Sets the dialog field to null 
    public ErrorDialogFragment() { 
     super(); 
     mDialog = null; 
    } 

    // Set the dialog to display 
    public void setDialog(Dialog dialog) { 
     mDialog = dialog; 
    } 

    // Return a Dialog to the DialogFragment. 
    @Override 
    public Dialog onCreateDialog(Bundle savedInstanceState) { 
     return mDialog; 
    } 
} 

@Override 
public void onConnectionFailed(ConnectionResult connectionResult) { 
    // Turn off the request flag 
    mInProgress = false; 
    /* 
    * If the error has a resolution, start a Google Play services 
    * activity to resolve it. 
    */ 
    if (connectionResult.hasResolution()) { 
     try { 
      connectionResult.startResolutionForResult(
        this, 
        CONNECTION_FAILURE_RESOLUTION_REQUEST); 
     } catch (SendIntentException e) { 
      // Log the error 
      e.printStackTrace(); 
     } 
    // If no resolution is available, display an error dialog 
    } else { 
     // Get the error code 
     int errorCode = connectionResult.getErrorCode(); 
     // Get the error dialog from Google Play services 
     Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
       errorCode, 
       this, 
       CONNECTION_FAILURE_RESOLUTION_REQUEST); 
     // If Google Play services can provide an error dialog 
     if (errorDialog != null) { 
      // Create a new DialogFragment for the error dialog 
      ErrorDialogFragment errorFragment = 
        new ErrorDialogFragment(); 
      // Set the dialog in the DialogFragment 
      errorFragment.setDialog(errorDialog); 
      // Show the error dialog in the DialogFragment 
      errorFragment.show(
        getSupportFragmentManager(), 
        "Activity Recognition"); 
     } 
    } 
} 

@Override 
public void onConnected(Bundle arg0) { 


    switch (mRequestType) { 
    case START: 
     /* 
    * Request activity recognition updates using the preset 
    * detection interval and PendingIntent. This call is 
    * synchronous. 
    */ 
    mActivityRecognitionClient.requestActivityUpdates(
      DETECTION_INTERVAL_MILLISECONDS, 
      mActivityRecognitionPendingIntent); 
     break; 
    case STOP : 
     mActivityRecognitionClient.removeActivityUpdates(
       mActivityRecognitionPendingIntent); 
     break; 

    default : 
     Log.e(TAG, "Unknown request type in onConnected()."); 
     break; 
    } 


    /* 
    * Since the preceding call is synchronous, turn off the 
    * in progress flag and disconnect the client 
    */ 
    mInProgress = false; 
    mActivityRecognitionClient.disconnect(); 
} 

@Override 
public void onDisconnected() { 
    // Turn off the request flag 
    mInProgress = false; 
    // Delete the client 
    mActivityRecognitionClient = null; 
} 

@Override 
protected void onPause() { 
    super.onPause(); 
    stopUpdates(); 
} 

@Override 
protected void onResume() { 
    super.onResume(); 
    startUpdates(); 
} 

@Override 
protected void onStop() { 
    super.onStop(); 
    stopUpdates(); 
} 


} 

IntentService

import android.support.v4.app.NotificationCompat; 
import android.util.Log; 

import com.google.android.gms.location.ActivityRecognitionResult; 
import com.google.android.gms.location.DetectedActivity; 

public class ActivityRecognitionIntentService extends IntentService { 

    // Formats the timestamp in the log 
    private static final String DATE_FORMAT_PATTERN = "yyyy-MM-dd HH:mm:ss.SSSZ"; 

    private static final String TAG = "ActivityRecognitionIntentService"; 

    private static final String SHARED_PREFERENCES = "ActivityRecognition"; 

    private static final String KEY_PREVIOUS_ACTIVITY_TYPE = "KEY_PREVIOUS_ACTIVITY_TYPE"; 

    // A date formatter 
    private SimpleDateFormat mDateFormat; 

    // Store the app's shared preferences repository 
    private SharedPreferences mPrefs; 
    protected Messenger messenger; 

    public ActivityRecognitionIntentService() { 
     // Set the label for the service's background thread 
     super("ActivityRecognitionIntentService"); 

    } 

    public ActivityRecognitionIntentService(String name) { 
     super(name); 
    } 

    @Override 
    public void onStart(Intent intent, int startId) { 
     Bundle extras = intent.getExtras(); 
     messenger = (Messenger) extras.get("messenger"); 
     intent.removeExtra("messenger"); 
     super.onStart(intent, startId); 
    } 

    /** 
    * Called when a new activity detection update is available. 
    */ 
    @Override 
    protected void onHandleIntent(Intent intent) { 

     // Get a handle to the repository 
     Context mContext = getApplicationContext(); 


     mPrefs = mContext.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE); 

     // Get a date formatter, and catch errors in the returned timestamp 
     try { 
      mDateFormat = (SimpleDateFormat) DateFormat.getDateTimeInstance(); 
     } catch (Exception e) { 
      Log.e(TAG, getString(R.string.date_format_error)); 
     } 

     // Format the timestamp according to the pattern, then localize the 
     // pattern 
     mDateFormat.applyPattern(DATE_FORMAT_PATTERN); 
     mDateFormat.applyLocalizedPattern(mDateFormat.toLocalizedPattern()); 

     // If the intent contains an update 
     if (ActivityRecognitionResult.hasResult(intent)) { 

      // Get the update 
      ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent); 


      // Get the most probable activity from the list of activities in the 
      // update 
      DetectedActivity mostProbableActivity = result.getMostProbableActivity(); 

      // Get the confidence percentage for the most probable activity 
      int confidence = mostProbableActivity.getConfidence(); 

      // Get the type of activity 
      int activityType = mostProbableActivity.getType(); 

      // Check to see if the repository contains a previous activity 
      if (!mPrefs.contains(KEY_PREVIOUS_ACTIVITY_TYPE)) { 

       // This is the first type an activity has been detected. Store 
       // the type 
       Editor editor = mPrefs.edit(); 
       editor.putInt(KEY_PREVIOUS_ACTIVITY_TYPE, activityType); 
       editor.commit(); 

       // If the repository contains a type 
      } else if (
       // The confidence level for the current activity is > 50% 
        (confidence >= 50)) { 

       // Notify the user 
       final String userAction = getNameFromType(activityType); 
       sendNotification(userAction); 

       if (messenger != null) { 
        Message msg = Message.obtain(); 
        Bundle data = new Bundle(); 
         data.putString(MainActivity.KEY_ACTION, userAction); 
        msg.setData(data); //put the data here 
        try { 
         messenger.send(msg); 
        } catch (RemoteException e) { 
          Log.i("error", "error"); 
        } 
       } 
      } 
     } 
    } 

    /** 
    * Post a notification to the user. The notification prompts the user to 
    * click it to open the device's GPS settings 
    */ 
    private void sendNotification(String type) { 

     // Create a notification builder that's compatible with platforms >= 
     // version 4 
     NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext()); 

     // Set the title, text, and icon 
     builder.setContentTitle(getString(R.string.app_name)).setContentText(type)// getString(R.string.turn_on_GPS)) 
       .setSmallIcon(R.drawable.ic_launcher) 

       // Get the Intent that starts the Location settings panel 
       .setContentIntent(getContentIntent()); 

     // Get an instance of the Notification Manager 
     NotificationManager notifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 

     // Build the notification and post it 
     notifyManager.notify(0, builder.build()); 
    } 

    /** 
    * Get a content Intent for the notification 
    * 
    * @return A PendingIntent that starts the device's Location Settings panel. 
    */ 
    private PendingIntent getContentIntent() { 

     // Set the Intent action to open Location Settings 
     Intent gpsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); 

     // Create a PendingIntent to start an Activity 
     return PendingIntent.getActivity(getApplicationContext(), 0, gpsIntent, PendingIntent.FLAG_UPDATE_CURRENT); 
    } 


    /** 
    * Map detected activity types to strings 
    * 
    * @param activityType 
    *   The detected activity type 
    * @return A user-readable name for the type 
    */ 
    private String getNameFromType(int activityType) { 
     switch (activityType) { 
     case DetectedActivity.IN_VEHICLE: 
      return "in_vehicle"; 
     case DetectedActivity.ON_BICYCLE: 
      return "on_bicycle"; 
     case DetectedActivity.ON_FOOT: 
      return "on_foot"; 
     case DetectedActivity.STILL: 
      return "still"; 
     case DetectedActivity.UNKNOWN: 
      return "unknown"; 
     case DetectedActivity.TILTING: 
      return "tilting"; 
     } 
     return "unknown"; 
    } 
} 

回答

1

IntentServices不準更新UI,SI它們被設計爲運行後臺任務。

您應該根據通知設計您的服務界面,而不是單擊可以打開應用程序活動以顯示有關服務狀態的詳細信息。