bcoder

4月 192015
 
一、为什么要使用多线程?

  默认情况下,当一个Android应用启动后,应用内部运行的线程只有一个,就是应用的UI线程,负责界面的展示以后用户和屏幕元素的互动。那么当我们需要进行网络下载、图片加载、复杂运算等比较耗时的操作时,如果也要主线程中进行,UI界面就没有足够的CPU时钟进行处理了,就会造成界面卡死的情况,这就是我们所说的ANR(Application Not Responding)。所以,为了防止出现这种情况,像这些耗时的操作我就需要开一个子线程去进行处理。

二、Runnable接口

  我们在网上看线程的讲解的时候经常会看到Runnable这个接口的使用,其实Runnable只声明了一个接口函数,就是run()函数,它的作用就是给各种的线程类去继承并实现run方法。比如:FutureTask<V>、Thread、TimerTask等都实现了这个接口。我们只要记住它是一个只声明了run()函数的接口就好了。

三、使用Thread类实现多线程

  上面是一个Thread线程的例子,在这里要注意:

  1. Thread启动的线程不能直接访问UI组件,要通过组件的.post方法访问,如上面的textView.post(new Runnable() {})
  2. 要使用start()方法启动线程,不可以使用run()方法
四、使用AsyncTask实现多线程

上面是一个AsyncTask的例子,

  • onPreExecute:doInBackground运行之前的函数,可以操作UI的组件
  • doInBackground: 耗时的操作(网络下载、图像处理等)放到这个函数里
  • onPostExecute:doInBackground运行之后的函数,可以操作UI的组件
  • onProgressUpdate:用于在UI显示运算进度,需要在doInBackground里调用publishProgress

AsyncTask的优点:

  1. 结构清晰,易于理解
  2. 可显示进度
  3. 可方便操作UI组件

AsyncTask的缺点:

  1. 不能多个实例同时运行,每次要创建一个新的实例,比如myTask.execute(“OK”);就会抛异常

五、HandlerThread

  HandlerThread适用于在一个线程中执行多个实时性不高的操作.具体参考下面的链接

  HandlerThread的多个任务只能串行执行,不能同时执行多个任务

  对HandlerThread的理解

六、ExectuorService线程池
七、IntentService

  IntentService实际是继承自Service的一个类,用于方便在一个Service创建一个执行比较耗时的任务

  IntentService里面只有一个工作线程,也只能同时执行一个任务

  Service的系统权限比较高,不容易被系统杀死

八、FutureTask、TimerTask继承自Runnable接口,并不是实现多线程的类,只是实现多线程的辅助类,如new Thread(futureTask).start();这样的。他们与直接使用Runnable接口的差别如下:

  1. FutureTask可以取消,可以返回结果
  2. TimerTask可以定时执行

 

4月 172015
 

一般Android的默认图片编辑器是支持对图片进行剪裁操作的,所以如果我们的应用需要对图片进行剪裁操作,调用系统的图片编辑器即可,代码如下:

如果输出到文件(设置MediaStore.EXTRA_OUTPUT的值):

如果在Activity中处理返回的图片流(return-data的值为true):

 

 

4月 112015
 

今天看java的垃圾回收,突然想到java的垃圾回收和排档(或者食堂)的餐盘回收有点类似。

食堂的餐盘回收一般会有以下几种方式:一是用餐者自行将餐盘放回回收处,二是食堂有专门的服务员来回收餐盘。

java的垃圾回收机制和第二种很相似,有垃圾回收器这个“服务员”来回收程序运行中产生的不再使用的对象。

服务员会定时的检查放在餐桌上的盘子,看是否还有人在使用,如果没人使用就会进行回收

 Posted by on 2015-04-11

接口和抽象类

 分类:Java, Java语言 阅读 (1,188)  No Responses »
3月 072015
 

接口和抽象类的区别:

  1. 抽象类可以有方法实现,但是接口不能
  2. 一个类可以实现(也可以说是继承)多个接口,但是只能继承自一个抽象类
  3. 接口注重的是功能的定义,抽象类强调的是所属关系
  4. 接口中的变量默认的是public static final的,并且必须赋初值,也就是不能有自己的私有成员;抽象类在这方面和普通的类差不多,可以有自己的私有成员

接口和抽象类的相同点:

  1. 都不能被实例化
  2. 抽象类的子类或者接口的实现类必须实现抽象类或者接口的全部抽象方法

 

 Posted by on 2015-03-07
2月 262015
 

  Home键:默认情况下,android中的home键只是切换到系统的home界面,并不会销毁当前的activity,即不会执行activity中的ondestroy方法,从任务栈中恢复那个应用的话,activity中的数据不会丢失

  Back键:而android中的back键,则先销毁当前activity,然后回到之前的应用界面中,而且此时activity中的数据都丢失了。

  如果我们想在按back键的时候,不销毁当前的activity,保留它的数据和状态的话,我们可以改写源码中对back键的处理来达到这个目的,代码如下:

  当然这样做的缺点时,之前打开的应用全部都被关闭掉了,比如用户在用浏览器看新闻,通过通知栏消息打开了你的应用,在你的应用中按back键就回到了home界面,前面的浏览器也被关掉了。

2月 242015
 

一、安装svn

# yum install httpd
# yum install httpd-devel
# yum install subversion
# yum install mod_dav_svn
# yum install mod_auth_mysql

验证是否安装成功,输入命令:
# svnserve –version

输出上面的信息后证明安装成功

 二、创建代码库

首先创建一个目录用于存放svn的各个项目

# mkdir /opt/svn

使用svnadmin创建一个代码库

# svnadmin create /opt/svn/repo1

这样第一个项目的代码库就创建完成了,进入到repo1目录中,可以看到conf, db,format,hooks, locks, README.txt等文件,说明代码库建立成功

三、配置代码库

进入到/opt/svn/repo1/conf目录中,可以看到三个文件authz, passwd, svnserve.conf,其中authz是用于配置用户组和用户的文件,passwd是用于设置用户名和密码的文件,svnserve.conf是用于配置服务器的文件

1. 配置passwd

输入下面命令编辑passwd文件

# vi /opt/svn/repo1/conf/passwd

在[users]节点下面以下面格式输入“用户名 = 密码”,如:bcoder = 123456

2. 配置authz

输入下面命令编辑authz文件

# vi /opt/svn/repo1/conf/authz

[groups]节点下面是用于配置用户组的,可在每行输入”组名 = 用户1,用户2,用户3……”,如:” grpdeveloper = dev1, dev2, dev3 ”
[代码库路径]用于配置用户或者组对该代码库的权限,可在每行输入“用户名=rw”,r是读权限,rw是读写权限。如果对用户组则需要在用户组名前面加上 “@”,如:“@grpdeveloper”

这里我们简单的设置如下:

 3. 配置svnserve.conf

输入下面的命令编辑svnserve.conf

# vi /opt/svn/repo1/conf/svnserve.conf

anon-access用于设置匿名用户的权限,read为只读,write为读写,none为不能访问,通常设置为none
auth-access用于设置登录用户的权限,read为只读,write为读写,none为不能访问,通常设置为none
password-db用于指定存储用户名密码的文件,即/opt/svn/repo1/conf/中的passwd文件,默认password-db = passwd即可
authz-db用于指定用户权限的文件,即/opt/svn/repo1/conf/中的authz文件,默认authz-db=authz即可

四、启动svn服务器

输入下面的命令启动svn服务器

# svnserve -d -r -/opt/svn/repo1

五、使用客户端checkout代码库

在客户端使用下面地址checkout,svn://你的IP地址/

六、停止svn服务器

输入下面的命令停止svn服务器

# killall svnserve

七、启动多个代码库

假设我们在/opt/svn/下面建立了多个代码库,如

# svnadmin create /opt/svn/repo1
# svnadmin create /opt/svn/repo2
# svnadmin create /opt/svn/repo3

那么如果我们想使用多个代码库,在启动svn服务器的时候使用如下命令

# svnserve -d -r /opt/svn/

即使用多个代码库的上一级目录启动svn服务器,现在在客户端checkout的时候就要输入代码库的名字了,如:svn://你的IP地址/repo1

2月 102015
 

uses RichEdit;

1. 设置RichEdit的行间距,代码如下

2. 为RichEdit设置行号,代码如下:

3. 根据鼠标位置定位光标的方法。

当RichEdit为可用状态时,是不用代码控制此操作的,TRichEdit本身就可以定位光标。但是当RichEdit开始不可用时,则此方法就可能用到了。本例中RichEdit1开始时是不可用的,当在ApplicationEvents1中接收到RichEdit1被双击时则设置RichEdit1的Enable := true;并且定位光标。

4. 使Richedit中的链接可以点击

 

 

1月 062015
 

  在Delphi开发中,如果我们想让一个窗口始终置顶显示,则我们只需要把窗口FormStyle属性设置为fsStayOnTop就可以了,但是如果这个窗口不是主窗口,而是子窗口,那就有些麻烦了,设置FormStyle为fsStayOnTop后也无效。解决办法就是在子窗口中重载CreateParams函数,并将WndParent设置为0即可,具体代码如下:

 Delphi如何使子窗口显示在任务栏中

 

 Posted by on 2015-01-06
12月 312014
 

方法一:

  定时调用GetForegroundWindow获取最前端的窗口句柄,然后判断该窗口宽度高度是否等于屏幕的宽度高度。代码如下,大家参考:

  这种方法真是弱啊弱,看看第二种方法吧

方法二:

  第二种方法是通过SHAppBarMessage函数给系统发送一个监听消息,用于监听一些关于AppBar的信息,该消息的第二个参数里有一个属性是用于指定回调消息的,程序中定义一个消息码用于监听。当传回的消息的wParam是ABN_FULLSCREENAPP 时判断lParam为真假来判断是进入全屏还是退出全屏。

 

12月 252014
 

  SharedPreferences貌似很简单的一个类,却也存在着陷阱,如下面,我们写了几行简单的保存配置的代码,但却隐含着bug

  那么为什么这段代码不能保存runcount的数据呢,因为prefs.edit()每次返回一个新的Editor对象,所以执行两次prefs.edit()其实调用的是两个Editor对象,如下adnroid源码中的解释

  因此,我们应该先将prefs.edit()赋值给一个Editor对象,然后由该对象进行存值和提交操作,如下: