android之仿qq
android之仿qq
- 仿qq
- 1、环境准备
- 2、功能
- 3、项目结构
- 4、gradle准备环境+其他准备
- 4.1. 短信验证
- 4.2. okhttp
- 4.3、openfire和smack
- 5、适配器+listview(此处以fragment为例)
- 6、抽屉栏和导航栏
- 7、转换按钮
- 8、okhttp的使用<以反馈为例>
- 9、短信验证
- 10、图灵机器人
- 11、与openfire交互
仿qq
1、环境准备
开发环境:
1.1、前端:Android Studio3.5.3、spark客户端
1.2、后台:IDEA2019.2.4、openfire
- Android Studio :qq页面;
- spark :与qq进行聊天的另一客户端;
- IDEA2019.2.4,采用springboot框架;
- openfire :实现即时聊天的服务器;
2、功能
2.1 应用功能
登录
手机号短信验证+账号进行注册
手机号短信验证+密码找回
与图灵机器人聊天
在线即时聊天
qq页面设计(Navigation、Drawerable、Toolbar、Adapter、switch button…)
动态栏页面列表的选择展示
意见反馈
2.2 采用的接口
图灵机器人
mob短信验证
openfire的xmpp协议
okhttp–基于websocket
3、项目结构
- 表user:
- 表friend:
- 表feedback:
- 表collect:
4、gradle准备环境+其他准备
4.1. 短信验证
AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
app:
classpath 'com.mob.sdk:MobSDK:+'// 注册MobSDK
apply plugin: 'com.mob.sdk'
MobSDK {appKey "xxxxx"appSecret "xxxxxx"SMSSDK {}
}
4.2. okhttp
- 我们一直使用的http协议只能由客户端发起,服务端无法直接进行推送,这就导致了如果服务端有持续的变化客户端想要获知就比较麻烦。WebSocket协议就是为了解决这个问题应运而生。
- WebSocket协议,客户端和服务端都可以主动的推送消息,可以是文本也可以是二进制数据。而且没有同源策略的限制,不存在跨域问题。协议的标识符就是
ws
。像https一样如果加密的话就是wxs
AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
dependencies :
implementation "com.squareup.okhttp:okhttp:2.7.5"
implementation 'com.squareup.okio:okio:2.4.1'
implementation 'com.alibaba:fastjson:1.2.62'
4.3、openfire和smack
3.1【 openfire的安装和准备 】
3.2 smack配置:
5、适配器+listview(此处以fragment为例)
private ArrayList<String> qqpic;//头像private ArrayList<Object> qqname;//昵称private ArrayList<Object> qqqm;//个性签名private ListView friendList;private View root;public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {root = inflater.inflate(R.layout.fragment_dashboard, container, false);friendList = (ListView)root.findViewById(R.id.friendList);dataInit();ArrayAdapter<Object> tt = newMyAdapter(getActivity(),R.drawable.qq1,qqname,qqqm);friendList.setAdapter(tt);tt.notifyDataSetChanged();return root;}private void dataInit(){qqname = new ArrayList<Object>();qqname.add("qly");qqname.add("ljx");qqname.add("lucy");qqname.add("lily");qqname.add("lolo");qqname.add("fancy");qqname.add("koko");qqname.add("wwa");qqname.add("polo");qqqm = new ArrayList<Object>();qqqm.add("哗啦啦");qqqm.add("1111");qqqm.add("呜呜呜呜");qqqm.add("啊啊啊啊啊");qqqm.add("热热热热热热");qqqm.add("嗷嗷嗷啊啊");qqqm.add("踩踩踩从");qqqm.add("吱吱吱吱在");qqqm.add("十四说四十是");qqpic = new ArrayList<String>();qqpic.add(String.valueOf(R.drawable.qq1));qqpic.add(String.valueOf(R.drawable.qq2));qqpic.add(String.valueOf(R.drawable.qq3));qqpic.add(String.valueOf(R.drawable.qq4));qqpic.add(String.valueOf(R.drawable.qq5));qqpic.add(String.valueOf(R.drawable.qq6));qqpic.add(String.valueOf(R.drawable.qq7));qqpic.add(String.valueOf(R.drawable.qq8));qqpic.add(String.valueOf(R.drawable.qq9));}public class MyAdapter extends ArrayAdapter<Object> {//自定义适配器private Context context;private int resource;List<Object> object1;List<Object> object2;public MyAdapter(Context context, int resource, List<Object> object1, List<Object> object2) {super(context, resource, object1);this.context = context;this.resource = resource;this.object1 = object1;this.object2 = object2;}public MyAdapter(Context context, int resource) {super(context, resource);}public View getView(final int pos, View convertView, ViewGroup parent) {if (convertView == null)convertView = LayoutInflater.from(getActivity()).inflate(R.layout.friend, null);ImageView iv = (ImageView) convertView.findViewById(R.id.qqImg);iv.setImageResource(Integer.parseInt(qqpic.get(pos)));TextView name = (TextView) convertView.findViewById(R.id.qqName);name.setText(qqname.get(pos).toString());TextView qm = (TextView) convertView.findViewById(R.id.qqQm);qm.setText(qqqm.get(pos).toString());final Button bt = (Button) convertView.findViewById(R.id.chatBtn);bt.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Toast.makeText(getActivity(), "click\n", Toast.LENGTH_SHORT).show();}});return convertView;}}
ListView:
效果:
6、抽屉栏和导航栏
继承自AppCompatActivity的Activity:
/DrawerLayout/
DrawerLayout drawer = findViewById(R.id.drawer_layout);
NavigationView navigationView = findViewById(R.id.nav_view);
AppBarConfiguration m1 = new AppBarConfiguration.Builder(R.id.activity,R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow,R.id.nav_tools,R.id.feedback).setDrawerLayout(drawer).build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
NavigationUI.setupActionBarWithNavController(this, navController, m1);NavigationUI.setupWithNavController(navigationView, navController);
/NavigationView + DrawerLayout
View headerView = navigationView.getHeaderView(0);//获取头布局
infoBtn = headerView.findViewById(R.id.infobtn);
infoBtn.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View v) {System.out.println("-----------------");Intent intent1 = new Intent(MainActivity.this,MyInfoActivity.class);startActivity(intent1);}
});
抽屉点击
navigationView.setNavigationItemSelectedListener(new OnNavigationItemSelectedListener() {@Overridepublic boolean onNavigationItemSelected(@NonNull MenuItem item) {switch (item.getItemId()){case R.id.activity://点我了解会员Intent intent = new Intent(MainActivity.this, ShareAC.class);startActivity(intent);break;......}return true;}
});/bottom//
BottomNavigationView navView = findViewById(R.id.nav_view_main);
AppBarConfiguration m2 = new AppBarConfiguration.Builder(R.id.navigation_dashboard, R.id.navigation_home, R.id.navigation_notifications).build();
NavigationUI.setupActionBarWithNavController(this, navController, m2);
NavigationUI.setupWithNavController(navView, navController);
activity_main_drawer.xml:<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"tools:showIn="navigation_view"><group android:checkableBehavior="single"android:clickable="true"><itemandroid:id="@+id/activity"android:icon="@drawable/vip"android:title="点我了解会员" /><itemandroid:id="@+id/nav_home"android:icon="@drawable/wallet"android:title="@string/menu_home" /><itemandroid:id="@+id/nav_gallery"android:icon="@drawable/fav"android:title="@string/menu_gallery" /><itemandroid:id="@+id/nav_slideshow"android:icon="@drawable/file"android:title="@string/menu_slideshow" /><itemandroid:id="@+id/nav_tools"android:icon="@drawable/plug"android:title="@string/menu_tools" /><itemandroid:id="@+id/feedback"android:icon="@drawable/feedback"android:title="意见反馈" /></group></menu>
效果图:
7、转换按钮
dependencies添加:
implementation 'com.github.zcweng:switch-button:0.0.3@aar'
extends AppCompatActivity implements SwitchButton.OnCheckedChangeListener:
SwitchButton qzoneBtn1;
qzoneBtn1 = (SwitchButton) findViewById(R.id.qzoneBtn1);
qzoneBtn1.setOnCheckedChangeListener(new SwitchButton.OnCheckedChangeListener(){@Overridepublic void onCheckedChanged(SwitchButton view, boolean isChecked) {....}});
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><includelayout="@layout/headdtsz"android:layout_width="401dp"android:layout_height="wrap_content" /><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="66dp"><ImageViewandroid:id="@+id/imageView"android:layout_width="74dp"android:layout_height="match_parent"app:srcCompat="@drawable/qzone" /><TextViewandroid:id="@+id/textView"android:layout_width="202dp"android:layout_height="33dp"android:layout_alignParentStart="true"android:layout_alignParentLeft="true"android:layout_alignParentTop="true"android:layout_alignParentBottom="true"android:layout_marginStart="94dp"android:layout_marginLeft="94dp"android:layout_marginTop="17dp"android:layout_marginBottom="16dp"android:text="好友动态"android:textSize="12sp" /><com.suke.widget.SwitchButtonandroid:id="@+id/qzoneBtn1"android:layout_width="64dp"android:layout_height="40dp"android:layout_alignParentEnd="true"android:layout_alignParentBottom="true"android:layout_marginEnd="15dp"android:layout_marginBottom="12dp"app:sb_background="@color/smssdk_common_line_gray"app:sb_checkline_color="@color/smssdk_bg_gray"app:sb_show_indicator="false" /></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="66dp"><ImageViewandroid:id="@+id/imageView2"android:layout_width="74dp"android:layout_height="match_parent"app:srcCompat="@drawable/tencent_news" /><TextViewandroid:id="@+id/textView2"android:layout_width="202dp"android:layout_height="33dp"android:layout_alignParentStart="true"android:layout_alignParentLeft="true"android:layout_alignParentTop="true"android:layout_marginStart="95dp"android:layout_marginLeft="95dp"android:layout_marginTop="16dp"android:text="腾讯新闻"android:textSize="12sp" /><com.suke.widget.SwitchButtonandroid:id="@+id/newsBtn1"android:layout_width="64dp"android:layout_height="40dp"android:layout_alignParentEnd="true"android:layout_alignParentBottom="true"android:layout_marginEnd="15dp"android:layout_marginBottom="12dp"app:sb_background="@color/smssdk_common_line_gray"app:sb_checkline_color="@color/smssdk_bg_gray"app:sb_show_indicator="false" /></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="66dp"><ImageViewandroid:id="@+id/imageView3"android:layout_width="74dp"android:layout_height="wrap_content"app:srcCompat="@drawable/baidumap" /><TextViewandroid:id="@+id/textView3"android:layout_width="202dp"android:layout_height="33dp"android:layout_alignParentStart="true"android:layout_alignParentLeft="true"android:layout_alignParentBottom="true"android:layout_marginStart="91dp"android:layout_marginLeft="91dp"android:layout_marginBottom="15dp"android:text="百度地图"android:textSize="12sp" /><com.suke.widget.SwitchButtonandroid:id="@+id/mapBtn1"android:layout_width="64dp"android:layout_height="40dp"android:layout_alignParentEnd="true"android:layout_alignParentBottom="true"android:layout_marginEnd="15dp"android:layout_marginBottom="12dp"app:sb_background="@color/smssdk_common_line_gray"app:sb_checkline_color="@color/smssdk_bg_gray"app:sb_show_indicator="false" /></RelativeLayout><RelativeLayoutandroid:layout_width="match_parent"android:layout_height="66dp"><ImageViewandroid:id="@+id/imageView4"android:layout_width="74dp"android:layout_height="wrap_content"app:srcCompat="@drawable/baidu" /><TextViewandroid:id="@+id/textView4"android:layout_width="202dp"android:layout_height="33dp"android:layout_alignParentStart="true"android:layout_alignParentLeft="true"android:layout_alignParentBottom="true"android:layout_marginStart="90dp"android:layout_marginLeft="90dp"android:layout_marginBottom="16dp"android:text="百度"android:textSize="12sp" /><com.suke.widget.SwitchButtonandroid:id="@+id/searchBtn1"android:layout_width="64dp"android:layout_height="40dp"android:layout_alignParentEnd="true"android:layout_alignParentBottom="true"android:layout_marginEnd="15dp"android:layout_marginBottom="12dp"app:sb_background="@color/smssdk_common_line_gray"app:sb_checkline_color="@color/smssdk_bg_gray"app:sb_show_indicator="false" /></RelativeLayout></LinearLayout></LinearLayout></androidx.constraintlayout.widget.ConstraintLayout>
效果图:
8、okhttp的使用<以反馈为例>
在获取联系方式和反馈内容后,传给后台(post/get),通过handler获得反馈后的结果。(因为这里采用了线程)
//注意使用ip而非localhost或127.0.1
String feedbackUrl = "http://xxx.xxx.xxx.xxx:端口/feedback/insert?";
private static Handler handler;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.advice);submit = (Button)findViewById(R.id.btn_submit);submit.setOnClickListener(new View.OnClickListener(){@Overridepublic void onClick(View v) {advice = (EditText)findViewById(R.id.et_advice);final String content = advice.getText().toString();myPhone = (EditText)findViewById(R.id.phone);String phone = myPhone.getText().toString();final String addr = feedbackUrl + "phone=" + phone + "&content=" + content;System.out.println(addr);postFeedback(addr, content);}});handler = new Handler(){@Overridepublic void handleMessage(Message msg) {// super.handleMessage(msg);switch (msg.what) {case 0:String ans = msg.getData().get("hasFeedback").toString();if(ans.equals("true")) {Toast.makeText(FeedbackActivity.this, "反馈成功", Toast.LENGTH_SHORT).show();Intent intent = new Intent(FeedbackActivity.this, MainActivity.class);startActivity(intent);}break;default:Toast.makeText(FeedbackActivity.this, "反馈失败,请稍后再试", Toast.LENGTH_SHORT).show();}}};}//这里采用了post,若是get则去掉.post()或换成.get()private void postFeedback(final String addr, final String jsonString){final boolean flag = false;new Thread(new Runnable() {@Overridepublic void run() {MediaType mediaType = MediaType.parse("application/json; charset=utf-8");RequestBody body = RequestBody.create(mediaType, jsonString);OkHttpClient okHttpClient = new OkHttpClient();okHttpClient.setConnectTimeout(10, TimeUnit.SECONDS);Request request = new Request.Builder().url(addr).post(body).build();okHttpClient.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Request request, IOException e) {System.out.println("111-------fail-------------------------------------------");}@Overridepublic void onResponse(Response response) throws IOException {Message msg=new Message();msg.what=0;Bundle bundle=new Bundle();bundle.putString("hasFeedback",response.header("hasFeedback"));msg.setData(bundle);handler.sendMessage(msg);System.out.println("feedback:"+response.header("hasFeedback")+"222----------success------------------------------------------");}});}}).start();}
9、短信验证
下载官网的案例
10、图灵机器人
b站视频
11、与openfire交互
public class OpenfireConnect{private static XMPPTCPConnectionConfiguration config;private static XMPPTCPConnection conn;//AbstractXMPPConnectionprivate static HttpServletResponse resp;private static String isLogin = "false";private ArrayList<String> msg_ans = new ArrayList<String>();private static int flag = 1;static BASE64Encoder encoder = new sun.misc.BASE64Encoder();static BASE64Decoder decoder = new sun.misc.BASE64Decoder();static {try {config = XMPPTCPConnectionConfiguration.builder().setXmppDomain("自设服务器名称").setHost("自设主机名称") .setPort(5222)//.setDebuggerEnabled(true).setSecurityMode(ConnectionConfiguration.SecurityMode.disabled).build();conn = new XMPPTCPConnection(config);conn.connect();} catch (Exception e) {e.printStackTrace();}}@PostMapping("/conn")public static void login(@Param("username") String username,@Param("password") String password){try {if(conn!=null){conn.login(username, password);isLogin = "true";System.out.println("user "+username+" login successfully.");}} catch (XMPPException e) {e.printStackTrace();} catch (SmackException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}@GetMapping("/send")public void sendMessage(@Param("username") String username, @Param("password") String password, @Param("friend")String friend, @Param("msg") String msg, HttpServletResponse response){if(isLogin.equals("false"))login(username, password);flag = 0;//再构建聊天室ChatManager cm = ChatManager.getInstanceFor(conn);cm.addIncomingListener((from, message, chat) -> {String ans = message.getBody();flag = 1;response.addHeader("msg",ans);msg_ans.add(ans);System.out.println(friend +":response-------,msg----------"+response.getHeader("msg"));});if(flag == 0){response.addHeader("msg",null);msg_ans.clear();}else if(flag == 1){response.addHeader("msg",msg_ans.toString());}System.out.println("response,msg----------"+response.getHeader("msg"));try {EntityBareJid jid = JidCreate.entityBareFrom(friend+"@fancycom.qq");//这里就是Xmpp地址,用户名@域名Chat chat = cm.chatWith(jid);Message message = new Message();message.setBody(msg);chat.send(message);
// while (true);} catch (XmppStringprepException e) {e.printStackTrace();} catch (SmackException.NotConnectedException e) {e.printStackTrace();} catch (InterruptedException e) {e.printStackTrace();}}
android之仿qq相关推荐
- android 实现仿QQ登录可编辑下拉菜单
今天,简单讲讲android里如何实现向QQ一样的登录后记住用户名的下拉框. 这个其实也很简单,网上搜索了一下,很多相关的资料,基本都是PopupWindow+ListView的方式,实现起来比较灵活 ...
- android qq红点,Android高仿QQ小红点功能
先给大家展示下效果图: 绘制贝塞尔曲线: 主要是当在一定范围内拖拽时算出固定圆和拖拽圆的外切直线以及对应的切点,就可以通过path.quadTo()来绘制二阶贝塞尔曲线了~ 整体思路: 1.当小红点静 ...
- android+qq底部界面,Android 高仿QQ 界面滑动效果
Android高仿QQ界面滑动效果 点击或者滑动切换画面,用ViewPager实现, 首先是布局文件: android:layout_width="match_parent" an ...
- Android实现仿QQ登录可编辑下拉菜单
Android实现仿QQ登录可编辑下拉菜单 在Android里,直接提供的Spinner控件虽然可以实现下拉菜单的效果,但其效果并不理想,很多时候我们需要类似手机QQ那样既可以在文本框中直接输入编辑文 ...
- android qq底部图片选择器,Android 高仿QQ图片选择器
当做一款APP,需要选择本地图片时,首先考虑的无疑是系统相册,但是Android手机五花八门,再者手机像素的提升,大图无法返回等异常因数,导致适配机型比较困难,微信.QQ都相继的在自己的APP里集成了 ...
- android 仿qq好友动态,Android UI仿QQ好友列表分组悬浮效果
本文实例为大家分享了Android UI仿QQ好友列表分组悬浮效果的具体代码,供大家参考,具体内容如下 楼主是在平板上測试的.图片略微有点大,大家看看效果就好 接下来贴源代码: PinnedHeade ...
- Android qq消息气泡实现效果,Android 实现仿QQ拖拽气泡效果的示例
效果图: 一.实现思路 在列表中默认使用自定义的TextView控件来展示消息气泡,在自定义的TextView控件中重写onTouchEvent方法,然后在DOWN.MOVE.UP事件中分别处理拖拽效 ...
- Android实现仿QQ登录界面背景动画效果
登录QQ的时候,我们会看到在登录界面的背景不是静态的,而是一段动画效果,刚开始觉得蛮好奇的,现在我们也来实现一下这种效果,实现起来还是挺简单的. 实现步骤: 1.自定义CustomVideoView类 ...
- Android高仿QQ消息列表、侧拉删除菜单按钮效果
目 录(本篇字数:3000) 介绍 Item布局 自定义存放Item父容器 Bug分析 ·一.解决滑动冲突 二.解决Item点击事件的冲突 三.限制只能有一个menu被打开 博文续篇 ListV ...
最新文章
- debian下安装LNMP(三)
- SQL Server 2008不能修改表的解决方法
- 论营销的重要性:以一个磁铁为例
- msys2安装gcc、g++编译器
- 七、配置ssh keys连通github跟ssh-agent
- 可有可无的Mysql工作技巧
- angular4动态添加html,angular4 动态创建组件
- python椭圆曲线加密_如何理解椭圆曲线加密并对其进行编码
- Anaconda3下载失败的解决方法
- 2010头号病毒追杀令——恶意下载者001
- 在 Mac 上修复 Touch ID 问题的 6 种方法
- mysql 取出当前第几列_mysql 获取表有多少列
- 前端开发必备,【项目实战】
- 如何开发自己的股票软件102
- RNA-seq——五、根据差异基因画火山图、在火山图上标记基因名
- word文档如何插入目录
- 延安.居民家庭计算机普及率,2004~2014年家庭互联网普及率及电脑持有率
- Pyramidal Feature Shrinking for Salient Object Detection
- JavaScript控制光标定位操作
- 文件服务器禁用u盘复制数据,如何禁止U盘拷贝
热门文章
- worldpress(管理员头像) 您可以在Gravatar修改您的资料图片
- 偏差(Bias)与方差(Variance)详解
- UIScrollView Scrollable Content Size Ambiguity 解决方法
- jieba分词三种分词模式、用户自定义词典、停用词词典的使用
- 数据结构java版之《简单排序》
- 饥荒创建账号服务器,饥荒服务器搭建详细图文教程 饥荒怎么创建服务器
- Echarts的使用总结
- Android自定义相机不存储照片,转换成Bitmap上传
- PDF加密文件不能复制、不能打印的解决办法
- Linux学习之ROS-Academy-for-Beginners安装记录与问题