import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.wwj.sina.weibo.R;
import com.wwj.sina.weibo.interfaces.Const;
import com.wwj.sina.weibo.library.StorageManager;
import com.wwj.sina.weibo.library.WeiboManager;
import com.wwj.sina.weibo.object.Status;
import com.wwj.sina.weibo.util.Tools;
import com.wwj.sina.weibo.workqueue.DoneAndProcess;
import com.wwj.sina.weibo.workqueue.task.ParentTask;
/**
-
微博列表适配器 主要用来显示首页、提示我的、收藏微博列表
-
@author wwj
*/
public class WeiboListAdapter extends BaseAdapter implements Const,
DoneAndProcess {
protected Activity activity;
protected int type;
protected LayoutInflater layoutInflater;
protected List statuses;
public WeiboListAdapter(Activity activity) {
this.activity = activity;
}
/**
-
需要传入一个已经封装微博数据的List对象 type表示
-
@param activity
-
@param statuses
-
@param type
-
表示处理的微博数据类型,在Const中定义相关常量
*/
public WeiboListAdapter(Activity activity, List statuses, int type) {
this.activity = activity;
this.type = type;
layoutInflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
this.statuses = new ArrayList();
if (statuses != null)
this.statuses.addAll(statuses);
try {
// 保存微博数据
StorageManager.saveList(statuses, PATH_STORAGE, type);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public int getCount() {
// 获取微博数,加1为了最后一项显示"更多"
return statuses.size() + 1;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
// 获取制定位置的Status对象
public Status getStatus(int position) {
if (statuses.size() > 0) {
return statuses.get(position);
} else {
return null;
}
}
// 获取已经显示的微博的最小ID
public long getMinId() {
if (statuses.size() > 0)
return statuses.get(statuses.size() - 1).id;
else
return Long.MAX_VALUE;
}
// 获取已经显示的微博最大ID
public long getMaxId() {
if (statuses.size() > 0)
return statuses.get(0).id;
else
return 0;
}
// 添加新的微博
// 在刷新、显示更多微博时会根据不同的情况决定如何添加微博
public void putStatuses(List statuses) {
if (statuses == null || this.statuses == null)
return;
if (statuses.size() == 0)
return;
if (this.statuses.size() == 0) {
this.statuses.addAll(statuses);
} else if (statuses
.get(0)
.getCreatedAt()
.before(this.statuses.get(this.statuses.size() - 1)
.getCreatedAt())) {
this.statuses.addAll(statuses);
// 添加的statuses比原来的新,并且数量小于等于默认返回数量,直接将statuses添加到前面
} else if (statuses.get(statuses.size() - 1).getCreatedAt()
.after(this.statuses.get(0).getCreatedAt())
&& statuses.size() <= DEFAULT_STATUS_COUNT) {
this.statuses.addAll(0, statuses);
} else {
this.statuses.clear();
this.statuses.addAll(statuses);
}
try {
// 保存微博信息
StorageManager.saveList(this.statuses, PATH_STORAGE, type);
} catch (Exception e) {
e.printStackTrace();
}
// 并且刷新ListView
this.notifyDataSetChanged();
}
// 控制View行为的
private boolean showMoreAnimFlag = false;
protected boolean showRefreshAnimFlag = false;
public void showMoreAnim() {
showMoreAnimFlag = true;
notifyDataSetChanged();
}
public void hideMoreAnim() {
showMoreAnimFlag = false;
notifyDataSetChanged();
}
public void showRefreshAnim() {
showMoreAnimFlag = true;
notifyDataSetChanged();
}
public void hideRefreshAnim() {
showRefreshAnimFlag = false;
notifyDataSetChanged();
}
// 通过url装载要显示的图像,如果图像文件不存在,回通过hideView标志决定是否隐藏ImageView组件
// hideView: true 隐藏ImageView hideView:false 不做任何动作
private void loadImage(ImageView imageView, String url, boolean hideView) {
if (url != null) {
String imageUrl = WeiboManager.getImageurl(activity, url);
if (imageUrl != null) {
imageView.setImageURI(Uri.fromFile(new File(imageUrl)));
imageView.setVisibility(View.VISIBLE);
return;
}
}
if (hideView)
imageView.setVisibility(View.GONE);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = layoutInflater
.inflate(R.layout.weibo_list_item, null);
}
View weiboListItem = convertView.findViewById(R.id.ll_weibo_list_item); // 微博列表项
View moreWeiboListItem = convertView
.findViewById(R.id.rl_more_weibo_list_item); // “更多”列表项
View refreshWeiboListItem = convertView
.findViewById(R.id.rl_refresh_weibo_list_item); // "刷新"列表项
refreshWeiboListItem.setVisibility(View.GONE);
// 当列表项不是最后一项时继续执行
if (position < statuses.size()) {
weiboListItem.setVisibility(View.VISIBLE);
moreWeiboListItem.setVisibility(View.GONE); // “更多”不显示
Status status = statuses.get(position);
TextView statusText = (TextView) convertView
.findViewById(R.id.tv_text);
TextView name = (TextView) convertView.findViewById(R.id.tv_name);
TextView createAt = (TextView) convertView
.findViewById(R.id.tv_created_at);
ImageView profileImage = (ImageView) convertView
.findViewById(R.id.iv_profile_image);
profileImage.setImageResource(R.drawable.portrait); // 设置默认头像
ImageView picture = (ImageView) convertView
.findViewById(R.id.iv_picture);
ImageView statusImage = (ImageView) convertView
.findViewById(R.id.iv_status_image);
ImageView verified = (ImageView) convertView
.findViewById(R.id.iv_verified);
verified.setVisibility(View.GONE); // 设置认证不可见
if (status.user != null) {
// 设置用户认证图标,即各种颜色的“V”或其他符号
Tools.userVerified(verified, status.user.verified_type);
}
statusImage.setImageBitmap(null);
LinearLayout insideContent = (LinearLayout) convertView
.findViewById(R.id.ll_inside_content);
ImageView retweetdetailImage = (ImageView) convertView
.findViewById(R.id.iv_retweetdetail_image);
retweetdetailImage.setImageBitmap(null);
TextView retweetdetailText = (TextView) convertView
.findViewById(R.id.tv_retweetdetail_text);
TextView source = (TextView) convertView
.findViewById(R.id.tv_source);
// 装载图像
if (status.user != null) {
loadImage(profileImage, status.user.profile_image_url, false);
}
loadImage(statusImage, status.thumbnail_pic, true);
statusText.setText(Tools.changeTextToFace(activity,
Html.fromHtml(Tools.atBlue(status.text))));
if (status.user != null)
name.setText(status.user.name); // 显示用户昵称
// 当前微博有图像
if (WeiboManager.hasPicture(status))
picture.setVisibility(View.VISIBLE);
else
picture.setVisibility(View.INVISIBLE);
createAt.setText(Tools.getTimeStr(status.getCreatedAt(), new Date()));
source.setText("来自: " + status.getTextSource()); // 设置微博来源
if (status.retweeted_status != null // 如果转发的数据不为空
&& status.retweeted_status.user != null) {
insideContent.setVisibility(View.VISIBLE);
retweetdetailText.setText(Html.fromHtml(Tools.atBlue(“@”
-
status.retweeted_status.user.name + “:”
-
status.retweeted_status.text)));
loadImage(retweetdetailImage,
status.retweeted_status.thumbnail_pic, false);
} else {
insideContent.setVisibility(View.GONE);
}
} else {
weiboListItem.setVisibility(View.GONE);
moreWeiboListItem.setVisibility(View.VISIBLE); // 显示“更多”
View moreAnim = convertView.findViewById(R.id.pb_more);
if (showMoreAnimFlag) {
moreAnim.setVisibility(View.VISIBLE);
} else {
moreAnim.setVisibility(View.GONE);
}
}
return convertView;
}
@Override
public void doneProcess(ParentTask task) {
notifyDataSetChanged(); // 通知更新列表数据
}
}
关于adapter我们需要关注getView这个方法,因为我们要显示的内容都在这里完成,由于每一条的微博数据比较多,所以童鞋们要注意每一项内容显示到哪个控件上。显示的数据是通过构造方法传进来的,每一条微博数据就是一个Status对象,所以我们需要定义相应的实体类,这个类我们怎么知道怎么定义,这就要知道请求API所返回的内容,
比如:https://api.weibo.com/2/statuses/home_timeline.json。我们请求这个API的时候,返回的字段就是我们需要定义的,如果不太清楚,既要好好看看一下开放平台给我们说明。
可以到这里查看:http://open.weibo.com/wiki/2/statuses/home_timeline。
那里很清楚说明了,请求方式,请求参数还有返回的json数据结构。
返回字段说明
| 返回值字段 | 字段类型 | 字段说明 |
| — | — | — |
| created_at | string | 微博创建时间 |
| id | int64 | 微博ID |
| mid | int64 | 微博MID |
| idstr | string | 字符串型的微博ID |
| text | string | 微博信息内容 |
| source | string | 微博来源 |
| favorited | boolean | 是否已收藏,true:是,false:否 |
| truncated | boolean | 是否被截断,true:是,false:否 |
| in_reply_to_status_id | string | (暂未支持)回复ID |
| in_reply_to_user_id | string | (暂未支持)回复人UID |
| in_reply_to_screen_name | string | (暂未支持)回复人昵称 |
| thumbnail_pic | string | 缩略图片地址,没有时不返回此字段 |
| bmiddle_pic | string | 中等尺寸图片地址,没有时不返回此字段 |
| original_pic | string | 原始图片地址,没有时不返回此字段 |
| geo | object | 地理信息字段 详细 |
| user | object | 微博作者的用户信息字段 详细 |
| retweeted_status | object | 被转发的原微博信息字段,当该微博为转发微博时返回 详细 |
| reposts_count | int | 转发数 |
| comments_count | int | 评论数 |
| attitudes_count | int | 表态数 |
| mlevel | int | 暂未支持 |
| visible | object | 微博的可见性及指定可见分组信息。该object中type取值,0:普通微博,1:私密微博,3:指定分组微博,4:密友微博;list_id为分组的组号 |
| pic_urls | object | 微博配图地址。多图时返回多图链接。无配图返回“[]” |
| ad | object array | 微博流内的推广微博ID |
package com.wwj.sina.weibo.object;
import java.io.Serializable;
import java.util.Date;
import com.wwj.sina.weibo.interfaces.WeiboObject;
import com.wwj.sina.weibo.util.Tools;
import android.text.Html;
/**
-
微博实体类
-
@author wwj
*/
@SuppressWarnings(“serial”)
public class Status implements WeiboObject, Serializable {
/** 字符串型的微博ID */
public String idstr;
/** 创建时间 */
public String created_at;
/** 微博ID */
public long id;
/** 微博信息内容 */
public String text;
/** 微博来源(html形式) */
public String source;
/** 是否已收藏 */
public boolean favorited;
/** 是否被截断 */
public boolean truncated;
/** 回复ID */
public long in_reply_to_status_id;
/** 回复人UID */
public long in_reply_to_user_id;
/** 回复人昵称 */
public String in_reply_to_screen_name;
/** 微博MID */
public long mid;
/** 中等尺寸图片地址 */
public String bmiddle_pic;
/** 原始图片地址 */
public String original_pic;
/** 缩略图片地址 */
public String thumbnail_pic;
/** 转发数 */
public int reposts_count;
/** 评论数 */
public int comments_count;
/** 转发的微博内容 */
public Status retweeted_status;
/** 微博作者的用户信息字段 */
public User user; // 不要初始化,否则可能会引起递归创建对象,导致stack溢出
/** 获取Date形式的创建时间 */
public Date getCreatedAt() {
return Tools.strToDate(created_at);
}
/** 文本形式的source, */
private String text_source;
/** 获取文本形式的source */
public String getTextSource() {
if (text_source == null) {
try {
// 有时返回的来源是null,可能是一个bug,所以必须加上try…catch…
text_source = Html.fromHtml(source).toString();
} catch (Exception e) {
text_source = source;
}
}
return text_source;
}
}
我们在授权第三方应用程序访问用户的数据成功后,就会异步获取用户首页微博数据,然后显示到界面上。
package com.wwj.sina.weibo.listener;
import java.io.IOException;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.os.Message;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.weibo.net.DialogError;
import com.weibo.net.WeiboDialogListener;
import com.weibo.net.WeiboException;
import com.weibo.net.AsyncWeiboRunner.RequestListener;
import com.wwj.sina.weibo.Home;
import com.wwj.sina.weibo.R;
import com.wwj.sina.weibo.adapters.WeiboListAdapter;
import com.wwj.sina.weibo.interfaces.Const;
import com.wwj.sina.weibo.library.JSONAndObject;
import com.wwj.sina.weibo.library.StorageManager;
import com.wwj.sina.weibo.library.WeiboManager;
import com.wwj.sina.weibo.listener.impl.StatusRequestListenerImpl;
import com.wwj.sina.weibo.object.Status;
import com.wwj.sina.weibo.object.User;
import com.wwj.sina.weibo.util.LogUtils;
import com.wwj.sina.weibo.util.SettingUtil;
import com.wwj.sina.weibo.util.Tools;
public class AuthDialogListener implements WeiboDialogListener, Const {
private Activity activity;
public AuthDialogListener(Activity activity) {
super();
this.activity = activity;
}
// 认证成功后调用
public void onComplete(Bundle values) {
// 保存access_token 和 expires_in
String token = values.getString(“access_token”);
String expires_in = values.getString(“expires_in”);
SettingUtil.set(activity, SettingUtil.ACCESS_TOKEN, token);
SettingUtil.set(activity, SettingUtil.EXPIRES_IN, expires_in);
Toast.makeText(activity, “认证成功”, Toast.LENGTH_SHORT).show();
final Home homeActivity = (Home) activity;
WeiboListAdapter weiboListAdapter = null;
// 得到用户的唯一标识
long uid = Long.parseLong(values.getString(“uid”));
// 保存用户UID
StorageManager.setValue(activity, “uid”, uid);
WeiboManager.getUserAsync(homeActivity,
StorageManager.getValue(homeActivity, “uid”, 0),
new RequestListener() {
@Override
public void onIOException(IOException e) {
}
@Override
public void onError(WeiboException e) {
}
@Override
public void onComplete(String response) {
User user = new User();
JSONAndObject.convertSingleObject((Object) user,
response);
Message msg = new Message();
msg.obj = user;
homeActivity.handler.sendMessage(msg);
}
});
View homeReloadAnim = homeActivity.findViewById(R.id.pb_home_reload);
View homeReload = homeActivity.findViewById(R.id.btn_home_reload);
homeReloadAnim.setVisibility(View.VISIBLE);
homeReload.setVisibility(View.GONE);
LinearLayout ll_home_layout = (LinearLayout) homeActivity
.findViewById(R.id.ll_home_layout);
List statuses = WeiboManager.getHomeTimelineAsync(homeActivity,
new StatusRequestListenerImpl(homeActivity, ll_home_layout,
HOME));
weiboListAdapter = new WeiboListAdapter(activity, statuses, Const.HOME);
homeActivity.homeTimelineAdapter = weiboListAdapter;
homeActivity.imageWorkQueueMonitor = Tools
.getGlobalObject(homeActivity).getImageWorkQueueMonitor(
homeActivity);
homeActivity.taskWorkQueueMonitor = Tools.getGlobalObject(homeActivity)
.getTaskWorkQueueMonitor(activity);
homeActivity.imageWorkQueueMonitor.addDoneAndProcess(Const.HOME,
weiboListAdapter);
}
public void onWeiboException(WeiboException e) {
LogUtils.e(“### onWeiboException”);
// 当认证过程中捕获到WeiboException时调用
Toast.makeText(activity, “Auth exception:” + e.getMessage(),
Toast.LENGTH_LONG).show();
activity.finish();
}
public void onError(DialogError e) {
LogUtils.e(“### onError”);
// Oauth2.0认证过程中,当认证对话框中的webView接收数据出现错误时调用此方法
Toast.makeText(activity, “Auth error:” + e.getMessage(),
Toast.LENGTH_LONG).show();
activity.finish();
}
public void onCancel() {
LogUtils.e(“### onCancel”);
// Oauth2.0认证过程中,如果认证窗口被关闭或认证取消时调用
Toast.makeText(activity, “Auth cancel”, Toast.LENGTH_LONG).show();
activity.finish();
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/083dfcea68b935c6c8799bbe7c3b21c2.jpeg)
结语
- 现在随着短视频,抖音,快手的流行NDK模块开发也显得越发重要,需要这块人才的企业也越来越多,随之学习这块的人也变多了,音视频的开发,往往是比较难的,而这个比较难的技术就是NDK里面的技术。
- 音视频/高清大图片/人工智能/直播/抖音等等这年与用户最紧密,与我们生活最相关的技术一直都在寻找最终的技术落地平台,以前是windows系统,而现在则是移动系统了,移动系统中又是以Android占比绝大部分为前提,所以AndroidNDK技术已经是我们必备技能了。
- 要学习好NDK,其中的关于C/C++,jni,Linux基础都是需要学习的,除此之外,音视频的编解码技术,流媒体协议,ffmpeg这些都是音视频开发必备技能,而且
- OpenCV/OpenGl/这些又是图像处理必备知识,下面这些我都是当年自己搜集的资料和做的一些图,因为当年我就感觉视频这块会是一个大的趋势。所以提前做了一些准备。现在拿出来分享给大家。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
lAgF4GLR-1711992159768)]
[外链图片转存中…(img-TfmtKYBl-1711992159769)]
[外链图片转存中…(img-BhULqP1j-1711992159769)]
[外链图片转存中…(img-NXsphCJD-1711992159770)]
[外链图片转存中…(img-2mN30rY7-1711992159770)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
![](https://i-blog.csdnimg.cn/blog_migrate/083dfcea68b935c6c8799bbe7c3b21c2.jpeg)
结语
- 现在随着短视频,抖音,快手的流行NDK模块开发也显得越发重要,需要这块人才的企业也越来越多,随之学习这块的人也变多了,音视频的开发,往往是比较难的,而这个比较难的技术就是NDK里面的技术。
- 音视频/高清大图片/人工智能/直播/抖音等等这年与用户最紧密,与我们生活最相关的技术一直都在寻找最终的技术落地平台,以前是windows系统,而现在则是移动系统了,移动系统中又是以Android占比绝大部分为前提,所以AndroidNDK技术已经是我们必备技能了。
- 要学习好NDK,其中的关于C/C++,jni,Linux基础都是需要学习的,除此之外,音视频的编解码技术,流媒体协议,ffmpeg这些都是音视频开发必备技能,而且
- OpenCV/OpenGl/这些又是图像处理必备知识,下面这些我都是当年自己搜集的资料和做的一些图,因为当年我就感觉视频这块会是一个大的趋势。所以提前做了一些准备。现在拿出来分享给大家。
[外链图片转存中…(img-QXHk9gC6-1711992159770)]
[外链图片转存中…(img-jY7tI22V-1711992159770)]