开源学习 百度推送实战项目 友聊 (四)
来源:互联网 发布:gdi 高级编程 pdf版 编辑:程序博客网 时间:2024/05/24 05:50
这篇文章是 ”友聊“ 开源项目学习系列的第四篇,前三篇文章请查看这里:
友聊 学习记录(一)
友聊 学习记录(二)
友聊 学习记录 (三)
这篇文章里会主要记录项目中两个Fragment的使用,实现的功能。
先看下LeftFragment 的效果
- 自定义的ExpandableListView ,项目中使用的开源控件IphoneTreeView。 关于ExpandableListView ,也可以参考之前在论坛里发的一个实例demo, 具体详情看这里
- 长按联系人,弹出QuickActionWidget , 继承Popwindow,定义了很多特性,上面的每个Button 都可以监听到,做出响应。
- 整个Layout,使用的是自定义的 HorizontalScrollView, 可以左右滑动,监听事件。项目中左右滑动会更新联系人,发出刷新的声音。
ExpandableListView 关键是在数据构造,事件的监听和响应。项目中处理点击事件,又添加了长按事件的监听,使用Tag区分GroupView 和ChildView ,做出不同的响应。
再看QuickActioinWidget 的相关操作
1 2 3 4 5 6 7 8 91011121314151617181920212223242526272829303132333435363738394041424344454647
// 显示子列表长按时弹窗private void showChildQuickActionBar(View view) { mBar = new QuickActionBar(getActivity()); mBar.addQuickAction(new QuickAction(getActivity(), R.drawable.ic_action_share_pressed, R.string.open)); mBar.addQuickAction(new QuickAction(getActivity(), R.drawable.ic_action_rename_pressed, R.string.rename)); mBar.addQuickAction(new QuickAction(getActivity(), R.drawable.ic_action_move_pressed, R.string.move)); mBar.addQuickAction(new QuickAction(getActivity(), R.drawable.ic_action_delete_pressed, R.string.delete)); mBar.setOnQuickActionClickListener(mActionListener); mBar.show(view); }// QuickClickListener 的定义private OnQuickActionClickListener mActionListener = new OnQuickActionClickListener() { public void onQuickActionClicked(QuickActionWidget widget, int position) { User u = mChildren.get(mLongPressGroupId).get(mLongPressChildId); if (u != null) switch (position) { case 0: mMsgDB.clearNewCount(u.getUserId());// 新消息置空 Intent toChatIntent = new Intent(getActivity(), ChatActivity.class); toChatIntent.putExtra("user", u); startActivity(toChatIntent); break; case 1: T.showShort(mApplication, "rename"); break; case 2: T.showShort(mApplication, "move"); break; case 3: mUserDB.delUser(u); updateAdapter(); mRecentDB.delRecent(u.getUserId()); ((MainActivity) getActivity()).upDateList(); T.showShort(mApplication, "删除成功!"); break; default: break; } } };
HorizontalScrollView 的使用很简单,都是在XML 中定义好相关的属性,实现左右滑动接口事件。
1 2 3 4 5 6 7 8 9101112131415161718
<com.way.pullrefresh.PullToRefreshHorizontalScrollView xmlns:ptr="http://schemas.android.com/apk/res-auto" android:id="@+id/pull_refresh_horizontalscrollview" android:layout_width="fill_parent" android:layout_height="fill_parent" ptr:ptrAnimationStyle="flip" android:fillViewport="true" ptr:ptrDrawable="@drawable/refresh_arrow_2" ptr:ptrHeaderBackground="@drawable/coversation_bg_2" ptr:ptrMode="both" > <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <include layout="@layout/main_left_fragment_content" /> </LinearLayout> </com.way.pullrefresh.PullToRefreshHorizontalScrollView>
添加监听事件
1 2 3 4 5 6 7 8 910111213141516
//不同的操作,响应不同的声音mSoundListener = new SoundPullEventListener(getActivity()); mSoundListener.addSoundEvent(State.PULL_TO_REFRESH, R.raw.pull_event); mSoundListener.addSoundEvent(State.RESET, R.raw.reset_sound); mSoundListener.addSoundEvent(State.REFRESHING, R.raw.refreshing_sound);// 刷新监听mPullRefreshScrollView .setOnRefreshListener(new OnRefreshListener<HorizontalScrollView>() { @Override public void onRefresh( PullToRefreshBase<HorizontalScrollView> refreshView) { new GetDataTask().execute(); } });
这样LeftFragment 的只要功能基本完成了。接下来看RightFragment
先看下RightFragment 的效果图。
普通的设置界面,也可以设计的很赞
这里使用了SlidingLayer,每一项点进去再回来,代码都很简单。有点类似ViewFlipper 的效果。若是我写,傻傻滴有要把每个页面都写成Fragment了。
设计接口,监听设置状态是否改变。
1 2 3 4 5 6 7 8 9101112131415161718192021
@Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { // TODO Auto-generated method stub switch (buttonView.getId()) { case R.id.message_notify_switch: mSpUtil.setMsgNotify(isChecked); break; case R.id.message_sound_switch: mSpUtil.setMsgSound(isChecked); break; case R.id.pullrefresh_sound_switch: mSpUtil.setPullRefreshSound(isChecked); listener.onSwitchChange(isChecked); break; case R.id.show_head_switch: mSpUtil.setShowHead(isChecked); break; default: break; } }
再看下SlidingLayer 的用法,SlidingLayer 有个接口OnInteractListener,有四个方法,open() ,close(), opened(),closed()
12345678
// 打开layer的操作 case R.id.accountSetting: mSlidingLayer.removeAllViews(); if (!mSlidingLayer.isOpened()) { mSlidingLayer.addView(mAcountSetView); mSlidingLayer.openLayer(true); } break;
RightFragment 的逻辑比较简单,没什么可说的。
接下来看Application类的设计
看下声明的字段,都知道干什么的了。
1 2 3 4 5 6 7 8 91011121314151617181920
public static final int[] heads = { R.drawable.h0, R.drawable.h1, R.drawable.h2, R.drawable.h3, R.drawable.h4, R.drawable.h5, R.drawable.h6, R.drawable.h7, R.drawable.h8, R.drawable.h9, R.drawable.h10, R.drawable.h11, R.drawable.h12, R.drawable.h13, R.drawable.h14, R.drawable.h15, R.drawable.h16, R.drawable.h17, R.drawable.h18 }; public static final int NUM_PAGE = 6;// 总共有多少页 public static int NUM = 20;// 每页20个表情,还有最后一个删除button private static PushApplication mApplication; private BaiduPush mBaiduPushServer; private Map<String, Integer> mFaceMap = new LinkedHashMap<String, Integer>(); private SharePreferenceUtil mSpUtil; private UserDB mUserDB; private MessageDB mMsgDB; private RecentDB mRecentDB; private List<User> mUserList; private MediaPlayer mMediaPlayer; private NotificationManager mNotificationManager; private Notification mNotification; private Gson mGson;
需要使用的公共的全家变量放在这里,虽然这个方法知道的很多,作者使用的确实相当灵活,轻车熟路。
最后是CrashHandler 类的设计
直接看下代码
1 2 3 4 5 6 7 8 910111213141516171819202122232425262728
public class CrashHandler implements UncaughtExceptionHandler { private Thread.UncaughtExceptionHandler mDefaultHandler;// 系统默认的UncaughtException处理类 private static CrashHandler INSTANCE;// CrashHandler实例 private Context mContext;// 程序的Context对象 /** 保证只有一个CrashHandler实例 */ private CrashHandler() { } /** 获取CrashHandler实例 ,单例模式 */ public static CrashHandler getInstance() { if (INSTANCE == null) INSTANCE = new CrashHandler(); return INSTANCE; } /** * 初始化 * * @param context */ public void init(Context context) { mContext = context; mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();// 获取系统默认的UncaughtException处理器 Thread.setDefaultUncaughtExceptionHandler(this);// 设置该CrashHandler为程序的默认处理器 }
这个类的处理思路,在Application中实例化后,如果有没有处理的异常。
- 获取异常报告,包括app 信息,手机信息
- 将异常保存为文件
- 使用Email 发送报告
获取异常的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99100101102103104105106107108109110
/** * 获取APP崩溃异常报告 * * @param ex * @return */ private String getCrashReport(Context context, Throwable ex) { PackageInfo pinfo = getPackageInfo(context); StringBuffer exceptionStr = new StringBuffer(); exceptionStr.append("Version: " + pinfo.versionName + "(" + pinfo.versionCode + ")n"); exceptionStr.append("Android: " + android.os.Build.VERSION.RELEASE + "(" + android.os.Build.MODEL + ")n"); exceptionStr.append("Exception: " + ex.getMessage() + "n"); StackTraceElement[] elements = ex.getStackTrace(); for (int i = 0; i < elements.length; i++) { exceptionStr.append(elements[i].toString() + "n"); } return exceptionStr.toString(); }// 将异常保存为文件private File save2File(String crashReport) { // TODO Auto-generated method stub String fileName = "crash-" + System.currentTimeMillis() + ".txt"; if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { try { File dir = new File(Environment.getExternalStorageDirectory() .getAbsolutePath() + File.separator + "crash"); if (!dir.exists()) dir.mkdir(); File file = new File(dir, fileName); FileOutputStream fos = new FileOutputStream(file); fos.write(crashReport.toString().getBytes()); fos.close(); return file; } catch (Exception e) { L.i("save2File error:" + e.getMessage()); } } return null; }// 发送异常报告private void sendAppCrashReport(final Context context, final String crashReport, final File file) { // TODO Auto-generated method stub AlertDialog dialog; AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setIcon(android.R.drawable.ic_dialog_info); builder.setTitle(R.string.app_error); builder.setMessage(R.string.app_error_message); builder.setPositiveButton(R.string.submit_report, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { try { Intent intent = new Intent(Intent.ACTION_SEND); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); String[] tos = { "songyongqiang@kingsky-iot.com" }; intent.putExtra(Intent.EXTRA_EMAIL, tos); intent.putExtra(Intent.EXTRA_SUBJECT, "管车易APP客户端 - 错误报告"); if (file != null) { intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(file)); intent.putExtra(Intent.EXTRA_TEXT, "请将此错误报告发送给我,以便我尽快修复此问题,谢谢合作!n"); } else { intent.putExtra(Intent.EXTRA_TEXT, "请将此错误报告发送给我,以便我尽快修复此问题,谢谢合作!n" + crashReport); } intent.setType("text/plain"); intent.setType("message/rfc882"); Intent.createChooser(intent, "Choose Email Client"); context.startActivity(intent); } catch (Exception e) { T.showLong(context, "There are no email clients installed."); } finally { dialog.dismiss(); // 退出 android.os.Process.killProcess(android.os.Process .myPid()); System.exit(1); } } }); builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); // 退出 android.os.Process.killProcess(android.os.Process .myPid()); System.exit(1); } }); dialog = builder.create(); dialog.getWindow() .setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); dialog.show(); }
关于Fragment,Application ,以及CrashHandler 的学习就结束了。
下一篇,将接着学习 **友聊 ** 项目中Util 类 以及数据库相关的代码。
声明:eoe文章著作权属于作者,受法律保护,转载时请务必以超链接形式附带如下信息
原文作者: imesong
原文地址: http://my.eoe.cn/imesong/archive/21794.html
- 开源学习 百度推送实战项目 友聊 (四)
- 开源学习 百度推送实战项目 友聊 (一)
- 开源学习 百度推送实战项目 友聊 (二)
- 开源学习 百度推送实战项目 友聊 (三)
- 开源学习 百度推送实战项目 友聊 (五)
- 开源学习 百度推送实战项目 友聊 (六)
- 开源学习 百度推送实战项目 友聊 (七)
- 百度云推送项目实战
- android studio集成 百度云推送项目实战 注意事项
- 百度推送 项目集成
- Python开源机器学习项目实战
- 百度推送SDK之API(四)
- 开源项目DataTierGenerator学习(四)
- 百度云推送与APNS推送结合项目经验心得
- 百度开源项目
- 百度推送java sdk学习记录
- 百度推送
- 百度推送
- Android this与Activity.this的区别
- 找不到或无法加载主类org.codehaus.plexus.classworlds.launcher.Launcher MAC下面报的错误
- linux top 中的time+
- 一、Python's "Beautiful Heart"
- java中的IO流
- 开源学习 百度推送实战项目 友聊 (四)
- MYSQL修改设置root密码的命令及方法
- 开源代码网站收集
- 修改ligerui的display内容
- 程序中堆和栈增长方向以及大小端问题
- SecureCRT和WinSCP
- eclipse配置maven
- 调试之pdb文件(C++)
- 判断SOCKET是否连接