最近要在tablet和ipad上开发,为了做到cross platform,选用了titanium这个开发工具,感觉还可以,除了环境慢一些。
Titanium号称一次开发,分别可以在android以及ios上运行。
今天简单实现了一个对几个view移动排序的功能,通过手指的拖拽,拿上来分享一下。
注意只在android上做了测试。
var window = Ti.UI.createWindow({ backgroundColor : 'white', fullscreen : false }); var v_space = 10; var c_height = 100; var ismoving = false; var moving_obj; var blank_pos; var start_y = 0; var start_top = 0; var onViewTouchstart = function(e) { if (!e.source.id || e.source.id != "t_box") { return; } if (ismoving) { return; } moving_obj = getCByTouchY(t_box, e.y); if (moving_obj != null) { ismoving = true; } else { return; } moving_obj.opacity = 0.6; blank_pos = moving_obj.id; start_top = moving_obj.top; start_y = e.y; }; var onViewTouchmove = function(e) { if (!ismoving) { return; } var ey = e.y; var e_pos = Math.floor((ey - 10) / (v_space + c_height)); var c_willmove = getCByTouchY(t_box, ey); if (c_willmove != null) { c_willmove.top = blank_pos * (v_space + c_height) + 10; c_willmove.id = blank_pos; blank_pos = e_pos; } else { } moving_obj.top = start_top + ey - start_y; }; var onViewTouchend = function(e) { if (!ismoving) { return; } moving_obj.opacity = 1; moving_obj.id = blank_pos; moving_obj.top = blank_pos * (v_space + c_height) + 10; ismoving = false; moving_obj = null; }; var onViewTouchcancel = function(e) { if (!ismoving) { return; } moving_obj.opacity = 1; moving_obj.id = blank_pos; moving_obj.top = blank_pos * (v_space + c_height) + 10; ismoving = false; moving_obj = null; }; var t_box = Ti.UI.createView({ id : "t_box", backgroundColor : "#999", bottom : 250, left : 10, right : 10, height : 450 }); for (var i = 0; i < 4; i++) { var test_view = Ti.UI.createView({ id : i, backgroundColor : "#00f", top : i * (v_space + c_height) + 10, left : 20, width : 200, height : c_height, touchEnabled : false }); var aLabel = Ti.UI.createLabel({ text : 'Label' + i, font : { fontSize : 20 }, textAlign : 'center', touchEnabled : false }); test_view.add(aLabel); t_box.add(test_view); } t_box.addEventListener("touchstart", onViewTouchstart); t_box.addEventListener("touchmove", onViewTouchmove); t_box.addEventListener("touchend", onViewTouchend); t_box.addEventListener("touchcancel", onViewTouchcancel); function getCByTouchY(p, pos_y) { var childs = p.children; for (var i = 0; i < childs.length; i++) { var c = childs[i]; if (c == moving_obj) { continue; } if (c.top < pos_y && (c.top + c_height ) > pos_y) { return c; } } return null; } window.add(t_box); window.open();
进程间通信最简单的方式就是发送WM_COPYDATA消息。
发送WM_COPYDATA消息:
SendMessage(接收窗口句柄,WM_COPYDATA, (WPARAM)发送窗口句柄, (LPARAM)&CopyData);
其中的CopyData为COPYDATASTRUCT结构类型,该结构定义如下:
typedef struct tagCOPYDATASTRUCT {
开发中有时需要进程间传递数据,比如对于只允许单实例运行的程序,当已有实例运行时,再次打开程序,可能需要向当前运行的实例传递信息进行特殊处理。对于传递少量数据的情况,最简单的就是用SendMessage发送WM_COPYDATA消息,所带参数wParam和lParam可以携带相关数据。由于SendMessage是阻塞的,在接收数据进程处理完数据之前不会返回,发送方不会删除或修改数据,因此这种方法是简单且安全的,不过数据量不能太大,否则会由于处理时间过长造成阻塞假死。
用SendMessage发送WM_COPYDATA的方法如下:
lResult = SendMessage( // returns LRESULT in lResult (HWND) hWndControl, // handle to destination control (UINT) WM_COPYDATA, // message ID (WPARAM) wParam, // = (WPARAM) () wParam; (LPARAM) lParam // = (LPARAM) () lParam;
);
其中,wParam为发送数据方的窗口句柄,lParam为指向一个COPYDATASTRUCT类型结构体的指针,该结构体中包含了传递的数据信息。COPYDATASTRUCT定义如下:
typedef struct tagCOPYDATASTRUCT {
ULONG_PTR dwData;
DWORD cbData;
PVOID lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
其中,dwData为自定义的数据,cbData指定lpData指向数据的大小,lpData为指向数据的指针。按照前面所说,在使用WM_COPYDATA时要保证数据的只读属性,即不能有发送方的其他线程对传递数据进行改写。(这也解释了为什么不允许用PostMessage发送WM_COPYDATA,因为PostMessage函数是异步的。还有一点需要注意的是由于SendMessage是阻塞的,所以容易引起死锁,可以考虑用SendMessageTimeout代替。)另外,如果传递数据中涉及到对象或系统资源,必须确保接收方可以对其进行处理,比如HDC、HBITMAP之类的资源是无效的,他们属于不同的进程。
在使用的时候,要用FindWindow等API找到接收方的窗口句柄;接收方的程序中要添加对WM_COPYDATA消息的响应。
前几天写程序用到WM_COPYDATA进行进程间通信,但是接收方怎么也收不到消息。调试发现找到的窗口句柄是没有问题的,查看MSDN也没有什么提示,百思不得其解。
后来看了一些示例代码,发现不同之处是我的SendMessage调用中wParam和lParam参数都是0,因为我只是需要通过WM_COPYDATA消息通知一下接收程序即可,不用传递任何数据。试着将这两个参数改为非空,接收方就可以收到消息了。总结结论为:wParam参数是否为0没有影响,但是lParam参数必须为非空,即必须指向一个有效的COPYDATASTRUCT结构体。
原因是什么呢?查了一些资料发现,SendMessage(WM_COPYDATA)底层是通过文件映射(File Mapping)完成的,大概流程是发送方线程根据COPYDATASTRUCT结构体中的传递数据信息,在共享内存中进行数据复制,接收方线程则会到共享内存中读取数据进行处理。因此如果指向COPYDATASTRUCT结构的指针为空的话,流程是无法进行的,所以接收方也理所当然收不到消息。
前面这段是转载的.自己最近再次去深究核心编程,这里给出的例子也是父进程与子进程之间进行通讯的方式:
父进程:
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <string>
#include <iomanip>
#include "CString.h"
using namespace std;
void main()
{
STARTUPINFO si = {sizeof(STARTUPINFO)};
SECURITY_ATTRIBUTES saProcess,saThread;
PROCESS_INFORMATION poProcessChild;
DWORD dProcessID = GetCurrentProcessId();
TCHAR str[100];
wsprintf( str,TEXT("%s %ld"),TEXT("E:\\测试程序\\2012-8-5\\RecvProcess\\Debug\\RecvProcess.exe"),dProcessID );
saThread.lpSecurityDescriptor = NULL;
saThread.bInheritHandle = TRUE;
saThread.nLength = sizeof( SECURITY_ATTRIBUTES );
saProcess.lpSecurityDescriptor = NULL;
saProcess.bInheritHandle = TRUE;
saProcess.nLength = sizeof( SECURITY_ATTRIBUTES );
BOOL bCreate = CreateProcess( NULL,str,&saProcess,&saThread,TRUE,CREATE_SUSPENDED,NULL,NULL,&si,&poProcessChild );
HWND hWnd = FindWindow( NULL,TEXT("RecvProcess") );
ResumeThread( poProcessChild.hThread );
COPYDATASTRUCT cpd; /*给COPYDATASTRUCT结构赋值*/
cpd.dwData = 0;
cpd.cbData = dProcessID;
cpd.lpData = NULL;
SendMessage( hWnd,WM_COPYDATA,NULL,(LPARAM)&cpd );
Sleep( 1000 );
}
接收端:
DWORD ProcessID = pCopyDataStruct->cbData;
或者使用命令行:
CString strCommandLine = GetCommandLine();
MessageBox( strCommandLine );
activity是单独的,用于处理用户操作。几乎所有的activity都要和用户打交道,所以activity类创建了一个窗口,开发人员可以通过setContentView(View)接口把UI放到activity创建的窗口上,当 activity指向全屏窗口时,也可以用其他方式实现:作为漂浮窗口(通过windowIsFloating的主题集合),或者嵌入到其他的 activity(使用ActivityGroup)。大部分的Activity子类都需要实现以下两个接口:
- onCreate(Bundle)接口是初始化activity的地方. 在这儿通常可以调用setContentView(int)设置在资源文件中定义的UI, 使用findViewById(int) 可以获得UI中定义的窗口.
- onPause()接口是使用者准备离开activity的地方,在这儿,任何的修改都应该被提交(通常用于ContentProvider保存数据).
为了能够使用Context.startActivity(),所有的activity类都必须在AndroidManifest.xml文件中定义有相关的“activity”项。
activity类是Android 应用生命周期的重要部分。
Activity生命周期
在系统中的Activity被一个Activity栈所管理。当一个新的Activity启动时,将被放置到栈顶,成为运行中的Activity,前一个Activity保留在栈中,不再放到前台,直到新的Activity退出为止。
Activity有四种本质区别的状态:
活动状态
Activity在用户界面中处于最上层,完全能被用户看到
暂停状态
Activity在界面上被部分遮挡,该Activity不再处于用户界面的最上层,且不能够与用户进行交互
停止状态
Activity在界面上被部分遮挡,该Activity不再处于用户界面的最上层,且不能够与用户进行交互
非活动状态
在以上三种状态中的Activity则处于非活动状态
状态转换图
下面的图显示了Activity的重要状态转换,矩形框表明Activity在状态转换之间的回调接口,开发人员可以重载实现以便执行相关代码,带有颜色的椭圆形表明Activity所处的状态。
在上图中,Activity有三个关键的循环:
Activity从创建到销毁有多种状态,从一种状态到另一种状态时会激发相应的回调方法,这些回调方法包括:
onCreate 、onStart 、onResume 、onPause 、onStop 、onDestroy 、onRestart
以图片的形式去记忆:
我们把Activity比作一本书,我们要看书,首先从书架上取出书(onCreate),然后放到桌上(onStart),接着打开书(onResume),这样我们就可以看书并可以在书本上写字了。
如果这时候我们要启动另一个Activity,也就是要看另一本书,首先我们放下手中的笔或者说合上书(onPause),然后从书架上拿下另一本书(书2:onCreate),然后把书本2放到桌上并打开(书2:onStart、onResume)。
如果书本1被书本2完全盖住了,即不可见了,就调用书本1的onStop;而如果书本2较小,没有完全盖住书本1,则不会调用。
我们还可以把书本1放回书架上,即onDestroy。
public class Activity extends ApplicationContext {
protected void onCreate(Bundle icicle);
protected void onStart();
protected void onRestart();
protected void onResume();
protected void onFreeze(Bundle outIcicle);
protected void onPause();
protected void onStop();
protected void onDestroy();
}
------本文从网上收集整理