startActivityForResult与onActivityResult(转)

androidActivity之间的跳转不只是有startActivity(Intent i)的,startActivityForResult(Intent intent, int requestCode)也是常用的方法。

其作用是可以用onActivityResult(int requestCode, int resultCode, Intent data)方法获得请求Activity结束之后的操作。
需要注意三个方法:startActivityForResult(Intent intent, int requestCode),onActivityResult(int requestCode, int resultCode, Intent data),setResult(int resultCode, Intent data)
例如如下代码:从From跳转至ToB和ToC
From:
if(条件){
Intent intent = new Intent(this, ToB.class);
startActivityForResult(serverIntent, REQUEST_CODE_01);//跳转至ToB
}else{
Intent intent = new Intent(this, ToC.class);
startActivityForResult(serverIntent, REQUEST_CODE_02);//跳转至ToC
}
public void onActivityResult(int requestCode, int resultCode, Intent data){
          switch (requestCode) {
case REQUEST_CODE_01:
                        if(resultCode==Activity.RESULT_OK)
                        //do something
                        break;
                case REQUEST_CODE_02:
//do something
                        break;
}
}
这里说说startActivityForResult(Intent intent, int requestCode)的参数,第一个Intent不用说了,需要注意的是第二个,我们用的是REQUEST_CODE_01和REQUEST_CODE_02,其实这个是我们自己定义的一个int型常量,用于标记的,具体作用可在onActivityResult方法里看到,用于判断是从哪个Activity返回的。
ToB:
Intent intent = new Intent();
intent.putExtra(key, value);
setResult(Activity.RESULT_OK, intent);
finish();//结束之后会将结果传回From
ToC:
Intent intent = new Intent();
intent.putExtra(key, value);
setResult(Activity.RESULT_OK, intent);
finish();//结束之后会将结果传回From
setResult的第一个参数对应上面onActivityResult的第二个参数,注意别把onActivityResult的第一个参数与第二个参数搞混淆了,一个是请求标记,一个是返回标记。
欢迎补充~~~

Android调用相机并将照片存储到sd卡上

Android中实现拍照有两种方法,一种是调用系统自带的相机,然后使用其返回的照片数据。 还有一种是自己用Camera类和其他相关类实现相机功能,这种方法定制度比较高,洗染也比较复杂,一般平常的应用只需使用第一种即可。

用Intent启动相机的代码:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);

拍完照后就可以在onActivityResult(int requestCode, int resultCode, Intent data)中获取到Bitmap对象了。

Bitmap bitmap = (Bitmap) data.getExtras().get("data");
要将图像存储到sd卡之前最好先检查一下sd卡是否可用

    String sdStatus = Environment.getExternalStorageState();
if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { // 检测sd是否可用
Log.v("TestFile",
"SD card is not avaiable/writeable right now.");
return;
}
以下代码可以实现将图像文件存到“sdcard/myImage/”文件夹下,名称为“111.jpg”

复制代码
            File file = new File("/sdcard/myImage/");
file.mkdirs();// 创建文件夹
String fileName = "/sdcard/myImage/111.jpg";

try {
b = new FileOutputStream(fileName);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, b);// 把数据写入文件
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
b.flush();
b.close();
} catch (IOException e) {
e.printStackTrace();
}
}

复制代码
另外要注意的是读写sd卡文件必须首先要在Mainifest.xml文件中配置权限:

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

一个demo,实现调用系统相机拍照,将其显示在屏幕上,并且存到sd卡。

完整代码如下:

MyCaremaActivity.java

复制代码
package barry.android.c;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class MyCaremaActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Button button = (Button) findViewById(R.id.button);

button.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);
}
});
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (resultCode == Activity.RESULT_OK) {

String sdStatus = Environment.getExternalStorageState();
if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { // 检测sd是否可用
Log.v("TestFile",
"SD card is not avaiable/writeable right now.");
return;
}

Bundle bundle = data.getExtras();
Bitmap bitmap = (Bitmap) bundle.get("data");// 获取相机返回的数据,并转换为Bitmap图片格式
FileOutputStream b = null;
File file = new File("/sdcard/myImage/");
file.mkdirs();// 创建文件夹
String fileName = "/sdcard/myImage/111.jpg";

try {
b = new FileOutputStream(fileName);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, b);// 把数据写入文件
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
b.flush();
b.close();
} catch (IOException e) {
e.printStackTrace();
}
}

((ImageView) findViewById(R.id.imageView)).setImageBitmap(bitmap);// 将图片显示在ImageView里
}
}
}

复制代码

 

main.xml

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

<Button
android:id="@+id/button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="点击启动相机" />

<ImageView
android:id="@+id/imageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#999999" />

</LinearLayout>

复制代码
AndroidMainifest.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="barry.android.c"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk android:minSdkVersion="7" />

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

<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".MyCaremaActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

复制代码

升级ADT v14/15/16等,修改代码后bin目录下不自动生成apk的解决方案(转)

升级到ADT v14/15/16,修改代码后bin目录下不自动生成apk的解决方案

ADT14引入的功能,不自动生成apk,除非export或者Run/Debug。

参考:http://developer.android.com/sdk/eclipse-adt.htmlADT R14

进入Preferences -> Android -> Build -> 去选“Skip packaging and dexing ...”选项。


Eclipse 生成android程序apk文件(转)

转自:http://www.open-open.com/lib/view/open1328973035359.html

1、Eclipse工程中右键工程,弹出选项中选择 android工具 → 生成签名应用包:

Eclipse 生成android程序apk文件

2、选择需要打包的android项目工程:

Eclipse 生成android程序apk文件

3、如果已有私钥文件,选择私钥文件 输入密码,如果没有私钥文件见第6和7步创建私钥文件:

Eclipse 生成android程序apk文件

4、输入私钥别名和密码:

Eclipse 生成android程序apk文件

5、选择APK包存储的位置,并完成设置,开始生成APK签名包:

Eclipse 生成android程序apk文件

6、没有私钥文件的情况,创建私钥文件:

Eclipse 生成android程序apk文件

7、输入私钥文件所需信息,并创建:

Eclipse 生成android程序apk文件
Eclipse 生成android程序apk文件

Android带删除按钮的ListView(转)

不用说了,上图先:

带删除 按钮的ListView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.util.ArrayList;
import com.ql.adapter.DeletableAdapter;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
public class Test_4_Activity extends Activity {
    private DeletableAdapter adapter;
    private ArrayList<String> text;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test4);
        ListView list_view = (ListView) findViewById(R.id.list_view);
        text = new ArrayList<String>();
        text.add("111");
        text.add("222");
        text.add("333");
        text.add("444");
        // 初始化数据结束
        adapter = new DeletableAdapter(this, text);
        list_view.setAdapter(adapter);
        // list_view.setSelector(R.drawable.list_select_color);
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                text.add("10000");
                adapter.notifyDataSetChanged();
            }
        });
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.ql.activity.R;
public class DeletableAdapter extends BaseAdapter {
    private Context context;
    private ArrayList<String> text;
    public DeletableAdapter(Context context, ArrayList<String> text) {
        this.context = context;
        this.text = text;
    }
    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return text.size();
    }
    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return text.get(position);
    }
    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        final int index = position;
        View view = convertView;
        if (view == null) {
            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.row_simple_list_item_2, null);
        }
        final TextView textView = (TextView) view
                .findViewById(R.id.simple_item_1);
        textView.setText(text.get(position));
        final ImageView imageView = (ImageView) view
                .findViewById(R.id.simple_item_2);
        imageView.setBackgroundResource(android.R.drawable.ic_delete);
        imageView.setTag(position);
        imageView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                text.remove(index);
                notifyDataSetChanged();
                Toast.makeText(context, textView.getText().toString(),
                        Toast.LENGTH_SHORT).show();
            }
        });
        return view;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">
    <ImageView
        android:id="@+id/simple_item_2"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_alignParentRight="true"
        android:focusable="false" />
    <TextView
        android:id="@+id/simple_item_1"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_alignParentLeft="true" />
</RelativeLayout>

这里要实现点击ListView里面的一个控件而不是选中一行。

最好重写Adapter,而不要使用其自带的SimpleAdapter,否则该子控件的事件就不那么好处理了!


Android 详解SQLite存储方式,并把SQLite的数据库文件存储在SD卡中!!!(转)

原文地址: http://blog.csdn.net/xiaominghimi/archive/2011/01/04/6114629.aspx

上一篇跟各位童鞋介绍了SharedPreference 和 File流如何存储数据,并且推荐使用FileOutputStream/FileInputStream来存储咱们游戏数据,那么这一篇则是像大家介绍另外一种适合游戏数据存储的方式:SQLite 轻量级数据库!

先介绍几个基本概念知识:

什么是SQLite:

SQLite是一款轻量级数据库,它的设计目的是嵌入式,而且它占用的资源非常少,在嵌入式设备中,只需要几百KB!!!!!

SQLite的特性:

  • 轻量级
    使用 SQLite 只需要带一个动态库,就可以享受它的全部功能,而且那个动态库的尺寸想当小。
  • 独立性
    SQLite 数据库的核心引擎不需要依赖第三方软件,也不需要所谓的“安装”。
  • 隔离性
    SQLite 数据库中所有的信息(比如表、视图、触发器等)都包含在一个文件夹内,方便管理和维护。
  • 跨平台
    SQLite 目前支持大部分操作系统,不至电脑操作系统更在众多的手机系统也是能够运行,比如:Android。
  • 多语言接口
    SQLite 数据库支持多语言编程接口。
  • 安全性
    SQLite 数据库通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只能有一个可以写入数据.

优点:1.能存储较多的数据。

2.能将数据库文件存放到SD卡中!

什么是 SQLiteDatabase? 

一个 SQLiteDatabase 的实例代表了一个SQLite 的数据库,通过SQLiteDatabase 实例的一些方法,我们可以执行SQL 语句,对数        据库进行增、删、查、改的操作。需要注意的是,数据库对于一个应用来说是私有的,并且在一个应用当中,数据库的名字也是惟一的。

什么是 SQLiteOpenHelper ?

根据这名字,我们可以看出这个类是一个辅助类。这个类主要生成一个数据库,并对数据库的版本进行管理。当在程序当中调用这个类的        方法getWritableDatabase(),或者getReadableDatabase()方法的时候,如果当时没有数据,那么Android 系统就会自动生成一        个数  据库。SQLiteOpenHelper 是一个抽象类,我们通常需要继承它,并且实现里边的3 个函数,

什么是 ContentValues 类?

ContentValues 类和Hashmap/Hashtable 比较类似,它也是负责存储一些名值对,但是它存储的名值对当中的名是一个

String 类型,而值都是基本类型。

什么是 Cursor ?

Cursor 在Android 当中是一个非常有用的接口,通过Cursor 我们可以对从数据库查询出来的结果集进行随  机的读写访问。

OK,基本知识就介绍到这里,下面开始上代码:还是按照我的一贯风格,代码中该解释的地方都已经在代码中及时注释和讲解了!

顺便来张项目截图:

先给出xml:

 

Xhtml代码 
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     android:orientation="vertical" android:layout_width="fill_parent"
  4.     android:layout_height="fill_parent">
  5.     <TextView android:layout_width="fill_parent"
  6.         android:layout_height="wrap_content" android:text="SQL 练习!(如果你使用的SD卡存储数据方式,为了保证正常操作,请你先点击创建一张表然后再操作)"
  7.         android:textSize="20sp" android:textColor="#ff0000" android:id="@+id/tv_title" />
  8.     <Button android:id="@+id/sql_addOne" android:layout_width="fill_parent"
  9.         android:layout_height="wrap_content" android:text="插入一条记录"></Button>
  10.     <Button android:id="@+id/sql_check" android:layout_width="fill_parent"
  11.         android:layout_height="wrap_content" android:text="查询数据库"></Button>
  12.     <Button android:id="@+id/sql_edit" android:layout_width="fill_parent"
  13.         android:layout_height="wrap_content" android:text="修改一条记录"></Button>
  14.     <Button android:id="@+id/sql_deleteOne" android:layout_width="fill_parent"
  15.         android:layout_height="wrap_content" android:text="删除一条记录"></Button>
  16.     <Button android:id="@+id/sql_deleteTable" android:layout_width="fill_parent"
  17.         android:layout_height="wrap_content" android:text="删除数据表单"></Button>
  18.     <Button android:id="@+id/sql_newTable" android:layout_width="fill_parent"
  19.         android:layout_height="wrap_content" android:text="新建数据表单"></Button>
  20. </LinearLayout>

 

 

 

 xml中定义了我们需要练习用到的几个操作按钮,这里不多解释了,下面看java源码:先看我们继承的 SQLiteOpenHelper 类

 

Java代码 
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
  1. package com.himi;
  2. import android.content.Context;
  3. import android.database.sqlite.SQLiteDatabase;
  4. import android.database.sqlite.SQLiteOpenHelper;
  5. import android.util.Log;
  6. /**
  7.  *
  8.  * @author Himi
  9.  * @解释 此类我们只需要传建一个构造函数 以及重写两个方法就OK啦、
  10.  *
  11.  */
  12. public class MySQLiteOpenHelper extends SQLiteOpenHelper {
  13.     public final static int VERSION = 1;// 版本号
  14.     public final static String TABLE_NAME = "himi";// 表名
  15.     public final static String ID = "id";// 后面ContentProvider使用
  16.     public final static String TEXT = "text";
  17.     public static final String DATABASE_NAME = "Himi.db";
  18.     public MySQLiteOpenHelper(Context context) {
  19.         // 在Android 中创建和打开一个数据库都可以使用openOrCreateDatabase 方法来实现,
  20.         // 因为它会自动去检测是否存在这个数据库,如果存在则打开,不过不存在则创建一个数据库;
  21.         // 创建成功则返回一个 SQLiteDatabase对象,否则抛出异常FileNotFoundException。
  22.         // 下面是来创建一个名为"DATABASE_NAME"的数据库,并返回一个SQLiteDatabase对象
  23.         super(context, DATABASE_NAME, null, VERSION);
  24.     }
  25.     @Override
  26.     // 在数据库第一次生成的时候会调用这个方法,一般我们在这个方法里边生成数据库表;
  27.     public void onCreate(SQLiteDatabase db) {
  28.         String str_sql = "CREATE TABLE " + TABLE_NAME + "(" + ID
  29.                 + " INTEGER PRIMARY KEY AUTOINCREMENT," + TEXT + " text );";
  30.         // CREATE TABLE 创建一张表 然后后面是我们的表名
  31.         // 然后表的列,第一个是id 方便操作数据,int类型
  32.         // PRIMARY KEY 是指主键 这是一个int型,用于唯一的标识一行;
  33.         // AUTOINCREMENT 表示数据库会为每条记录的key加一,确保记录的唯一性;
  34.         // 最后我加入一列文本 String类型
  35.         // ----------注意:这里str_sql是sql语句,类似dos命令,要注意空格!
  36.         db.execSQL(str_sql);
  37.         // execSQL()方法是执行一句sql语句
  38.         // 虽然此句我们生成了一张数据库表和包含该表的sql.himi文件,
  39.         // 但是要注意 不是方法是创建,是传入的一句str_sql这句sql语句表示创建!!
  40.     }
  41.     @Override
  42.     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  43.         // 一般默认情况下,当我们插入 数据库就立即更新
  44.         // 当数据库需要升级的时候,Android 系统会主动的调用这个方法。
  45.         // 一般我们在这个方法里边删除数据表,并建立新的数据表,
  46.         // 当然是否还需要做其他的操作,完全取决于游戏需求。
  47.         Log.v("Himi", "onUpgrade");
  48.     }
  49. }

 

 

 

下面看最重要的MainActivity中的代码:

 

Java代码 
·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
  1. package com.himi;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import android.app.Activity;
  5. import android.content.ContentValues;
  6. import android.database.Cursor;
  7. import android.database.sqlite.SQLiteDatabase;
  8. import android.os.Bundle;
  9. import android.view.View;
  10. import android.view.Window;
  11. import android.view.WindowManager;
  12. import android.view.View.OnClickListener;
  13. import android.widget.Button;
  14. import android.widget.TextView;
  15. // ------------第三种保存方式--------《SQLite》---------
  16. /**
  17.  * @author Himi
  18.  * @保存方式:SQLite 轻量级数据库、
  19.  * @优点: 可以将自己的数据存储到文件系统或者数据库当中, 也可以将自己的数据存
  20.  *         储到SQLite数据库当中,还可以存到SD卡中
  21.  * @注意1:数据库对于一个游戏(一个应用)来说是私有的,并且在一个游戏当中,
  22.  *         数据库的名字也是唯一的。
  23.  * @注意2 apk中创建的数据库外部的进程是没有权限去读/写的,
  24.  *         我们需要把数据库文件创建到sdcard上可以解决类似问题.
  25.  * @注意3 当你删除id靠前的数据或者全部删除数据的时候,SQLite不会自动排序,
  26.  *        也就是说再添加数据的时候你不指定id那么SQLite默认还是在原有id最后添加一条新数据
  27.  * @注意4 android 中 的SQLite 语法区分大小写的!!!!!这点要注意!
  28.  *   String UPDATA_DATA = "UPDATE himi SET text='通过SQL语句来修改数据'  WHERE id=1";
  29.  *                  千万 不能可以写成
  30.  *   String UPDATA_DATA = "updata himi set text='通过SQL语句来修改数据'  where id=1";
  31.  */
  32. public class MainActivity extends Activity implements OnClickListener {
  33.     private Button btn_addOne, btn_deleteone, btn_check, btn_deleteTable,
  34.             btn_edit, btn_newTable;
  35.     private TextView tv;
  36.     private MySQLiteOpenHelper myOpenHelper;// 创建一个继承SQLiteOpenHelper类实例
  37.     private SQLiteDatabase mysql ;
  38. //---------------以下两个成员变量是针对在SD卡中存储数据库文件使用
  39. //  private File path = new File("/sdcard/himi");// 创建目录
  40. //  private File f = new File("/sdcard/himi/himi.db");// 创建文件
  41.     @Override
  42.     public void onCreate(Bundle savedInstanceState) {
  43.         super.onCreate(savedInstanceState);
  44.         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
  45.                 WindowManager.LayoutParams.FLAG_FULLSCREEN);
  46.         this.requestWindowFeature(Window.FEATURE_NO_TITLE);
  47.         setContentView(R.layout.main);
  48.         tv = (TextView) findViewById(R.id.tv_title);
  49.         btn_addOne = (Button) findViewById(R.id.sql_addOne);
  50.         btn_check = (Button) findViewById(R.id.sql_check);
  51.         btn_deleteone = (Button) findViewById(R.id.sql_deleteOne);
  52.         btn_deleteTable = (Button) findViewById(R.id.sql_deleteTable);
  53.         btn_newTable = (Button) findViewById(R.id.sql_newTable);
  54.         btn_edit = (Button) findViewById(R.id.sql_edit);
  55.         btn_edit.setOnClickListener(this);
  56.         btn_addOne.setOnClickListener(this);
  57.         btn_check.setOnClickListener(this);
  58.         btn_deleteone.setOnClickListener(this);
  59.         btn_deleteTable.setOnClickListener(this);
  60.         btn_newTable.setOnClickListener(this);
  61.         myOpenHelper = new MySQLiteOpenHelper(this);// 实例一个数据库辅助器
  62. //备注1  ----如果你使用的是将数据库的文件创建在SD卡中,那么创建数据库mysql如下操作:
  63. //      if (!path.exists()) {// 目录存在返回false
  64. //          path.mkdirs();// 创建一个目录
  65. //      }
  66. //      if (!f.exists()) {// 文件存在返回false
  67. //          try {
  68. //              f.createNewFile();//创建文件
  69. //          } catch (IOException e) {
  70. //              // TODO Auto-generated catch block
  71. //              e.printStackTrace();
  72. //          }
  73. //      }
  74.     }
  75.     @Override
  76.     public void onClick(View v) {
  77.         try {
  78. //备注2----如果你使用的是将数据库的文件创建在SD卡中,那么创建数据库mysql如下操作:
  79. //              mysql = SQLiteDatabase.openOrCreateDatabase(f, null);
  80. //备注3--- 如果想把数据库文件默认放在系统中,那么创建数据库mysql如下操作:
  81.                 mysql = myOpenHelper.getWritableDatabase(); // 实例数据库
  82.             if (v == btn_addOne) {// 添加数据
  83.                 // ---------------------- 读写句柄来插入---------
  84.                 // ContentValues 其实就是一个哈希表HashMap, key值是字段名称,
  85.                 //Value值是字段的值。然后 通过 ContentValues 的 put 方法就可以
  86.                 //把数据放到ContentValues中,然后插入到表中去!
  87.                 ContentValues cv = new ContentValues();
  88.                 cv.put(MySQLiteOpenHelper.TEXT, "测试新的数据");
  89.                 mysql.insert(MySQLiteOpenHelper.TABLE_NAME, null, cv);
  90.                 // inser() 第一个参数 标识需要插入操作的表名
  91.                 // 第二个参数 :默认传null即可
  92.                 // 第三个是插入的数据
  93.                 // ---------------------- SQL语句插入--------------
  94.                 // String INSERT_DATA =
  95.                 // "INSERT INTO himi (id,text) values (1, '通过SQL语句插入')";
  96.                 // db.execSQL(INSERT_DATA);
  97.                 tv.setText("添加数据成功!点击查看数据库查询");
  98.             } else if (v == btn_deleteone) {// 删除数据
  99.                 // ---------------------- 读写句柄来删除
  100.                 mysql.delete("himi", MySQLiteOpenHelper.ID + "=1", null);
  101.                 // 第一个参数 需要操作的表名
  102.                 // 第二个参数为 id+操作的下标 如果这里我们传入null,表示全部删除
  103.                 // 第三个参数默认传null即可
  104.                 // ----------------------- SQL语句来删除
  105.                 // String DELETE_DATA = "DELETE FROM himi WHERE id=1";
  106.                 // db.execSQL(DELETE_DATA);
  107.                 tv.setText("删除数据成功!点击查看数据库查询");
  108.             } else if (v == btn_check) {// 遍历数据
  109. //备注4------
  110.                 Cursor cur = mysql.rawQuery("SELECT * FROM "
  111.                         + MySQLiteOpenHelper.TABLE_NAME, null);
  112.                 if (cur != null) {
  113.                     String temp = "";
  114.                     int i = 0;
  115.                     while (cur.moveToNext()) {//直到返回false说明表中到了数据末尾
  116.                         temp += cur.getString(0);
  117.                         // 参数0 指的是列的下标,这里的0指的是id列
  118.                         temp += cur.getString(1);
  119.                         // 这里的0相对于当前应该是咱们的text列了
  120.                         i++;
  121.                         temp += "  "; // 这里是我整理显示格式 ,呵呵~
  122.                         if (i % 3 == 0) // 这里是我整理显示格式 ,呵呵~
  123.                             temp += "\n";// 这里是我整理显示格式 ,呵呵~
  124.                     }
  125.                     tv.setText(temp);
  126.                 }
  127.             } else if (v == btn_edit) {// 修改数据
  128.                 // ------------------------句柄方式来修改 -------------
  129.                 ContentValues cv = new ContentValues();
  130.                 cv.put(MySQLiteOpenHelper.TEXT, "修改后的数据");
  131.                 mysql.update("himi", cv, "id " + "=" + Integer.toString(3), null);
  132.                 // ------------------------SQL语句来修改 -------------
  133.                 // String UPDATA_DATA =
  134.                 // "UPDATE himi SET text='通过SQL语句来修改数据'  WHERE id=1";
  135.                 // db.execSQL(UPDATA_DATA);
  136.                 tv.setText("修改数据成功!点击查看数据库查询");
  137.             } else if (v == btn_deleteTable) {// 删除表
  138.                 mysql.execSQL("DROP TABLE himi");
  139.                 tv.setText("删除表成功!点击查看数据库查询");
  140.             } else if (v == btn_newTable) {// 新建表
  141.                 String TABLE_NAME = "himi";
  142.                 String ID = "id";
  143.                 String TEXT = "text";
  144.                 String str_sql2 = "CREATE TABLE " + TABLE_NAME + "(" + ID
  145.                         + " INTEGER PRIMARY KEY AUTOINCREMENT," + TEXT
  146.                         + " text );";
  147.                 mysql.execSQL(str_sql2);
  148.                 tv.setText("新建表成功!点击查看数据库查询");
  149.             }
  150.             // 删除数据库:
  151.             // this.deleteDatabase("himi.db");
  152.         } catch (Exception e) {
  153.             tv.setText("操作失败!");
  154.         } finally {// 如果try中异常,也要对数据库进行关闭
  155.             mysql.close();
  156.         }
  157.     }
  158. }

 

以上代码中我们实现了两种存储方式:

一种存储默认系统路径/data-data-com.himi-databases下,另外一种则是保存在了/sdcard-himi下,生成数据库文件himi.db

那么这里两种实现方式大概步骤和区别说下:

-----------如果我们使用默认系统路径存储数据库文件:

第一步:新建一个类继承SQLiteOpenHelper;写一个构造,重写两个函数!

第二步:在新建的类中的onCreate(SQLiteDatabase db) 方法中创建一个表;

第三步:在进行删除数据、添加数据等操作的之前我们要得到数据库读写句柄得到一个数据库实例;

 注意: 继承写这个辅助类,是为了在我们没有数据库的时候自动为我们生成一个数据库,并且生成数据库文件,这里也同时创建了一张表,因为我们在onCreate里是在数据库中创建一张表的操作;这里还要注意在我们new 这个我们这个MySQLiteOpenHelper 类实例对象的时候并没有创建数据库哟~!而是在我们调用 (备注3)MySQLiteOpenHelper ..getWritableDatabase() 这个方法得到数据库读写句柄的时候,android 会分析是否已经有了数据库,如果没有会默认为我们创建一个数据库并且在系统路径data-data-com.himi-databases下生成himi.db 文件!

(如果我们使用sd卡存储数据库文件,就没有必要写这个类了,而是我们自己Open自己的文件得到一个数据库,西西,反而方便~ )

-----------如果我们需要把数据库文件存储到SD卡中:

      第一步:确认模拟器存在SD卡,关于SD卡的两种创建方法见我的博文:【Android 2D游戏开发之十】

      第二步:(备注1)先创建SD卡目录和路径已经我们的数据库文件!这里不像上面默认路径中的那样,如果没有数据库会默认系统路径生成一个数据库和一个数据库文件!我们必须手动创建数据库文件!

第三步:在进行删除数据、添加数据等操作的之前我们要得到数据库读写句柄得到一个数据库实例;(备注2)此时的创建也不是像系统默认创建,而是我们通过打开第一步创建好的文件得到数据库实例。这里仅仅是创建一个数据库!!!!

第四步:在进行删除数据、添加数据等操作的之前我们还要创建一个表!

第五步:在配置文件AndroidMainfest.xml 声明写入SD卡的权限,上一篇已经介绍权限了,不知道的自己去看下吧。

     有些童鞋不理解什么默认路径方式中就有表?那是因为我们在它默认给我们创建数据库的时候我们有创建表的操作,就是MySQLiteOpenHelper类中的onCreate()方法里的操作!所以我们如果要在进行删除数据、添加数据等操作的之前还要创建一个表,创建表的方法都是一样的。

总结:不管哪种方式我们都要-创建数据库-创建表-然后进行操作!

备注4:

在Android中查询数据是通过Cursor类来实现的,当我们使用SQLiteDatabase.query()方法时,会得到一个Cursor对象,Cursor指向的就是每一条数据。它提供了很多有关查询的方法,具体方法如下:

以下是方法和说明:

move 以当前的位置为参考,将Cursor移动到指定的位置,成功返回true, 失败返回false

moveToPosition 将Cursor移动到指定的位置,成功返回true,失败返回false

moveToNext  将Cursor向前移动一个位置,成功返回true,失败返回false

moveToLast 将Cursor向后移动一个位置,成功返回true,失败返回 false。

movetoFirst  将Cursor移动到第一行,成功返回true,失败返回false

isBeforeFirst  返回Cursor是否指向第一项数据之前

isAfterLast  返回Cursor是否指向最后一项数据之后

isClosed    返回Cursor是否关闭

isFirst 返回Cursor是否指向第一项数据

isLast       返回Cursor是否指向最后一项数据

isNull       返回指定位置的值是否为null

getCount     返回总的数据项数

getInt          返回当前行中指定的索引数据

 

本篇源码:http://download.csdn.net/source/2959222


Android调用相机并将照片存储到sd卡上(转)

Android中实现拍照有两种方法,一种是调用系统自带的相机,然后使用其返回的照片数据。 还有一种是自己用Camera类和其他相关类实现相机功能,这种方法定制度比较高,洗染也比较复杂,一般平常的应用只需使用第一种即可。

用Intent启动相机的代码:

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);

拍完照后就可以在onActivityResult(int requestCode, int resultCode, Intent data)中获取到Bitmap对象了。

Bitmap bitmap = (Bitmap) data.getExtras().get("data");
要将图像存储到sd卡之前最好先检查一下sd卡是否可用

    String sdStatus = Environment.getExternalStorageState();
if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { // 检测sd是否可用
Log.v("TestFile",
"SD card is not avaiable/writeable right now.");
return;
}
以下代码可以实现将图像文件存到“sdcard/myImage/”文件夹下,名称为“111.jpg”

            File file = new File("/sdcard/myImage/");
file.mkdirs();// 创建文件夹
String fileName = "/sdcard/myImage/111.jpg";

try {
b = new FileOutputStream(fileName);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, b);// 把数据写入文件
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
b.flush();
b.close();
} catch (IOException e) {
e.printStackTrace();
}
}

另外要注意的是读写sd卡文件必须首先要在Mainifest.xml文件中配置权限:

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

一个demo,实现调用系统相机拍照,将其显示在屏幕上,并且存到sd卡。

完整代码如下:

MyCaremaActivity.java

package barry.android.c;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;

public class MyCaremaActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

Button button = (Button) findViewById(R.id.button);

button.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);
}
});
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if (resultCode == Activity.RESULT_OK) {

String sdStatus = Environment.getExternalStorageState();
if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { // 检测sd是否可用
Log.v("TestFile",
"SD card is not avaiable/writeable right now.");
return;
}

Bundle bundle = data.getExtras();
Bitmap bitmap = (Bitmap) bundle.get("data");// 获取相机返回的数据,并转换为Bitmap图片格式
FileOutputStream b = null;
File file = new File("/sdcard/myImage/");
file.mkdirs();// 创建文件夹
String fileName = "/sdcard/myImage/111.jpg";

try {
b = new FileOutputStream(fileName);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, b);// 把数据写入文件
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
b.flush();
b.close();
} catch (IOException e) {
e.printStackTrace();
}
}

((ImageView) findViewById(R.id.imageView)).setImageBitmap(bitmap);// 将图片显示在ImageView里
}
}
}

 

main.xml

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

<Button
android:id="@+id/button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="点击启动相机" />

<ImageView
android:id="@+id/imageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#999999" />

</LinearLayout>

AndroidMainifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="barry.android.c"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk android:minSdkVersion="7" />

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

<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity
android:label="@string/app_name"
android:name=".MyCaremaActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

小米手机亲测可用。

用AutoCompleteTextView实现历史记录提示(转)


这画面不陌生吧,百度的提示,他的词库并不是历史记录,是搜索引擎收集的当前最常搜索的内容。假如我们也要在android的应用实现如上功能怎么做呢?
方法很简单,android已经帮我们写好了api ,这里就用到了AutoCompleteTextView组件。
网上有不少教程,那个提示框字符集都是事先写好的,例如用一个String[] 数组去包含了这些数据,但是,我们也可以吧用户输入的作为历史记录保存
下面先上我写的代码:
import android.app.Activity;

  1. import android.content.SharedPreferences;
  2. import android.os.Bundle;
  3. import android.util.Log;
  4. import android.view.View;
  5. import android.view.View.OnClickListener;
  6. import android.view.View.OnFocusChangeListener;
  7. import android.widget.ArrayAdapter;
  8. import android.widget.AutoCompleteTextView;
  9. import android.widget.Button;
  10. public class Read_historyActivity extends Activity implements
  11.         OnClickListener {
  12.     private AutoCompleteTextView autoTv;
  13.     /** Called when the activity is first created. */
  14.     @Override
  15.     public void onCreate(Bundle savedInstanceState) {
  16.         super.onCreate(savedInstanceState);
  17.         setContentView(R.layout.main);
  18.         autoTv = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView1);
  19.         initAutoComplete("history",autoTv);
  20.         Button search = (Button) findViewById(R.id.button1);
  21.         search.setOnClickListener(this);
  22.     }
  23.     @Override
  24.     public void onClick(View v) {
  25.         // 这里可以设定:当搜索成功时,才执行保存操作
  26.         saveHistory("history",autoTv);
  27.     }
  28.     /**
  29.      * 初始化AutoCompleteTextView,最多显示5项提示,使
  30.      * AutoCompleteTextView在一开始获得焦点时自动提示
  31.      * @param field 保存在sharedPreference中的字段名
  32.      * @param auto 要操作的AutoCompleteTextView
  33.      */
  34.     private void initAutoComplete(String field,AutoCompleteTextView auto) {
  35.         SharedPreferences sp = getSharedPreferences("network_url", 0);
  36.         String longhistory = sp.getString("history", "nothing");
  37.         String[]  hisArrays = longhistory.split(",");
  38.         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
  39.                 android.R.layout.simple_dropdown_item_1line, hisArrays);
  40.         //只保留最近的50条的记录
  41.         if(hisArrays.length > 50){
  42.             String[] newArrays = new String[50];
  43.             System.arraycopy(hisArrays, 0, newArrays, 0, 50);
  44.             adapter = new ArrayAdapter<String>(this,
  45.                     android.R.layout.simple_dropdown_item_1line, newArrays);
  46.         }
  47.         auto.setAdapter(adapter);
  48.         auto.setDropDownHeight(350);
  49.         auto.setThreshold(1);
  50.         auto.setCompletionHint("最近的5条记录");
  51.         auto.setOnFocusChangeListener(new OnFocusChangeListener() {
  52.             @Override
  53.             public void onFocusChange(View v, boolean hasFocus) {
  54.                 AutoCompleteTextView view = (AutoCompleteTextView) v;
  55.                 if (hasFocus) {
  56.                         view.showDropDown();
  57.                 }
  58.             }
  59.         });
  60.     }
  61.     /**
  62.      * 把指定AutoCompleteTextView中内容保存到sharedPreference中指定的字符段
  63.      * @param field  保存在sharedPreference中的字段名
  64.      * @param auto  要操作的AutoCompleteTextView
  65.      */
  66.     private void saveHistory(String field,AutoCompleteTextView auto) {
  67.         String text = auto.getText().toString();
  68.         SharedPreferences sp = getSharedPreferences("network_url", 0);
  69.         String longhistory = sp.getString(field, "nothing");
  70.         if (!longhistory.contains(text + ",")) {
  71.             StringBuilder sb = new StringBuilder(longhistory);
  72.             sb.insert(0, text + ",");
  73.             sp.edit().putString("history", sb.toString()).commit();
  74.         }
  75. <span style="font-family: monospace; white-space: pre; background-color: rgb(240, 240, 240); ">   }
  76. }</span>

上面的代码我实现了autocomplettextview的从sharepreference中读取历史记录并显示的功能,当没有任何输入时,提示最新的5项历史记录(这里可以加个条件,当有历史记录时才显示)
补上布局的代码

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout
  3.     xmlns:android="http://schemas.android.com/apk/res/android"
  4.     android:orientation="vertical"
  5.     android:layout_width="fill_parent"
  6.     android:layout_height="fill_parent">
  7.     <TextView android:layout_width="fill_parent"
  8.         android:layout_height="wrap_content"
  9.         android:text="@string/hello" />
  10.     <LinearLayout android:layout_width="0px"
  11.         android:layout_height="0px" android:focusable="true"
  12.         android:focusableInTouchMode="true"></LinearLayout>
  13.     <AutoCompleteTextView
  14.         android:hint="请输入文字进行搜索" android:layout_height="wrap_content"
  15.         android:layout_width="match_parent"
  16.         android:id="@+id/autoCompleteTextView1">
  17.     </AutoCompleteTextView>
  18.     <Button android:text="搜索" android:id="@+id/button1"
  19.         android:layout_width="wrap_content"
  20.         android:layout_height="wrap_content"></Button>
  21. </LinearLayout>

当之有一个edittext或者auto的时候,进入画面时是默认得到焦点的,要想去除焦点,可以在auto之前加一个o像素的layout,并设置他先得到焦点。

效果图如下

下面出现的是源码内容
需要注意的是,我这里用到的AutoCompleteTextView的几个方法
1. setAdapter()方法:这里要传递的adapter参数必须是继承ListAdapter和Filterable的,其中arrayAdapter和simpleAdapter都能满足要求,我们常用arrayAdapter,因为他不需要像simpleAdapte那样设置他的显示位置和textview组件。
要想掌握它,就必须查看他的源码,我们可以看看arrayadapter是如何实现
凡是继承了Filterable的adapter都必须重写getFilter接口方法

  1. public Filter getFilter() {
  2.     if (mFilter == null) {
  3.         mFilter = new ArrayFilter();
  4.     }
  5.     return mFilter;
  6. }

这个filter 就是实现过滤方法的对象,同样,我们可以查看他的源码是如何实现的

  1. /**
  2.     * <p>An array filter constrains the content of the array adapter with
  3.     * a prefix. Each item that does not start with the supplied prefix
  4.     * is removed from the list.</p>
  5.     */
  6.    private class ArrayFilter extends Filter {
  7.        @Override
  8.        protected FilterResults performFiltering(CharSequence prefix) {
  9.            FilterResults results = new FilterResults();
  10.            if (mOriginalValues == null) {
  11.                synchronized (mLock) {
  12.                    mOriginalValues = new ArrayList<T>(mObjects);
  13.                }
  14.            }
  15.            if (prefix == null || prefix.length() == 0) {
  16.                synchronized (mLock) {
  17.                    ArrayList<T> list = new ArrayList<T>(mOriginalValues);
  18.                    results.values = list;
  19.                    results.count = list.size();
  20.                }
  21.            } else {
  22.                String prefixString = prefix.toString().toLowerCase();
  23.                final ArrayList<T> values = mOriginalValues;
  24.                final int count = values.size();
  25.                final ArrayList<T> newValues = new ArrayList<T>(count);
  26.                for (int i = 0; i < count; i++) {
  27.                    final T value = values.get(i);
  28.                    final String valueText = value.toString().toLowerCase();
  29.                    // First match against the whole, non-splitted value
  30.                    if (valueText.startsWith(prefixString)) {
  31.                        newValues.add(value);
  32.                    } else {
  33.                        final String[] words = valueText.split(" ");
  34.                        final int wordCount = words.length;
  35.                        for (int k = 0; k < wordCount; k++) {
  36.                            if (words[k].startsWith(prefixString)) {
  37.                                newValues.add(value);
  38.                                break;
  39.                            }
  40.                        }
  41.                    }
  42.                }
  43.                results.values = newValues;
  44.                results.count = newValues.size();
  45.            }
  46.            return results;
  47.        }

这是arrayAdapter自定义的一个私有内部类,所谓私有,就意味着你不能通过继承去修改这种过滤方法,同样你也不能直接得到他过滤后结果集results。假如你想使用新的过滤方法,你必须重写getfilter()方法,返回的filter对象是你要新建的filter对象(在里面包含performFiltering()方法重新构造你要的过滤方法)

2.setDropDownHeight方法 ,用来设置提示下拉框的高度,注意,这只是限制了提示下拉框的高度,提示数据集的个数并没有变化
3.setThreshold方法,设置从输入第几个字符起出现提示
4.setCompletionHint方法,设置提示框最下面显示的文字
5.setOnFocusChangeListener方法,里面包含OnFocusChangeListener监听器,设置焦点改变事件
6.showdropdown方法,让下拉框弹出来

我没有用到的一些方法列举
1.clearListSelection,去除selector样式,只是暂时的去除,当用户再输入时又重新出现
2.dismissDropDown,关闭下拉提示框
3.enoughToFilter,这是一个是否满足过滤条件的方法,sdk建议我们可以重写这个方法
4. getAdapter,得到一个可过滤的列表适配器
5.getDropDownAnchor,得到下拉框的锚计的view的id
6.getDropDownBackground,得到下拉框的背景色
7.setDropDownBackgroundDrawable,设置下拉框的背景色
8.setDropDownBackgroundResource,设置下拉框的背景资源
9.setDropDownVerticalOffset,设置下拉表垂直偏移量,即是list里包含的数据项数目
10.getDropDownVerticalOffset ,得到下拉表垂直偏移量
11..setDropDownHorizontalOffset,设置水平偏移量
12.setDropDownAnimationStyle,设置下拉框的弹出动画
13.getThreshold,得到过滤字符个数
14.setOnItemClickListener,设置下拉框点击事件
15.getListSelection,得到下拉框选中为位置
16.getOnItemClickListener。得到单项点击事件
17.getOnItemSelectedListener得到单项选中事件
18.getAdapter,得到那个设置的适配器

一些隐藏方法和构造我没有列举了,具体可以参考api文档
可下载我的写的demo: http://download.csdn.net/detail/iamkila/4042528


Android 3.0 访问WebService 出现 android.os.NetworkOnMainThreadException异常 (转)

以前用2.2 访问WebService没有问题,到3.0上访问出现android.os.NetworkOnMainThreadException

找了资料经过实践,解决方法是在activity类中的onCreate方法中添加strict代码,如下:

  1. public void onCreate() {    
  2.      .......  
  3.      StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()       
  4.             .detectDiskReads()       
  5.             .detectDiskWrites()       
  6.             .detectNetwork()   // or .detectAll() for all detectable problems       
  7.             .penaltyLog()       
  8.             .build());       
  9.      StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()       
  10.             .detectLeakedSqlLiteObjects()    
  11.             .penaltyLog()       
  12.             .penaltyDeath()       
  13.             .build());    
  14.      ......  
  15. }    

似乎是3.0在网络上做了更加严格的限制

package org.sword.android;

import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.os.Bundle;
import android.os.StrictMode;
import android.widget.Button;

public class InternetActivity extends Activity {
   
private static final String SERVER_UTL = "http://www.webservicex.net/WeatherForecast.asmx/GetWeatherByZipCode";
private Button button;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
        .detectDiskReads()
        .detectDiskWrites()
        .detectNetwork()   // or .detectAll() for all detectable problems
        .penaltyLog()
        .build());
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
        .detectLeakedSqlLiteObjects()
        .detectLeakedClosableObjects()
        .penaltyLog()
        .penaltyDeath()
        .build());
        getWeather();
    }
    
    private void getWeather(){
        try {
                final String SERVER_URL = "http://webservice.webxml.com.cn/WebServices/WeatherWS.asmx/getWeather"; // 定义需要获取的内容来源地址
                HttpPost request = new HttpPost(SERVER_URL); // 根据内容来源地址创建一个Http请求
                List params = new ArrayList();
                params.add(new BasicNameValuePair("theCityCode", "长沙")); // 添加必须的参数
                params.add(new BasicNameValuePair("theUserID", "")); // 添加必须的参数
                request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8)); // 设置参数的编码
                HttpResponse httpResponse = new DefaultHttpClient().execute(request); // 发送请求并获取反馈
                // 解析返回的内容
                if (httpResponse.getStatusLine().getStatusCode() != 404)
                {
                        String result = EntityUtils.toString(httpResponse.getEntity());
                        System.out.println("result =" + result);
                }
        } catch (Exception e) {
        e.printStackTrace();
        }
}
}


android 使用JavaMail(转载)

今天学习了一下JavaMail,javamail发送邮件确实是一个比较麻烦的问题不用第三方邮件程序。为了以后使用方便,自己写了段代码微笑

Javamail-Android配置步骤:

  1. 下载Android版本JavaMail包,additional.jar、mail.jar和activation.jar,下载地址JavaMail-Android
  2. 在项目与src同一目录级别下,新建文件夹lib,将下载的3个jar包放入该文件夹
  3. 右键->Properties->Java Build Path->Libraries,选择Add External JARs,找到项目下lib目录的3个jar包

我的代码有三个类:
第一个类:MailSenderInfo.java

 

 

package com.util.mail;
/**
* 发送邮件需要使用的基本信息
*/
import java.util.Properties;
public class MailSenderInfo {
    // 发送邮件的服务器的IP和端口
    private String mailServerHost;
    private String mailServerPort = "25";
    // 邮件发送者的地址
    private String fromAddress;
    // 邮件接收者的地址
    private String toAddress;
    // 登陆邮件发送服务器的用户名和密码
    private String userName;
    private String password;
    // 是否需要身份验证
    private boolean validate = false;
    // 邮件主题
    private String subject;
    // 邮件的文本内容
    private String content;
    // 邮件附件的文件名
    private String[] attachFileNames;  
    /**
      * 获得邮件会话属性
      */
    public Properties getProperties(){
      Properties p = new Properties();
      p.put("mail.smtp.host", this.mailServerHost);
      p.put("mail.smtp.port", this.mailServerPort);
      p.put("mail.smtp.auth", validate ? "true" : "false");
      return p;
    }
    public String getMailServerHost() {
      return mailServerHost;
    }
    public void setMailServerHost(String mailServerHost) {
      this.mailServerHost = mailServerHost;
    }
    public String getMailServerPort() {
      return mailServerPort;
    }
    public void setMailServerPort(String mailServerPort) {
      this.mailServerPort = mailServerPort;
    }
    public boolean isValidate() {
      return validate;
    }
    public void setValidate(boolean validate) {
      this.validate = validate;
    }
    public String[] getAttachFileNames() {
      return attachFileNames;
    }
    public void setAttachFileNames(String[] fileNames) {
      this.attachFileNames = fileNames;
    }
    public String getFromAddress() {
      return fromAddress;
    }
    public void setFromAddress(String fromAddress) {
      this.fromAddress = fromAddress;
    }
    public String getPassword() {
      return password;
    }
    public void setPassword(String password) {
      this.password = password;
    }
    public String getToAddress() {
      return toAddress;
    }
    public void setToAddress(String toAddress) {
      this.toAddress = toAddress;
    }
    public String getUserName() {
      return userName;
    }
    public void setUserName(String userName) {
      this.userName = userName;
    }
    public String getSubject() {
      return subject;
    }
    public void setSubject(String subject) {
      this.subject = subject;
    }
    public String getContent() {
      return content;
    }
    public void setContent(String textContent) {
      this.content = textContent;
    }
}

 

第二个类:MultiMailsender.java

 

 

 

package com.util.mail;
import java.util.Date;
import java.util.Properties;
import javax.mail.Address;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
/**
 * 发送邮件给多个接收者、抄送邮件
 */
public class MultiMailsender {
    
    /**
      * 以文本格式发送邮件
      * @param mailInfo 待发送的邮件的信息
      */
        public boolean sendTextMail(MultiMailSenderInfo mailInfo) {
          // 判断是否需要身份认证
          MyAuthenticator authenticator = null;
          Properties pro = mailInfo.getProperties();
          if (mailInfo.isValidate()) {
          // 如果需要身份认证,则创建一个密码验证器
            authenticator = new MyAuthenticator(mailInfo.getUserName(), mailInfo.getPassword());
          }
          // 根据邮件会话属性和密码验证器构造一个发送邮件的session
          Session sendMailSession = Session.getDefaultInstance(pro,authenticator);
          try {
          // 根据session创建一个邮件消息
          Message mailMessage = new MimeMessage(sendMailSession);
          // 创建邮件发送者地址
          Address from = new InternetAddress(mailInfo.getFromAddress());
          // 设置邮件消息的发送者
          mailMessage.setFrom(from);
          // 创建邮件的接收者地址,并设置到邮件消息中
          Address[] tos = null;
          String[] receivers = mailInfo.getReceivers();
          if (receivers != null){
              // 为每个邮件接收者创建一个地址
              tos = new InternetAddress[receivers.length + 1];
              tos[0] = new InternetAddress(mailInfo.getToAddress());
              for (int i=0; i<receivers.length; i++){
                  tos[i+1] = new InternetAddress(receivers[i]);
              }
          } else {
              tos = new InternetAddress[1];
              tos[0] = new InternetAddress(mailInfo.getToAddress());
          }
          // Message.RecipientType.TO属性表示接收者的类型为TO
          mailMessage.setRecipients(Message.RecipientType.TO,tos);
          // 设置邮件消息的主题
          mailMessage.setSubject(mailInfo.getSubject());
          // 设置邮件消息发送的时间
          mailMessage.setSentDate(new Date());
          // 设置邮件消息的主要内容
          String mailContent = mailInfo.getContent();
          mailMessage.setText(mailContent);
          // 发送邮件
          Transport.send(mailMessage);
          return true;
          } catch (MessagingException ex) {
              ex.printStackTrace();
          }
          return false;
        }
    /**
     * 发送邮件给多个接收者,以Html内容
     * @param mailInfo    带发送邮件的信息
     * @return
     */
    public static boolean sendMailtoMultiReceiver(MultiMailSenderInfo mailInfo){
        MyAuthenticator authenticator = null;
        if (mailInfo.isValidate()) {
            authenticator = new MyAuthenticator(mailInfo.getUserName(),
                    mailInfo.getPassword());
        }
        Session sendMailSession = Session.getInstance(mailInfo
                .getProperties(), authenticator);
        try {
            Message mailMessage = new MimeMessage(sendMailSession);
            // 创建邮件发送者地址
            Address from = new InternetAddress(mailInfo.getFromAddress());
            mailMessage.setFrom(from);
            // 创建邮件的接收者地址,并设置到邮件消息中
            Address[] tos = null;
            String[] receivers = mailInfo.getReceivers();
            if (receivers != null){
                // 为每个邮件接收者创建一个地址
                tos = new InternetAddress[receivers.length + 1];
                tos[0] = new InternetAddress(mailInfo.getToAddress());
                for (int i=0; i<receivers.length; i++){
                    tos[i+1] = new InternetAddress(receivers[i]);
                }
            } else {
                tos = new InternetAddress[1];
                tos[0] = new InternetAddress(mailInfo.getToAddress());
            }
            // 将所有接收者地址都添加到邮件接收者属性中
            mailMessage.setRecipients(Message.RecipientType.TO, tos);
            
            mailMessage.setSubject(mailInfo.getSubject());
            mailMessage.setSentDate(new Date());
            // 设置邮件内容
            Multipart mainPart = new MimeMultipart();
            BodyPart html = new MimeBodyPart();
            html.setContent(mailInfo.getContent(), "text/html; charset=GBK");
            mainPart.addBodyPart(html);
            mailMessage.setContent(mainPart);
            // 发送邮件
            Transport.send(mailMessage);
            return true;
        } catch (MessagingException ex) {
            ex.printStackTrace();
        }
        return false;
    }
    
    /**
     * 发送带抄送的邮件
     * @param mailInfo    待发送邮件的消息
     * @return
     */
    public static boolean sendMailtoMultiCC(MultiMailSenderInfo mailInfo){
        MyAuthenticator authenticator = null;
        if (mailInfo.isValidate()) {
            authenticator = new MyAuthenticator(mailInfo.getUserName(),
                    mailInfo.getPassword());
        }
        Session sendMailSession = Session.getInstance(mailInfo
                .getProperties(), authenticator);
        try {
            Message mailMessage = new MimeMessage(sendMailSession);
            // 创建邮件发送者地址
            Address from = new InternetAddress(mailInfo.getFromAddress());
            mailMessage.setFrom(from);
            // 创建邮件的接收者地址,并设置到邮件消息中
            Address to = new InternetAddress(mailInfo.getToAddress());
            mailMessage.setRecipient(Message.RecipientType.TO, to);
            
            // 获取抄送者信息
            String[] ccs = mailInfo.getCcs();
            if (ccs != null){
                // 为每个邮件接收者创建一个地址
                Address[] ccAdresses = new InternetAddress[ccs.length];
                for (int i=0; i<ccs.length; i++){
                    ccAdresses[i] = new InternetAddress(ccs[i]);
                }
                // 将抄送者信息设置到邮件信息中,注意类型为Message.RecipientType.CC
                mailMessage.setRecipients(Message.RecipientType.CC, ccAdresses);
            }
            
            mailMessage.setSubject(mailInfo.getSubject());
            mailMessage.setSentDate(new Date());
            // 设置邮件内容
            Multipart mainPart = new MimeMultipart();
            BodyPart html = new MimeBodyPart();
            html.setContent(mailInfo.getContent(), "text/html; charset=GBK");
            mainPart.addBodyPart(html);
            mailMessage.setContent(mainPart);
            // 发送邮件
            Transport.send(mailMessage);
            return true;
        } catch (MessagingException ex) {
            ex.printStackTrace();
        }
        return false;
    }
    
    /**
     * 发送多接收者类型邮件的基本信息
     */
    public static class MultiMailSenderInfo extends MailSenderInfo{
        // 邮件的接收者,可以有多个
        private String[] receivers;
        // 邮件的抄送者,可以有多个
        private String[] ccs;
        
        public String[] getCcs() {
            return ccs;
        }
        public void setCcs(String[] ccs) {
            this.ccs = ccs;
        }
        public String[] getReceivers() {
            return receivers;
        }
        public void setReceivers(String[] receivers) {
            this.receivers = receivers;
        }
    }
}

 

第三个类:MyAuthenticator.java

 

 

 

package com.util.mail;
 
import javax.mail.*;
   
public class MyAuthenticator extends Authenticator{
    String userName=null;
    String password=null;
      
    public MyAuthenticator(){
    }
    public MyAuthenticator(String username, String password) {
        this.userName = username;
        this.password = password;
    }
    protected PasswordAuthentication getPasswordAuthentication(){
        return new PasswordAuthentication(userName, password);
    }
}

 

下面给出使用上面三个类的代码:

 

 

 

public static void main(String[] args){
         //这个类主要是设置邮件
      MultiMailSenderInfo mailInfo = new MultiMailSenderInfo();
      mailInfo.setMailServerHost("smtp.163.com");
      mailInfo.setMailServerPort("25");
      mailInfo.setValidate(true);
      mailInfo.setUserName("xxx@163.com");
      mailInfo.setPassword("**********");//您的邮箱密码
      mailInfo.setFromAddress("xxx@163.com");
      mailInfo.setToAddress("xxx@163.com");
      mailInfo.setSubject("设置邮箱标题");
      mailInfo.setContent("设置邮箱内容");
      String[] receivers = new String[]{"***@163.com", "***@tom.com"};
      String[] ccs = receivers; mailInfo.setReceivers(receivers);
      mailInfo.setCcs(ccs);
      //这个类主要来发送邮件
      MultiMailsender sms = new MultiMailsender();
      sms.sendTextMail(mailInfo);//发送文体格式

     //原文这里好像是一处错误,我简单修改了下(博主注释)
  MultiMailsender.sendMailtoMultiReceiver(mailInfo);//发送html格式
      MultiMailsender.sendMailtoMultiCC(mailInfo);//发送抄送

 

最后,给出朋友们几个注意的地方:
1、使用此代码你可以完成你的javamail的邮件发送功能、发多个邮箱。三个类缺一不可。
2、这三个类我打包是用的com.util.mail包,如果不喜欢,你可以自己改,但三个类文件必须在同一个包中
3、不要使用你刚刚注册过的邮箱在程序中发邮件,如果你的163邮箱是刚注册不久,那你就不要使用“smtp.163.com”。因为你发不出去。刚注册的邮箱是不会给你这种权限的,也就是你不能通过验证。要使用你经常用的邮箱,而且时间比较长的。
4、另一个问题就是mailInfo.setMailServerHost("smtp.163.com");mailInfo.setFromAddress("xxx@163.com");这两句话。即如果你使用163smtp服务器,那么发送邮件地址就必须用163的邮箱,如果不的话,是不会发送成功的。
5、关于javamail验证错误的问题,网上的解释有很多,但我看见的只有一个。就是我的第三个类。你只要复制全了代码,我想是不会有问题的。

6、 然后在Android项目中添加网络访问权限

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

 



 
  •  

    May 2012
    S M T W T F S
    « Mar    
     12345
    6789101112
    13141516171819
    20212223242526
    2728293031  
BLOG Service Provided By BLOG.CD 9:25:51
BLOG.CD