学习内容
- Google Android Training
http://developer.android.com/training/index.html - Github托管
https://github.com/kesenhoo/android-training-course-in-chinese - 中文阅读地址
http://hukai.me/android-training-course-in-chinese/index.html
以下是仅对我个人有意义的笔记
6. Android联系人与位置信息
6.1. Android联系人信息
6.1.1. 获取联系人列表
manifest 里面需要获取的权限
<uses-permission android:name="android.permission.READ_CONTACTS" />
CursorAdapter+Contacts Provider+ContactsContract(该类定义了一些对查询Contacts Provider很有用的常量和方法。当我们使用这个类的时候,我们不用自己定义内容URI、表名、列名等常量[例如,Contacts.DISPLAY_NAME=联系人的名字])
查询联系人列表(实现)
- 自定义一个listview
使用CursorAdapter,在onItemClick上实现点击获取个人信息
// Create the contact's content Uri;这里就可以为个人信息操作提供个人详情信息了 mContactUri = Contacts.getLookupUri(mContactId, mContactKey);
CursorLoader获取获取Contacts Provider中的数据。CursorLoader在一个与UI线程相独立的工作线程进行查询操作。
初始化
// 在onActivityCreated()/onCreate()中 getLoaderManager().initLoader(0, null, this);
调用上面语句后,会被loader框架自动调用onCreateLoader()
@Override public Loader<Cursor> onCreateLoader(int loaderId, Bundle args) { /* * Makes search string into pattern and * stores it in the selection array */ mSelectionArgs[0] = "%" + mSearchString + "%"; // Starts the query return new CursorLoader( getActivity(), Contacts.CONTENT_URI,//对于内容URI,则使用了Contacts.CONTENT_URI,这个URI关联到整个表 PROJECTION,//定义查询映射,如果要查询 SELECTION,//定义查询标准,这里就是写数据库查询语句的地方 mSelectionArgs,//定义包含选择字符串的变量 null ); }
- 根据特定的数据类型匹配联系人,就设置一下SELECTION
- 根据任意类型的数据匹配联系人,在CursorLoader里面设置使用 Contacts.CONTENT_FILTER_URI,并且PROJECTION、SELECTION、mSelectionArgs设为null。
onLoadFinished()返回查询结果
mCursorAdapter.swapCursor(cursor);
onLoaderReset()发现搜索到的东西过时的时候会调用,需要先删除SimpleCursorAdapter对已经存在Cursor的引用
mCursorAdapter.swapCursor(null);
6.1.2. 获取联系人详情
- 依旧是需要读取联系人权限
- 果要把Cursor绑定到ListView,记得要获取Data._ID,否则的话,界面绑定就不会起作用。同时也需要获取Data.MIMETYPE列,这样才能识别我们获取到的每一行数据的数据类型。
- 这里大概就是比较考验数据库语句的地方,根据需求来定义语句
6.1.3. 使用Intents修改联系人信息(通过Intent启动Contacts应用去运行适当的Activity)
添加一个联系人
原理:使用Contacts应用去插入一个联系人将会向Contacts Provider中的ContactsContract.RawContacts表中插入一个原始联系人。
Intent intent = new Intent(Intents.Insert.ACTION);
- 实现:比较简单,略。
update联系人
原理: 跟添加差不多,但是需要给这个Intent添加对应联系人的Contacts.CONTENT_LOOKUP_URI和MIME类型Contacts.CONTENT_ITEM_TYPE。
Intent editIntent = new Intent(Intent.ACTION_EDIT); //该方法的参数分别是联系人的Contacts._ID和Contacts.LOOKUP_KEY mSelectedContactUri = Contacts.getLookupUri(mCurrentId, mCurrentLookupKey);
扩展 :让用户自己选择插入还是编辑
Intent intentInsertEdit = new Intent(Intent.ACTION_INSERT_OR_EDIT);
6.1.4. 显示联系人头像(QuickContactBadge)
6.2. Android位置信息
6.2.1. 获取最后可知位置(Google Play services location APIs,fused location provider)
- SDK Manager下载和安装Google Play services location APIs组件
获取权限和决定选取哪种精度
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> //精度:一个城市的街区 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
实现,在Activity的onConnect里面调用
mLastLocation = LocationServices.FusedLocationApi.getLastLocation( mGoogleApiClient);
6.2.2. 获取位置更新
创建一个 LocationRequest 以保存请求 fused location provider 的参数
protected void createLocationRequest() { //更新间隔: setInterval()) - 接收位置更新的速率(每毫秒) LocationRequest mLocationRequest = new LocationRequest(); //最快更新间隔:setFastestInterval()) - 处理位置更新的最快速率(每毫秒)。 mLocationRequest.setInterval(10000); //精度:setPriority()) mLocationRequest.setFastestInterval(5000); mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); }
使用LocationRequest
@Override public void onConnected(Bundle connectionHint) { ... if (mRequestingLocationUpdates) { startLocationUpdates(); } } /**调用mLocationRequest更新地点*/ protected void startLocationUpdates() { LocationServices.FusedLocationApi.requestLocationUpdates( mGoogleApiClient, mLocationRequest, this); }
在Activity里面调用
public class MainActivity extends ActionBarActivity implements ConnectionCallbacks, OnConnectionFailedListener, LocationListener { ... @Override public void onLocationChanged(Location location) { mCurrentLocation = location; mCurrentLocation.getLatitude(); mCurrentLocation.getLongitude() } }
停止。onPause()
LocationServices.FusedLocationApi.removeLocationUpdates( mGoogleApiClient, this);
激活 onResume()
if (mGoogleApiClient.isConnected() && !mRequestingLocationUpdates) { startLocationUpdates();}
把状态保存在activity,也就是保存在 bundle,在onCreate的时候实现
private void updateValuesFromBundle(Bundle savedInstanceState) { if (savedInstanceState != null) { // Update the value of mRequestingLocationUpdates from the Bundle, and // make sure that the Start Updates and Stop Updates buttons are // correctly enabled or disabled. if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) { mRequestingLocationUpdates = savedInstanceState.getBoolean( REQUESTING_LOCATION_UPDATES_KEY); setButtonsEnabledState(); } // Update the value of mCurrentLocation from the Bundle and update the // UI to show the correct latitude and longitude. if (savedInstanceState.keySet().contains(LOCATION_KEY)) { // Since LOCATION_KEY was found in the Bundle, we can be sure that // mCurrentLocationis not null. mCurrentLocation = savedInstanceState.getParcelable(LOCATION_KEY); } // Update the value of mLastUpdateTime from the Bundle and update the UI. if (savedInstanceState.keySet().contains(LAST_UPDATED_TIME_STRING_KEY)) { mLastUpdateTime = savedInstanceState.getString( LAST_UPDATED_TIME_STRING_KEY); } updateUI(); }
6.2.3. 显示位置地址
FetchAddressIntentService 继承 IntentService(IntentService 类提供了一种结构使一个任务在后台线程运行。AsyncTask 类也可以执行后台操作,但是它被设计用于短时间运行的操作。)
- 在manifest里面注册
用Geocoder完成反向地理编码(将一个地理位置传换成地址的过程)
@Override protected void onHandleIntent(Intent intent) { Geocoder geocoder = new Geocoder(this, Locale.getDefault()); ... }
获取数据(需要完善错误机制)
// Get the location passed to this service through an extra. Location location = intent.getParcelableExtra( Constants.LOCATION_DATA_EXTRA); …… //获取到的地址信息 addresses = geocoder.getFromLocation( location.getLatitude(), location.getLongitude(), 1);
返回信息
private void deliverResultToReceiver(int resultCode, String message) { Bundle bundle = new Bundle(); bundle.putString(Constants.RESULT_DATA_KEY, message); mReceiver.send(resultCode, bundle); }
activity使用 (要在确认连接稳定的情况下调取方法)
public class MainActivity extends ActionBarActivity implements ConnectionCallbacks, OnConnectionFailedListener { ... @Override public void onConnected(Bundle connectionHint) { // Gets the best and most recent location currently available, // which may be null in rare cases when a location is not available. mLastLocation = LocationServices.FusedLocationApi.getLastLocation( mGoogleApiClient); if (mLastLocation != null) { // Determine whether a Geocoder is available. if (!Geocoder.isPresent()) { Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show(); return; } if (mAddressRequested) { startIntentService(); } } } } /**关键方法*/ protected void startIntentService() { Intent intent = new Intent(this, FetchAddressIntentService.class); intent.putExtra(Constants.RECEIVER, mResultReceiver); intent.putExtra(Constants.LOCATION_DATA_EXTRA, mLastLocation); startService(intent); }
6.2.4. 创建和监视地理围栏
- 原理:经纬度+半径=地理围栏
- 创建:获取权限 + Geofence.Builder 创建地理围栏+ GeofencingRequest中的 GeofencingRequestBuilder 类来需要监视的地理围栏,监视并设置如何触发
- 使用
- 定义地理围栏转义Intent PendingIntent
- 添加地理围栏 GeoencingApi.addGeofences()
停止
LocationServices.GeofencingApi.removeGeofences( mGoogleApiClient, // This is the same pending intent that was used in addGeofences(). getGeofencePendingIntent() ).setResultCallback(this); // Result processed in onResult(). }