android自定义回调
⑴ android 回调方法怎么写
package com.smart;
/**
* 定义回调接口
*/
public interface CallBack {
void execute();
}
package com.smart;
/**
* 工具类
*/
public class Tools {
public void test(CallBack callBack){
long begin = System.currentTimeMillis(); //测试起始时间
callBack.execute();///进行回调操作
long end = System.currentTimeMillis(); //测试结束时间
System.out.println("[use time]:" + (end - begin)); //打印使用时间
}
public static void main(String[] args){
Tools tools = new Tools();
tools.test(new CallBack(){
public void execute() {
//A.method(); 测试类A的某个方法执行的时间
//B.method(); 测试类B的某个方式执行的时间
System.out.print("回调" );
}
});
}
}
package com.smart;
/**
* 工具类
*/
public class Tools {
public void test(CallBack callBack){
long begin = System.currentTimeMillis();//测试起始时间
callBack.execute();///进行回调操作
long end = System.currentTimeMillis();//测试结束时间
System.out.println("[use time]:" + (end - begin));//打印使用时间
}
public static void main(String[] args){
Tools tools = new Tools();
tools.test(new CallBack(){
public void execute() {
//A.method(); 测试类A的某个方法执行的时间
//B.method(); 测试类B的某个方式执行的时间
System.out.print("回调");
}
});
}
}
⑵ Android 自定义控件中实现接口回调时为什么影响界面绘线
SurfaceView是View的子类,它内嵌了一个专门用于绘制的Surface,你可以控制这个Surface的格式和尺寸,Surfaceview控制这个Surface的绘制位置。surface是纵深排序(Z-ordered)的,说明它总在自己所在窗口的后面。SurfaceView提供了一个可见区域,只有在这个可见区域内的surface内容才可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者 surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面有透明控件,那么每次surface变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。
SurfaceView默认使用双缓冲技术的,它支持在子线程中绘制图像,这样就不会阻塞主线程了,所以它更适合于游戏的开发。
SurfaceView的使用
首先继承SurfaceView,并实现SurfaceHolder.Callback接口,实现它的三个方法:surfaceCreated,surfaceChanged,surfaceDestroyed。
surfaceCreated(SurfaceHolder holder):surface创建的时候调用,一般在该方法中启动绘图的线程。
surfaceChanged(SurfaceHolder holder, int format, int width,int height):surface尺寸发生改变的时候调用,如横竖屏切换。
surfaceDestroyed(SurfaceHolder holder) :surface被销毁的时候调用,如退出游戏画面,一般在该方法中停止绘图线程。
还需要获得SurfaceHolder,并添加回调函数,这样这三个方法才会执行。
SurfaceView实战
下面通过一个小demo来学习SurfaceView在实际项目中的使用,绘制一个精灵,该精灵有四个方向的行走动画,让精灵沿着屏幕四周不停的行走。
⑶ 如何在android的jni线程中实现回调
JNI回调是指在c/c++代码中调用java函数,当在c/c++的线程中执行回调函数时,会导致回调失败。 其中一种在Android系统的解决方案是: 把c/c++中所有线程的创建,由pthread_create函数替换为由Java层的创建线程的函数AndroidRuntime::createJavaThread。 假设有c++函数: [cpp] view plain void *thread_entry(void *args) { while(1) { printf("thread running...\n"); sleep(1); } } void init() { pthread_t thread; pthread_create(&thread,NULL,thread_entry,(void *)NULL); } init()函数创建一个线程,需要在该线程中调用java类Test的回调函数Receive: [cpp] view plain public void Receive(char buffer[],int length){ String msg = new String(buffer); msg = "received from jni callback:" + msg; Log.d("Test", msg); } 首先在c++中定义回调函数指针: [cpp] view plain //test.h #include <pthread.h> //function type for receiving data from native typedef void (*ReceiveCallback)(unsigned char *buf, int len); /** Callback for creating a thread that can call into the Java framework code. * This must be used to create any threads that report events up to the framework. */ typedef pthread_t (* CreateThreadCallback)(const char* name, void (*start)(void *), void* arg); typedef struct{ ReceiveCallback recv_cb; CreateThreadCallback create_thread_cb; }Callback; 再修改c++中的init和thread_entry函数: [cpp] view plain //test.c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <sys/wait.h> #include <unistd.h> #include "test.h" void *thread_entry(void *args) { char *str = "i'm happy now"; Callback cb = NULL; int len; if(args != NULL){ cb = (Callback *)args; } len = strlen(str); while(1) { printf("thread running...\n"); //invoke callback method to java if(cb != NULL && cb->recv_cb != NULL){ cb->recv_cb((unsigned char*)str, len); } sleep(1); } } void init(Callback *cb) { pthread_t thread; //pthread_create(&thread,NULL,thread_entry,(void *)NULL); if(cb != NULL && cb->create_thread_cb != NULL) { cb->create_thread_cb("thread",thread_entry,(void *)cb); } } 然后在jni中实现回调函数,以及其他实现: [cpp] view plain //jni_test.c #include <stdlib.h> #include <malloc.h> #include <jni.h> #include <JNIHelp.h> #include "android_runtime/AndroidRuntime.h" #include "test.h" #define RADIO_PROVIDER_CLASS_NAME "com/tonny/Test" using namespace android; static jobject mCallbacksObj = NULL; static jmethodID method_receive; static void (JNIEnv* env, const char* methodName) { if (env->ExceptionCheck()) { LOGE("An exception was thrown by callback '%s'.", methodName); LOGE_EX(env); env->ExceptionClear(); } } static void receive_callback(unsigned char *buf, int len) { int i; JNIEnv* env = AndroidRuntime::getJNIEnv(); jcharArray array = env->NewCharArray(len); jchar *pArray ; if(array == NULL){ LOGE("receive_callback: NewCharArray error."); return; } pArray = (jchar*)calloc(len, sizeof(jchar)); if(pArray == NULL){ LOGE("receive_callback: calloc error."); return; } // buffer to jchar array for(i = 0; i < len; i++) { *(pArray + i) = *(buf + i); } // buffer to jcharArray env->SetCharArrayRegion(array,0,len,pArray); //invoke java callback method env->CallVoidMethod(mCallbacksObj, method_receive,array,len); //release resource env->DeleteLocalRef(array); free(pArray); pArray = NULL; (env, __FUNCTION__); } static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg) { return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg); } static Callback mCallbacks = { receive_callback, create_thread_callback }; static void jni_class_init_native (JNIEnv* env, jclass clazz) { method_receive = env->GetMethodID(clazz, "Receive", "([CI)V"); } static int jni_init (JNIEnv *env, jobject obj) { if (!mCallbacksObj) mCallbacksObj = env->NewGlobalRef(obj); return init(&mCallbacks); } static const JNINativeMethod gMethods[] = { { "class_init_native", "()V", (void *)jni_class_init_native }, { "native_init", "()I", (void *)jni_init }, }; static int registerMethods(JNIEnv* env) { const char* const kClassName = RADIO_PROVIDER_CLASS_NAME; jclass clazz; /* look up the class */ clazz = env->FindClass(kClassName); if (clazz == NULL) { LOGE("Can't find class %s/n", kClassName); return -1; } /* register all the methods */ if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK) { LOGE("Failed registering methods for %s/n", kClassName); return -1; } /* fill out the rest of the ID cache */ return 0; } jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; LOGI("Radio JNI_OnLoad"); if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { LOGE("ERROR: GetEnv failed/n"); goto fail; } if(env == NULL){ goto fail; } if (registerMethods(env) != 0) { LOGE("ERROR: PlatformLibrary native registration failed/n"); goto fail; } /* success -- return valid version number */ result = JNI_VERSION_1_4; fail: return result; } jni的Android.mk文件中共享库设置为: [cpp] view plain LOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelper 最后再实现Java中的Test类: [java] view plain //com.tonny.Test.java public class Test { static{ try { System.loadLibrary("test"); class_init_native(); } catch(UnsatisfiedLinkError ule){ System.err.println("WARNING: Could not load library libtest.so!"); } } public int initialize() { return native_radio_init(); } public void Receive(char buffer[],int length){ String msg = new String(buffer); msg = "received from jni callback" + msg; Log.d("Test", msg); } protected static native void class_init_native(); protected native int native_init(); }
⑷ android接口回调的几种
可以使用Observer,观察者模式来实现回调。或者接口中传入类,然后在接口处理之后,进行调用类的方法进行回调。
接口回调示例
public interface ConfirmDialogListener{
public void onLeft(Object obj); //按确认键
public void onRight(Object obj);//按back键
}
public static Dialog confirmDialog(final Context activity, final ConfirmDialogListener listener,final Object obj){
if(listener != null)
listener.onRight(obj);
}
⑸ android中回调函数是怎么调用的
CallBack是回调的意思,一般称之为回调函数
网络的解释:http://ke..com/link?url=8yMUwVEFRzxR4JGMxVN_
用一个比较形象的例子:
你饿了,想吃饭,就一会去问你妈一声"开饭没有啊?"
这就是正常函数调用.
但是今天你妈包饺子,花的时间比较长,你跑啊跑啊,就烦了.于是你给你妈说,我先出去玩会,开饭的时候打我手机.
等过了一阵,你妈给你打电话说"开饭啦,回来吃饭吧!"
其中,你告诉你妈打手机找你,就是你把回调函数句柄保存到你妈的动作.你妈打
⑹ android定义在抽象方法中的回调函数有哪些
提示:在阅读本文章之前,请确保您对Touch事件的分发机制有一定的了解
在Android的学习过程中经常会听到或者见到“回调”这个词,那么什么是回调呢?所谓的回调函数就是:在A类中定义了一个方法,这个方法中用到了一个接口和该接口中的抽象方法,但是抽象方法没有具体的实现,需要B类去实现,B类实现该方法后,它本身不会去调用该方法,而是传递给A类,供A类去调用,这种机制就称为回调。
下面我们拿具体的Button的点击事件进行模拟分析:
首先,在View类中我们能找到setOnClickListener(OnClickListener l)方法:
⑺ Android 回调接口是啥,回调机制详解
在Android中到处可见接口回调机制,尤其是UI事件处理方面,这里介绍android接口回调机制,涉及到android接口回调相关知识
在使用接口回调的时候发现了一个经常犯的错误,就是回调函数里面的实现有可能是用多线程或者是异步任务去做的,这就会导致咱们期望函数回调完毕去返回一个主函数的结果,实际发现是行不通的,因为如果回调是多线程的话是无法和主函数同步的,也就是返回的数据是错误的,这是非常隐秘的一个错误。那有什么好的方法去实现数据的线性传递呢?先介绍下回调机制原理。
回调函数
回调函数就是一个通过函数指针调用的函数。如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,咱们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
开发中,接口回调是经常用到的。
接口回调的意思即,注册之后并不立马执行,而在某个时机触发执行。
举个例子:
A有一个问题不会,他去问B,B暂时解决不出来,B说,等咱(B)解决了再告诉(A)此时A可以继续先做别的事情。
那么就只有当B解决完问题后告诉A问题解决了,A才可以能解决这个问题。
代码中比如最常用的:
一个Activity中给按钮一个接口回调方法,只有用户点击了这个按钮,告诉按钮被点击了,才会执行按钮接口回调的方法
Button btn = new Button(this);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
那么下面通过一个Demo理解接口回调:
主线程开启一个异步任务,当异步任务接收到数据,则把数据用TextView显示出来
1、首先 咱们需要定义一个接口,定义一个方法,参数为一个字符串:
package com.xqx.InterfaceDemo;
public interface ChangeTitle {
void onChangeTitle(String title);
}
2、写一个异步任务,把接口作为构造方法参数,在doInBackground()方法中判断如果有数据,则接口回调
package com.xqx.InterfaceDemo;
import android.content.Context;
import android.os.AsyncTask;
public class MyTask extends AsyncTask<String,Void,String>{
private ChangeTitle changeTitle;
public MyTask(ChangeTitle changeTitle) {
this.changeTitle = changeTitle;
}
@Override
protected String doInBackground(String... strings) {
if (strings[0]!=null){
changeTitle.onChangeTitle(strings[0]);
}
return null;
}
}
3、主Activity,给异步任务参数传this,即 接口回调方法在此类中执行,那么就需要实现ChangeTitle接口,重写接口中
onChangeTitle 方法
package com.xqx.InterfaceDemo;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity implements ChangeTitle {
private TextView textView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textView = (TextView) findViewById(R.id.textView);
new MyTask(this).execute("我是标题");
}
// 重写接口方法,执行相应操作
@Override
public void onChangeTitle(String title) {
textView.setText(title);
}
}
⑻ android自定义控件怎么用
一、控件自定义属性介绍
以下示例中代码均在values/attrs.xml 中定义,属性均可随意命名。
1. reference:参考某一资源ID。
示例:
<declare-styleable name = "名称">
<attr name = "background" format = "reference" />
<attr name = "src" format = "reference" />
</declare-styleable>
2. color:颜色值。
示例:
<declare-styleable name = "名称">
<attr name = "textColor" format = "color" />
</declare-styleable>
3. boolean:布尔值。
示例:
<declare-styleable name = "名称">
<attr name = "focusable" format = "boolean" />
</declare-styleable>
4. dimension:尺寸值。
示例:
<declare-styleable name = "名称">
<attr name = "layout_width" format = "dimension" />
</declare-styleable>
5. float:浮点值。
示例:
<declare-styleable name = "名称">
<attr name = "fromAlpha" format = "float" />
<attr name = "toAlpha" format = "float" />
</declare-styleable>
6. integer:整型值。
示例:
<declare-styleable name = "名称">
<attr name = "frameDuration" format="integer" />
<attr name = "framesCount" format="integer" />
</declare-styleable>
7. string:字符串。
示例:
<declare-styleable name = "名称">
<attr name = "text" format = "string" />
</declare-styleable>
8. fraction:百分数。
示例:
<declare-styleable name="名称">
<attr name = "pivotX" format = "fraction" />
<attr name = "pivotY" format = "fraction" />
</declare-styleable>
9. enum:枚举值。
示例:
<declare-styleable name="名称">
<attr name="orientation">
<enum name="horizontal" value="0" />
<enum name="vertical" value="1" />
</attr>
</declare-styleable>
10. flag:位或运算。
示例:
<declare-styleable name="名称">
<attr name="windowSoftInputMode">
<flag name = "stateUnspecified" value = "0" />
<flag name = "stateUnchanged" value = "1" />
<flag name = "stateHidden" value = "2" />
<flag name = "stateAlwaysHidden" value = "3" />
</attr>
</declare-styleable>
11.多类型。
示例:
<declare-styleable name = "名称">
<attr name = "background" format = "reference|color" />
</declare-styleable>
二、属性的使用以及自定义控件的实现
1、构思控件的组成元素,思考所需自定义的属性。
比如:我要做一个 <带阴影的按钮,按钮正下方有文字说明>(类似9宫格按钮)
新建values/attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="custom_view">
<attr name="custom_id" format="integer" />
<attr name="src" format="reference" />
<attr name="background" format="reference" />
<attr name="text" format="string" />
<attr name="textColor" format="color" />
<attr name="textSize" format="dimension" />
</declare-styleable>
</resources>
以上,所定义为custom_view,custom_id为按钮id,src为按钮,background为阴影背景,text为按钮说明,textColor为字体颜色,textSize为字体大小。
2、怎么自定义控件呢,怎么使用这些属性呢?话不多说请看代码,CustomView :
package com.nanlus.custom;
import com.nanlus.custom.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
public class CustomView extends FrameLayout implements OnClickListener {
private CustomListener customListener = null;
private Drawable mSrc = null, mBackground = null;
private String mText = "";
private int mTextColor = 0;
private float mTextSize = 20;
private int mCustomId = 0;
private ImageView mBackgroundView = null;
private ImageButton mButtonView = null;
private TextView mTextView = null;
private LayoutParams mParams = null;
public CustomView(Context context) {
super(context);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.custom_view);
mSrc = a.getDrawable(R.styleable.custom_view_src);
mBackground = a.getDrawable(R.styleable.custom_view_background);
mText = a.getString(R.styleable.custom_view_text);
mTextColor = a.getColor(R.styleable.custom_view_textColor,
Color.WHITE);
mTextSize = a.getDimension(R.styleable.custom_view_textSize, 20);
mCustomId = a.getInt(R.styleable.custom_view_custom_id, 0);
mTextView = new TextView(context);
mTextView.setTextSize(mTextSize);
mTextView.setTextColor(mTextColor);
mTextView.setText(mText);
mTextView.setGravity(Gravity.CENTER);
mTextView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
mButtonView = new ImageButton(context);
mButtonView.setImageDrawable(mSrc);
mButtonView.setBackgroundDrawable(null);
mButtonView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
mButtonView.setOnClickListener(this);
mBackgroundView = new ImageView(context);
mBackgroundView.setImageDrawable(mBackground);
mBackgroundView.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
addView(mBackgroundView);
addView(mButtonView);
addView(mTextView);
this.setOnClickListener(this);
a.recycle();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mParams = (LayoutParams) mButtonView.getLayoutParams();
if (mParams != null) {
mParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
mButtonView.setLayoutParams(mParams);
}
mParams = (LayoutParams) mBackgroundView.getLayoutParams();
if (mParams != null) {
mParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
mBackgroundView.setLayoutParams(mParams);
}
mParams = (LayoutParams) mTextView.getLayoutParams();
if (mParams != null) {
mParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
mTextView.setLayoutParams(mParams);
}
}
public void setCustomListener(CustomListener l) {
customListener = l;
}
@Override
public void onClick(View v) {
if (customListener != null) {
customListener.onCuscomClick(v, mCustomId);
}
}
public interface CustomListener {
void onCuscomClick(View v, int custom_id);
}
}
代码很简单,就不多说,下面来看看我们的CustomView是怎么用的,请看:
3、自定义控件的使用
话不多说,请看代码,main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:nanlus="http://schemas.android.com/apk/res/com.nanlus.custom"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:orientation="horizontal" >
<com.nanlus.custom.CustomView
android:id="@+id/custom1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
nanlus:background="@drawable/background"
nanlus:custom_id="1"
nanlus:src="@drawable/style_button"
nanlus:text="按钮1" >
</com.nanlus.custom.CustomView>
</LinearLayout>
</RelativeLayout>
在这里需要解释一下,
xmlns:nanlus="http://schemas.android.com/apk/res/com.nanlus.custom"
nanlus为在xml中的前缀,com.nanlus.custom为包名
4、在Activity中,直接上代码
package com.nanlus.custom;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.nanlus.BaseActivity;
import com.nanlus.custom.R;
import com.nanlus.custom.CustomView.CustomListener;
public class CustomActivity extends BaseActivity implements CustomListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((CustomView) this.findViewById(R.id.custom1)).setCustomListener(this);
}
@Override
public void onCuscomClick(View v, int custom_id) {
switch (custom_id) {
case 1:
Toast.makeText(this, "hello !!!", Toast.LENGTH_LONG).show();
break;
default:
break;
}
}
}
⑼ Android怎么定义回调函数
class
a
implements
camera.previewcallback{
/**
*
预览帧回调函数
*
*/
public
void
onpreviewframe(byte[]
data,
camera
camera)
{
//当视频流开启的时候就可以在这个方法里做你想做的事,那么这个就是一个回调函数
}
}
⑽ android代码中,什么时候需要自定义回调函数
当你想要把具体的操作,让具体的人来完成,自己定义一个接口就好。使用的时候用接口,具体的人来实现你的接口,也就是实现了回调。