假设我们自定义了一下的布局:
package com.InterfaceDemo.interfacedemo;
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
public class MyControl extends LinearLayout
{
public MyControl(Context context, AttributeSet attrs, int defStyle)
{
super( context, attrs, defStyle );
}
public MyControl(Context context, AttributeSet attrs)
{
this( context, null, 0 );
}
public MyControl(Context context)
{
this( context, null );
}
public MyControl(Activity activity,int type,String ty){
this( activity.getApplicationContext() );
initView(activity.getApplicationContext());
}
private void initView(Context context){
LinearLayout linearLayout = new LinearLayout( context );
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT );
linearLayout.setOrientation( LinearLayout.VERTICAL );
linearLayout.setLayoutParams( params );
//创建一个文本编辑框
final EditText edit = new EditText(context);
LayoutParams editParams = new LayoutParams(LayoutParams.FILL_PARENT , LayoutParams.WRAP_CONTENT);
edit.setLayoutParams(editParams);
//创建一个按钮
Button button = new Button(context);
LayoutParams btpParams = new LayoutParams(LayoutParams.WRAP_CONTENT , LayoutParams.WRAP_CONTENT);
button.setLayoutParams(btpParams);
button.setText("点击获取");
button.setOnClickListener( new OnClickListener()
{
@Override
public void onClick(View v)
{
// TODO Auto-generated method stub
callBack.onButtonClick( edit.getText().toString() );
}
} );
linearLayout.addView( button );
linearLayout.addView( edit );
this.addView( linearLayout );
}
//自定义一个接口
public interface MycallBack{
public void onButtonClick(String s);
};
MycallBack callBack;
public void setInterface(MycallBack callBack){
this.callBack = callBack;
}
}
我们在项目中要使用的时候有两种方式:
A:在对应的xml中声明
B:在代码中生成对象
下面来看看两者在使用的时候的区别:
A: 直接在xml中
<!-- 自定义控件 -->
<!-- <com.InterfaceDemo.interfacedemo.MyControl -->
<!-- android:id="@+id/mycontrol" -->
<!-- android:layout_width="fill_parent" -->
<!-- android:layout_height="wrap_content" -->
<!-- /> -->
此时需要注意的是在我们的自定义代码中需要同时实现三个构造函数:
public MyControl(Context context, AttributeSet attrs, int defStyle)
{
super( context, attrs, defStyle );
}
public MyControl(Context context, AttributeSet attrs)
{
this( context, null, 0 );
}
public MyControl(Context context)
{
this( context, null );
}
同时initView(context);的位置大家可以试着放到不同构造器中,我测试的结果是最好放在有三个参数的构造器中比较保险
B:在代码中生成对象。这个方法一般用的会比较多,此刻我们如果需要在构造对象的时候传递一些参数过来的话可以这么处理:
public MyControl(Context context, AttributeSet attrs, int defStyle)
{
super( context, attrs, defStyle );
}
public MyControl(Context context, AttributeSet attrs)
{
this( context, null, 0 );
}
public MyControl(Context context)
{
this( context, null );
}
//自定义构造器,传递相应的参数,最关键的是调用系统的构造器
public MyControl(Activity activity,int type,String ty){
this( activity.getApplicationContext() );
initView(activity.getApplicationContext());
}
dalvik字节码有两种类型,原始类型和引用类型。对象和数组是引用类型,其它都是原始类型。
V void,只能用于返回值类型
Z boolean
B byte
S short
C char
I int
J long(64位)
F float
D double(64位)
对象以Lpackage/name/ObjectName;的形式表示。前面的L表示这是一个对象类型,package/name/是该对象所在的包,ObjectName是对象的名字,“;”表示对象名称的结束。相当于java中的package.name.ObjectName。例如:Ljava/lang/String;相当于java.lang.String
数组的表示形式
[I——表示一个整型一维数组,相当于java中的int[]。
对于多维数组,只要增加[就行了。[[I相当于int[][],[[[I相当于int[][][]。注意每一维的最多255个。
对象数组的表示:[Ljava/lang/String;表示一个String对象数组。
方法
表示形式:Lpackage/name/ObjectName;->MethodName(III)Z
Lpackage/name/ObjectName;表示类型,MethodName是方法名。III为参数(在此是3个整型参数),Z是返回类型(bool型)。
方法的参数是一个接一个的,中间没有隔开。
一个更复杂的例子:
method(I[[IILjava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
在java中则为:
String method(int, int[][], int, String, Object[])
字段
表示形式:
Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;
即包名,字段名和各字段类型。
寄存器
在dalvik字节码中,寄存器都是32位的,能够支持任何类型。64位类型(Long和Double型)用2个寄存器表示。
有两种方式指定一个方法中有多少寄存器是可用的。.registers指令指定了方法中寄存器的总数。.locals指令表明了方法中非参寄存器的数量。
方法的传参
当一个方法被调用的时候,方法的参数被置于最后N个寄存器中。如果一个方法有2个参数,5个寄存器(v0-v4),那么参数将置于最后2个寄存器——v3和v4。
非静态方法中的第一个参数总是调用该方法的对象。
例如,非静态方法LMyObject;->callMe(II)V有2个整型参数,另外还有一个隐含的LMyObject;参数,所以总共有3个参数。假如在该方法中指定了5个寄存器(v0-v4),以.registers方式指定5个或以.locals方式指定2个(即2个local寄存器+3个参数寄存器)。当该方法被调用的时候,调用该方法的对象(即this引用)存放在v2中,第一个整型参数存放在v3中,第二个整型参数存放在v4中。
对于静态方法除了没有隐含的this参数外其它都一样。
寄存器的命名方式
有两种方式——V命名方式和P命名方式。P命名方式中的第一个寄存器就是方法中的第一个参数寄存器。在下表中我们用这两种命名方式来表示上一个例子中有5个寄存器和3个参数的方法。
v0 第一个local register
v1 第二个local register
v2 p0 第一个parameter register
v3 p1 第二个parameter register
v4 p2 第三个parameter register
你可以用任何一种方式来引用参数寄存器——他们没有任何差别。
注意:baksmali默认对参数寄存器使用P命名方式。如果想使用V命名方式,可以使用-pl—no-parameter-registers选项。
使用P命名方式是为了防止以后如果要在方法中增加寄存器,需要对参数寄存器重新进行编号的缺点。
Long/Double值
Long和double类型是64位的,需要2个寄存器(切记切记)。
例如,对于非静态方法LMyObject;->MyMethod(IJZ)V,参数分别是LMyObject;,int,long,bool。故该方法需要5个寄存器来存储参数。
p0 this
p1 I
p2,p3 J
p4 Z
转:http://www.rapidsnail.com/Tutorial/t/2012/1018/30/15343/the-android-ontouch-and-onclick-conflict-processing.aspx
public boolean onTouch(View V, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
X1 = event.getX();
Y1 = event.getY();
}
if (event.getAction() == MotionEvent.ACTION_UP) {
X2 = event.getX();
Y2 = event.getY();
if (Math.abs(X1 - X2) < 6) {
Toast.makeText(getApplicationContext(), "onClick",
Toast.LENGTH_SHORT).show();
return false; // distance is smaller, as the click event
// handling
}
if (Math.abs(X1 - X2) > 60) {// onTouch real events
Toast.makeText(getApplicationContext(), "onTouch",
Toast.LENGTH_SHORT).show();
}
}
return true; // returns, not to execute click events
}