新浪微博客户端开发之发布微博
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); } } }
我们通过调用addTask方法,把任务添加到任务列表当中,这个方法是线程同步的。
任务监视类:/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方法就行了,但在完整的项目里面,涉及到很多不同的任务,我们需要保证好的用户体验还要考虑程序的性能,所以需要使用特殊的解决方案,任务队列就是实现各种微博任务的解决方案。
我还要做特别的说明,整个微博项目代码量是很足的,只要涉及到这部分代码,我就会贴出来,所以会有点乱,有点烦,如果网友有哪部分不太明白的话,可以给我留言,我会在新的文章当中进行说明。