新浪微博客户端开发之发布微博
2013年11月22日新浪微博开发系列博客
题外话:
关于新浪微博客户端的开发我基本上是摸清楚了,之所以那么久才开始接下去写这系列的博客,主要也是小巫要摸透整个微博客户端的开发流程,要了解需要用到的技术和如何实现业务流程,再加上自己平时工作忙,最近也是忙学校的事情,所以耽搁了很久,其实实习之后发现自己之前与自己之前的计划是有点出入的,我是打算在实习期间把新浪微博客户端开发完毕,并且想自主研发一款app,但现实是我想跟我想做是不一样的,我不能估计我是否能在限定的时间里完成,因为我现在一点想法都没有,我不能去冒险把它作为自己毕业设计的内容,所以我打算做比较有把握的,所以想把新浪微博客户端作为毕业设计,但最终的效果肯定是跟现在的这个不一样的,我会继续完善,完善的程度是可以通过审核并且上线。所以如果想用做新浪微博客户端的童鞋注意了,不能抄袭哦,尊重原创作品。
题外话说到这里,开始本篇博客所要介绍的内容。
经过这段时间,我已经实现的功能列表如下:
新浪微博客户端开发之授权登录+获取微博列表
Android UI--自定义ListView(实现下拉刷新+加载更多)
Acitivity都放在com.wwj.sina.weibo这个包下面
发布微博的窗口是:/xiaowu_twitter/src/com/wwj/sina/weibo/PostWeibo.java
package com.wwj.sina.weibo;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ImageSpan;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.wwj.sina.weibo.adapters.FaceListAdapter;
import com.wwj.sina.weibo.interfaces.Const;
import com.wwj.sina.weibo.library.FaceMan;
import com.wwj.sina.weibo.library.StorageManager;
import com.wwj.sina.weibo.util.Tools;
import com.wwj.sina.weibo.workqueue.task.CommentWeiboTask;
import com.wwj.sina.weibo.workqueue.task.PostWeiboTask;
import com.wwj.sina.weibo.workqueue.task.RepostWeiboTask;
/**
* 发布微博
* @author wwj
*
*/
public class PostWeibo extends Activity implements Const, OnClickListener,
OnTouchListener, OnItemClickListener {
private Button btn_back; // 返回
private Button btn_send; // 发送
private EditText weiboContent; // 微博内容
private ImageView minPicViewer; // 微博图片
private TextView postWeiboTitle; // 微博标题栏
private View inputBoard; // 输入板(表情)
private ImageView insertAtButton; // 插入@
private ImageView insertLocationButton; // 插入位置
private ImageView insertFaceButton; // 插入表情
private ImageView insertPicButton; // 插入图片
private ImageView insertTopicButton; // 插入主题
private View isCommentView; // 评论
private CheckBox isCommentCheckBox; // 同时作为评论
private CheckBox postWeiboCheckBox; // 同为发送一条微博
private GridView faceList; // 表情列表
private Bitmap bitmap;
private static String filename; // 文件名(这里是图片)
private int type; // 发布微博类型
private long statusId; // 状态Id
private String title; // 标题
private String text; // 发送的文本
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.post_weibo);
loadView();
setListener();
// 表情网格视图填充数据
faceList.setAdapter(new FaceListAdapter(this));
bitmap = (Bitmap) getLastNonConfigurationInstance();
if (bitmap != null) {
minPicViewer.setVisibility(View.VISIBLE);
minPicViewer.setImageBitmap(bitmap);
}
// 获得Intent传过来的参数
statusId = getIntent().getLongExtra("status_id", 0);
type = getIntent().getIntExtra("type", TYPE_POST_WEIBO);
title = getIntent().getStringExtra("title");
text = getIntent().getStringExtra("text");
viewSetting();
}
private void viewSetting() {
switch (type) {
case TYPE_POST_WEIBO:
break;
case TYPE_FORWARD: // 转发微博
insertPicButton.setVisibility(View.GONE);
isCommentView.setVisibility(View.VISIBLE);
postWeiboCheckBox.setVisibility(View.GONE);
isCommentCheckBox.setVisibility(View.VISIBLE);
if (title != null) {
postWeiboTitle.setText(title);
}
if (text != null) {
weiboContent.setText(Tools.changeTextToFace(this,
Html.fromHtml(Tools.atBlue(text))));
weiboContent.getText().insert(0, " ");
weiboContent.setSelection(0, 1);
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
imm.showSoftInput(weiboContent, InputMethodManager.SHOW_FORCED);
}
break;
case TYPE_COMMENT: // 评论微博
insertPicButton.setVisibility(View.GONE);
isCommentView.setVisibility(View.VISIBLE);
postWeiboCheckBox.setVisibility(View.VISIBLE);
isCommentCheckBox.setVisibility(View.GONE);
if (title != null) {
postWeiboTitle.setText(title);
}
break;
}
}
private void setListener() {
btn_back.setOnClickListener(this);
btn_send.setOnClickListener(this);
insertAtButton.setOnClickListener(this);
insertLocationButton.setOnClickListener(this);
insertFaceButton.setOnClickListener(this);
insertPicButton.setOnClickListener(this);
insertTopicButton.setOnClickListener(this);
faceList.setOnItemClickListener(this);
minPicViewer.setOnClickListener(this);
}
/** 加载视图 **/
private void loadView() {
btn_back = (Button) findViewById(R.id.btn_back);
btn_send = (Button) findViewById(R.id.btn_send);
weiboContent = (EditText) findViewById(R.id.et_weibo_content);
minPicViewer = (ImageView) findViewById(R.id.iv_insert_pic_min_viewer);
postWeiboTitle = (TextView) findViewById(R.id.tv_post_weibo_title);
inputBoard = findViewById(R.id.fl_input_board);
faceList = (GridView) findViewById(R.id.gv_face_list);
insertAtButton = (ImageView) findViewById(R.id.btn_insert_at);
insertLocationButton = (ImageView) findViewById(R.id.btn_insert_location);
insertFaceButton = (ImageView) findViewById(R.id.btn_insert_face);
insertPicButton = (ImageView) findViewById(R.id.btn_insert_pic);
insertTopicButton = (ImageView) findViewById(R.id.btn_insert_topic);
isCommentView = findViewById(R.id.fl_is_comment);
isCommentCheckBox = (CheckBox) findViewById(R.id.cb_is_comment);
postWeiboCheckBox = (CheckBox) findViewById(R.id.cb_post_weibo);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
switch (parent.getId()) {
case R.id.gv_face_list:
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
FaceMan.getFaceResourceId(position));
ImageSpan imageSpan = new ImageSpan(bitmap);
String faceText = FaceMan.getFaceText(position);
SpannableString spannableString = new SpannableString(faceText);
spannableString.setSpan(imageSpan, 0, faceText.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
weiboContent.getText().insert(weiboContent.getSelectionStart(),
spannableString);
break;
default:
break;
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (v.getId()) {
case R.id.et_weibo_content:
inputBoard.setVisibility(View.GONE);
break;
default:
break;
}
return false;
}
@Override
public Object onRetainNonConfigurationInstance() {
return bitmap;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case CODE_REQUEST_CAPTURE_IMAGE: // 照相机
switch (resultCode) {
case Activity.RESULT_OK: // 确定键
minPicViewer.setVisibility(View.VISIBLE); // 设置图片可见
bitmap = (Bitmap) data.getExtras().get("data"); // 获取图片数据
minPicViewer.setImageBitmap(bitmap); // 显示图片
filename = StorageManager.saveBitmap(bitmap);
break;
default:
break;
}
break;
case CODE_REQUEST_PICTURE_VIEWER: // 来自查看图片的返回结果
switch (resultCode) {
case CODE_RESULT_REMOVE: // 删除
filename = null;
bitmap = null;
minPicViewer.setImageBitmap(null);
minPicViewer.setVisibility(View.GONE);
System.out.println("hhhh");
break;
case CODE_RESULT_RETURN: // 返回键
if (data != null) {
filename = data.getStringExtra("filename"); // 得到文件名
bitmap = BitmapFactory.decodeFile(filename);
minPicViewer.setImageBitmap(bitmap);
}
break;
default:
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
@Override
public void onClick(View v) {
Intent intent = null;
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
switch (v.getId()) {
case R.id.btn_back: // 返回
finish();
break;
case R.id.btn_send: // 发布
send();
break;
case R.id.btn_insert_pic: // 插入图片
intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, CODE_REQUEST_CAPTURE_IMAGE);
break;
case R.id.btn_insert_location: // 插入位置
break;
case R.id.btn_insert_topic: // 插入主题
String topicText = "请输入主题";
weiboContent.getText().insert(weiboContent.getSelectionStart(),
"#" + topicText + "#");
weiboContent.setSelection(weiboContent.getSelectionStart()
- topicText.length() - 1,
weiboContent.getSelectionStart() - 1);
imm.showSoftInput(weiboContent, InputMethodManager.SHOW_FORCED);
break;
case R.id.btn_insert_at: // 插入@
String atText = "请输入用户名";
weiboContent.getText().insert(weiboContent.getSelectionStart(),
"@" + atText + " ");
weiboContent.setSelection(weiboContent.getSelectionStart() - 1
- atText.length(), weiboContent.getSelectionStart() - 1);
imm.showSoftInput(weiboContent, InputMethodManager.SHOW_FORCED);
break;
case R.id.btn_insert_face: // 插入表情
if (inputBoard.getVisibility() == View.GONE) {
insertFaceButton
.setImageResource(R.drawable.btn_insert_keyboard);
inputBoard.setVisibility(View.VISIBLE);
faceList.setVisibility(View.VISIBLE);
} else {
insertFaceButton.setImageResource(R.drawable.btn_insert_face);
inputBoard.setVisibility(View.GONE);
faceList.setVisibility(View.GONE);
}
break;
case R.id.iv_insert_pic_min_viewer: // 图片浏览
intent = new Intent(PostWeibo.this, PictureViewer.class);
intent.putExtra("filename", filename);
startActivityForResult(intent, CODE_REQUEST_PICTURE_VIEWER);
break;
default:
break;
}
}
// 发送
private void send() {
String text = weiboContent.getText().toString();
switch (type) {
case TYPE_POST_WEIBO: // 发送微博
if (filename != null && "".equals("")) {
text = "分享图片";
} else if ("".equals(text)) {
Toast.makeText(this, "请输入微博内容", Toast.LENGTH_LONG).show();
return;
}
// 创建一个发布微博的任务
PostWeiboTask postWeiboTask = new PostWeiboTask();
postWeiboTask.text = text;
postWeiboTask.file = filename;
Tools.getGlobalObject(this).getWorkQueueStorage()
.addTask(postWeiboTask);
Toast.makeText(this, "已经提交发布微博任务到工作队列", Toast.LENGTH_LONG).show();
break;
case TYPE_FORWARD: // 转发微博
if ("".equals(text)) {
Toast.makeText(this, "请输入微博内容", Toast.LENGTH_LONG).show();
return;
}
RepostWeiboTask repostWeiboTask = new RepostWeiboTask();
repostWeiboTask.id = statusId;
repostWeiboTask.text = text;
if (isCommentCheckBox.isChecked()) { // 是否评论
repostWeiboTask.isComment = 1;
} else {
repostWeiboTask.isComment = 0;
}
Tools.getGlobalObject(this).getWorkQueueStorage()
.addTask(repostWeiboTask);
Toast.makeText(this, "已经提交转发微博任务到工作队列", Toast.LENGTH_LONG).show();
break;
case TYPE_COMMENT:
if ("".equals(text)) {
Toast.makeText(this, "请输入微博内容", Toast.LENGTH_LONG).show();
return;
}
CommentWeiboTask commentWeiboTask = new CommentWeiboTask();
commentWeiboTask.text = text;
commentWeiboTask.weiboText = text + this.text;
commentWeiboTask.id = statusId;
if (postWeiboCheckBox.isChecked()) {
commentWeiboTask.postWeibo = true;
} else {
commentWeiboTask.postWeibo = false;
}
Tools.getGlobalObject(this).getWorkQueueStorage()
.addTask(commentWeiboTask);
// 返回结果
setResult(TYPE_COMMENT);
Toast.makeText(this, "已经提交评论微博任务到工作队列", Toast.LENGTH_LONG);
break;
}
finish();
}
@Override
protected void onDestroy() {
filename = null;
super.onDestroy();
}
}
来说说实现发布微博功能的关键点:
1. 任务队列(多线程的实现)
2. 任务存储
3. 任务监视
4. 任务处理
发布微博我们点击发送按钮就会调用send()方法,来看看send方法里面做了什么操作
// 发送
private void send() {
String text = weiboContent.getText().toString();
switch (type) {
case TYPE_POST_WEIBO: // 发送微博
if (filename != null && "".equals("")) {
text = "分享图片";
} else if ("".equals(text)) {
Toast.makeText(this, "请输入微博内容", Toast.LENGTH_LONG).show();
return;
}
// 创建一个发布微博的任务
PostWeiboTask postWeiboTask = new PostWeiboTask();
postWeiboTask.text = text;
postWeiboTask.file = filename;
Tools.getGlobalObject(this).getWorkQueueStorage()
.addTask(postWeiboTask);
Toast.makeText(this, "已经提交发布微博任务到工作队列", Toast.LENGTH_LONG).show();
break;
case TYPE_FORWARD: // 转发微博
if ("".equals(text)) {
Toast.makeText(this, "请输入微博内容", Toast.LENGTH_LONG).show();
return;
}
RepostWeiboTask repostWeiboTask = new RepostWeiboTask();
repostWeiboTask.id = statusId;
repostWeiboTask.text = text;
if (isCommentCheckBox.isChecked()) { // 是否评论
repostWeiboTask.isComment = 1;
} else {
repostWeiboTask.isComment = 0;
}
Tools.getGlobalObject(this).getWorkQueueStorage()
.addTask(repostWeiboTask);
Toast.makeText(this, "已经提交转发微博任务到工作队列", Toast.LENGTH_LONG).show();
break;
case TYPE_COMMENT:
if ("".equals(text)) {
Toast.makeText(this, "请输入微博内容", Toast.LENGTH_LONG).show();
return;
}
CommentWeiboTask commentWeiboTask = new CommentWeiboTask();
commentWeiboTask.text = text;
commentWeiboTask.weiboText = text + this.text;
commentWeiboTask.id = statusId;
if (postWeiboCheckBox.isChecked()) {
commentWeiboTask.postWeibo = true;
} else {
commentWeiboTask.postWeibo = false;
}
Tools.getGlobalObject(this).getWorkQueueStorage()
.addTask(commentWeiboTask);
// 返回结果
setResult(TYPE_COMMENT);
Toast.makeText(this, "已经提交评论微博任务到工作队列", Toast.LENGTH_LONG);
break;
}
finish();
}
这里只看发送微博就行了,至于转发微博还有评论都是提交到任务队列里去的,都是类似的实现过程,所以我介绍完发布微博这个流程,关于转发和评论的实现我就不多介绍,只会在需要注意的地方介绍一下。
我们可以看到,会先创建一个任务,然后把任务添加到任务队列里面
PostWeiboTask这个类,里面的内容如下:
package com.wwj.sina.weibo.workqueue.task;
/**
* 发布微博任务
* @author wwj
*
*/
public class PostWeiboTask extends ParentTask {
public String text;
public String file;
}
它继承ParentTask这个类
package com.wwj.sina.weibo.workqueue.task;
import com.wwj.sina.weibo.workqueue.DoneAndProcess;
public class ParentTask {
public DoneAndProcess doneAndProcess;
}
而ParentTask有DoneAndProcess这个接口属性
package com.wwj.sina.weibo.workqueue;
import com.wwj.sina.weibo.workqueue.task.ParentTask;
/**
* 完成任务后的接口
* @author wwj
*
*/
public interface DoneAndProcess {
void doneProcess(ParentTask task);
}
这个接口定义了一个doneProcess这个方法,里面传入一个ParentTask对象,用于完成任务后的收尾工作,这里是用来刷新数据。
与之对应的执行任务的接口DoingAndProcess
package com.wwj.sina.weibo.workqueue;
import java.util.List;
/**
* 处理任务的接口
* @author wwj
*
*/
public interface DoingAndProcess {
void doingProcess(List list) throws Exception;
}
这个接口有一个方法是doingProcess,传入List为参数,意味着它要执行List里面的任务,实现这个接口的类就是用要实现各种任务的,实现这个接口的类叫TaskMan。
package com.wwj.sina.weibo.workqueue.task;
import java.util.List;
import android.app.Activity;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;
import com.wwj.sina.weibo.net.PullFile;
import com.wwj.sina.weibo.workqueue.DoingAndProcess;
import com.wwj.sina.weibo.workqueue.task.process.CommentWeiboProcess;
import com.wwj.sina.weibo.workqueue.task.process.FavoriteWeiboProcess;
import com.wwj.sina.weibo.workqueue.task.process.PostWeiboProcess;
import com.wwj.sina.weibo.workqueue.task.process.RepostWeiboProcess;
/**
* 处理任务的中枢
*
* @author wwj
*
*/
public class TaskMan implements DoingAndProcess {
private Activity activity;
private PostWeiboProcess postWeiboProcess;
private RepostWeiboProcess repostWeiboProcess;
private CommentWeiboProcess commentWeiboProcess;
private FavoriteWeiboProcess favoriteWeiboProcess;
private Handler msgHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
String str = String.valueOf(msg.obj);
Toast.makeText(activity, str, Toast.LENGTH_LONG).show();
super.handleMessage(msg);
};
};
public TaskMan(Activity activity) {
super();
this.activity = activity;
// 创建各种任务处理类对象
postWeiboProcess = new PostWeiboProcess(activity);
repostWeiboProcess = new RepostWeiboProcess(activity);
commentWeiboProcess = new CommentWeiboProcess(activity);
favoriteWeiboProcess = new FavoriteWeiboProcess(activity);
}
@Override
public void doingProcess(List list) throws Exception {
// 开始处理各种任务
for (Object task : list) {
// 处理发布微博任务
if (task instanceof PostWeiboTask) {
try {
postWeiboProcess.process((PostWeiboTask) task);
Message msg = new Message();
msg.obj = "成功发布微博";
msgHandler.sendMessage(msg);
} catch (Exception e) {
exceptionProcess(task);
throw e;
}
// 处理下载文件任务
} else if (task instanceof PullFileTask) {
PullFileTask pullFileTask = (PullFileTask) task;
PullFile pullFile = new PullFile();
pullFile.doingProcess(pullFileTask.fileUrl);
// 处理转发微博任务
} else if (task instanceof RepostWeiboTask) {
try {
repostWeiboProcess.process((RepostWeiboTask) task);
Message msg = new Message();
msg.obj = "成功转发微博";
msgHandler.sendMessage(msg);
} catch (Exception e) {
exceptionProcess(task);
throw e;
}
// 处理评论微博任务
} else if (task instanceof CommentWeiboTask) {
try {
commentWeiboProcess.process((CommentWeiboTask) task);
Message msg = new Message();
msg.obj = "成功评论微博";
msgHandler.sendMessage(msg);
} catch (Exception e) {
exceptionProcess(task);
throw e;
}
// 处理收藏微博任务
} else if (task instanceof FavoriteWeiboTask) {
try {
favoriteWeiboProcess.process((FavoriteWeiboTask) task);
} catch (Exception e) {
exceptionProcess(task);
throw e;
}
}
}
}
// 执行任务类失败时调用该方法
private void exceptionProcess(Object task) {
Message msg = new Message();
// 任务处理
if (task instanceof PostWeiboTask) {
msg.obj = "微博发布失败";
} else if (task instanceof RepostWeiboTask) {
msg.obj = "转发微博失败";
} else if (task instanceof CommentWeiboTask) {
msg.obj = "评论微博失败";
} else if (task instanceof FavoriteWeiboTask) {
msg.obj = "收藏微博失败";
}
msgHandler.sendMessage(msg);
}
}
这个类很重要哈,我们可以看到任务队列里面的任务都在这里完成了,具体实现任务处理的类,这里只介绍PostWeiboProcess。
package com.wwj.sina.weibo.workqueue.task.process;
import com.wwj.sina.weibo.library.WeiboManager;
import com.wwj.sina.weibo.util.Tools;
import com.wwj.sina.weibo.workqueue.task.PostWeiboTask;
import android.app.Activity;
/**
* 发博微博任务处理类
* @author wwj
*
*/
public class PostWeiboProcess {
private Activity activity;
public PostWeiboProcess(Activity activity) {
super();
this.activity = activity;
}
// 提交微博
public void process(PostWeiboTask task) throws Exception {
// 发布微博
WeiboManager.update(activity, Tools.getWeibo(activity), task.text, task.file);
}
}
这个就是发布微博的处理类,它有一个process方法,把发布微博的任务对象传入,这里的task就是在send()方面里面传入的,然后通过WeiboManager方法调用update的方法实现发布微博。
关于任务队列这一块是实现新浪微博最核心的,稍微有点复杂,下面我帮大家整理一下思路:
任务存储类:/xiaowu_twitter/src/com/wwj/sina/weibo/workqueue/WorkQueueStorage.java
这个类呢就是用来存储任务的,获取当前需要执行的任务,也用来移除执行完的任务列表,安装先进先出的方式实现任务按顺序执行,所以每次获取的任务就是放在最前面的,因为List的排列是顺序的。
package com.wwj.sina.weibo.workqueue;
import java.util.ArrayList;
import java.util.List;
/**
* 任务存储
*
* @author wwj
*
*/
public class WorkQueueStorage {
// 存储文件下载任务的List
private List<String> webFileDoingList = new ArrayList<String>();
// 存储通用任务的List, 所有任务都必须是ParentTask的子类
private List taskList = new ArrayList();
// 获取文件下载任务(要下载的URL)
public List<String> getDoingWebFileUrls() {
// 进行同步
synchronized (webFileDoingList) {
if (webFileDoingList.size() > 0) {
List<String> resultList = new ArrayList<String>();
resultList.addAll(webFileDoingList);
return resultList;
} else {
return null;
}
}
}
// 删除文件下载队列中的任务
public void removeDoingWebFileUrl(List<String> list) {
synchronized (webFileDoingList) {
if (list != null)
webFileDoingList.removeAll(list);
}
}
// 想文件下载队列添加任务(一个Url)
public void addDoingWebFileUrl(String url) {
synchronized (webFileDoingList) {
webFileDoingList.add(url);
}
}
// 目前必须只得到到一个任务,如果一下得到多个任务,需要修改WorkQueueMonitor类的代码
// 获取一个通用任务
public List getDoingTasks() {
synchronized (taskList) {
List result = new ArrayList();
if (taskList.size() > 0) {
result.add(taskList.get(0));
return result;
} else {
return null;
}
}
}
// 删除通用任务
public void removeTask(List tasks) {
synchronized (taskList) {
if (taskList.size() > 0) {
taskList.removeAll(tasks);
}
}
}
// 添加通用任务
public void addTask(Object task) {
synchronized (taskList) {
taskList.add(task);
}
}
}
任务监视类:/xiaowu_twitter/src/com/wwj/sina/weibo/workqueue/WorkQueueMonitor.java
package com.wwj.sina.weibo.workqueue;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.os.Handler;
import android.os.Message;
import com.wwj.sina.weibo.interfaces.Const;
import com.wwj.sina.weibo.util.LogUtils;
import com.wwj.sina.weibo.workqueue.task.ParentTask;
/**
* 任务监视
*
* @author Lining 说明:除了任务存储外,还需要通过线程不断扫描保存的任务的List,一旦发现任务,立刻处理。
* 这个工作交给WorkQueueMonitor类来完成
*/
public class WorkQueueMonitor implements Runnable, Const {
private WorkQueueStorage storage; // 任务存储
private Map<Integer, DoneAndProcess> doneAndProcessMap = new HashMap<Integer, DoneAndProcess>();
private DoingAndProcess doingAndProcess; // 处理任务接口对象
private Activity activity;
private boolean stopFlag = false; // 停止标识
private Thread thread; // 线程引用
private int monitorType = MONITOR_TYPE_IMAGE; // 监视类型,默认为图片
// 任务完成后,处理剩余的工作,主要是执行doneAndProcess方法
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
ParentTask parentTask = (ParentTask) msg.obj;
// 如果任务本身有doneAndProcess方法,则执行此方法
if (parentTask != null && parentTask.doneAndProcess != null) {
parentTask.doneAndProcess.doneProcess(parentTask);
} else { // 否则由构造方法传入的doneAndProcess
Collection<DoneAndProcess> doneAndProcesses = doneAndProcessMap
.values();
for (DoneAndProcess doneAndProcess : doneAndProcesses) {
doneAndProcess.doneProcess(parentTask);
}
}
};
};
/**
* 构造函数
*
* @param activity
* 窗口
* @param storage
* 任务存储对象
* @param doingAndProcess
* 正在处理的任务接口对象
* @param monitorType
* 监视类型
*/
public WorkQueueMonitor(Activity activity, WorkQueueStorage storage,
DoingAndProcess doingAndProcess, int monitorType) {
super();
this.activity = activity;
this.storage = storage;
this.doingAndProcess = doingAndProcess;
this.monitorType = monitorType;
}
// 开启线程
public void start() {
if (thread == null) {
thread = new Thread(this);
thread.start(); // 启动线程
}
}
// 停止线程
public void stop() {
stopFlag = true;
}
// 扫描文件下载任务队列
private void imageScan() {
LogUtils.i("+++ imageScan");
// 获取文件下载任务
List<String> webFileDoingList = storage.getDoingWebFileUrls();
while (webFileDoingList != null) {
try {
// 处理文件下载任务
doingAndProcess.doingProcess(webFileDoingList);
handler.sendEmptyMessage(0);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 删除已处理完的任务
storage.removeDoingWebFileUrl(webFileDoingList);
}
webFileDoingList = storage.getDoingWebFileUrls();
}
}
// 扫描通用任务
private void taskScan() {
List taskList = storage.getDoingTasks();
while (taskList != null) {
try {
doingAndProcess.doingProcess(taskList);
Message msg = new Message();
if (taskList.size() > 0) {
msg.obj = taskList.get(0);
}
handler.sendMessage(msg);
} catch (Exception e) {
e.printStackTrace();
} finally {
storage.removeTask(taskList);
}
taskList = storage.getDoingTasks();
}
}
@Override
public void run() {
while (!stopFlag) {
if (monitorType == MONITOR_TYPE_IMAGE) {
imageScan();
} else if (monitorType == MONITOR_TYPE_TASK) {
taskScan();
}
try {
// 每200毫秒扫描一次任务队列
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void addDoneAndProcess(int type, DoneAndProcess doneAndProcess) {
if (doneAndProcess != null) {
doneAndProcessMap.put(type, doneAndProcess);
}
}
}
任务队列如何实现?就是通过线程不断扫描任务列表,只要任务列表有任务就马上执行,关于任务会分两种,一种是图片下载任务,另一种是普通任务(发布微博、收藏微博、转发微博等)。当调用WorkQueueMonitor这个类的start方法就启动线程,然后执行run方法,根据不同任务类型执行任务。具体调用start方法的地方是在GlobalObject这个类里面。
/xiaowu_twitter/src/com/wwj/sina/weibo/GlobalObject.java
package com.wwj.sina.weibo;
import android.app.Activity;
import android.app.Application;
import com.weibo.net.Weibo;
import com.wwj.sina.weibo.interfaces.Const;
import com.wwj.sina.weibo.listener.AuthDialogListener;
import com.wwj.sina.weibo.net.PullFile;
import com.wwj.sina.weibo.object.Consumer;
import com.wwj.sina.weibo.workqueue.WorkQueueMonitor;
import com.wwj.sina.weibo.workqueue.WorkQueueStorage;
import com.wwj.sina.weibo.workqueue.task.TaskMan;
/**
* 全局对象Application级别
*
* @author Administrator
*
*/
public class GlobalObject extends Application implements Const {
// 调试开关
public static final boolean DEBUG = true;
private Weibo weibo;
// 任务存储
private WorkQueueStorage workQueueStorage;
// 图像下载监视器
private WorkQueueMonitor imageWorkQueueMonitor;
// 通用任务监视器
private WorkQueueMonitor taskWorkQueueMonitor;
/**
* 获得微博对象
*
* @param activity
* @return
*/
public Weibo getWeibo(Activity activity) {
// 如果微博对象为null或者会话无效
if (weibo == null || !weibo.isSessionValid()) {
weibo = Weibo.getInstance(); // 获取Weibo对象
weibo.setupConsumerConfig(Consumer.consumerKey,
Consumer.consumerSecret);
weibo.setRedirectUrl(Consumer.redirectUrl);
// 授权认证
weibo.authorize(activity, new AuthDialogListener(activity));
}
return weibo;
}
public Weibo getWeibo() {
return weibo;
}
/**
* 获取图像工作队列监视器
* @param activity
* @return
*/
public WorkQueueMonitor getImageWorkQueueMonitor(Activity activity) {
if (imageWorkQueueMonitor == null) {
// Pullfile用于下载文件,实现了DoingAndProcess接口
imageWorkQueueMonitor = new WorkQueueMonitor(activity,
getWorkQueueStorage(), new PullFile(), MONITOR_TYPE_IMAGE);
// 开启线程
imageWorkQueueMonitor.start();
}
return imageWorkQueueMonitor;
}
/**
* 获取通用任务监视器
* @param activity
* @return
*/
public WorkQueueMonitor getTaskWorkQueueMonitor(Activity activity) {
if (taskWorkQueueMonitor == null) {
// TaskMan用于处理通用任务
taskWorkQueueMonitor = new WorkQueueMonitor(activity,
getWorkQueueStorage(), new TaskMan(activity),
MONITOR_TYPE_TASK);
// 开启线程
taskWorkQueueMonitor.start();
}
return taskWorkQueueMonitor;
}
public WorkQueueMonitor getImageWorkQueueMonitor() {
return imageWorkQueueMonitor;
}
public WorkQueueMonitor getTaskWorkQueueMonitor() {
return taskWorkQueueMonitor;
}
public WorkQueueStorage getWorkQueueStorage() {
if (workQueueStorage == null) {
workQueueStorage = new WorkQueueStorage();
}
return workQueueStorage;
}
public void closeWorkQueue() {
if (imageWorkQueueMonitor != null) {
imageWorkQueueMonitor.stop();
imageWorkQueueMonitor = null;
}
if (taskWorkQueueMonitor != null) {
taskWorkQueueMonitor.stop();
taskWorkQueueMonitor = null;
}
}
}
通过调用getTaskWorkQueueMonitor()方法就启动了监视器线程,每过200毫秒扫描一下通用任务列表,这里调用
WorkQueueMonitor中的taskScan方法来实现循环扫描将WorkQueueStorage存储的需要执行的任务通过调用doingProcess执行,实现DoingAndProcess接口的类有TaskMan还有PullFileTask,传入任务队列之就会遍历List来分别执行相应的任务,比如发布微博,就调用PostWeiboProcess的process方法。
我不知道我在这里把流程说清楚了没有,我想这个需要自己去跟踪一下代码会比较清楚,如果不太明白的童鞋可以认真看几遍代码,就可以把整个调用的流程搞清楚的。
之前的博客就已经介绍过WeiboManager这个方法的,但是不完整的,这个类也非常重要,因为在这个类里面你就可以知道如何调用新浪微博API的了,这一块还涉及到线程异步的知识点,是通过AsyncWeiboRunner这个类实现的,我在测试的时候,发现原来非异步的操作已经不行了,因为在Android4.0的时候会抛异常,提示是在主线程不能进行网络操作,我也发表相关的博客,可以到以下地址查看:
http://blog.csdn.net/wwj_748/article/details/14003851
所以在开发的时候要注意这一点,获取不了数据可能就是网络操作出错了,当然有很多原因也会造成,这就需要你们自己去查找原因了。
WeiManager中发布微博的方法:
public static String update(Activity activity, Weibo weibo, String text,
String file) throws WeiboException {
WeiboParameters bundle = new WeiboParameters();
bundle.add("source", Weibo.getAppKey());
bundle.add("status", text);
String url = Weibo.SERVER + "statuses/update.json";
if (file != null) {
bundle.add("pic", file);
url = Weibo.SERVER + "statuses/upload.json";
}
String rlt = "";
rlt = weibo.request(activity, url, bundle, Utility.HTTPMETHOD_POST,
weibo.getAccessToken());
return rlt;
}
以上就是关于发布微博业务实现流程,可能有人觉得怎么那么麻烦,直接调用不就行了么?当然你只想实现发布微博一个功能的话,直接调用update方法就行了,但在完整的项目里面,涉及到很多不同的任务,我们需要保证好的用户体验还要考虑程序的性能,所以需要使用特殊的解决方案,任务队列就是实现各种微博任务的解决方案。
我还要做特别的说明,整个微博项目代码量是很足的,只要涉及到这部分代码,我就会贴出来,所以会有点乱,有点烦,如果网友有哪部分不太明白的话,可以给我留言,我会在新的文章当中进行说明。