代码之家  ›  专栏  ›  技术社区  ›  Hoque MD Zahidul

如何使用LazyLoading在单个循环视图或适配器中显示多个数据源数据?

  •  0
  • Hoque MD Zahidul  · 技术社区  · 6 年前

    上面的图片是一个简单的设计,我想发展。 我有四种不同类型的数据,不同的视图类型,如下图所示,在这里输入图像描述。但这不是问题。问题是数据将来自不同的API和延迟加载,就像当用户从回收视图滚动列表时,它将从服务器获取数据。我的问题是如何将它们组合在一个适配器中,因为我需要使用延迟加载,所以我不能一次加载整个数据,所以我需要在用户滚动时调用不同类型的API,如目标列表API、评估API、post API等。任何人都可以给我举个例子。我该怎么办?另外,当用户滚动时,它也会调用另一个api,比如count和comment count。目前,在我的,我正在调用单一API,并在single recycle视图中显示它。目前,我正在使用android架构组件LiveData

    碎片:

    public class NewsFeedFragment extends FcaFragment {
    
        private View view;
        private RecyclerView postRecyclerView;
        private PostsAdapter postsAdapter;
        private List<Post> posts;
        private TimelineViewModel timelineViewModel;
        private ImageView addPostView;
        private View addPostPanel;
        private long lastApiCallTime;
        private SwipyRefreshLayout swipeRefresh;
        private long lastScroolItemInPost= 0;
    
        public NewsFeedFragment() {
    
        }
    
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            if(lastScroolItemInPost  < 1) {
                initViewModel(1 , 0 , true);
                lastScroolItemInPost = 1;
            }else {
                initViewModel(((int) lastScroolItemInPost + 5), lastScroolItemInPost , true);
                lastScroolItemInPost += 5;
            }
    
    
            final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ownerActivity);
    
            view = inflater.inflate(R.layout.fragment_news_feed, container, false);
            postRecyclerView = (RecyclerView) view.findViewById(R.id.postRecyclerView);
            postRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                }
    
                @Override
                public void onScrolled(RecyclerView postRecyclerView, int dx, int dy) {
                    super.onScrolled(postRecyclerView, dx, dy);
    
    
                    int lastVisiableItemInPostList   = linearLayoutManager.findLastVisibleItemPosition();
    
    
                    if(lastScroolItemInPost < lastVisiableItemInPostList)
                    {
                            if(lastScroolItemInPost == 1)
                            {
                            initViewModel((int) (lastScroolItemInPost + 2), ( lastScroolItemInPost - 2 )  , false);
                            lastScroolItemInPost += 2;
                            }else{
                                initViewModel((int) (lastScroolItemInPost + 2), ( lastScroolItemInPost - 2 ) , false );
                                lastScroolItemInPost += 2;
                            }
    
    
                    }
    
                   }
    
            });
    
            posts = new ArrayList<>();
    
            postRecyclerView.setLayoutManager(linearLayoutManager);
            postsAdapter = new PostsAdapter(ownerActivity,posts,timelineViewModel);
            postRecyclerView.setAdapter(postsAdapter);
            swipeRefresh = (SwipyRefreshLayout) view.findViewById(R.id.swipeRefresh);
            swipeRefresh.setOnRefreshListener(new SwipyRefreshLayout.OnRefreshListener() {
                @Override
                public void onRefresh(SwipyRefreshLayoutDirection direction) {
                    if(direction == SwipyRefreshLayoutDirection.TOP){
                        timelineViewModel.fetchPosts2();
                    }
    
                    if(direction == SwipyRefreshLayoutDirection.BOTTOM){
                        timelineViewModel.fetchPosts();
                    }
                }
            });
    
    
    
    
            return view;
        }
    
    
    
    
        private void initViewModel(int lastVisiableItemInPostList , long lastScroolItemInPost , boolean isFirstTimeOpenFeedFragment) {
            TimelineViewModel.Factory factory = new TimelineViewModel.Factory(UserPreferences.getToken(ownerActivity), TaskUtils.getMySelfContact(ownerActivity));
            timelineViewModel = ViewModelProviders.of(this,factory).get(TimelineViewModel.class);
            timelineViewModel.getPostList().observe(this, new Observer<List<Post>>() {
                @Override
                public void onChanged(@Nullable List<Post> posts) {
    
                    postsAdapter.setPostList(posts);
                    swipeRefresh.setRefreshing(false);
    
                }
            });
            timelineViewModel.getPostDeleted().observe(this, new Observer<Boolean>() {
                @Override
                public void onChanged(@Nullable Boolean aBoolean) {
                    if(aBoolean){
                        postsAdapter.setPostList(Post.getAll());
                    }
                }
            });
            timelineViewModel.init( lastVisiableItemInPostList ,  lastScroolItemInPost ,isFirstTimeOpenFeedFragment);
        }
    
    }
    

    视图模型:

    public class TimelineViewModel extends FCViewModel implements PostDetailsDownloadManager.PostDetailDownloadedListener,OnContactReceivedListner{
    
    
    
    
    
        public TimelineViewModel(String token,Contact user){
            super(token);
            this.user = user;
    
            post = new MutableLiveData<>();
            postDeleted = new MutableLiveData<>();
        }
    
        public void init(int lastVisiableItemInPostList , long lastScroolItemInPost , boolean isFirstTimeOpenFeedFragment){
            repository = 
            //postDetailsDownloadManager = ServiceLocator.getServiceLocator().postDetailsDownloadManager;
    
            likePostDownloadManager = ServiceLocator.getServiceLocator().likePostDownloadManager;
            likePostDownloadManager.setPostDetailDownloadedListener(new DataDownloadManager.DataDownloadedListener<LikePostTouple>() {
                @Override
                public void onDataDownloaded(List<LikePostTouple> dataTouple) {
                    TimelineViewModel.this.post.setValue(Post.getAll());
                }
    
                @Override
                public void onSingleDataDownloaded(LikePostTouple dataTouple) {
    
                }
            });
    
            postDetailDownloadManager = ServiceLocator.getServiceLocator().postDetailDownloadManager;
            postDetailDownloadManager.setPostDetailDownloadedListener(new DataDownloadManager.DataDownloadedListener<PostTouple>() {
                @Override
                public void onDataDownloaded(List<PostTouple> dataTouple) {
                    TimelineViewModel.this.post.setValue(Post.getAll());
                }
    
                @Override
                public void onSingleDataDownloaded(PostTouple dataTouple) {
    
                }
            });
            post.setValue(Post.getAll());
            if(isFirstTimeOpenFeedFragment)
            {
                fetchPosts2();
            }
    
            try {
                if(Post.getAll().size() > 0)
                {
                    List<Post> tempPosts = Post.getAll();
                    List<Post> passList = tempPosts.subList( (int) lastScroolItemInPost ,lastVisiableItemInPostList);
                    fetchLikesOfPosts(passList);
                }else{
                    fetchLikesOfPosts(Post.getAll());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    
            Log.d("Testing Injecting", repository.toString());
        }
    
        public LiveData<List<Post>> getPostList() {
            return post;
        }
    
        public MutableLiveData<Boolean> getPostDeleted() {
            return postDeleted;
        }
    
        boolean isContactFetched = false;
    
        public void fetchPosts(){
            if(Contact.getAll().size() < 1){
                fetchContacts();
                return;
            }
            Map<String,Object> requestData = new HashMap<>();
            requestData.put("type",1);
            requestData.put("cpid",Post.getLastPid());
            isDataLoading = true;
            repository.getData(new Repository.DataFetchedListener<List<Post>>() {
                @Override
                public void onDataFetched(List<Post> posts) {
                    isDataLoading = false;
                    Log.d("fetched posts",""+posts.size());
                    post.setValue(Post.getAll());
                    fetchPostDetails(posts);
                    if(posts.size() > 0){
                        fetchLikesOfPosts(posts);
                    }
                }
            },requestData);
        }
    
    
        private boolean isDataLoading = false;
        public void fetchPosts2(){
            if(Contact.getAll().size() < 1){
                fetchContacts();
                return;
            }
            Map<String,Object> requestData = new HashMap<>();
            requestData.put("type",2);
            requestData.put("cpid", Post.getFirstPid()); // cpid means cursor pid
            isDataLoading = true;
            repository.getData(new Repository.DataFetchedListener<List<Post>>() {
                @Override
                public void onDataFetched(List<Post> posts) {
                    isDataLoading = false;
                    Log.d("fetched posts",""+posts.size());
                    post.setValue(Post.getAll());
                    fetchPostDetails(posts);
                    if(posts.size() > 0){
                        fetchLikesOfPosts(posts);
                    }
                }
            },requestData);
        }
    
        public boolean isDataLoading() {
            return isDataLoading;
        }
    
    
    
        private void fetchContacts() {
            contactRepository.getData(new Repository.DataFetchedListener<List<Contact>>() {
                @Override
                public void onDataFetched(List<Contact> data) {
                    if(data.size()>0 && !isContactFetched) {
                        fetchPosts2();
                        isContactFetched = true;
                    }
                }
            },null);
        }
    
    
    
        @NonNull
        private PostTouple getPostToubleFromPost(Post post) throws JSONException {
            Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
            String json =   gson.toJson(post);
            JSONObject postJson = new JSONObject(json);
            return new PostTouple(postJson,post.getPid());
        }
    
        @NonNull
        private LikePostTouple getLkePostToupleFromPost(Post post) throws JSONException {
            Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
            String json =   gson.toJson(post);
            JSONObject postJson = new JSONObject(json);
            return new LikePostTouple(postJson,post.getPid());
        }
    
        public void giveLike(String token, final long pid){
            Map<String,Object> requestData = new HashMap<>();
            requestData.put("token",token);
            requestData.put("pid",Long.toString(pid));
    
            likeRepository.postData(new Repository.DataFetchedListener<Post>() {
                @Override
                public void onDataFetched(Post data) {
                    Log.d("Like post", data.toString());
                    Post post = getPostById(pid);
                    post.setLikes(data.getLikes());
                    post.setComments(data.getComments());
                    TimelineViewModel.this.post.setValue(TimelineViewModel.this.post.getValue());
                    fetchLikesOfLikedPost(data);
                }
            },requestData);
        }
    
        private void fetchLikesOfLikedPost(Post data) {
            try {
                likePostDownloadManager.addItemInQueue(getLkePostToupleFromPost(data));
                likePostDownloadManager.startDownload();
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    
        private Post getPostById(long pid){
            List<Post> posts = post.getValue();
            for(Post post : posts){
                if(post.getPid()==pid){
                    return post;
                }
            }
            return null;
        }
    
        public Contact getSenderContactFromComment(Post post) {
            if(post.getPqrc().equals(user.getUserId())){
                return user;
            }
            Contact contact = Contact.getByUserId(post.getPqrc());
    
            return contact;
        }
    
        public String getDescriptionForType5(Post post,String message){
    
            try {
                PostDetail postDetail = PostDetail.getByPostId(post.getPid());
                if(postDetail!=null) {
                    String qrc = JSonUtils.qrcFromCntOfPostDetails(postDetail.getContent());
                    int sid = JSonUtils.skillidFromCntOfPostDetails(postDetail.getContent());
                    if (qrc == null || sid == 0) {
                        return "";
                    }
                    SkillDb skill = SkillDb.getBySId(Integer.toString(sid));
    
                    Contact contact = getPosterContact(post.getPqrc());
    
                    return contact.getName() + " " + message + " " + skill.getSkillName() + ".";
                }
    
                return "";
            } catch (Exception e) {
                e.printStackTrace();
            }
            return "";
        }
    
        public String getDescriptionForPost(Post post, String message){
            if(post.getCtype()==1){
                return post.getDescr();
            }
    
            if(post.getCtype() == 2){
                String postDetail = getContent(post);
                if (postDetail != null) return Html.fromHtml("<a href=\""+ postDetail +"\">"+postDetail+"</a>").toString();
            }
    
            if(post.getCtype()==5){
                return getDescriptionForType5(post, message);
            }
    
            return "";
    
        }
    
        @Nullable
        public String getContent(Post post) {
            PostDetail postDetail = PostDetail.getByPostId(post.getPid());
            if(postDetail!=null){
                return postDetail.getContent();
            }
            return null;
        }
    
    
        public Contact getPosterContact(String qrc){
            try {
                String userqrc = user.getUserId();
                if (userqrc.equals(qrc)) {
                    return user;
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            try {
                return Contact.getByUserId(qrc);
            }catch (Exception e){
                e.printStackTrace();
            }
            return null;
        }
    
        public void fetchUrlPreview(String url, final UrlMetaDataFetchListener metaDataFetchListener){
            String modifiedUrl = !url.contains("http://")&&!url.contains("https://")? "http://"+url : url;
            TextCrawler textCrawler = new TextCrawler();
    
    
            LinkPreviewCallback linkPreviewCallback = new LinkPreviewCallback() {
                @Override
                public void onPre() {
    
                }
    
                @Override
                public void onPos(SourceContent sourceContent, boolean b) {
                    String imageUrl = sourceContent.getImages().isEmpty()? "" : sourceContent.getImages().get(0);
                    metaDataFetchListener.onMetaDataFetched(sourceContent.getTitle(),sourceContent.getDescription(), imageUrl);
                }
            };
    
            textCrawler.makePreview(linkPreviewCallback, modifiedUrl,1);
        }
    
    
        public interface UrlMetaDataFetchListener{
            void onMetaDataFetched(String title, String description, String imageUrl);
        }
    
        @Override
        public void onPostDownloaded(PostTouple postTouple) {
            this.post.setValue(Post.getAll());
        }
    
        @Override
        public void onContactsReceived() {
            fetchPosts();
        }
    
    
        public void deletePost(long pid) {
            Map<String, Object> requestData = new HashMap<>();
            requestData.put("token",token);
            requestData.put("pid",pid);
            repository.postData(new Repository.DataFetchedListener<Post>() {
                @Override
                public void onDataFetched(Post data) {
                    postDeleted.setValue(data!=null);
                }
            },requestData);
        }
    
        public boolean isMyPost(Post post){
            return user.getUserId().equals(post.getPqrc());
        }
    
        public static class Factory extends ViewModelProvider.NewInstanceFactory {
    
             private String token;
             private Contact user;
    
            public Factory(String token,Contact user) {
                this.token = token;
                this.user = user;
            }
    
            @Override
            public <T extends ViewModel> T create(Class<T> modelClass) {
    
                return (T) new TimelineViewModel(token,user);
            }
        }
    }
    

    适配器:

    公共类PostsAdapter扩展RecyclerView.适配器{

    private Context context;
    private List<Post> postList;
    private int[] badges = {R.drawable.badge1, R.drawable.badge2, R.drawable.badge3};
    private List<Integer> randomNumbers = Utils.getRandomNumberList(2,true);
    private ArrayDeque<Integer> randomQueue = new ArrayDeque<>(randomNumbers);
    private static Map<Long,URLPreview> urlPreviewMap = new HashMap<>();
    private TimelineViewModel timelineViewModel;
    
    public PostsAdapter(Context context, List<Post> postList, TimelineViewModel timelineViewModel){
        super();
        this.context = context;
        this.postList = postList;
        this.timelineViewModel = timelineViewModel;
    }
    
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View view = inflater.inflate(R.layout.post_item_layout, null);
        PostViewHolder postViewHolder = new PostViewHolder(view);
        postViewHolder.setIsRecyclable(false);
        return postViewHolder;
    }
    
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
        final Post post = postList.get(position);
        final PostViewHolder postViewHolder = (PostViewHolder) holder;
        final String postDetail = timelineViewModel.getDescriptionForPost(post,context.getResources().getString(R.string.postType5message));
    
    
        setPostDescription(post, postViewHolder, postDetail);
        handlePreviewVisibility(post, postViewHolder);
    
    
        postViewHolder.setLikes(""+post.getLikes()+" Likes");
        postViewHolder.setCommentCount("" + post.getComments() + " Comments");
        postViewHolder.setSupDescription("Posted By System");
    
        int randomNumber = getRandomNumber();
        postViewHolder.setBadgeIcon(badges[randomNumber]);
    
        setPostLikedIndicator(post, postViewHolder);
    
        postViewHolder.getLikeButtonWrapper().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
    
    
                giveLikeToPost(post);
                if(post.getIsLiked() == 0) {
                    post.setLikes(post.getLikes() + 1);
                    postViewHolder.setLikes("" + post.getLikes() + " Likes");
                    post.setIsLiked(1);
                    setPostLikedIndicator(post, postViewHolder);
                }
            }
        });
    
        postViewHolder.getCommentPanel().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                CommentPostFragment fragment = CommentPostFragment.GetInstance(post.getPid());
                ViewUtils.launchFragmentKeepingInBackStack(context,fragment);
            }
        });
    
        Contact contact = timelineViewModel.getPosterContact(post.getPqrc());
    
        if(contact!=null && TaskUtils.isNotEmpty(contact.getImageToken())){
            Utils.setImageToImageView(postViewHolder.getPosterImage(),timelineViewModel.getToken(),contact.getImageToken());
            postViewHolder.getPosterNameTextView().setText(contact.getName());
        }
    
    
        postViewHolder.getPostingDate().setText(Utils.getDateFromMilliseconds(post.getdC()));
        if(post.getCtype() != 3)
        {
    
            postViewHolder.contentImage.setVisibility(View.GONE);
            postViewHolder.fullScreenIndicatorIcon.setVisibility(View.GONE);
        }
    
        if(post.getCtype() == 3){
            setContentOfType3(post, postViewHolder);
        }
    
    
    
    
    }
    
    @Override
    public void onViewRecycled(RecyclerView.ViewHolder holder) {
        super.onViewRecycled(holder);
        PostViewHolder viewHolder = (PostViewHolder) holder;
        viewHolder.pTitle.setText("");
        viewHolder.pDescription.setText("");
        viewHolder.pImage.setImageDrawable(null);
    
    }
    
    private void handlePreviewVisibility(Post post, PostViewHolder postViewHolder) {
        if(post.getCtype()==2){
            postViewHolder.preview.setVisibility(View.VISIBLE);
        }else{
            postViewHolder.preview.setVisibility(View.GONE);
        }
    }
    
    private void handleShowingOptionsIcon(Post post, PostViewHolder postViewHolder) {
        if(post.getCtype()!=5 && timelineViewModel.isMyPost(post)){
            postViewHolder.options.setVisibility(View.VISIBLE);
        }else{
            postViewHolder.options.setVisibility(View.GONE);
        }
    }
    
    
    
    
    
    private void giveLikeToPost(Post post) {
        post.setLikes(post.getLikes()+1);
    
        post.setIsLiked(1);
    
        //notifyDataSetChanged();
    
        timelineViewModel.giveLike(UserPreferences.getToken(context),post.getPid());
    
    }
    
    private void setPostLikedIndicator(Post post, PostViewHolder postViewHolder) {
        if(post.getIsLiked()==1) {
            postViewHolder.getLikeButton().setImageDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_like_red, null));
        }else{
            postViewHolder.getLikeButton().setImageDrawable(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_like_filled, null));
        }
    }
    
    private void setPostDescription(final Post post, final PostViewHolder postViewHolder, final String postDetail) {
        if(post.getCtype()==2){
    
            String postDescription = "<p>"+ post.getDescr()+"</p>";
            postViewHolder.description.setText( Html.fromHtml(postDescription +"<a href=\""+ postDetail +"\">"+postDetail+"</a>")  );
            postViewHolder.descriptionContainer.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String url = !postDetail.contains("http://")&&!postDetail.contains("https://")? "http://"+postDetail : postDetail;
                    Uri uri = Uri.parse(url);
                    context.startActivity(new Intent(Intent.ACTION_VIEW,uri));
                }
            });
            URLPreview urlPreview = null;
            if((urlPreview=urlPreviewMap.get(post.getPid()))==null) {
                timelineViewModel.fetchUrlPreview(postDetail, new TimelineViewModel.UrlMetaDataFetchListener() {
                    @Override
                    public void onMetaDataFetched(String title, String description, String imageUrl) {
                        showURLPreview(title, description, imageUrl, postViewHolder);
                        urlPreviewMap.put(post.getPid(),new URLPreview(title,description,imageUrl));
                    }
                });
            }else {
                showURLPreview(urlPreview.getTitle(),urlPreview.getDescription(),urlPreview.getImageUrl(),postViewHolder);
            }
    
        }else if(post.getCtype() == 3)
        {
          String postDescription = post.getDescr();
          postViewHolder.description.setText(postDescription);
        }
        else {
            postViewHolder.setDescription(postDetail);
        }
    }
    private void initImageClickListener(final ImageView imageView, final String pictureLink) {
        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                List<String> pictureLinks = new ArrayList<String>();
                pictureLinks.add(pictureLink);
    
    
                int[] screenLocation = new int[2];
                imageView.getLocationOnScreen(screenLocation);
    
                ImagePagerFragment imagePagerFragment = ImagePagerFragment.newInstance(pictureLinks, 0, screenLocation, imageView.getWidth(), imageView.getHeight());
                ViewUtils.launchPopUpFragmentUpdated(context, imagePagerFragment);
            }
        });
    }
    
    
    private void showURLPreview(String title, String description, String imageUrl, PostViewHolder postViewHolder) {
    

    context.getSystemService(Context.LAYOUT_充气机服务);

        if(!TaskUtils.isEmpty(imageUrl)) {
            Picasso.with(context)
                    .load(imageUrl)
                    .into(postViewHolder.pImage);
        }
    

    视图.findViewById(右。id.说明);

        postViewHolder.pTitle.setText(title);
        postViewHolder.pDescription.setText(description);
    
    
    }
    
    
    @Override
    public int getItemCount() {
        return postList.size();
    }
    
    private int getRandomNumber(){
        if(!randomQueue.isEmpty()){
            return randomQueue.poll();
        }
    
        randomQueue = new ArrayDeque<>(randomNumbers);
        return randomQueue.poll();
    }
    
    public void setPostList(List<Post> postList) {
        this.postList = postList;
        notifyDataSetChanged();
        Log.d("Data rec", postList.size()+"");
    }
    
    class PostViewHolder extends RecyclerView.ViewHolder implements PopupMenu.OnMenuItemClickListener {
    
    
    
    
        }
    
        public void setLikes(String likes) {
            this.likes.setText(likes);
        }
        public void setCommentCount(String commentCount)
        {
            this.commentCount.setText(commentCount);
        }
    
        public void setDescription(String description){
            this.description.setText(description);
        }
    
        public void setSupDescription(String subDescription){
            this.supDescription.setText(subDescription);
        }
    
        public void setBadgeIcon(int resID){
            Utils.setImageViewFromResource(badgeIcon,resID);
        }
    
        public ImageView getLikeButton() {
            return likeButton;
        }
        public RelativeLayout getLikeButtonWrapper()
        {
            return likeButtonWrapper;
        }
    
        public ImageView getCommentButton() {
            return commentButton;
        }
    
        public ImageView getPosterImage() {
            return posterImage;
        }
    
        public TextView getPosterNameTextView() {
            return posterNameTextView;
        }
    
        public TextView getPostingDate() {
            return postingDate;
        }
    
        public RelativeLayout getCommentPanel() {
            return commentPanel;
        }
    
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            timelineViewModel.deletePost(postList.get(getAdapterPosition()).getPid());
            return false;
        }
    }
    

    }

    0 回复  |  直到 6 年前