最近在仿写微信,需要将用户登录后的朋友列表显示出来。
基本思路是,在用户点击登录按钮后,将用户名(username)保存到intent中,然后启动活动,在活动中通过
Intent intent = getIntent();String username = intent.getStringExtra();在这里插入代码片
得到username,然后开启线程,向服务端发送请求朋友列表的包,像下面这样
// 新开线程,向服务端发送一个请求朋友列表的包
new Thread() {
@Override
public void run() {
try {
RequestFriendsPacket packet = new RequestFriendsPacket(username);
Socket socket = new Socket("10.0.2.2", 2018);
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
out.write(packet.serialize());
out.flush();
byte[] buffer = new byte[1024];
int length = in.read(buffer);
String friendsInThread = new String(buffer, 0, length);
// 通过消息机制修改主线程中的friends
Message message = new Message();
message.what = 0x0001;
message.obj = friendsInThread;
mainActHandler.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
这样就得到了朋友列表信息(friends),然后拆解这个字符串数组得到一组朋友的名字,如下所示
String allFriends[] = friends.split("[|]");// 拆解得到本用户所有的朋友
for (int i = 0; i < allFriends.length; i++)
Log.d("friends=====", allFriends[i]);
然后初始化RecyerView中的聊天摘要列表(chatItemList)即可。
不过这里要注意几个问题(也就是我遇到的坑,呜呜):
1、请求好友信息(friends)的线程跑的是比主线程慢的,所以原本在主线程中执行的initFragment();是要放在Handler中的,这里的Handler是处理子线程请求完成后发送给主线程的消息的,一定要在这里初始化我们的Fragment,不然会导致Fragment的聊天摘要的朋友名字缺失。我写的Handler如下:
public Handler mainActHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0x0001) {
friends = (String) msg.obj;
Log.d("mainActHandler===", friends + "====");
// fragments[0] = new WeixinFragment(friends);
initFragment();
}
}
};在这里插入代码片
2、在Fragment中获取与之关联的Activity时,最好放在方法体中而不要放在外面,因为放在外面的话有可能不会执行,如下所示:
public class WeixinFragment extends Fragment {
private List<ChatItem> chatItemList = new ArrayList<>();
private MainActivity mainActivity;
private String friends = "";
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mainActivity = (MainActivity) getActivity();// 获取主活动
// 得到主活动中的当前用户名,然后根据这个发送一个请求朋友列表的包给服务端,服务端根据用户名
// 进入数据库查询都该用户的所有朋友,然后将信息(一个包含朋友列表的字符串)返回到本地即可
Log.d("===fragmentIndex:", Integer.toString(mainActivity.getFragmentIndex()));
friends = mainActivity.getFriends();// 这句话如果报空指针异常,将mainActivity = (MainActivity) getActivity();// 获取主活动移动到onCreateView()方法中
Log.d("===friends:", friends);
initChatItems();// 初始化各个聊天子项
// 获取“微信”碎片
LinearLayout chatItemLayout = (LinearLayout) inflater.inflate(R.layout.fragment_weixin, container, false);
// 获取”微信“碎片中的RecyclerView,也就是聊天项目列表
RecyclerView chatItemRecyclerView = chatItemLayout.findViewById(R.id.chat_item_recycler_view);
// 设置分割线
// chatItemRecyclerView.addItemDecoration(new DividerItemDecoration(mainActivity, DividerItemDecoration.VERTICAL));
chatItemRecyclerView.addItemDecoration(new RecycleViewDivider(getContext(), LinearLayoutManager.VERTICAL));
// 获取布局管理
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mainActivity);
chatItemRecyclerView.setLayoutManager(linearLayoutManager);
ChatItemAdapter chatItemAdapter = new ChatItemAdapter(getActivity(), chatItemList);
chatItemRecyclerView.setAdapter(chatItemAdapter);
// 这里要注意,重新渲染的话R.layout.fragment_weixin
// 是会被重置的,这就解释了为什么页面会加载不出来了
// 所以直接将chatItemLayout返回就可以了
// return inflater.inflate(R.layout.fragment_weixin, container, false);
return chatItemLayout;
}
3、请求好友列表信息(friends)时,向服务端写完数据一定要马上读取服务端返回的数据,不然等当前socket关掉了的话,在程序其他位置在创建socket是无法得到这个socket的,更别提获取他的数据了(小白水平有限,在这个地方卡了好久……)