0%

SimpleDateFormat可以按我们的要求的格式输出时间,比较简单,直接上代码:

        Date d = new Date();
        System.out.println(d);
        DateFormat format=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //y=年,M=月,d=日,h=时,m=分,s=秒
        System.out.println(format.format(d));

输出结果如下: Tue Jul 19 08:26:02 CST 2011 2011-07-19 08:26:02

MediaRecorder可以很方便的拍照、录像、录音,本文只介绍录音的使用方法。虽然录音时声源可以选择通话,但是在真机上运行不行,不知如何解决,我机上(i897 lidroid 2.2 Rom)的录音通话软件很好用,所以说理论上还有有方法实现的,毕竟已经有人实现了。下面上代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<Button android:id="@+id/start"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="开始录音"
/>
<Button android:id="@+id/stop"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="停止"
/>
</LinearLayout>

两个按钮,一个开始,一个停止。

package com.pocketdigi;

import android.app.Activity;
import android.media.MediaRecorder;
import android.media.MediaRecorder.AudioSource;
import android.media.MediaRecorder.OutputFormat;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MediaRecorderActivity extends Activity {
    Button start,stop;
    MediaRecorder mr;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        start=(Button)findViewById(R.id.start);
        stop=(Button)findViewById(R.id.stop);
        

        start.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                mr=new MediaRecorder();
                mr.setAudioSource(AudioSource.MIC);
                //设置音源,这里是来自麦克风,虽然有VOICE_CALL,但经真机测试,不行
                mr.setOutputFormat(OutputFormat.RAW_AMR);
                //输出格式
                mr.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
                //编码
                mr.setOutputFile("/sdcard/1.amr");
                //输出文件路径,貌似文件必须是不存在的,不会自己清空
                try{
                    mr.prepare();
                    //做些准备工作
                    mr.start();
                    //开始
                }catch(Exception e){
                    e.printStackTrace();
                }
            }});
        stop.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                mr.stop();
                                mr.reset();
                //停止
                mr.release();
                //释放
            }});
        
    }
}

注意添加权限:

    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

不加权限会出现类似unsupported parameter: x-pvmf/media-input-node/cap-config-interface;valtype=key_specific_value之类的错误 源码打包: [download id=”20”]

要在ListView里实现多选,前面说过ListView加入CheckBox 自己实现多选MULTIPLE CHOICE,如果你的需求比较简单,用自带的simple_list_item_multiple_choice就可以了. 布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<ListView android:id="@+id/list"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:cacheColorHint="@null"
  />
  <Button android:id="@+id/btn"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:text="获取选中ID"
  />
</LinearLayout>

一个ListView,一个Button Java代码:

package com.pocketdigi;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

public class Test2Activity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        final ListView lv=(ListView)findViewById(R.id.list);
        String[] Names=new String[]{"a","b","c"};
        ArrayAdapter Adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_multiple_choice, Names);
        //使用系统内置的layout
        lv.setAdapter(Adapter);
        lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
        //设置多选模式
        Button btn=(Button)findViewById(R.id.btn);
        btn.setOnClickListener(new OnClickListener(){

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                long[] ids=lv.getCheckItemIds();
                //得到选中的itemId
                String str="";
                for(int i=0;i

默认情况下,重写onKeyDown方法是无法捕捉到HOME键的,原因不太清楚,不过我想是因为系统也在捕捉HOME键,而且优先级比我们的程序要高.我们可以通过修改窗口类型来达到我们的目的. 首先重写onAttachedToWindow方法:

    @Override
    public void onAttachedToWindow() {
        // TODO Auto-generated method stub
        super.onAttachedToWindow();
        this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);
                        //设置窗口类型
    }

onAttachedToWindow 在API文档中英文原文解释:Called when the main window associated with the activity has been attached to the window manager.在主窗口被关联到被附加到窗口管理器的Activity时调用,其实说得模糊点应该就是在Activity启动时调用的.加了这个后,在UI上有点小变化,如果你的Activity不是占满全屏的(AlertDialog样式),默认情况下是会显示Activity下面的窗口的(没有被遮住的部分),但是加了这个以后,Activity以外的空间是全黑的. 然后就可以在onKeyDown里捕捉到了:

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        // TODO Auto-generated method stub
        
        if(keyCode==KeyEvent.KEYCODE_HOME){
            System.out.println("按到HOME键");
            return false;
        }
        return super.onKeyDown(keyCode, event);
    }

前面讲过AudioManager可以修改系统的情景模式,其实看它名字,就知道Android系统的音量也是由它管理的.下面介绍几个AudioManager的几个音量调整方面的方法. 首先是得到AudioManager实例:

AudioManager am=(AudioManager)getSystemService(Context.AUDIO_SERVICE);

调整音量方法有两种,一种是渐进式,即像手动按音量键一样,一步一步增加或减少,另一种是直接设置音量值. 首先是步进的方法: public void adjustStreamVolume (int streamType, int direction, int flags)

am.adjustStreamVolume (AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FLAG_SHOW_UI); 

解释一下三个参数 第一个streamType是需要调整音量的类型,这里设的是媒体音量,可以是: STREAM_ALARM 警报 STREAM_MUSIC 音乐回放即媒体音量 STREAM_NOTIFICATION 窗口顶部状态栏Notification, STREAM_RING 铃声 STREAM_SYSTEM 系统 STREAM_VOICE_CALL 通话 STREAM_DTMF 双音多频,不是很明白什么东西 第二个direction,是调整的方向,增加或减少,可以是: ADJUST_LOWER 降低音量 ADJUST_RAISE 升高音量 ADJUST_SAME 保持不变,这个主要用于向用户展示当前的音量 第三个flags是一些附加参数,只介绍两个常用的 FLAG_PLAY_SOUND 调整音量时播放声音 FLAG_SHOW_UI 调整时显示音量条,就是按音量键出现的那个 然后是直接设置音量值的方法: public void setStreamVolume (int streamType, int index, int flags)

am.setStreamVolume(AudioManager.STREAM_MUSIC, am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), AudioManager.FLAG_PLAY_SOUND);

第一个和第三个参数与上面的相同,第二个参数是一个音量的int值,getStreamMaxVolume(int streamType)得到的是该类型音量的最大值,可以根据这个值计算你需要的音量,我这里直接调到最大.

前面已经介绍过用ContentProvider读取手机内的音频文件,今天学习下读取联系人信息.为了简便,我想以后所有演示程序信息都用System.out.println输出,不会显示在手机屏幕上,需要到Eclipse的Logcat里查看.其实读取联系人跟读取音频\视频之类的信息没有什么区别,无非表不同 字段不同.需要android.permission.READ_CONTACTS权限

package com.hello;
 
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.MediaStore;
import android.provider.ContactsContract.PhoneLookup;
 
public class HelloWorldActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ContentResolver cr = getContentResolver();
        Uri URI = ContactsContract.Contacts.CONTENT_URI;
        String[] columns  = new String[] {ContactsContract.Contacts._ID,PhoneLookup.DISPLAY_NAME};
        //查询联系人ID和联系人名称两列
        Cursor cursor = cr.query(URI, columns, PhoneLookup.HAS_PHONE_NUMBER+"=1", null, null);
        //限定只返回有号码的联系人
        while(cursor.moveToNext()){
            String phoneNum="";
            Cursor cursor2=cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER}, 
                    ContactsContract.CommonDataKinds.Phone.CONTACT_ID+"="+cursor.getLong(0), null, null);
            //因为号码与联系人不存在一个表中,一个联系人可能存在多个号码,所以根据联系人ID查找号码,存在phoneNum中
            while(cursor2.moveToNext()){
                phoneNum+=cursor2.getString(0)+" ";
                //循环把该联系的所属的号码加进phoneNum
            }
            cursor2.close();
            System.out.println(cursor.getLong(0)+":"+cursor.getString(1)+phoneNum);
            //循环输出ID,名称,号码
        }
        cursor.close();
    }
 
}

2011年7月18日加注:如果短信内容过长,可以使用SmsManager.divideMessage(String text)方法自动拆分成一个ArrayList数组,再根据数组长度循环发送,或者直接用sendMultipartTextMessage方法发送,参数与sendTextMessage类似,无非是短信内容变成了用divideMessage拆成的ArrayList,两个广播也是,所以不再写例子. 前面说到可以通过发送Intent的方式跳转到短信发送界面,让用户自行发送短信,今天学习的SmsManager可以在后台发送短信,无需用户操作,某些无良开发者就用这个SmsManager功能在后台偷偷给SP发短信,导致用户话费被扣.其实,这些应用还是很好分辨的,因为要通过SmsManager发送短信,必须添加android.permission.SEND_SMS权限,在安装的时候稍稍注意就可以了,当然也有通过在程序中下载其他有短信权限的应用,后台安装发送短信的情况,在安装的时候注意该应用是否有安装其他应用的权限(android.permission.INSTALL_PACKAGES),如果没有这个权限,安装应用是必须先经过用户点击的. 下面贴上代码:

package com.hello;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.telephony.SmsManager;

public class HelloWorldActivity extends Activity {
    /** Called when the activity is first created. */
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        String action="com.pocketdigi";
        
        sendReceiver receiver=new sendReceiver();
        IntentFilter filter=new IntentFilter();
        filter.addAction(action);
        registerReceiver(receiver,filter);
        //必须先注册广播接收器,否则接收不到发送结果
        
        SmsManager smsMgr = SmsManager.getDefault(); 
        Intent intent = new Intent(action);
        PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent, 0);
        smsMgr.sendTextMessage("10086", null, "1561", pi, null);
        //参数分别为号码,短信服务中心号码(null即可),短信内容,短信发送结果广播PendingIntent,短信到达广播
     //关于短信到达广播(对方接收到短信时广播),据网上说,中国移动有,中国联通没有,有兴趣的同学自己试试,没兴趣直接null
    }
    
    class sendReceiver extends BroadcastReceiver{
        //写个接收器
        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub
            int resultCode = getResultCode();
            if(resultCode==Activity.RESULT_OK){
                System.out.println("发送成功");
            }else{
                System.out.println("发送失败");
            }
        }
    }
}

ContentProvider是Android里一个很重要的组件,可以让我们很方便地读取系统内各种共享的数据,如联系人,音频,视频,图片等.在系统开机,或者插入SD卡后,系统会自动索引卡内的媒体文件,存入数据库,其他应用程序需要调用时可以通过ContentProvider来获取.ContentProvider的使用跟SQLite数据库非常相似,只是查询的表名改成了相应的Uri.

package com.hello;

import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;

public class HelloWorldActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ContentResolver cr = getContentResolver();
        //ContentProvider只能由ContentResolver发送请求
        Uri AUDIO_URI = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        //获取音频文件的URI,
        //视频 MediaStore.Video.Media.EXTERNAL_CONTENT_URI
        //图片MediaStore.Images.Media.EXTERNAL_CONTENT_URI
        String[] columns  = new String[] {MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA};
        //要读的列名,这些常量可以查GOOGLE官方开发文档,TITLE是标题 DATA是路径
        Cursor cursor = cr.query(AUDIO_URI, columns, MediaStore.Audio.Media.DURATION+">?", new String[]{"10000"}, null);
        //跟查询SQL一样了,除了第一个参数不同外.后面根据时长过滤小于10秒的文件
        while(cursor.moveToNext()){
            //循环读取第一列,即文件路径,0列是标题
            System.out.println(cursor.getString(1));
        }
        cursor.close();
       
        
    }

}

Android中系统的声音以及振动是通过AudioManager来管理的. 切换情景模式只需要两句代码:

        AudioManager am=(AudioManager)getSystemService(Context.AUDIO_SERVICE);
        //得到AudioManager对象
        am.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
        //参数为 设置情景模式的类型
        //AudioManager.RINGER_MODE_NORMAL 正常模式,有声,是否震动取决于原来系统声音设置中振动的设置
        //AudioManager.RINGER_MODE_SILENT 静音模式,无声不震
        //AudioManager.RINGER_MODE_VIBRATE 震动模式,无声,震动

在Android中设置飞行状态是用BroadCast的,可以通过发送action为”Intent.ACTION_AIRPLANE_MODE_CHANGED”的广播来打开或状态飞行模式. 首先,修改飞行模式需要android.permission.WRITE_SETTINGS权限,请自行添加. 下面是完整代码:

package com.hello;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import android.provider.Settings;
//虽然只用到Settings.System类,但还是不建议直接导入该类,因为会跟java.lang.System同名冲突
//当然也可以不导,直接用android.provider.Settings.System
public class HelloWorldActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ContentResolver cr = getContentResolver();
        if(Settings.System.getString(cr,Settings.System.AIRPLANE_MODE_ON).equals("0")){
            //获取当前飞行模式状态,返回的是String值0,或1.0为关闭飞行,1为开启飞行
            //如果关闭飞行,则打开飞行
            Settings.System.putString(cr,Settings.System.AIRPLANE_MODE_ON, "1");
            Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
            sendBroadcast(intent);
        }else{
            //否则关闭飞行
            Settings.System.putString(cr,Settings.System.AIRPLANE_MODE_ON, "0");
            Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
            sendBroadcast(intent);
        }
        
    }

}