内容提供器
内容提供器是用来读取和存储数据,使用它可以将我们自己的数据共享给别人,同时可以读取到别人的数据在别人容许的情况下。他是唯一个可以在不同的应用程序间共享数据的方式,没有公共的存储区域,所有的android应用程序都可以访问。
android系统自带一些内容提供器为常用的数据类型,如音乐,视频,图片,联系人资料等,你可以通过android.provider包查看这些东东,你可以通过这些内容提供器查询他们包含的数据(但是你必须要得到其他用户程序的许可)。
如果你想让你的数据可以让别人共享,你必须做两个操作,1.你需要建立你自己的contentProvider(一个系统提供的contentProvider的子类)存储数据,2.你通过别人提供的provider去存储自己的数据(这个provider必须很你需要操作的数据类型一样,且你拥有这个provider写的权利)。
contentprovider基础
一个contentprovider怎样存储数据,完全有他的开发者控制,但是所有的contentprovider必须实现相同的接口,用来查询内容和返回结果,比如添加数据,修改,和删除。
用户可以通过系统提供的一个接口getContentResolver回去contentResolver对象(在activity中调用这个对象),当你得到这个对象后,
一般在activity中使用的方法为
ContentResolver c = getContentResolver();这个时候你就可以和提供contentprovider的应用进行交互了,
当我们发起一个查询事件时,系统识别contentProvider通过在查询中提供的uri,然后确定这个contentprovider启动并且在运行,android系统在启动的时候就初始化所有的contentprovider对象(自己提供的contentprovider需要在manifest文件中声明,具体做法一会讲)
对一些公共的应用你永远不需要自己去实现(开源软件的好处,省力,省钱,支持开源,但同时也降低了我们程序员的水准),实际上你根本不需要直接和一个contentprovider打交道(除非是自己的),android系统为没个contentprovider提供了一个实例(单例模式),但是它可以和多个contentresolver打交道(线程安全的),线程安全是由contentresolver和contentprovider完成的,我们使用者不比为此担忧。
数据模式
contentprovider是按照表的方式公开自己的数据。每一个行是一条记录,每一列是一个具体的值,这里就不举例了,如果连表都不知道的话,建议你还是别存从事软件开发了,免得降低程序员的水准,呵呵,题外话
在android的中,每一行数据都必须包含一列,列名为"_id",他是表的主键。主键的概念和作用参考数据库方面的书
每一个查询都返回一个Cursor对象,做过oracle pl/sql编程的可定知道他的意思。cursor对象可以让我们从一行移另一行,一列移动到另一列,可以很方便的读数据。他还提供读取特定类型的数据的方法,如getString,getInteger等方法,前提是你必须知道每个字段所代表的类型。(一会将详细介绍查询结果和cursor对象)
Uri
uri的作用是准确的定位我们需要的contentprovider提供的数据,否则就会乱套(不安全的,得带),每一个contentprovider都提供一个公开的uri ,他可以准确的标识一个数据集,一个contentprovider控制多个数据集,通过uri可以准确的标识他们,中的每一个数据集。所有的uri必须以content://开头,content:是作为识别contentprovider的标识。
如果你自己定义了一个contentprovider,那么你也需要为他建立一个uri,简化他人调用的工作and make future updates cleaner(请大侠解释),android定义content_uri 常量给所有的和平台交互的provider(Android defines CONTENT_URI constants for all the providers that come with the platform)。例如,查询联系的联系人和联系的图片的uri为:
android.provider.Contacts.Phones.COntent_URI 和android.provider.Contacts.Photos.CONTENT_URI.
uri 对所有和contentprovider交互的用户。每个contentresolver的方法的第一个参数就是uri,他定义了将要和哪个contentprovider的contentresolver进行对话,以及将要对哪个表进行操作。
查询一个contentprovider
你需要分三步去查询一个contentprovidr
1.contentprovidr定义的uri
2.你需要返回的表的列名
3.这些数据的类型(本人有点疑问)
如果你要查询某条特定的数据,你还需要制定ID
生成查询
你可以通过ContentResolver对象的query方法或者Activity.managedQuery方法,这个方法的参数都一样,都返回一个cursor对象,但是managedQuery方法可以让activity管理cursor对象的生命周期,他可以做好多事情,比如,当activity pauses以后,会自动关闭cursor对象。当activity restart的时候,它可以自动去重新查询。你也可以调用activit的startmanagingCursor(Cursor c)方法去管理这个对象。
query方法和managedQuery方法的第一个参数为provider的uri,关于uri上面已经介绍过了,
android系统提供了一些辅助方法,比如,COntentUris.withAppendedId()和Uri.withAppendedPath()方法,他们可以很方便的为uri添加一个id,两个方法都是静态的,都返回一个uri对象,下面是android 帮助文档中提供的例子
import android.provider.Contacts.People;
import android.content.ContentUris;
import android.net.Uri;
import android.database.Cursor;
// Use the ContentUris method to produce the base URI for the contact with _ID == 23.
//Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23);
// Alternatively, use the Uri method to produce the base URI.
// It takes a string rather than an integer.
Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23");
// Then query for this specific record:
Cursor cur = managedQuery(myPerson, null, null, null, null);
query()和managedQuery()方法的参数代表的意思如下:
参数1:uri。参数2:需要返回的列名,比如_id,number,nember_key等,如果为空,则返回所有列。参数3:相当于sql语句的where条件,比如 “_id” = 12,"_id" = ? 。如果为null的时候,则返回所有列,前提是你的uri是返回全部的uri。参数4:如果参选3中包含形如"_id" = ?的条件,那么此项不能为空。否则此项为空,目的是提供查询速度,让sql语句软解析。参数5:是排序,比如要按照id排序,则为“id desc ”,不需要加order by。详细请查看android api android.content.contentResolver
查询返回的数据
每个查询都会返回o个或者多条记录。不会返回null,而且每行都会包含_id这列,
读取返回的数据
从cursor中读数据的时候,一定要知道数据的类型,但是你也可以通过getString方法,读取到所有数据,但是返回的对象都是string类型的,在你实际应用中,你还是要转换成真正的类型,所以还是第一次就使用对象的get方法把,你可以使用index或者列名去读数据。好像没有提供直接使用列名读数据的方法,不知道为什么,待解(难道是我没注意到)。
如下:
if (cur.moveToFirst()) {
String name;
String phoneNumber;
int nameColumn = cur.getColumnIndex(People.NAME);
int phoneColumn = cur.getColumnIndex(People.NUMBER);
String imagePath;
do {
// Get the field values
name = cur.getString(nameColumn);
phoneNumber = cur.getString(phoneColumn);
// Do something with the values.
...
} while (cur.moveToNext());
}
如果一个查询返回的是二进制数据,如image或者音乐。那么数据可以直接存在表中,也可以通过一个uri链接到相应内容。使用uri可以获取数据。一般情况下,小数据,如20-50k或者更小的,直接存在数据库,可以通过getBlod()方法到到btye数据。如果table存在的uri,那么你不需要直接打开或者读取这个文件,(不过要有这个权限)。你应该调用ContentResolver.onpenInputStream()获取inputStream对象,然后可以读。
修改数据
1.add
2.updata
3.batch update
3.delete
一. 添加数据
添加数据的第一步,你需要创建一个key-value对象在ContentValues(相当于map,内部实现还是以map实现的,android封装了java的map对象)。数据设置好后,调用contentResolver的insert方法就可以插入了
insert方法返回的不是我们想象的id类型,而是一个uri对象,代表新插入记录的uri。你可以使用他查询刚才添加的记录。如下:
ContentValues values = new ContentValues();
// Add Abraham Lincoln to contacts and make him a favorite.
values.put(People.NAME, "Abraham Lincoln");
// 1 = the new contact is added to favorites
// 0 = the new contact is not added to favorites
values.put(People.STARRED, 1);
Uri uri = getContentResolver().insert(People.CONTENT_URI, values);
二. 修改,删除就不说了,基本上差不多,update和delete方法。
创建一个contentprovider
1.创建一个contentProvider子类
2.定义uri
3.使用创建的类。打开一个SQLiteDatabase对象。openRendHelper和openWirterHelper方法。
4.在manifest文件中声明这个类,一定要声明,<provider android:name="com.example.autos.AutoInfoProvider"
android:authorities="com.example.autos.autoinfoprovider"
. . . />
</provider>
实现类里,需要实现的方法有 query,insert update getType oncreate
格式为 content://xxx.xxx.xxx全部数据,某一条数据 content://xxx.xxx.xxx/id
<provider android:name="com.example.autos.AutoInfoProvider"
android:authorities="com.example.autos.autoinfoprovider"
. . . />
</provider>
import java.util.Calendar;
import java.util.Date;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DiaryDbAdapter {
public static final String KEY_TITLE = "title";
public static final String KEY_BODY = "body";
public static final String KEY_ROWID = "_id";
public static final String KEY_CREATED = "created";
private static final String TAG = "DiaryDbAdapter";
private DatabaseHelper mDbHelper;
private SQLiteDatabase mDb;
private static final String DATABASE_CREATE = "create table diary (_id integer primary key autoincrement, "
+ "title text not null, body text not null, created text not null);";
private static final String DATABASE_NAME = "database";
private static final String DATABASE_TABLE = "diary";
private static final int DATABASE_VERSION = 1;
private final Context mCtx;
private static class DatabaseHelper extends SQLiteOpenHelper {
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DATABASE_CREATE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS diary");
onCreate(db);
}
}
public DiaryDbAdapter(Context ctx) {
this.mCtx = ctx;
}
public DiaryDbAdapter open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}
public void closeclose() {
mDbHelper.close();
}
public long createDiary(String title, String body) {
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_TITLE, title);
initialValues.put(KEY_BODY, body);
Calendar calendar = Calendar.getInstance();
String created = calendar.get(Calendar.YEAR) + "年"
+ calendar.get(Calendar.MONTH) + "月"
+ calendar.get(Calendar.DAY_OF_MONTH) + "日"
+ calendar.get(Calendar.HOUR_OF_DAY) + "时"
+ calendar.get(Calendar.MINUTE) + "分";
initialValues.put(KEY_CREATED, created);
return mDb.insert(DATABASE_TABLE, null, initialValues);
}
public boolean deleteDiary(long rowId) {
return mDb.delete(DATABASE_TABLE, KEY_ROWID + "=" + rowId, null) > 0;
}
public Cursor getAllNotes() {
return mDb.query(DATABASE_TABLE, new String[] { KEY_ROWID, KEY_TITLE,
KEY_BODY, KEY_CREATED }, null, null, null, null, null);
}
public Cursor getDiary(long rowId) throws SQLException {
Cursor mCursor =
mDb.query(true, DATABASE_TABLE, new String[] { KEY_ROWID, KEY_TITLE,
KEY_BODY, KEY_CREATED }, KEY_ROWID + "=" + rowId, null, null,
null, null, null);
if (mCursor != null) {
mCursor.moveToFirst();
}
return mCursor;
}
public boolean updateDiary(long rowId, String title, String body) {
ContentValues args = new ContentValues();
args.put(KEY_TITLE, title);
args.put(KEY_BODY, body);
Calendar calendar = Calendar.getInstance();
String created = calendar.get(Calendar.YEAR) + "年"
+ calendar.get(Calendar.MONTH) + "月"
+ calendar.get(Calendar.DAY_OF_MONTH) + "日"
+ calendar.get(Calendar.HOUR_OF_DAY) + "时"
+ calendar.get(Calendar.MINUTE) + "分";
args.put(KEY_CREATED, created);
return mDb.update(DATABASE_TABLE, args, KEY_ROWID + "=" + rowId, null) > 0;
}
}
layout_weight是LinearLayouts的view布局里一个很重要的值。 所有的view的layout_weight缺省值都是为0,意味着他们只在屏幕上占据它们需要显示的空间大小。 activity根据这个View的比0大的layout_weight值来划分剩余的空间和其它Views定义的layout_weight也按比例进行空间的划分。 给个例子:假设我们在水平行上有一个文本标签和两个文本编辑框view. 文本标签没有定义layout_weight 值,所以它将占据最小的需要提供的空间. 如果每个文本框view的layout_weight 都被设置为1, 在父布局中的剩余的宽度将被它们平分.如果一个文本view的layout_weight值为2,另外一个是1, 那么剩余空间的三分之一将给第一个文本框,三分之二将给第二个文本框
转:http://dev.10086.cn/cmdn/wiki/index.php?doc-view-6074.html
1、参照方法一,设置系统变量,启动模拟器
2、依次进入 settings->Wireless controls->Mobile networks->Access Point Names
3、设置以下参数:
- Proxy : your proxy address
- Port : your proxy port
- Username : your username if needed, or <Not set>
Password : your password if needed, or <Not set>
4、设置DNS参数:
Android模拟器默认的地址是10.0.2.3,默认的DNS也是10.0.2.3,对于在家里上网学习Android的人(像我)来讲,一般 电脑的IP都是192.168.1.100之类的,不在同一个网段。所以就会出现电脑可以上网但是模拟器不能上网的情况。其实设置方 法很简单,只要把模拟 器的默认DNS设置成电脑的DNS地址即可。
第一步:adb shell (进入模拟器的linux系统)
第二步:getprop (getprop会列出系统当前的各项属性)
第三步:得到模拟器的DNS地址
在结果里可以看到:
[net.dns1]: [10.0.2.3]
[net.dns2]: [10.0.2.4]
[net.dns3]: [10.0.2.5]
[net.dns4]: [10.0.2.6]
第四步:把dns改成我们自己的DNS
setprop net.dns1 192.168.1.1 或者 setprop net.dns1 192.168.0.1
注:一般TP-LINK及D-LINK的无线DNS都是192.168.1.1,有些公司有线DNS默认192.168.0.1;
如果以上两个DNS不好用,请直接使用ipconfig /all(windows系统) 或者 ifconfig -a(linux/unix系统)命令确认。
大功告成,再去使用模拟器的浏览器的话,你就可以发现你已经可以上网了。