Archive for the Category » 技术交流 «

ApnsPHP完成推送后处理错误日志的正确方法

通过苹果的apns批量发送push消息,如果中间发生错误,应该需要捕获错误发生的对象,然后对那些发生错误的消息应该在后台进行标识,这是我们常见的处理逻辑,在ApnsPHP中很好的实现了这个逻辑,大致的代码如下:


//假设前面已经有了下面一句
$message->setCustomIdentifier($id); //这里的id可以是你消息对于的数据库id

...

$push->send();
$push->disconnect();

//在发送完以后,可以进行下面的处理

$aErrorQueue = $push->getErrors();
$error_ids = array();
if (!empty($aErrorQueue)) {
foreach ($aErrorQueue AS $e) {
$error_ids[] = $e['MESSAGE']->getCustomIdentifier();
}

这里面关键的一句是 $e[‘MESSAGE’]->getCustomIdentifier();

getErrors()返回的数组,每条记录也是个数组,key为MESSAGE对应的值是个ApnsPHP_Message对象,该对象可以使用getCustomIdentifier()方法取回前面通过 setCustomIdentifier($id)传入的$id值

android中获取当前activity的名称

之前看到网上和教程中通常的做法如下:

private String getRunningActivityName(){       
        ActivityManager activityManager=(ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        String runningActivity=activityManager.getRunningTasks(1).get(0).topActivity.getClassName();
        return runningActivity;               
    }

这个方法不好的是需要在AndroidManifest.xml里面定义权限

<uses-permission android:name="android.permission.GET_TASKS" />

事实上有更简单的方法,我一般都这么干!

private String getRunningActivityName(){   
        String contextString = context.toString();
        return contextString.substring(contextString.lastIndexOf(".")+1, contextString.indexOf("@"));

既不用定义权限,也代码简单。

发布个竞彩足球预测软件测试版本

前些日子碰巧得到个有经验的朋友指点,研究了一番竞彩足球,实战几番后,萌发了用数学的方法了尽可能的提高选择投注命中率,经过前一段的测试验证,已经有了比较满意的算法结果,这两天把android的客户单弄了个屌丝版本发布出来,欢迎对足彩有兴趣的朋友下载交流!说不定你会发现找到了新的投资理财机会,哈哈!

安装APK下载地址: http://www.toplee.com/caipiao.apk

iphone的版本过些时间也会发布一个出来,尽请期待!

Yii rules验证中可以使用的占位符列表

Here’s a list of many placeholders and the validators that are using them:

  • CBooleanValidator: {true} {false}
  • CCaptchaValidator: {id}
  • CCompareValidator: {compareAttribute} {compareValue} {operator}
  • CExistValidator: {table} {column} {value}
  • CFileValidator: {file} {limit} {extensions}
  • CNumberValidator: {min} {max}
  • CRequiredValidator: {value}
  • CStringValidator: {min} {max} {length}
  • CTypeValidator: {type}
  • CUniqueValidator: {table} {column} {value}
  • CUrlValidator: {schemes}

Of course, {attribute} is known in all validators. So, which placeholders are known depends on the validator and the condition as well: By default {min} is only used when the value is below the min value (as defined in rules) and {max} when the value is above the max value.

setenforce 0

不重启机器就得时不时来这么一下,不爽,习惯了FreeBSD,突然切换到CentOS,还得磨合!

关于ListView的性能,推荐一篇老外的好文章

对于纯文字内容的ListView,基本可以不看了,除非你数据量巨大,那你还是需要看。

对于有大量图片的ListView,这篇文章必须看,我之前在Android上开发应用时遇到一个ListView,每个Item里面都是若干张小图片,纠结于性能的改进很长时间,最终受益于这篇文章得以改进!

原文很长,我就不贴内容了,这里是链接地址: Performance Tips for Android’s ListView

新浪微博 Android SDK中OAuth2.0隐式授权部分的一个代码逻辑问题

在最近使用新浪微博android sdk开发微博登录的时候,从日志中发现一个问题,就是自定义的WeiboDialogListener里面的方法,比如onComplete或者onCancel等,经常会被两次调用,这样其实会导致一些隐性问题,比如增加额外的客户端和服务端的开销,因为我们通常会在onComplete()里面完成更多后续逻辑的处理,而发生这样的情况时,会被处理两次,一开始我犯懒,就在方法外面加入了一个变量 isCompleted 来进行判断,算是暂时解决了问题,后来在好几个地方要开发类似功能的时候,总感觉心里有点儿不爽,于是决定找找到底啥原因

看了看微博sdk里面的代码,在 WeiboDialog.java里面找到了问题,这个java文件主要实现的是创建OAuth的UI,并且通过实现和调用WebViewClient的方法来访问微博的api以及咱们app的callback url, 进而通过WebViewClient里面捕获当前请求的URL,分析URL参数后进行相应逻辑的判断,通过分析,问题应该是在这部分。

在WeiboDialog.java里面有个函数 handleRedirectUrl(),这个函数就是用来判断认证和授权过程中返回参数的,代码如下:

private void handleRedirectUrl(WebView view, String url) {
        
Bundle values = Utility.parseUrl(url);
 
        
String error = values.getString("error");
        
String error_code = values.getString("error_code");
        
        
if (error == null && error_code == null) {
            
mListener.onComplete(values);
        
} else if (error.equals("access_denied")) {
            
// 用户或授权服务器拒绝授予数据访问权限
            
mListener.onCancel();
        
} else {
            
mListener.onWeiboException(new WeiboException(error, Integer.parseInt(error_code)));
        
}
    
}

一看就知道啥意思了,关键的逻辑就在这里面,回调我们自己实现的WeiboDialogListener里面的方法,顺藤摸瓜,调用该方法的代码就在实现WebViewClient里面,研究了一下该部分代码,找到了原因

在WebViewClient中,我们需要实现至少shouldOverrideUrlLoading()方法,该方法在每次加载新url的时候调用,另外,我们还通常会实现onPageStarted()方法,该方法也是在新url开始加载的时候进行调用(注意:在frame里面加载是不会调用的,详细文档见http://developer.android.com/reference/android/webkit/WebViewClient.html)

在WeiboDialog.java实现WebViewClient对象的时候,在shouldOverrideUrlLoading()和onPageStarted()里面都同时调用了handleRedirectUrl()来进行回调url和参数的判断,结果就导致了我遇到的问题,于是我们可以把里面的一个去掉,或者增加一个参数来进行判断,避免重复调用,目前一切正常了!

onClick / onLong / onGesture 同时存在时,点击、滑动、长按屏幕的事件处理顺序

在Android开发中,如果一个Activity里面同时继承实现了 onClickListener、onLongClickListener、onGestureListener, 此时手指在点击、滑动、长按屏幕是各个事件处理的顺序是如何的呢,通过实际项目中写日志得到如下的结果:

点击松开: onDown / onShowPress(稍长会有) / onSingleTapUp /onClick
滑动松开: onDown / onScroll(多次) / onFling / onClick / onLongClick
长按松开:onDown / onShowPress / onLongClick / onLongPress
长按并滑动后松开: onDown /onShowPress / onLongClick / onScroll(多次) / onFling

知道这个顺序后,就知道如何处理各个需要的逻辑了,同时需要注意一点:在每个过程中,任何一个事件里面return true了,后面的就将不再执行,如果要同时执行多个事件,可以在每个事件内部处理完后,return false, 后面的事件就将继续进行

RelativeLayout的选中状态变化

在layout的xml文件中设置focusable以及background,并定义background指向的xml文件中有关selector,到此还是不够的,如果不在java文件里面定义onClickListener事件的话,在手机上运行并不会看到选中状态的变化。

Android动画背景图自动播放的实现

我们在开发android应用的时候,经常会遇到类似从网络加载大图,在加载的过程中,在图片要显示的ImageView位置,先显示一个转圈的loading动画图,给用户的体验会更好一些,要实现这个动画图很简单,使用在/res/anim中定义xml的方式,通常使用…. 来实现。

不过大多数朋友都会遇到的问题是,动画是做好了,但是界面在加载的时候,动画并不会自动播放,还得通过屏幕点击等事件来触发,这就失去了意义了,实际上,android的动画AnimationDrawable 组件里面有个start()方法用于启动动画播放,但是这个方法不能直接写在onClick,onStart,onResume里面,写进去也是无效的,无法启动动画,只能写在比如事件监听当中,于是我们可以使用点小技巧来实现自动播放

目前我知道的有三种方法:

ImageView imageView = (ImageView)findViewById(R.id.xxx);

方法一:使用Runnalbe()来加载

imageView.setBackgroundResource(R.anim.xxxxx);
final AnimationDrawable animationDrawable = (AnimationDrawable)imageView.getBackground();
imageView.post(new Runnable() {
    @
Override
        
public void run()  {
            
animationDrawable.start();
        
}
});

方法二:使用AsyncTask异步加载启动

imageView.setBackgroundResource(R.anim.xxxxx);
AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getBackground();
RunAnim runAnim=new RunAnim();
runAnim.execute("");
 
class RunAnim extends AsyncTask<String, String, String> {
        @
Override
        
protected String doInBackground(String... params) {
            
if (!animationDrawable.isRunning()) {
                
animationDrawable.stop();
                
animationDrawable.start();
            
}
            
return "";
        
}
}

方法三:通过添加addOnPreDrawListener来自动加载

imageView.setBackgroundResource(R.anim.xxxxx);
AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getBackground();
imageView.getViewTreeObserver().addOnPreDrawListener(preDrawListener);
 
OnPreDrawListener preDrawListener = new OnPreDrawListener(){
    @
Override
    
public boolean onPreDraw() {
        
animationDrawable.start();
        
return true; //必须要有这个true返回
    
}
};

以上三种方法经过测试没有问题,另外网上有一些说使用重写Activity的onWindowFocusChanged()方法来实现,但是还是有不足,得改变焦点才能触发,虽然理论可以自动实现改变焦点,感觉还是不甚可取。