Category Archives: Programming

Android里TextView中链接识别问题

假设你有一些文本内容,这些文本内容中可能会有一些URL。如果你希望用户在看这些文本内容的时候,同时可以方便的触发这些链接,该怎么做呢?

很多人会说,用Linkify, 简单的两句话就可以实现了:

textView.setText(content);
Linkify.addLinks(textView, Linkify.WEB_URLS);

但是Linkify除了可以指定识别链接的类型外,没有任何可以定制的内容。比如想单击链接打开浏览器,长按链接复制地址到剪贴板,就无法实现。

更重要的是,Linkify对链接的识别貌似非常粗糙,尤其是包含中文的内容。下面是Linkify识别结果的一个例子:

Screenshot_20160514-143339

尝试找各种解决方案,最后觉得Android-TextView-LinkBuilder是最好的一个方案。

contentView.setText(content);
LinkBuilder.on(contentView).addLinks(getPostSupportedLinks()).build();
    public static void openLink(String link, Activity activity) {
        Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(link));
        try {
            activity.startActivity(browserIntent);
        } catch(ActivityNotFoundException e) {
            Toast.makeText(activity, "链接打开错误:" + e.toString(), Toast.LENGTH_LONG).show();
        }
    }

    public static void sendEmail(String link, Activity activity) {
        /* Create the Intent */
        final Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);

        /* Fill it with Data */
        emailIntent.setType("plain/text");
        emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, new String[]{link});
        emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "");
        emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, " \n \n \n \n--\n来自zSMTH的邮件\n");

        try {
            activity.startActivity(Intent.createChooser(emailIntent, "发邮件..."));
        } catch(ActivityNotFoundException e) {
            Toast.makeText(activity, "链接打开错误:" + e.toString(), Toast.LENGTH_LONG).show();
        }
    }

    // this will be called in PostRecyclerViewAdapter & MailContentActivity
    public static List<Link> getPostSupportedLinks(final Activity activity) {
        List<Link> links = new ArrayList<>();

        // web URL link
        Link weburl = new Link(Regex.WEB_URL_PATTERN);
        weburl.setTextColor(Color.parseColor("#00BCD4"));
        weburl.setHighlightAlpha(.4f);
        weburl.setOnClickListener(new Link.OnClickListener() {
            @Override
            public void onClick(String clickedText) {
                ActivityUtils.openLink(clickedText, activity);
            }
        });
        weburl.setOnLongClickListener(new Link.OnLongClickListener() {
            @Override
            public void onLongClick(String clickedText) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                    final android.content.ClipboardManager clipboardManager = (android.content.ClipboardManager)
                            activity.getSystemService(Context.CLIPBOARD_SERVICE);
                    final android.content.ClipData clipData = android.content.ClipData.newPlainText("PostContent", clickedText);
                    clipboardManager.setPrimaryClip(clipData);
                } else {
                    final android.text.ClipboardManager clipboardManager = (android.text.ClipboardManager)activity.getSystemService(Context.CLIPBOARD_SERVICE);
                    clipboardManager.setText(clickedText);
                }
                Toast.makeText(SMTHApplication.getAppContext(), "链接已复制到剪贴板", Toast.LENGTH_SHORT).show();
            }
        });

        // email link
        Link emaillink = new Link(Regex.EMAIL_ADDRESS_PATTERN);
        emaillink.setTextColor(Color.parseColor("#00BCD4"));
        emaillink.setHighlightAlpha(.4f);
        emaillink.setOnClickListener(new Link.OnClickListener() {
            @Override
            public void onClick(String clickedText) {
                ActivityUtils.sendEmail(clickedText, activity);
            }
        });

        links.add(weburl);
        links.add(emaillink);

        return links;
    }

这样就可以完全由自己去控制需要识别的内容,然后对单击、长按动作采用合适的操作了。

https://github.com/klinker24/Android-TextView-LinkBuilder

RxJava的学习教程

读完下面的三篇文章,基本上就知道怎么用了

1.给 Android 开发者的 RxJava 详解

http://gank.io/post/560e15be2dca930e00da1083

2.RxJava学习总结

http://wangxinghe.me/blog/2016-03-27/rxjava-basis/

3. RxJava使用场景小结

http://blog.csdn.net/lzyzsd/article/details/50120801

码农专用的字体

http://www.slant.co/topics/67/~what-are-the-best-programming-font

“source code pro”高举榜首,微软的Consolas得票也不少。个人感觉Consolas更好看一点,没有source code pro那么宽。字体宽一行放的内容就少了.

Windows下git文件可执行属性的处理

在使用openshift的过程中,.openshift\action_hooks\下面的脚本,在deploy的时候没有自动执行。研究了半天,才发现是windows平台下,文件的可执行属性没有加上,所以到了server端之后,这些脚本都没有成功的执行,解决的方法如下:

D:\workspaces\hrm\.openshift\action_hooks>git update-index --chmod=+x build

D:\workspaces\hrm\.openshift\action_hooks>git update-index --chmod=+x deploy

D:\workspaces\hrm\.openshift\action_hooks>git commit -a -m "update permission"
[master 69a5e52] update permission
 0 files changed
 mode change 100644 => 100755 .openshift/action_hooks/build
 mode change 100644 => 100755 .openshift/action_hooks/deploy

D:\workspaces\hrm\.openshift\action_hooks>git push

这样action_hooks下面的脚本就可以正确的被执行了

use python lint in Sublime Text

1. install SublimeLinter

2. install SublimeLinter-PEP8

3. install pep8 on your system:

pip install pep8

 

4. configure SublimeLinter, add “pep8” path of your system

        "python_paths": {
            "linux": [],
            "osx": [],
            "windows": [
                "C:\\Python27\\Scripts\\pep8.exe"
            ]
        },

5. configure other lint option, such as ignore E501

        "linters": {
            "pep8": {
                "@disable": false,
                "args": [],
                "excludes": [],
                "ignore": "E501",
                "max-line-length": null,
                "select": ""
            }
        },

 

Find and kill a process in one line using bash and regex

http://stackoverflow.com/questions/3510673/find-and-kill-a-process-in-one-line-using-bash-and-regex

grep的时候,里面对p加一个中括号,很简洁有效!

In bash, you should be able to do:

/bin/ps aux | grep "/usr/local/bin/[p]ython2.7 /home/miniui/fw_dinners/main.py" | awk '{print $2}' | xargs kill -9

Details on its workings are as follows:

  • The ps gives you the list of all the processes.
  • The grep filters that based on your search string, [p] is a trick to stop you picking up the actual grepprocess itself.
  • The awk just gives you the second field of each line, which is the PID.
  • The $(x) construct means to execute x then take its output and put it on the command line. The output of that ps pipeline inside that construct above is the list of process IDs so you end up with a command likekill 1234 1122 7654.

Here’s a transcript showing it in action:

pax> sleep 3600 &
[1] 2225
pax> sleep 3600 &
[2] 2226
pax> sleep 3600 &
[3] 2227
pax> sleep 3600 &
[4] 2228
pax> sleep 3600 &
[5] 2229
pax> kill $(ps aux | grep '[s]leep' | awk '{print $2}')
[5]+  Terminated              sleep 3600
[1]   Terminated              sleep 3600
[2]   Terminated              sleep 3600
[3]-  Terminated              sleep 3600
[4]+  Terminated              sleep 3600
pax> _

and you can see it terminating all the sleepers.


Explaining the grep '[p]ython csp_build.py' bit in a bit more detail:

When you do sleep 3600 & followed by ps -ef | grep sleep, you tend to get two processes with sleepin it, the sleep 3600 and the grep sleep (because they both have sleep in them, that’s not rocket science).

However, ps -ef | grep '[s]leep' won’t create a process with sleep in it, it instead creates grep '[s]leep' and here’s the tricky bit: the grep doesn’t find it because it’s looking for the regular expression “any character from the character class [s] (which is s) followed by leep.

In other words, it’s looking for sleep but the grep process is grep '[s]leep' which doesn’t have sleep in it.

When I was shown this (by someone here on SO), I immediately started using it because

  • it’s one less process than adding | grep -v grep; and
  • it’s elegant and sneaky, a rare combination 🙂

使用PyPi的国内镜像来加速pip的安装过程

作为 easy_install 的升级版,pip 为 Python 的包管理提供了极大的方便。一行命令即可完成所需模块的安装:

$ sudo pip install ipython -v

省去了手动搜索、下载、编译的麻烦。

但是在国内直接访问PyPi网站,实在是够慢。好在pip支持使用镜像源,这里有所有镜像的列表和当前状态:

http://www.pypi-mirrors.org/

国内有一个:

e.pypi.python.org BEIJING, BEIJING CN

 

要使用这个镜像,只要修改pip 的配置文件:

http://www.pip-installer.org/en/latest/configuration.html

使用pip的用户可以如下配置:

在unix和macos,配置文件为:$HOME/.pip/pip.conf
在windows上,配置文件为:%HOME%\pip\pip.ini

需要在配置文件内加上:

[global]
index-url = http://e.pypi.python.org/simple

这样,用 pip 安装 Python 包的时候,速度就可以得到明显提升。

MySQL列缺省值的设定

http://dev.mysql.com/doc/refman/5.0/en/data-type-defaults.html

Data Type Default Values

The DEFAULT value clause in a data type specification indicates a default value for a column. With one exception, the default value must be a constant; it cannot be a function or an expression. This means, for example, that you cannot set the default for a date column to be the value of a function such as NOW() orCURRENT_DATE. The exception is that you can specify CURRENT_TIMESTAMP as the default for aTIMESTAMP column. See Section 11.1.5.5, “Automatic Initialization and Updating for TIMESTAMP.

关于时间类型初始化的更多信息:

http://dev.mysql.com/doc/refman/5.0/en/timestamp-initialization.html

 

What’s in a Good Commit?

http://dev.solita.fi/2013/07/04/whats-in-a-good-commit.html

Let’s begin with a horror story.

You hear that issue FOO-123 has been fixed. The bug had something to do with a subsystem you know well, so you have your own hunch about what might have caused it. To confirm your suspicion, you decide to take a look at how the bug was fixed. You spend quite some time rummaging through the revision history until you manage to narrow the fix down to four consecutive revisions, described in their commit messages as “dao tweaks”, “moar”, “Fixes.” and “remove debug stuff”. Each changeset looks huge. There are hundreds of lines of changes spread over a dozen of files. “What the…”, you begin but pause, unable to choose just one of the myriad of profanities racing through your mind. “The fix shouldn’t be more than a three-line change!”

My Mind is Full of Profanity

Does this sound familiar? All too many developers use their version control system as nothing more than a haphazard pile of backups. The resulting history is useless for anything other than retrieving the files’ contents at a given point in time. The following tips can help you turn your VCS from a backup system into a valuable tool for communication and documentation.

1. Only make one change per commit

If you fix FOO-123 as well as FOO-234, refactor a couple of classes, add a button or two to the UI, and change tabs to spaces throughout the project, all in one commit, it’s simply impossible for anyone to review the fix to FOO-123. You are the only one who knows which of your changes are part of the fix. In a week even you’ll forget that.

What if a week later it turns out that your fix caused a new bug that’s even worse? You can’t undo the change using backout (Hg) or revert (Git), because that would mean stripping out all those other changes you made and a week’s worth of work depends on them.

The solution is to only make one change in each commit. There are no hard and fast rules about what constitutes a single change, but if you can describe everything you did in a single sentence without using the word “and”, you’re probably in the clear.

One of the cool things about distributed version control systems is that if you end up with a working directory full of unrelated changes, you can clean up the mess you’ve made, but it’s better not to make a mess in the first place. Before jumping into changing the code, decide what it is that you want to do and how you want to do it. Then focus on making that one change only.

It seems impossible to work on a piece of code without coming up with ideas on how it could be improved. You notice bugs, poorly factored code, and curious things that you’d like to investigate. No matter how tempting they seem, do not get sidetracked! These findings are valuable, so jot them down in a notebook or a TODO-file, but don’t return to them until you current task is finished.

This is not just about better commits. When you’re immersed in a programming problem, your head is full of little details related to the code you’re working on. You lose all that if you start thinking about something else, and getting back into the flow takes time. To maximize your productivity you need to minimize task switches.

Of course there are times when you find out that there’s no way to finish your current task without first making some other change. The easiest way to keep the two changes separate is to shelve (Hg) or stash (Git) your current, unfinished change, make and commit the change that you depend on, and then return to your original task.

2. Make the whole change in one commit

A change is also hard to review and undo if it’s spread over several commits. Typically this is a side effect of working on too many things at once. If you bite off more than you can chew, most of your changes will be unfinished by the time you want to save some of them. Focusing on one task at a time takes you a long way towards committing complete changes.

Some changes take so much time that you can’t afford to start all over again if you make a mistake, so you need to save work-in-progress versions of your work. Luckily DVCSs allow you to save WIP versions for your own use while still publishing a single changeset to the central repository. You can make as many WIP commits as you want and then use histedit (Hg) or rebase (Git) to fold/squash them into a single changeset when you’re done.

Another approach, which I prefer because it keeps WIP changes clearly separated from permanent changesets, is to use Git’s index or a patch inMercurial Queues to store the latest known-good WIP version, which you update every time you make progress. If you make a mistake, you can restore your working directory to the version in the index/patch. I like to think of it as a one-slot quicksave for version control.

3. Document what you have changed

The commit message “Fixes” contains very little useful information. “Commit” contains none whatsoever. If someone is interested in the revision history, messages like this force them to read through the changes, and reading code is both slow and mentally taxing. By writing a gibberish commit message you save a minute but can waste hours of other people’s time.

A good commit message tells the reader what part of the codebase was changed and how without them having to look at the code:

SomeClass: use bleh instead of xyzzy in someMethod (fixes FOO-123)

4. Document why you made the change

Presumably there’s always a good reason for every change made to a codebase. If that reason is not documented, the codebase becomes exposed to the following risks:

  • The other developers do not understand why the code was written the way it was. When they change the code, they introduce problems that the original author had identified and avoided.
  • The other developers assume that the code was written the way it was for a Good Reason™ so it’s best left untouched. They treat it as a black box and add complex workarounds to avoid changing it. As a consequence the codebase becomes bloated and hard to understand.

If you need to break the project’s conventions, or if there’s a subtle reason why your code must be the way it is, document the reason in the code with a comment:

-  xyzzy(bars);
+  // Our bars are already sorted, so bleh is much faster than xyzzy
+  bleh(bars);

If your code adheres to conventions and there are no subtleties to it, there’s no need for inline documentation. It’s still valuable to know why the new code is preferred over the old (especially if the change happens to introduce a new problem), so document the reason in the commit message:

SomeClass: Don't flush caches in someMethod

The caches are flushed automatically at the end of each request.

If the change fixes a reported issue, make sure you mention the ticket’s number in the commit message so that a developer looking at the revision history can better understand the context in which the change was made.

5. Never commit code that’s been commented out

I’ve never understood the reasoning behind committing code that’s been commented out. I assume it’s to keep old versions of the code around just in case the new code doesn’t work, but that’s just bizarre. Keeping track of old versions is the reason we use a version control system in the first place!

Why was the code commented out? Does it work? Should it work? Has it ever worked? Is it something we should strive towards or run away from? Code that’s been commented out is worse than useless, because every time it’s read, it raises questions like these without providing any answers. It only serves to confuse and distract from the code in use.

There’s only one rule when it comes to committing commented-out code:

NO!

android里自动打开软键盘

打开关闭软键盘需要使用InputMethodManager这个系统服务。

http://developer.android.com/reference/android/view/inputmethod/InputMethodManager.html

有一点需要注意:打开关闭软键盘的代码不能在onCreate里直接执行,因为这时候view还有创建完毕,所以执行了也没用。可以起一个timer, 延时一段时候后再执行,如下代码:

m_titleEditText = (EditText) findViewById(R.id.edittext_title);
m_titleEditText.requestFocus();
// turn on IME automatically
Timer timer = new Timer();
timer.schedule(new TimerTask() {
            @Override
            public void run() {
                InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
                imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
            }
        }, 300);