需要全部源码请点赞关注收藏后评论区留言私信~~~

艺术家常说“距离产生美”,其实距离近才是优势,谁不希望自己的工作事少钱多离家近呢?不光是工作,像租房买房、恋爱交友,大家都希望找个近点的,比如58、赶集主打同城交易,微信、陌陌主打同城交友,所谓近水楼台先得月嘛。 正因为位置信息如此重要,所以手机早早支持定位功能,还锲而不舍推进卫星定位、基站定位、WiFi定位等手段。 通过分享自己的位置,人们可以迅速找到附近志同道合的朋友,从而在传统社交之外开辟了新领域——周边社交。

一、需求描述

附近的人除了交友聊天,还存在下列的周边互动场景:

(1)个人有闲置物品,扔了可惜,想送给有需要的乡里乡亲;

(2)家里水电坏了,想临时找个附近的水电工上门修理;

(3)孩子长大了,看看周边有没有美术老师练习绘画、音乐老师练习钢琴之类; 为此需要增加地图导航功能,不仅在地图上标出周围人群的所在地,还需提供导航服务以便用户出行。

二、功能分析

(1)详情对话框:人员详情既包括头像图片,也包括昵称、性别、爱好、地址等文字描述。 (2)地图定位:自己位置和他人位置都用到了定位功能。

(3)地图导航:从当前位置驱车前往对方所在地,需要地图服务提供导航路线以便出行。

(4)网络通信框架:上传人员信息与获取人员列表均需与后端交互。

(5)图片加载框架:利用Glide框架加载人员头像。

(6)移动数据格式JSON:通过JSON结构封装http交互数据。

下面介绍一些代码模块之间的互相关系

(1)ChooseLocationActivity.java:这是选择自身位置的地图界面。

(2)InfoEditActivity.java:这是个人信息的编辑页面。

(3)NearbyActivity.java:这是显示附近人员的地图界面。

(4)NearbyLoadTask.java:这是附近人员列表的加载任务。

(5)PersonDialog.java:这是人员详情对话框,支持打对方电话、去对方那里等功能。

三、效果展示

首先选择自己的位置

点击下一步输入一些自己的基本信息

可以在下拉框中选择查看的人们列表 此处最好用多部手机进行测试并且开启后台服务器

四、代码

部分代码如下 如需要全部源码请点赞关注收藏后评论区留言私信~~~

package com.example.location;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;import com.tencent.lbssearch.TencentSearch;
import com.tencent.lbssearch.object.param.Geo2AddressParam;
import com.tencent.lbssearch.object.result.Geo2AddressResultObject;
import com.tencent.map.geolocation.TencentLocation;
import com.tencent.map.geolocation.TencentLocationListener;
import com.tencent.map.geolocation.TencentLocationManager;
import com.tencent.map.geolocation.TencentLocationRequest;
import com.tencent.map.tools.net.http.HttpResponseListener;
import com.tencent.tencentmap.mapsdk.maps.CameraUpdate;
import com.tencent.tencentmap.mapsdk.maps.CameraUpdateFactory;
import com.tencent.tencentmap.mapsdk.maps.MapView;
import com.tencent.tencentmap.mapsdk.maps.TencentMap;
import com.tencent.tencentmap.mapsdk.maps.model.BitmapDescriptor;
import com.tencent.tencentmap.mapsdk.maps.model.BitmapDescriptorFactory;
import com.tencent.tencentmap.mapsdk.maps.model.CameraPosition;
import com.tencent.tencentmap.mapsdk.maps.model.LatLng;
import com.tencent.tencentmap.mapsdk.maps.model.Marker;
import com.tencent.tencentmap.mapsdk.maps.model.MarkerOptions;public class ChooseLocationActivity extends AppCompatActivity implementsTencentLocationListener, TencentMap.OnMapClickListener,TencentMap.OnMarkerDragListener, TencentMap.OnCameraChangeListener {private final static String TAG = "ChooseLocationActivity";private TencentLocationManager mLocationManager; // 声明一个腾讯定位管理器对象private MapView mMapView; // 声明一个地图视图对象private TencentMap mTencentMap; // 声明一个腾讯地图对象private boolean isFirstLoc = true; // 是否首次定位private float mZoom=12; // 缩放级别private LatLng mMyPos; // 当前的经纬度private String mAddress; // 详细地址@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_choose_location);initLocation(); // 初始化定位服务findViewById(R.id.btn_next).setOnClickListener(v -> gotoNext());}// 初始化定位服务private void initLocation() {mMapView = findViewById(R.id.mapView);mTencentMap = mMapView.getMap(); // 获取腾讯地图对象mTencentMap.setOnMapClickListener(this); // 设置地图的点击监听器mTencentMap.setOnMarkerDragListener(this); // 设置地图标记的拖动监听器mTencentMap.setOnCameraChangeListener(this); // 设置相机视角的变更监听器mLocationManager = TencentLocationManager.getInstance(this);// 创建腾讯定位请求对象TencentLocationRequest request = TencentLocationRequest.create();request.setInterval(30000).setAllowGPS(true);request.setRequestLevel(TencentLocationRequest.REQUEST_LEVEL_ADMIN_AREA);mLocationManager.requestLocationUpdates(request, this); // 开始定位监听}// 跳到个人信息填写页面private void gotoNext() {if (mMyPos == null) {Toast.makeText(this, "请先选择您的常住地点", Toast.LENGTH_SHORT).show();return;}Intent intent = new Intent(this, InfoEditActivity.class);intent.putExtra("latitude", mMyPos.latitude);intent.putExtra("longitude", mMyPos.longitude);intent.putExtra("address", mAddress);startActivity(intent);}@Overridepublic void onLocationChanged(TencentLocation location, int resultCode, String resultDesc) {if (resultCode == TencentLocation.ERROR_OK) { // 定位成功if (location != null && isFirstLoc) { // 首次定位isFirstLoc = false;// 创建一个经纬度对象LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());moveLocation(latLng, location.getAddress()); // 将地图移动到当前位置}} else { // 定位失败Log.d(TAG, "定位失败,错误代码为"+resultCode+",错误描述为"+resultDesc);}}@Overridepublic void onStatusUpdate(String s, int i, String s1) {}// 将地图移动到当前位置private void moveLocation(LatLng latLng, String address) {mMyPos = latLng;mAddress = address;CameraUpdate update = CameraUpdateFactory.newLatLngZoom(latLng, mZoom);mTencentMap.moveCamera(update); // 把相机视角移动到指定地点// 从指定视图中获取位图描述BitmapDescriptor bitmapDesc = BitmapDescriptorFactory.fromView(getMarkerView(mAddress));MarkerOptions marker = new MarkerOptions(latLng).draggable(true) // 可以拖动.visible(true).icon(bitmapDesc).snippet("这是您的当前位置");mTencentMap.addMarker(marker); // 往地图添加标记}// 获取标记视图private View getMarkerView(String address) {View view = getLayoutInflater().inflate(R.layout.marker_me, null);TextView tv_address = view.findViewById(R.id.tv_address);tv_address.setText(address);return view;}@Overridepublic void onMapClick(LatLng latLng) {mTencentMap.clearAllOverlays(); // 清除所有覆盖物mMyPos = latLng;// 创建一个腾讯搜索对象TencentSearch tencentSearch = new TencentSearch(this);Geo2AddressParam param = new Geo2AddressParam(mMyPos);// 根据经纬度查询地图上的详细地址tencentSearch.geo2address(param, new HttpResponseListener() {@Overridepublic void onSuccess(int i, Object o) {Geo2AddressResultObject result = (Geo2AddressResultObject) o;String address = String.format("%s(%s)",result.result.address, result.result.formatted_addresses.recommend);moveLocation(mMyPos, address); // 将地图移动到当前位置}@Overridepublic void onFailure(int i, String s, Throwable throwable) {Log.d(TAG, "geo2address onFailure code="+i+", msg="+s);}});}@Overridepublic void onMarkerDragStart(Marker marker) {}@Overridepublic void onMarkerDrag(Marker marker) {}@Overridepublic void onMarkerDragEnd(Marker marker) {onMapClick(marker.getPosition()); // 触发该位置的地图点击事件}@Overridepublic void onCameraChange(CameraPosition cameraPosition) {}@Overridepublic void onCameraChangeFinished(CameraPosition cameraPosition) {mZoom = cameraPosition.zoom;}@Overrideprotected void onStart() {super.onStart();mMapView.onStart();}@Overrideprotected void onStop() {super.onStop();mMapView.onStop();}@Overridepublic void onPause() {super.onPause();mMapView.onPause();}@Overridepublic void onResume() {super.onResume();mMapView.onResume();}@Overrideprotected void onDestroy() {super.onDestroy();mLocationManager.removeUpdates(this); // 移除定位监听mMapView.onDestroy();}
}

编辑自身页面的代码

package com.example.location;import androidx.appcompat.app.AppCompatActivity;import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RadioGroup;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;import com.example.location.bean.JoinResponse;
import com.example.location.constant.UrlConstant;
import com.example.location.util.BitmapUtil;
import com.example.location.util.DateUtil;
import com.example.location.util.SharedUtil;
import com.google.gson.Gson;import java.io.File;
import java.io.IOException;import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;public class InfoEditActivity extends AppCompatActivity {private final static String TAG = "InfoEditActivity";private int CHOOSE_CODE = 3; // 只在相册挑选图片的请求码private EditText et_name, et_phone, et_info; // 姓名、手机号、个人信息的编辑框private TextView tv_location; // 声明一个文本视图对象private ImageView iv_face; // 声明一个图像视图对象public boolean isMale = true; // 是否男性public int mLoveType=0; // 爱好类型public double mLatitude, mLongitude; // 经纬度public String mAddress; // 详细地址public Bitmap mOriginFace; // 原始的头像位图private ProgressDialog mDialog; // 声明一个对话框对象@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_info_edit);et_name = findViewById(R.id.et_name);RadioGroup rg_sex = findViewById(R.id.rg_sex);rg_sex.setOnCheckedChangeListener((group, checkedId) -> isMale = checkedId == R.id.rb_male);et_phone = findViewById(R.id.et_phone);tv_location = findViewById(R.id.tv_location);iv_face = findViewById(R.id.iv_face);et_info = findViewById(R.id.et_info);iv_face.setOnClickListener(v -> {// 创建一个内容获取动作的意图(准备跳到系统相册)Intent albumIntent = new Intent(Intent.ACTION_GET_CONTENT);albumIntent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false); // 是否允许多选albumIntent.setType("image/*"); // 类型为图像startActivityForResult(albumIntent, CHOOSE_CODE); // 打开系统相册});findViewById(R.id.btn_confirm).setOnClickListener(v -> saveInfo());initIntentData(); // 初始化意图数据initLoveSpinner(); // 初始化爱好类型下拉框}// 初始化意图数据private void initIntentData() {Bundle bundle = getIntent().getExtras();mLatitude = bundle.getDouble("latitude");mLongitude = bundle.getDouble("longitude");mAddress = bundle.getString("address");tv_location.setText(mAddress);}// 初始化爱好类型下拉框private void initLoveSpinner() {Spinner sp_love = findViewById(R.id.sp_love);ArrayAdapter<String> love_adapter = new ArrayAdapter<>(this,R.layout.item_select, loveArray);sp_love.setPrompt("请选择兴趣爱好");sp_love.setAdapter(love_adapter);sp_love.setOnItemSelectedListener(new LoveSelectedListener());sp_love.setSelection(0);}private String[] loveArray = {"唱歌", "跳舞", "绘画", "弹琴", "摄影", "出售闲置物品"};class LoveSelectedListener implements AdapterView.OnItemSelectedListener {public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {mLoveType = arg2;}public void onNothingSelected(AdapterView<?> arg0) {}}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent intent) {super.onActivityResult(requestCode, resultCode, intent);if (resultCode == RESULT_OK && requestCode == CHOOSE_CODE) { // 从相册返回if (intent.getData() != null) { // 从相册选择一张照片Uri uri = intent.getData(); // 获得已选择照片的路径对象// 根据指定图片的uri,获得自动缩小后的位图对象mOriginFace = BitmapUtil.getAutoZoomImage(this, uri, 500);iv_face.setImageBitmap(mOriginFace); // 设置图像视图的位图对象}}}// 保存个人信息private void saveInfo() {String name = et_name.getText().toString();String phone = et_phone.getText().toString();String info = et_info.getText().toString();if (TextUtils.isEmpty(name)) {Toast.makeText(this, "请先输入您的昵称", Toast.LENGTH_SHORT).show();return;}if (TextUtils.isEmpty(phone)) {Toast.makeText(this, "请先输入您的手机号码", Toast.LENGTH_SHORT).show();return;}if (TextUtils.isEmpty(info)) {Toast.makeText(this, "请先输入要发布的信息", Toast.LENGTH_SHORT).show();return;}if (mOriginFace == null) {Toast.makeText(this, "请先选择您的头像", Toast.LENGTH_SHORT).show();return;}int minScope = Math.min(mOriginFace.getWidth(), mOriginFace.getHeight());// 从原始位图裁剪出一个正方形位图Bitmap cropFace = Bitmap.createBitmap(mOriginFace, 0, 0, minScope, minScope);String path = String.format("%s/%s.jpg",getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(),DateUtil.getNowDateTime());BitmapUtil.saveImage(path, cropFace); // 把位图保存为图片文件// 弹出进度对话框mDialog = ProgressDialog.show(this, "请稍候", "正在保存位置信息......");// 下面把用户信息(包含头像)提交给HTTP服务端MultipartBody.Builder builder = new MultipartBody.Builder();// 往建造器对象添加文本格式的分段数据builder.addFormDataPart("name", name); // 昵称builder.addFormDataPart("sex", isMale?"0":"1"); // 性别builder.addFormDataPart("phone", phone); // 手机号builder.addFormDataPart("love", loveArray[mLoveType]); // 爱好builder.addFormDataPart("info", info); // 发布信息builder.addFormDataPart("address", mAddress); // 地址builder.addFormDataPart("latitude", mLatitude+""); // 纬度builder.addFormDataPart("longitude", mLongitude+""); // 经度// 往建造器对象添加图像格式的分段数据builder.addFormDataPart("image", path.substring(path.lastIndexOf("/")),RequestBody.create(new File(path), MediaType.parse("image/*")));RequestBody body = builder.build(); // 根据建造器生成请求结构OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象// 创建一个POST方式的请求结构Request request = new Request.Builder().post(body).url(UrlConstant.HTTP_PREFIX+"joinNearby").build();Call call = client.newCall(request); // 根据请求结构创建调用对象// 加入HTTP请求队列。异步调用,并设置接口应答的回调方法call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) { // 请求失败// 回到主线程操纵界面runOnUiThread(() -> {mDialog.dismiss(); // 关闭进度对话框Toast.makeText(InfoEditActivity.this,"保存位置信息出错:"+e.getMessage(), Toast.LENGTH_SHORT).show();});}@Overridepublic void onResponse(Call call, final Response response) throws IOException { // 请求成功String resp = response.body().string();JoinResponse joinResponse = new Gson().fromJson(resp, JoinResponse.class);// 回到主线程操纵界面runOnUiThread(() -> {mDialog.dismiss(); // 关闭进度对话框if ("0".equals(joinResponse.getCode())) {finishSave(); // 结束信息保存动作} else {Toast.makeText(InfoEditActivity.this, "保存位置信息失败:"+joinResponse.getDesc(), Toast.LENGTH_SHORT).show();}});}});}// 结束信息保存动作private void finishSave() {Toast.makeText(this, "成功保存您的位置信息", Toast.LENGTH_SHORT).show();SharedUtil.getIntance(this).writeString("commitMyInfo", "true");Intent intent = new Intent(this, NearbyActivity.class);// 设置启动标志:跳转到新页面时,栈中的原有实例都被清空,同时开辟新任务的活动栈intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);startActivity(intent);}}

创作不易 觉得有帮助请点赞关注收藏~~~ 

【Android App】实战项目之仿微信的附近的人(附源码和演示 超详细)相关推荐

  1. 【Android App】物联网实战项目之自动驾驶的智能小车(附源码和演示 超详细)

    需要源码请点赞关注收藏后评论区留言私信~~~~ 当今社会正在步入一个万物互联的时代,它的技术基石主要来自5G.物联网和人工智能. 三者融合产生了许多新产品,其中最璀璨的当数自动驾驶的电动车:它汇聚了最 ...

  2. 【Android App】实战项目之仿微信的视频通话(附源码和演示 超详细必看)

    需要源码请点赞关注收藏后评论区留言私信~~~ 虽然手机出现许多年了,它具备的功能也越来越丰富,但是最基本的通话功能几乎没有变化.从前使用固定电话的时候,通话就是听声音:如今使用最新的智能手机,通话仍旧 ...

  3. 【Android App】实战项目之仿拼多多的直播带货(附源码和演示 超详细必看)

    需要源码请点赞关注收藏后评论区留言私信~~~ 近年来电商业态发生了不小的改变,传统的电商平台把商品分门别类,配上精美的图文说明供消费者挑选,新潮的电商平台则请来明星网红,开启直播秀向广大粉丝推销商品, ...

  4. 【Android App】给三维的地球仪贴上动物贴纸实战(附源码和演示 超详细必看)

    需要源码和图片集请点赞关注收藏后评论区留言~~~ 一.纹理贴图 给三维物体穿衣服的动作,通常叫做给三维图形贴图,更专业地说叫纹理渲染. 渲染纹理的过程主要由三大项操作组成,分别说明如下: (1)启用纹 ...

  5. 【Android App】利用自带的人脸检测器和OpenCV检测人脸讲解及实战(附源码和演示 超详细)

    需要源码请点赞关注收藏后评论区留言私信~~~~ 一.利用人脸检测器识别人脸 对于简单的人脸识别操作,Android已经提供了专门的识别工具,名叫人脸检测器FaceDetector,部分常用方法如下 F ...

  6. 【Android App】人脸识别中扫描识别二维码实战解析(附源码和演示 超详细)

    需要源码请点赞关注收藏后评论区留言私信~~~ 一.扫描识别二维码 不仅可以利用zxing库生成二维码,同样利用zxing库可以扫描二维码并解析得到原始文本,此时除了给build.gradle添加如下一 ...

  7. 【Android App】定位导航GPS中开启手机定位功能讲解及实战(附源码和演示 超详细)

    需要源码请点赞关注收藏后评论区留言私信~~~ 一.开启定位功能 手机定位分为卫星定位和网络定位两大类. (1)卫星定位 卫星定位服务由几个全球卫星导航系统提供. 卫星定位的原理是根据多颗卫星与导航芯片 ...

  8. 【Android App】人脸识别中借助摄像头和OpenCV实时检测人脸讲解及实战(附源码和演示 超详细)

    需要全部代码请点赞关注收藏后评论区留言私信~~~ 一.借助摄像头实时检测人脸 与Android自带的人脸检测器相比,OpenCV具备更强劲的人脸识别功能,它可以通过摄像头实时检测人脸,实时检测的预览空 ...

  9. 【Android App】获取照片里的位置信息及使用全球卫星导航系统(GNSS)获取位置实战(附源码和演示 超详细)

    需要全部代码请点赞关注收藏后评论区留言私信~~~ 一.获取照片里的位置信息 手机拍摄的相片还保存着时间.地点.镜头参数等信息,这些信息由相片接口工具ExifInterface管理,它的常用方法说明如下 ...

最新文章

  1. 【原创】浅说windows下的中断请求级IRQL
  2. 谈谈Linux下的数据流重定向和管道命令
  3. Spring - Java/J2EE Application Framework 应用框架 第 12 章 Web框架
  4. oracle rac常用的网络检查命令
  5. mysql 删除数据_3.MySQL数据库创建、查询、删除
  6. mysql -e -f_twitter-不正确的字符串值:'\ xF0 \ x9F \ x8E \ xB6 \ xF0 \ x9F ...'MySQL
  7. 曹鹏php mysql视频教程_曹鹏 PHP+MYSQL 视频教程(flash)
  8. MongoDb学习(五)--Gridfs--上传下载
  9. 世界各国Google域名后缀对照表
  10. 酷狗外链播放器html5,WP博客制作并添加酷狗外链播放器
  11. Start request repeated too quickly解决方法
  12. lol1月8日服务器维护,LOL2018年1月16日停机维护公告_LOL国服8.1版本更新内容汇总_飞翔教程...
  13. C语言:编写一个函数,输入一个正整数,输出它的各个位数的平方和。
  14. 当我开始爱自己——卓别林
  15. 作为程序员,在挑选 iPad 时我在想什么?
  16. Echarts实现自定义图标——风向图
  17. tomcat跨域请求
  18. LOL服务器人数最新,2021LOL哪个区人多
  19. AUTODESK_TOXIK_V2008
  20. 统计力学练习: Ising模型的平均场解以及严格求解

热门文章

  1. 如何在GDB中忽略Signal信号处理
  2. 团队程序设计天梯赛-3.31排位赛总结
  3. 网狐游戏平台客户端命令行打包apk
  4. 2018最新csdn修改博客皮肤模板教程
  5. Android基础知识笔记
  6. android studio修改皮肤,Android Studio 自定义皮肤主题和背景
  7. Labeled Faces in the Wild: Updates and New Reporting Procedures
  8. 中国大陆第二代智能身份证 VS 香港智能身份证
  9. 暑假如何有效控制、预防近视?保护视力的护眼灯分享
  10. mul matlab,汇编语言MUL指令:无符号数乘法