当前位置:  编程技术>移动开发
本页文章导读:
    ▪替UITableViewCell增加按钮及处理按钮事件的方法        为UITableViewCell增加按钮及处理按钮事件的方法- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath { UIImage *image = [UIImage imageNamed:@"test.png"]; UIButton *button = [UIButton buttonWithType:UIB.........
    ▪ 一种扩充总线的方法        一种扩展总线的方法——彭晓林 欢迎交流:196568501(QQ) 注:此方法适合于SPI 扩展,I2C扩展 UART 等总线的扩展 1. MCU 为主控器 2. CLK 为时钟, DATA 为数据 3. CS1-C4 为片选 4. HUB为扩展芯片.........
    ▪ AsyncTask 也会引起线程不安全(抛出错误:CalledFromWrongThreadException)       AsyncTask 也会引起线程不安全(抛出异常:CalledFromWrongThreadException)?Android 中最常见的引起线程不安全的操作就是在非主线程中操作线程的UI,在 AsyncTask  出现之前,一般采用Handler 机制异.........

[1]替UITableViewCell增加按钮及处理按钮事件的方法
    来源: 互联网  发布时间: 2014-02-18
为UITableViewCell增加按钮及处理按钮事件的方法
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    UIImage *image = [UIImage imageNamed:@"test.png"];
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    CGRect frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);
    button.frame = frame;
    [button addTarget:self action:@selector(accessoryViewButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
    [button setBackgroundImage:image forState:UIControlStateNormal];
    cell.accessoryView = button;
}

根据按钮的位置获得行数:
- (void)accessoryViewButtonClicked:(id)sender
{
    CGPoint hitPoint = [sender convertPoint:CGPointZero toView:self.tableView];
    NSIndexPath *hitIndex = [self.tableView indexPathForRowAtPoint:hitPoint];
    //...
}

    
[2] 一种扩充总线的方法
    来源: 互联网  发布时间: 2014-02-18
一种扩展总线的方法

——彭晓林

欢迎交流:196568501(QQ)


注:此方法适合于SPI 扩展,I2C扩展 UART 等总线的扩展




1. MCU 为主控器

2. CLK 为时钟, DATA 为数据

3. CS1-C4 为片选

4. HUB为扩展芯片

5.  CLK1-CLK4 为扩展时钟, DATA1-DATA4 为扩展数据


    
[3] AsyncTask 也会引起线程不安全(抛出错误:CalledFromWrongThreadException)
    来源: 互联网  发布时间: 2014-02-18
AsyncTask 也会引起线程不安全(抛出异常:CalledFromWrongThreadException)?

Android 中最常见的引起线程不安全的操作就是在非主线程中操作线程的UI,在 AsyncTask  出现之前,一般采用Handler 机制异步操作UI。


做过Java的朋友都知道,java的异步线程源自于开源的Concurrent框架,AsyncTask  也正是移植自Concurrent框架。


关于 AsyncTask  和 Handler 的比较和各自用法,参考附录文档即可,在此不作累述,下面描述一种比较特别的场景:在程序启动后的第一个欢迎界面读取配置信息。


几个程序的声明:

异步任务执行类:

public class ExecuteAsyncTask extends AsyncTask<BaseTask, Integer, Object> 

        private TaskListener mListener;

基类:

public class BasicActivity  extends Activity implements TaskListener

protected void executeTask(BaseTask baseTask, TaskListener taskListener)
{
ExecuteAsyncTask mAsynctask = new ExecuteAsyncTask(baseTask, taskListener);
mAsynctask.execute((BaseTask) null);
}

        @Override
public void onTaskStart(Object object)
{}

        @Override
public void onTaskFinish(Object object)
{}

欢迎界面:

public class WelcomeActivity  extends BaseActivity
public void onTaskFinish(Object object)
{}

主界面:

public class MainActivity extends BaseActivity
public void onTaskFinish(Object object)
{}


如果我们直接用 Handler 发送一条延时执行的消息,来发起一个联网读取配置信息的任务(AsyncTask );信息获取成功后再通知软件,进入程序主界面。这时候会造成线程堵塞,也就是同步操作,如果网络异常,则会出现黑屏的情况。所以Handler需要与线程配合使用,提供两种写法:

第一种写法:

	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);		
		setContentView(R.layout.welcome_layout);
		HandlerThread thread = 
			new HandlerThread(WelcomeActivity.class.getSimpleName());
		thread.start();
		
		mHandler = new MyHandler(thread.getLooper());
		mHandler.sendEmptyMessage(MESSAGE_WHAT_CONFIG)

第二种写法:

	class AsyncConfigThread extends Thread
	{
		public void run()
		{
			mHandler.sendEmptyMessageDelayed(MESSAGE_WHAT_CONFIG, 500);
		}
	}
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);		
		setContentView(R.layout.welcome_layout);

		new AsyncConfigThread().start();

第二种写法比较常见,略过。


注意看,第一种写法中新创建了一个HandlerThread,然后将它的Looper传入到Handler中,相当于重新申请了一个消息队列;运行后发现线程安全问题:


WelcomeActivity(Thread id = 1) and BasicActivity(Thread id = 1)

MainActivity(Thread id = 10) and BasicActivity(Thread id = 1)


10-25 23:38:21.794 E/BaseActivity(24991): onCreate############################thread id = 1
10-25 23:38:25.494 E/WelcomeActivity(24991): executeTask############################thread id = 1
10-25 23:38:22.004 E/BaseActivity(24991): executeTask############################thread id = 10//新的消息队列线程号

10-25 23:38:27.384 I/ActivityManager( 1563): Starting: Intent { cmp=com.tfb.test/com.tfb.activity.MainActivity } from pid 24991

10-25 23:38:27.404 E/BaseActivity(24991): onCreate############################thread id = 1
10-25 23:38:27.564 E/BaseActivity(24991): executeTask############################thread id = 1
10-25 23:38:27.574 E/BaseActivity(24991): executeTask############################thread id = 1
10-25 23:38:27.574 E/BaseActivity(24991): executeTask############################thread id = 1
10-25 23:38:27.574 E/MainActivity(24991): ############################thread id = 1//此时线程号还是1,正确

10-25 23:38:29.704 E/MainActivity(24991): ############################thread id = 10//此时线程号发生了变化。。。
10-25 23:38:29.704 E/BaseActivity(24991): executeTask############################thread id = 1//BaseActivity的线程号一直保持1

10-25 23:48:35.754 E/AndroidRuntime(28680): FATAL EXCEPTION: WelcomeActivity
10-25 23:48:35.754 E/AndroidRuntime(28680): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
10-25 23:48:35.754 E/AndroidRuntime(28680): at android.view.ViewRoot.checkThread(ViewRoot.java:2932)
10-25 23:48:35.754 E/AndroidRuntime(28680): at android.view.ViewRoot.invalidateChild(ViewRoot.java:642)
10-25 23:48:35.754 E/AndroidRuntime(28680): at android.view.ViewRoot.invalidateChildInParent(ViewRoot.java:668)
10-25 23:48:35.754 E/AndroidRuntime(28680): at android.view.ViewGroup.invalidateChild(ViewGroup.java:2511)
10-25 23:48:35.754 E/AndroidRuntime(28680): at android.view.View.invalidate(View.java:5279)
10-25 23:48:35.754 E/AndroidRuntime(28680): at android.widget.TextView.setPadding(TextView.java:1595)
10-25 23:48:35.754 E/AndroidRuntime(28680): at android.view.View.setBackgroundDrawable(View.java:7571)
10-25 23:48:35.754 E/AndroidRuntime(28680): at android.view.View.setBackgroundResource(View.java:7535)
10-25 23:48:35.754 E/AndroidRuntime(28680): at com.tfb.activity.MainActivity.onTaskFinished(MainActivity.java:445)


注意看异常信息,MainActivity.java抛出与WelcomeActivity的线程安全异常,在第二个程序(都是基于BasicActivity的异步消息onTaskFinished()中抛出),很有意思;更有意思的是,同样的代码,在Android 4.0以上系统不存在这样的线程安全问题,只在Android 2.3.x上才会存在线程安全问题。:D


我们在使用这些应用技术之前,还是要熟悉下Looper的消息机制:


Android通过Looper、Handler来实现消息循环机制。Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。Android系统中的Looper负责管理线程的消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。


Android系统中的视图组件并不是线程安全的,如果要更新视图,必须在主线程中更新,不可以在子线程中执行更新的操作。


参考文档:

浅析Android中的消息机制 http://blog.csdn.net/liuhe688/article/details/6407225
详解Android中AsyncTask的使用 http://blog.csdn.net/liuhe688/article/details/6532519
AsyncTask和Handler对比 http://www.cnblogs.com/devinzhang/archive/2012/02/13/2350070.html




    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3