0%

情景:有几十张图片,存放在drawable目录下,通过Web Service可以取到要显示的图片文件名,通过这个文件名,来展示相应的图片。 两种方法:第一种是最笨的,写几十个if,else if,对比返回的文件名,确定要显示的图片的Resources ID. 第二种方法,用反射,这里介绍的就是第二种方法。 当我们在drawable目录下添加图片时,ADT会自动以该图片的文件名(不包括扩展名)为静态变量名,建立索引,打开gen目录下的R.java文件,可以发现,所有图片的索引都是R.drawable类下的静态变量。 我们就可通过Web Service返回的文件名(当然,要去掉扩展名的),用Java的反射机制,取到该静态变量的值,就是Resources ID,这样我们在程序中就可以直接使用了。

    public int getBigIconResourceId() {
            R.drawable drawables=new R.drawable();
            //默认的id
            int resId=0x7f02000b;
            try {
                //根据字符串字段名,取字段
                Field field=R.drawable.class.getField("big_1");
                //取值
                resId=(Integer)field.get(drawables);
            } catch (SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return resId;
        }

AIDL全称Android Interface Definition Language,即Android接口定义语言,通过它可以在进程间通讯,今天的例子演示的是在Activity与Service间通讯。 程序结构: 包com.example.aidl中有五个文件 AIDLService.java: Service MainActivity.java: 第一个Activity,在这里启动Service,并与之通讯 People.java: JavaBean,两字段,name,age,一方法say SecondActivity.java: 第二个Activity,与在MainActivity中启动的AIDLService通讯 PeopleAIDL.aidl AIDL定义文件,其实就是一个Interface,但扩展名不是java,添加这个文件后,在gen目录下会自动生成PeopleAIDL.java. 本例使用了AndroidAnnotations框架,没接触过的童鞋可能会看不太懂,但其实这个框架也蛮简单的,参考前文AndroidAnnotations框架@Ebean,@RootContext,@Background,@UiThread,@AfterInject,@AfterTextChange标签的使用方法,一看就明白。 布局:main_activity.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/hello_world"
        tools:context=".MainActivity" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:text="绑服务" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="22dp"
        android:layout_toRightOf="@+id/button1"
        android:text="setName" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@+id/textView1"
        android:text="setAge" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/button1"
        android:layout_marginTop="16dp"
        android:text="say" />

    <Button
        android:id="@+id/button5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/button4"
        android:layout_alignLeft="@+id/button2"
        android:text="SecondActivity" />

</RelativeLayout>

second_activity.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Bind Service" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Say" />

</LinearLayout>

接下来是Java代码: People.java:

package com.example.aidl;

import android.content.Context;
import android.widget.Toast;

import com.googlecode.androidannotations.annotations.EBean;
import com.googlecode.androidannotations.annotations.RootContext;

@EBean
public class People {
    @RootContext
    Context context;
    String name;
    int age;
    public void say()
    {
        Toast.makeText(context, "I'm "+name+" I "+age+" years old.", Toast.LENGTH_LONG).show();
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

用了androidannotations的@RootContext,上面的context会自动取到,不会为空。 PeopleAIDL.aidl:

package com.example.aidl;

interface PeopleAIDL {
    void setAge(int age);
    void setName(String name);
    void say();
}

网上的文章都称这个文件要放在包目录下,如果是多个包,到底是AndroidManifest.xml中声明的package还是其他包,没测试。保存后,ADT会在gen下的同名包下生成PeopleAIDL.java. AIDLService.java:

package com.example.aidl;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

import com.googlecode.androidannotations.annotations.Bean;
import com.googlecode.androidannotations.annotations.EService;

@EService
public class AIDLService extends Service {
    @Bean
    People people=new People();
    PeopleAIDL.Stub stub=new PeopleAIDL.Stub() {
        //下面的方法都是供远程调用的
        public void setName(String name) throws RemoteException {
            // TODO Auto-generated method stub
            people.setName(name);
        }
        
        public void setAge(int age) throws RemoteException {
            // TODO Auto-generated method stub
            people.setAge(age);
        }
        
        public void say() throws RemoteException {
            // TODO Auto-generated method stub
            people.say();
        }
    };
    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        //onBind方法要返回PeopleAIDL.Stub
        return stub;
    }
    
}

MainActivity.java:

package com.example.aidl;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.widget.Button;

import com.googlecode.androidannotations.annotations.Click;
import com.googlecode.androidannotations.annotations.EActivity;
import com.googlecode.androidannotations.annotations.ViewById;

@EActivity(R.layout.activity_main)
public class MainActivity extends Activity {
    PeopleAIDL peopleAIDL;
    @ViewById
    Button button1,button2,button3,button4,button5;

    ServiceConnection conn = new ServiceConnection(){
        public void onServiceConnected(ComponentName className, IBinder service) {
            //服务绑定成功,绑定动作好像是异步的
            peopleAIDL=PeopleAIDL.Stub.asInterface(service);
        }

        public void onServiceDisconnected(ComponentName className) {
        
        }
    };
    //下面是几个按钮的点击事件
    @Click
    void button1()
    {
        //绑定启动服务
        bindService(new Intent(this, AIDLService_.class), conn, Context.BIND_AUTO_CREATE);
        startService(new Intent(this, AIDLService_.class));
    }
    @Click
    void button2()
    {
        try {
            peopleAIDL.setName("zhangshan");
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    @Click
    void button3()
    {
        try {
            peopleAIDL.setAge(23);
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    @Click
    void button4()
    {
        try {
            peopleAIDL.say();
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    @Click
    void button5()
    {
        //SecondActivity后加_是因为用了androidannotations
        Intent intent=new Intent(this,SecondActivity_.class);
        startActivity(intent);
    }
    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        //退出时必须unbindService
        unbindService(conn);
        //如果Service仍需要在后台运行,不需要下面的这句
        stopService(new Intent(this, AIDLService_.class));
    }
}

SecondActivity.java:

package com.example.aidl;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.widget.Button;

import com.googlecode.androidannotations.annotations.Click;
import com.googlecode.androidannotations.annotations.EActivity;
import com.googlecode.androidannotations.annotations.ViewById;

@EActivity(R.layout.second_activity)
public class SecondActivity extends Activity {
    PeopleAIDL peopleAIDL;
    @ViewById
    Button button1,button2;
    
    private ServiceConnection conn = new ServiceConnection(){
        public void onServiceConnected(ComponentName className, IBinder service) {
            peopleAIDL=PeopleAIDL.Stub.asInterface(service);
        }

        public void onServiceDisconnected(ComponentName className) {
        }
    };
    
    @Click
    void button1()
    {
        bindService(new Intent(this, AIDLService_.class), conn, Context.BIND_AUTO_CREATE);
               //如果调用的是另一个应用的Service,使用new Intent("Service的Action");
    }
    @Click
    void button2()
    {
        try {
            peopleAIDL.say();
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

若调用的是另一个应用的Service,需要那个应用声明Service时加上Action,如:

        <service android:name=".service.GCService" >
            <intent-filter>
                <action android:name="com.pocketdigi.service.GCservice" />
            </intent-filter>
        </service>

在bindService的Intent里传入这个Action. 需要注意的是,两个应用的AIDL文件必须完全一致,包括在包名。

使用@EBean的JavaBean,能直接取到调用他的Context,支持@ViewById标签找到控件,因此,构造方法传过来的参数可以少很多。 上代码:

package com.example.androidannotations;

import android.content.Context;
import android.widget.TextView;
import android.widget.Toast;

import com.googlecode.androidannotations.annotations.AfterInject;
import com.googlecode.androidannotations.annotations.Background;
import com.googlecode.androidannotations.annotations.EBean;
import com.googlecode.androidannotations.annotations.RootContext;
import com.googlecode.androidannotations.annotations.UiThread;
import com.googlecode.androidannotations.annotations.ViewById;

@EBean
public class Student {
    //RootContext能取到调用该Bean的Context,构造方法不再需要传Context参数
    @RootContext
    Context context;
    @RootContext
    MainActivity activity;
    //ViewById也能在这里直接使用
    @ViewById
    TextView tv;
    public void Toast()
    {
        Toast.makeText(context, "在Ebean中调用", Toast.LENGTH_LONG).show();
    }
    //后台线程执行
    @Background
    public void backThread()
    {
        for(int i=0;i<9999;i++)
        {
            try {
                Thread.sleep(1000);
//				activity.updateTv(i);
                //更新UI,调用在UI线程执行的方法
                updateTv(i);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
        }
    }
    //UiThread在UI线程执行
    @UiThread
    public void updateTv(int i)
    {
        tv.setText(String.valueOf(i));
    }
    //AfterInject在构造方法执行完成后执行
    @AfterInject
    public void doSomethingAfterInject()
    {
        System.out.println("Student AfterInject");
    }

}

在Activity中的调用方法:

package com.example.androidannotations;

import android.app.Activity;
import android.text.Editable;
import android.widget.EditText;
import android.widget.TextView;

import com.googlecode.androidannotations.annotations.AfterTextChange;
import com.googlecode.androidannotations.annotations.AfterViews;
import com.googlecode.androidannotations.annotations.Bean;
import com.googlecode.androidannotations.annotations.Click;
import com.googlecode.androidannotations.annotations.EActivity;
import com.googlecode.androidannotations.annotations.Fullscreen;
import com.googlecode.androidannotations.annotations.NoTitle;
import com.googlecode.androidannotations.annotations.UiThread;
import com.googlecode.androidannotations.annotations.ViewById;
import com.googlecode.androidannotations.annotations.res.StringRes;

//Eactivity注释可以设置Layout,相当于setConentView方法
@EActivity(R.layout.activity_main)
@Fullscreen
@NoTitle
public class MainActivity extends Activity {
    //ViewById注释功能与findViewById相同,如果声明的变量名就是id,可以省去参数,否则应加上id,如ViewById(R.id.tv)
    
    @ViewById
    TextView tv;
    @ViewById
    EditText edit;
    @StringRes(R.string.hello_world)
    String hello;
    //需要使用@Bean标签
    @Bean
    Student stu;
    //AfterViews注释定义的方法会在OnCreate方法的setContentView后执行
    @AfterViews
    void init()
    {
        tv.setText("asfsdf");
    }
    //在EditText内容改变时,更新TextView内容
    @AfterTextChange(R.id.edit)
    void afterEditChange(Editable text, TextView hello)
    {
        tv.setText(hello.getText());
    }
    //点击TextView时调用
    @Click(R.id.tv)
    void tvClicked()
    {
        stu.Toast();
        stu.backThread();
    }
    //在stu中也可以回调这个方法来更新UI
    @UiThread
    public void updateTv(int i)
    {
        tv.setText(String.valueOf(i));
    }

    
}

AndroidAnnotations是一个第三方框架,通过注释来开发应用。使用AndroidAnnotations能大大减少代码量。 上个最简单的例子,在Eclipse中新建Android项目会自动生成一个Hello World的Activity,下面的例子是修改TextView的Text属性。

package com.example.androidannotations;
import android.app.Activity;
import android.widget.TextView;

import com.googlecode.androidannotations.annotations.AfterViews;
import com.googlecode.androidannotations.annotations.EActivity;
import com.googlecode.androidannotations.annotations.ViewById;

//Eactivity注释可以设置Layout,相当于setConentView方法
@EActivity(R.layout.activity_main)
public class MainActivity extends Activity {
    //ViewById注释功能与findViewById相同,如果声明的变量名就是id,可以省去参数,否则应加上id,如ViewById(R.id.tv)
    @ViewById
    TextView tv;
    //AfterViews注释定义的方法会在OnCreate方法的setContentView后执行
    @AfterViews
    void init()
    {
        tv.setText("asfsdf");
    }
}

源代码托管在GitHub,https://github.com/excilys/androidannotations/,怎么配置项目请参考Wiki. 下面是常用注释的使用方法: AfterInject 定义的方法在类的构造方法执行后执行 AfterTextChange 定义的方法在TextView及其子类的Text属性改变后执行 AfterViews 定义的方法在setContentView后执行 Background 定义的方法在后台线程执行 BeforeTextChange 定义的方法在TextView及其子类的Text属性改变前执行 Click 定义点击监听器 EActivity 在Activity中启用Annotations EProvider 在 ContentProvider中启用Annotations EReceive 在BroadcastReceiver中启用Annotations EService 在Service中启用Annotations EView 在自定义的View的子类中启用Annotations Fullscreen 全屏 NoTitle 无标题栏

项目需要,在Activity加载时通过代码动态在屏幕上显示数量位置不等的按钮,因为按钮的位置都根据底下的一张图片来确定的(其实就是Google地图的大头针功能),如果在onCreate或onResume事件中计算按钮数量及位置,因为底部的图片没加载完,无法得到想要的结果,Activity在UI加载完成后,会获取到焦点,调用onWindowFocusChanged事件,因些,只需重写这个事件,在这里计算即可。

有个项目需要动态确定TextView的位置,需要把TextView的中心点放在指定的坐标,但发现,构建了TextView后,无法用getHeight和getWidth方法取到高宽度,返回都是0. 用下面的方法可以取到所占的宽度:

        Paint paint=new Paint();
        paint.setTextSize(21.6f);//设置字符大小
        int textWidth=(int)paint.measureText(text, 0, text.length());

dismiss和hide方法都可以隐藏对话框,在需要的时候也可以用show方法调用显示。但是,这两者是有区别的。 dismiss方法会释放对话框所占的资源,而hide方法不会。activity退出前必须调用dismiss方法关闭对话框。 如果对话框上有progressbar,你会发现,调用dismiss方法后,再调用show方法,出来的对话框,上面的progressbar不再会转动,而调用hide方法的则没有问题。 所以,最正确的调用方法是,在activity的onDestory方法里调用dismiss方法,其他地方都用hide方法隐藏对话框。

匀速旋转,就是能过设置加速器android:interpolator,但是在xml中设置:

android:interpolator="@android:anim/linear_interpolator"

发现没有任何效果,还是加速的。 在代码中设置,解决:

        LinearInterpolator lir = new LinearInterpolator();
        rotate.setInterpolator(lir);

javadoc使用可以将在代码中的注释生成文档,方便其他开发者调用。本文不对javadoc作详细的介绍,只记录最简单最常用的情景。 使用方法: javadoc 选项 包名 选项: -public 只显示公有类及成员。 -protected 只显示受保护的和公有的类及成员。这是缺省状态。 -package 只显示包、受保护的和公有的类及成员。 -private 显示所有类和成员。 -windowtitle 窗口标题 -d doc 生成在doc 目录下 乱码问题,根据项目的编码设置: -encoding gbk -charset gbk 示例(cmd下先进src目录): javadoc -public -d doc -windowstitle API文档 com.pocketdigi com.pocketdigi.video 上面的命令,生成com.pocketdigi和com.pocketdigi.video两个包中,带public修饰符的类和方法的文档,生成的html标题为API文档,存放在doc目录下 另外,简单一点,可以使用Eclipse的导出功能,导出javadoc

当用户请求Action的一个方法时,ThinkPHP会检测该方法有没有前置或者后置操作。如,用户请求默认的index方法,系统会先检查有没有 _before_index方法,如果有,先执行_before_index方法,再执行index方法,执行完index方法后,会检测是否有_after_index方法,如果有,则执行。