社交类app android,GitHub - yuanyuano/Android-client: Android小项目——社交类app(低仿微信)...

项目简介

项目框架

c97cb937ac7f28c56cd3d53f32e2128f.pngc97cb937ac7f28c56cd3d53f32e2128f.pngc97cb937ac7f28c56cd3d53f32e2128f.png

网络传输

我们采用OKHTTP3的网络方式与服务器进行数据交互,将数据打包成Jason格式进行传输。我这里只给客户端的代码。

主要功能及代码分析

注册和登录

初始界面:用户选择登录or注册

115086d6390dd1a09aa41b86b87923a3.png

注册界面&登录界面

7f237a5bf034267eb78bcb0ef1abfa1e.png3d32d0c7ae3a436dc9bf45d896d223e4.png

登录和注册功能的实现主要使用OKHTTP3方式与服务器进行交互,两者的技术实现几乎完全一样。

登录——get用户信息,向服务器发送登录请求

String jsonstr = new Gson().toJson(hostInfo); //数据打包为Jason格式

RequestBody body = RequestBody.create(MediaType.parse("application/json"),jsonstr);

OkHttpClient client = new OkHttpClient();

//向服务器发送请求

Request request = new Request.Builder().url("http://192.168.43.121:8080/login").post(body).build();

//这里的http://192.168.43.121:8080就是我们服务器的url,login是为登录创建的存储文件夹

client.newCall(request).enqueue(new Callback() { //收到服务器回复

@Override

public void onFailure(Call call, IOException e) {

e.printStackTrace();

}

@Override

public void onResponse(Call call, Response response) throws IOException {

String back = response.body().string();

if(back.equals("success")){ //若收到服务器的回复为success,则成功。(这个success是你与服务器约定好的一个字符串)

Intent intent = new Intent(LoginActivity.this,MainActivity.class);

startActivity(intent);

}else if(back.equals("fail")){

Handler handler=new Handler(Looper.getMainLooper());

handler.post(new Runnable(){

public void run(){

Toast.makeText(LoginActivity.this,"手机号码或密码错误,请重新输入!",Toast.LENGTH_SHORT).show();

}

});

}

}

});

注册——get用户信息,向服务器发送注册请求

String jsonstr = new Gson().toJson(hostInfo); //数据打包成Jason格式

RequestBody body = RequestBody.create(MediaType.parse("application/json"),jsonstr);

OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder().url("http://192.168.43.121:8080/insert").post(body).build();

client.newCall(request).enqueue(new Callback() {

@Override

public void onFailure(Call call, IOException e) {

Log.v("call","fail");

}

@Override

public void onResponse(Call call, Response response) throws IOException {

String back = response.body().string();

if(back.equals("success")){

Handler handler=new Handler(Looper.getMainLooper());

handler.post(new Runnable(){

public void run(){

Toast.makeText(RegisterActivity.this,"注册成功,请重新登录!",Toast.LENGTH_SHORT).show();

}

});

Intent nextIntent = new Intent(RegisterActivity.this, LoginActivity.class);

startActivity(nextIntent);

finish();

}else if(back.equals("fail")){

Handler handler=new Handler(Looper.getMainLooper());

handler.post(new Runnable(){

public void run(){

Toast.makeText(RegisterActivity.this,"注册失败,请重试!",Toast.LENGTH_SHORT).show();

}

});

}

}

});

提醒: 注册的上传头像功能我用了一个第三方工具,我自己写的老是遇到各种报错问题,建议用第三方实现,第三方工具在后面会给出链接。

整体布局

登录成功以后进入主界面——动态页面,侧滑栏为 个人信息。

b1ceacd92c6c9995c02409eb747879ac.pnga3ce357554d96819c5cb43eafd576c14.png

列表的布局采用ListView、数据源和Adapter配合实现。

//侧滑菜单

private void initView(){

drawerLayout = findViewById(R.id.activity_na);

navigationView = findViewById(R.id.nav);

menu = findViewById(R.id.iv_menu);

View headerView = navigationView.getHeaderView(0);

user_image = headerView.findViewById(R.id.iv_menu_user);

user_name = headerView.findViewById(R.id.tv_menu_user);

user_sign = headerView.findViewById(R.id.tv_menu_usersign);

new Thread(new Runnable() {

@Override

public void run() {

try{

MyselfUtil rec = new MyselfUtil();

MyInfo = rec.httpGet(hostID);

handlerPra.sendMessage(handlerPra.obtainMessage(22,MyInfo));

}catch (Exception e){

e.printStackTrace();

}

}

}).start();

//获取头布局

menu.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

//点击菜单,跳出侧滑菜单

if (drawerLayout.isDrawerOpen(navigationView)){

drawerLayout.closeDrawer(navigationView);

}else{

drawerLayout.openDrawer(navigationView);

}

}

});

navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {

@Override

public boolean onNavigationItemSelected(@NonNull MenuItem item) {

switch(item.getItemId()){

case R.id.menu_item1:

Intent intent = new Intent(MainActivity.this,MyCollectActivity.class);

startActivity(intent);

break;

case R.id.menu_item2:

Intent intent2 = new Intent(MainActivity.this,MyLikeActivity.class);

startActivity(intent2);

break;

case R.id.menu_item3:

Intent intent3 = new Intent(MainActivity.this,CommentActivity.class);

startActivity(intent3);

break;

case R.id.menu_item4:

Intent intent4 = new Intent(MainActivity.this,MyMomentActivity.class);

startActivity(intent4);

break;

}

return true;

}

});

}

搜索和关注好友

2c8df29698983767b4434a3ef16bd92b.pngf6c0c752beea1623e4828c9ad33bf909.png

查询好友id:

将id提交给服务器查询,根据收到的其回复来判断是否存在该用户

private void search_fd(final EditText friendID){

Button search_btn = findViewById(R.id.follow_search_btn);

search_btn.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

int friend_int = Integer.parseInt(friendID.getText().toString());

foucs_friend ffd = new foucs_friend(hostID,friend_int);

String jsonstr = new Gson().toJson(ffd);

RequestBody body = RequestBody.create(MediaType.parse("application/json"),jsonstr);

OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()

.url("http://192.168.43.121:8080/findfriend")

.post(body)

.build();

client.newCall(request).enqueue(new Callback() {

@Override

public void onFailure(Call call, IOException e) {

}

@Override

public void onResponse(Call call, Response response) throws IOException {

String json;

json = response.body().string();

Gson gson = new Gson();

Log.v("aaa",json);

follow_fd = gson.fromJson(json,FocusInfo.class);

Message message = new Message();

message.what = 0;

handlerPra.sendMessage(message);

}

});

}

});

}

关注好友:

将数据提交给服务器,服务器将关注信息保存到 MySQL 数据库中

private void follow_fd(final EditText friendID) {

btn_focus.setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View view) {

int friend_int = Integer.parseInt(friendID.getText().toString());

//int friend_int = Integer.parseInt(friendID);

foucs_friend ffd = new foucs_friend(hostID,friend_int);

String jsonstr = new Gson().toJson(ffd);

RequestBody body = RequestBody.create(MediaType.parse("application/json"),jsonstr);

OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()

.url("http://192.168.43.121:8080/friendadd")

.post(body)

.build();

client.newCall(request).enqueue(new Callback() {

@Override

public void onFailure(Call call, IOException e) {

}

@Override

public void onResponse(Call call, Response response) throws IOException {

String back = response.body().string();

if(back.equals("success")){

Handler handler=new Handler(Looper.getMainLooper());

handler.post(new Runnable(){

public void run(){

btn_focus.setVisibility(View.INVISIBLE );

focus_tv.setVisibility(View.VISIBLE );

Toast.makeText(FollowActivity.this,"已关注",Toast.LENGTH_SHORT).show();

}

});

}

}

});

}

});

}

浏览动态(点赞评论收藏)

57036b16241b40ea31b50aa7dc986118.png93c8bac22dd2c8629c9d50cc919ee030.png

点赞、评论和收藏全部放在一个 Fragment 中,点赞和收藏可以直接向服务器发送请求,但是评论需要一个单独的Activity来get用户输入的具体评论信息,在那个Activity里面再进行数据上传,Fragment里面只调用这个Activity即可。

//在Fragment中实现点赞、评论和收藏功能

//收藏

adapter.setOnItemCollectListener(new ViewAdapter.onItemCollectListener() {

@Override

public void onCollectClick(final int i) {

PraiseOrCollectMsg msg = new PraiseOrCollectMsg();

msg.setDynamicID(list_item.get(i).getDynamicID());

msg.setHostID(1);

String jsonstr = new Gson().toJson(msg);

//向服务器发送请求

RequestBody body = RequestBody.create(MediaType.parse("application/json"),jsonstr);

OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()

.url("http://192.168.43.121:8080/findcollect")

.post(body)

.build();

client.newCall(request).enqueue(new okhttp3.Callback() {

@Override

public void onFailure(Call call, IOException e) {

}

@Override

public void onResponse(Call call, Response response) throws IOException {

String json = response.body().string();

Log.v("accepet",json);

list_item.get(i).setIsCollected(Integer.parseInt(json));

Message message = new Message();

message.what = 0;

handlerPra.sendMessage(message);

}

});

}

});

//评论

adapter.setOnItemCommentClickListener(new ViewAdapter.onItemCommentListener() {

@Override

public void onCommentClick(int i) {

System.out.println("");

comment(i); //调用评论功能的Activity

}

});

//点赞

adapter.setOnItemPraiseClickListener(new ViewAdapter.onItemPraiseListener() {

@Override

public void onPraiseClick(final int i) {

PraiseOrCollectMsg msg = new PraiseOrCollectMsg();

msg.setDynamicID(list_item.get(i).getDynamicID());

msg.setHostID(1);

String jsonstr = new Gson().toJson(msg);

RequestBody body = RequestBody.create(MediaType.parse("application/json"),jsonstr);

OkHttpClient client = new OkHttpClient();

//向服务器发送请求

Request request = new Request.Builder()

.url("http://192.168.43.121:8080/findpraise")

.post(body)

.build();

client.newCall(request).enqueue(new okhttp3.Callback() {

@Override

public void onFailure(Call call, IOException e) {

}

@Override

public void onResponse(Call call, Response response) throws IOException {

String json = response.body().string();

Gson gson = new Gson();

PraiseDetail pra = gson.fromJson(json,PraiseDetail.class);

list_item.get(i).setHasPraised(pra.haspriased);

list_item.get(i).setIsPraised(pra.isprased);

Message message = new Message();

message.what = 0;

handlerPra.sendMessage(message);

}

});

}

});

发布动态

01bae9da9f274cfc2fa28196d36c4b61.png

把发布动态功能放在Fragment里面,发布功能实现还是利用OKHTTP3网络传输。图片上传仍使用第三方工具。

我这里放一下 第三方工具包:PictureSelector

private void showAlbum() {

//参数很多,根据需要添加

PictureSelector.create(getActivity())

.openGallery(PictureMimeType.ofImage())// 全部.PictureMimeType.ofAll()、图片.ofImage()、视频.ofVideo()、音频.ofAudio()

.maxSelectNum(maxSelectNum)// 最大图片选择数量

.minSelectNum(1)// 最小选择数量

.imageSpanCount(4)// 每行显示个数

.selectionMode(PictureConfig.MULTIPLE)// 多选 or 单选PictureConfig.MULTIPLE : PictureConfig.SINGLE

.previewImage(true)// 是否可预览图片

.isCamera(true)// 是否显示拍照按钮

.isZoomAnim(true)// 图片列表点击 缩放效果 默认true

//.setOutputCameraPath("/CustomPath")// 自定义拍照保存路径

.enableCrop(true)// 是否裁剪

.compress(true)// 是否压缩

//.sizeMultiplier(0.5f)// glide 加载图片大小 0~1之间 如设置 .glideOverride()无效

.glideOverride(160, 160)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度

.withAspectRatio(1, 1)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定义

//.selectionMedia(selectList)// 是否传入已选图片

//.previewEggs(false)// 预览图片时 是否增强左右滑动图片体验(图片滑动一半即可看到上一张是否选中)

//.cropCompressQuality(90)// 裁剪压缩质量 默认100

//.compressMaxKB()//压缩最大值kb compressGrade()为Luban.CUSTOM_GEAR有效

//.compressWH() // 压缩宽高比 compressGrade()为Luban.CUSTOM_GEAR有效

//.cropWH()// 裁剪宽高比,设置如果大于图片本身宽高则无效

.rotateEnabled(false) // 裁剪是否可旋转图片

.scaleEnabled(true)// 裁剪是否可放大缩小图片

//.recordVideoSecond()//录制视频秒数 默认60s

.forResult(PictureConfig.CHOOSE_REQUEST);//结果回调onActivityResult code

}

个人信息

b1ceacd92c6c9995c02409eb747879ac.png

对于收到的点赞/评论/我的收藏,均使用 Handler机制 开启一个新的线程,搭配适配器进行页面显示。

我收到的点赞:

c78d00feb2b71e5f785dc6ed96b795eb.png

Handler handler = new Handler(){

@Override

public void handleMessage(@NonNull Message msg) {

lv.setAdapter(new LikeAdapter(MyLikeActivity.this,(List) msg.obj));

}

};

我收到的评论:

c51a51f4cb11ce7929704b3ac82c1ee5.png

Handler handlerPra = new Handler(){

@Override

public void handleMessage(Message msg){

if(msg.what == 0){

adapter.notifyDataSetChanged();

}

}

};

我的收藏:

5ffa49e652fe17cf10706d3e2d0e762f.png

Handler handlerPra = new Handler(){

@Override

public void handleMessage(Message msg){

if(msg.what == 0){

adapter.notifyDataSetChanged();

}

}

};

总结

整个项目大致的主要功能就是如此啦,技术上难度不算太大,每个功能的实现都是在重复地使用OKHTTP3与服务器进行数据交互,必要时使用Fragment代替Activity,列表显示就结合Adapter来实现,我遇到最大的问题倒是在图片上传那里,所以我强烈建议使用第三方,拍照、选择图片、图片裁剪、缩放等等,功能很全了。这次的安卓开发项目完成度比较高,功能低仿微信,在真机上运行没有太大的问题,算是一次小小的突破。不过中间有些bug,是在整合的时候出现的,由于时间有限我们没有太追究这些细枝末节,仅作学习参考。欢迎大家和我一起交流!

协议

本项目遵从MIT协议

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值