本文章简单的介绍了关于Android SDK安装图文教程,有需要的朋友可以学习一下下哈。好了费话不说多了我们来看看吧。
Android SDK可以通过SDK下载器自动下载和配置,适合网络好,下载速度快的情况下;也可以借助工具下载SDK文件,手工配置,适合网络不是很好,下载速度慢的情况下。
SDK下载器自动下载步骤如下:
1. 解压缩android-sdk_r08-windows下载器,并双击运行SDK Manager.exe:
如果你的电脑不支持https连接会看到如下界面:
请选择setting的将Force https://... Sources to be fetched by using http://... 的选项打勾
2. 勾选你想要安装的Packages,并点击Install Selected进行安装:
3. 确认对话框如下,选择Accept All进行下载安装
4. 则Android SDK下载器进入下载安装的过程
5. 根据你网速的情况,下载安装的时间或长或短,请耐心等待。
首先如果要在程序中使用sdcard进行存储,我们必须要在AndroidManifset.xml文件进行下面的权限设置:
在AndroidManifest.xml中加入访问SDCard的权限如下:
<!-- 在SDCard中创建与删除文件权限 -->
代码如下 |
复制代码 |
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
|
<!-- 往SDCard写入数据权限 -->
代码如下 |
复制代码 |
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
接着我们在使用SDcard进行读写的时候 会用到Environment类下面的几个静态方法
1: getDataDirectory() 获取到Androi中的data数据目录
2:getDownloadCacheDirectory() 获取到下载的缓存目录
3:getExternalStorageDirectory() 获取到外部存储的目录 一般指SDcard
4:getExternalStorageState() 获取外部设置的当前状态 一般指SDcard,
android系统中对于外部设置的状态,我们比较常用的应该是 MEDIA_MOUNTED(SDcard存在并且可以进行读写) MEDIA_MOUNTED_READ_ONLY (SDcard存在,只可以进行读操作) 当然还有其他的一些状态,可以在文档中进行查找到
5:getRootDirectory() 获取到Android Root路径
6:isExternalStorageEmulated() 返回Boolean值判断外部设置是否有效
7:isExternalStorageRemovable() 返回Boolean值,判断外部设置是否可以移除
【注】上面进行红色标记的方法,我们会常用
代码如下 |
复制代码 |
<span style="color:#ff0000;">Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) |
代码中这句:我们对SDcard的状态进行判断,</span>
下面看实现SDCard进行文件读写操作的Demo:
代码如下 |
复制代码 |
package com.jiangqq.sdcard;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class SDcardActivity extends Activity {
private Button bt1, bt2;
private EditText et1, et2;
private static final String FILENAME = "temp_file.txt";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bt1 = (Button) this.findViewById(R.id.bt1);
bt2 = (Button) this.findViewById(R.id.bt2);
et1 = (EditText) this.findViewById(R.id.et1);
et2 = (EditText) this.findViewById(R.id.et2);
bt1.setOnClickListener(new MySetOnClickListener());
bt2.setOnClickListener(new MySetOnClickListener());
}
private class MySetOnClickListener implements OnClickListener {
@Override
public void onClick(View v) {
File file = new File(Environment.getExternalStorageDirectory(),
FILENAME);
switch (v.getId()) {
case R.id.bt1:// 使用SDcard写操作
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(et1.getText().toString().getBytes());
fos.close();
Toast.makeText(SDcardActivity.this, "写入文件成功",
Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(SDcardActivity.this, "写入文件失败",
Toast.LENGTH_SHORT).show();
}
} else {
// 此时SDcard不存在或者不能进行读写操作的
Toast.makeText(SDcardActivity.this,
"此时SDcard不存在或者不能进行读写操作", Toast.LENGTH_SHORT).show();
}
break;
case R.id.bt2:// 使用SDcard读操作
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
try {
FileInputStream inputStream = new FileInputStream(file);
byte[] b = new byte[inputStream.available()];
inputStream.read(b);
et2.setText(new String(b));
Toast.makeText(SDcardActivity.this, "读取文件成功",
Toast.LENGTH_LONG).show();
} catch (Exception e) {
Toast.makeText(SDcardActivity.this, "读取失败",
Toast.LENGTH_SHORT).show();
}
} else {
// 此时SDcard不存在或者不能进行读写操作的
Toast.makeText(SDcardActivity.this,
"此时SDcard不存在或者不能进行读写操作", Toast.LENGTH_SHORT).show();
}
break;
}
}
}
}
|
本文章简单的android游戏开发实例教程,有需要学习手机游戏开发的朋友可以参考一下下哈。
地图我们创建好了接下来就是主角的出现。其实上文介绍了如何TiledMap和Stage的结合,角色的处理就简单了。
可以继承Actor类创建主角类,我就偷个懒,用Image代替。
编辑我们的TMX文件,添加一个对象层。
在主角要出现的地方加个形状
取名为play1
我们的主角是:
思路是我们遍历map中的所有Object,如果名字和我们设定的play1一致,那么就实例化一个Image,位置和Object一致,添加到舞台。
关键代码:
代码如下 |
复制代码 |
for (TiledObjectGroup group : map.objectGroups) {
for (TiledObject object : group.objects) {
if ("play1".equals(object.name)) {
player = new Image(new TextureRegion(new Texture(Gdx.files
.internal("map/player.png")), 0, 0, 27, 40));
player.x = object.x;
player.y = tileMapRenderer.getMapHeightUnits() - object.y; //map是左上角,Stage是左下角
stage.addActor(player);
}
}
}
|
效果如下:
然后现在来试试让主角动起来。
首先是我们如何控制,android设备的话优先选用触控。如果我们按住前方不放,主角向前。按住上方不放,主角向上。
那么如何确定我们按住的是哪个方向呢?
如图所示,黄色的是Stage,粉红的边框是整个Map,有部分显示,有一部分没有显示。右下角的绿色点是主角的位置,我们假定红色的点是我们的触碰点。
认定红色的触碰点为向前,我在提供一个方案,但是方法不唯一哈,我这样确定方向也不一定是最符合用户体验的。
以主角的位置为原点重现建立坐标系,得到触碰点的新坐标x,y.
确定了在新坐标系下的触碰点的象限,在判断x,y的大小就可以知道方向了。
代码如下:
代码如下 |
复制代码 |
Vector3 tmp = new Vector3(x, y, 0);
stage.getCamera().unproject(tmp);
float newx = tmp.x - player.x;
float newy = tmp.y - player.y;
if (newx > 0 && newy > 0) {
if (newx > newy) {
ChangeDirect(4);
} else {
ChangeDirect(1);
}
} else if (newx > 0 && newy < 0) {
if (newx > -newy) {
ChangeDirect(4);
} else {
ChangeDirect(2);
}
} else if (newx < 0 && newy > 0) {
if (-newx > newy) {
ChangeDirect(3);
} else {
ChangeDirect(1);
}
} else {
if (-newx > -newy) {
ChangeDirect(3);
} else {
ChangeDirect(2);
}
} |
直接移动Camera位置可以移动地图,但是我们的主角却从地图上消失了…处理办法是将你希望仍然显示在地图上的Actor的坐标随着Camera一起移动。
代码如下:
代码如下 |
复制代码 |
private void CameraMove(Vector3 vector3) {
stage.getCamera().position.add(vector3);
for (Actor actor : stage.getActors()) {
actor.x += vector3.x;
actor.y += vector3.y;
}
}
|
完整代码:
代码如下 |
复制代码 |
package com.cnblogs.htynkn.game;
import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.tiled.TileAtlas;
import com.badlogic.gdx.graphics.g2d.tiled.TileMapRenderer;
import com.badlogic.gdx.graphics.g2d.tiled.TiledLoader;
import com.badlogic.gdx.graphics.g2d.tiled.TiledMap;
import com.badlogic.gdx.graphics.g2d.tiled.TiledObject;
import com.badlogic.gdx.graphics.g2d.tiled.TiledObjectGroup;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;
public class firstGame implements ApplicationListener, InputProcessor {
Stage stage;
float width;
float height;
private TiledMap map;
private TileAtlas atlas;
private TileMapRenderer tileMapRenderer;
Image player;
Vector3 camDirection = new Vector3(1, 1, 0);
Vector2 maxCamPosition = new Vector2(0, 0);
Vector3 moveVector = new Vector3(0, 0, 0);
boolean isPress;
// Image image;
@Override
public void create() {
final String path = "map/";
final String mapname = "tilemap";
FileHandle mapHandle = Gdx.files.internal(path + mapname + ".tmx");
map = TiledLoader.createMap(mapHandle);
atlas = new TileAtlas(map, Gdx.files.internal("map/"));
tileMapRenderer = new TileMapRenderer(map, atlas, 10, 10);
maxCamPosition.set(tileMapRenderer.getMapWidthUnits(), tileMapRenderer
.getMapHeightUnits());
width = Gdx.graphics.getWidth();
height = Gdx.graphics.getHeight();
stage = new Stage(width, height, true);
Label label = new Label("FPS:", new LabelStyle(new BitmapFont(Gdx.files
.internal("font/blue.fnt"),
Gdx.files.internal("font/blue.png"), false), Color.WHITE),
"fpsLabel");
label.y = height - label.getPrefHeight();
label.x = 0;
stage.addActor(label);
for (TiledObjectGroup group : map.objectGroups) {
for (TiledObject object : group.objects) {
if ("play1".equals(object.name)) {
player = new Image(new TextureRegion(new Texture(Gdx.files
.internal("map/player.png")), 0, 0, 27, 40));
player.x = object.x;
player.y = tileMapRenderer.getMapHeightUnits() - object.y; // map是左上角,Stage是左下角
stage.addActor(player);
}
}
}
InputMultiplexer inputMultiplexer = new InputMultiplexer();
inputMultiplexer.addProcessor(this);
inputMultiplexer.addProcessor(stage);
Gdx.input.setInputProcessor(inputMultiplexer);
}
@Override
public void dispose() {
// TODO Auto-generated method stub
}
@Override
public void pause() {
// TODO Auto-generated method stub
}
@Override
public void render() {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
OrthographicCamera c = (OrthographicCamera) stage.getCamera();
if (isPress) {
CameraMove(moveVector);
}
((Label) stage.findActor("fpsLabel")).setText("FPS: "
+ Gdx.graphics.getFramesPerSecond());
stage.act(Gdx.graphics.getDeltaTime());
tileMapRenderer.render(c);
stage.draw();
}
private void CameraMove(Vector3 vector3) {
stage.getCamera().position.add(vector3);
for (Actor actor : stage.getActors()) {
actor.x += vector3.x;
actor.y += vector3.y;
}
}
@Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void resume() {
// TODO Auto-generated method stub
}
@Override
public boolean keyDown(int keycode) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean keyTyped(char character) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean keyUp(int keycode) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean scrolled(int amount) {
// TODO Auto-generated method stub
return false;
}
private void ChangeDirect(int typeId) {
switch (typeId) {
case 1:
moveVector.set(0, 1, 0);
Gdx.app.log("方向变动", "向上");
break;
case 2:
moveVector.set(0, -1, 0);
Gdx.app.log("方向变动", "向下");
break;
case 3:
moveVector.set(-1, 0, 0);
Gdx.app.log("方向变动", "向左");
break;
case 4:
moveVector.set(1, 0, 0);
Gdx.app.log("方向变动", "向右");
break;
}
}
@Override
public boolean touchDown(int x, int y, int pointer, int button) {
Vector3 tmp = new Vector3(x, y, 0);
stage.getCamera().unproject(tmp);
float newx = tmp.x - player.x;
float newy = tmp.y - player.y;
if (newx > 0 && newy > 0) {
if (newx > newy) {
ChangeDirect(4);
} else {
ChangeDirect(1);
}
} else if (newx > 0 && newy < 0) {
if (newx > -newy) {
ChangeDirect(4);
} else {
ChangeDirect(2);
}
} else if (newx < 0 && newy > 0) {
if (-newx > newy) {
ChangeDirect(3);
} else {
ChangeDirect(1);
}
} else {
if (-newx > -newy) {
ChangeDirect(3);
} else {
ChangeDirect(2);
}
}
isPress = true;
return false;
}
@Override
public boolean touchDragged(int x, int y, int pointer) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean touchMoved(int x, int y) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean touchUp(int x, int y, int pointer, int button) {
isPress = false;
Gdx.app.log("Info", "touchUp: x:" + x + " y: " + y + " pointer: "
+ pointer + " button: " + button);
return false;
}
}
|
本文章介绍了一篇关于手机开发中的android开时的 ui高效做法,有需要了解的朋友可以参考一下下哦。
一、选择恰当的图像尺寸
视图背景图总是会填充整个视图区域,图像尺寸的不适合会导致图像的自动缩放,为了避免这种情况,我们可以先将图片进行缩放到视图的大小。
代码如下 |
复制代码 |
originalImage = Bitmap.createScaledBitmap(
originalImage, //被缩放图
view.getWidth(), //视图宽度
view.getHright(), //视图高度
true //双限行过滤器
);
|
二、去掉不需要的默认窗口背景
在默认情况下,窗口有一个不透明的背景,有时候我们并不需要他,就可以去掉他。因为更新看不见的窗口是浪费时间的。
去掉的方法:
1.代码实现:
代码如下 |
复制代码 |
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//删除窗口背景
getWindow().setBackgroundDrawable(null);
}
|
2.xml里实现:
首先去顶你的res/xml/styles.xml里有
代码如下 |
复制代码 |
<resources>
<style name="NoBackGroundTheme" parent="android:Theme">
<item name="android:windowBackground">@null</item>
</style>
</resources>
然后在你的manifest.xml里声明
<activity android:name="MyActivity" android:theme="@style/NoBackGroundTheme">
......
</activity>
|
三、尽可能的使用简单的布局和视图
如果一个窗口包含很多的视图,那么启动时间长、测量时间长、绘制时间长、布局时间长;
如果视图树深度太深,会导致StackOverflowException异常,和用户界面反映会很慢很慢。
解决的方法:
1.使用TextView的复合drawables,减少层次
如有这样的布局:
代码如下 |
复制代码 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="@string/hello" />
<Image android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/image" android:background="@drawable/icon" />
</LinearLayout>
|
我们可以这样来取代他,从而来将少层次:
代码如下 |
复制代码 |
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="@string/hello" android:drawableRight="@drawable/icon"/>
|
2.使用ViewStub延迟展开视图
默认情况下,使用ViewStub包含的视图是不可见的。
代码如下 |
复制代码 |
<ViewStub android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/vs" android:layout="@layout/main"/>
|
这个里面包含的main视图是不会展现出来的,如果需要展现出来需要代码的处理
代码如下 |
复制代码 |
findViewById(R.id.vs).setVisibility(View.VISIBLE);
者
findViewById(R.id.vs).inflate();
|
3.使用<merge>合并视图
默认情况下,布局文件的根作为一个借点加入到父视图中,如果使用<merge>可以避免根节点。
如果最外层的布局是FrameLayout,那么可以使用merge替换掉,引用官方说明:
Obviously, using <merge /> works in this case because the parent of an activity's content view is always a FrameLayout. You could not apply this trick if your layout was using a LinearLayout as its root tag for instance.
代码如下 |
复制代码 |
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
.....
</merge>
|
4.使用RelativeLayout减少层次
5.自定义布局
通常在android应用中,数据都是在本应用沙盒之内的,其他外部应用不能够访问,那么如果一个应用需要访问另外一个应用的数据,怎么办呢?那就把另外一个应用的数据公布出来,比如android中的通讯录数据,这些数据是以ContentProvider方式提供与其他应用访问的。
那么我们也可以定义自己的ContentProvider来使跨应用共享数据。数据具体的存贮方式可以为数据库、文件,持久化或非持久化存储的其他形式。在这里我们还是使用sqlite数据库存贮数据吧。
老规矩,先来点基础知识。
一.基础知识
1:URI是什么?统一资源标识符,用来标识某一资源的。
通常一个Uri主要由以三部分组成:scheme、Authority、path
1.scheme:ContentProvider(内容提供者)的scheme已经由Android系统规定为:content://
2.主机名(或Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
3.路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
要操作persion表中id为5的记录,可以构建这样的路径:/persion/5
要操作persion表中id为20的记录的name字段, persion/name/10
要操作persion表中的所有记录,可以构建这样的路径:/persion
使用Uri类中的parse()方法获取Uri: Uri uri = Uri.parse("content://com.dongzi/persion")
上面Uri的scheme: content://
Authority: com.dongzi
path: /contact
2、UriMatcher、ContentUrist和ContentResolver
Android系统提供了两个用于操作Uri的工具类:UriMatcher 和ContentUris
UriMatcher:用于匹配Uri:
代码如下 |
复制代码 |
static final int CODES=2;
static final int CODE=1;
static final String AUTHORITY="com.dongzi"; //授权
static final UriMatcher uriMatcher; //Uri匹配
static { //注册匹配的Uri以及返回码
uriMatcher=new UriMatcher(UriMatcher.NO_MATCH); //不匹配任何路径返回-1
uriMatcher.addURI(AUTHORITY, "persion", CODES); //匹配content://com.dongzi/persion 返回2
uriMatcher.addURI(AUTHORITY, "persion/#", CODE); //匹配content://com.dongzi/persion/1234 返回1
}
|
ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
• withAppendedId(uri, id)用于为路径加上ID部分
• parseId(uri)方法用于从路径中获取ID部分
代码如下 |
复制代码 |
//为Uri添加ID
Uri uri=Uri.parse("content://"+AUTHORITY+"/persion");
ContentUris.withAppendedId(uri, 1234);
//生成后的Uri为:content://com.dongzi/person/1234
//获取Uri后面的ID
long id=ContentUris.parseId(Uri.parse("content://com.dongzi/person/1234"));
//得到ID为:1234 |
ContentResolver提供了如下主要方法:
代码如下 |
复制代码 |
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
//该方法用于供外部应用从ContentProvider删除数据。
return 0;
}
@Override
public String getType(Uri uri) {
//该方法用于返回当前Url所代表数据的MIME类型。
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
//该方法用于供外部应用往ContentProvider添加数据。
return null;
}
@Override
public boolean onCreate() {
//在其它应用第一次访问它时被创建。
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
//该方法用于供外部应用从ContentProvider中获取数据。
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
//该方法用于供外部应用更新ContentProvider中的数据。
return 0;
}
|
这里主要说下Url所代表数据的MIME类型:
如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,
例如:要得到所有person记录的Uri为content://com.dongzi/person,那么返回的MIME类型字符串应该为:"vnd.android.cursor.dir/person"。
如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,
例如:得到id为1234的person记录,Uri为content://com.dongzi/person/1234,那么返回的MIME类型字符串为:"vnd.android.cursor.item/person"。
使用ContentResolver操作ContentProvider中的数据
当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查 询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。ContentResolver提供了ContentProvider对应的增、删、改、查方法。
监听ContentProvider中数据的变化
如果我们需要得到数据变化通知,可以使用ContentObserver对数据(数据采用uri描述)进行通知更改以及监听。
代码如下 |
复制代码 |
//通知内容以及发生改变,同时注册了内容监听,监听到内容变化,就调用onChange方法
this.getContext().getContentResolver().notifyChange(uri, new ContentObserver(new Handler()){
public void onChange(boolean selfChange) {
//此处可以进行相应的业务处理
}
});
|
二.实战
说了那么多,是时候了解ContentProvider的使用了,我们这里采用sqlite存贮数据。当然,我们直接采用联系人数据不是更好?
1:首先我们定义DBHelper继承SQLiteOpenHelper,并建表。
代码如下 |
复制代码 |
package com.dongzi;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper {
static final String DB_NAME = "dongzi.db";
static final int DB_VERSION = 1;
static final String TABLE="persion";
static final String TABLE_COLUMN_NAME="name";
static final String TABLE_COLUMN_PHONE="phone";
static final String CREATE_TABLE = "create table persion(id integer primary key autoincrement,name varchar(40) phone varchar(40))";
static final String DRPO_TABLE="drop table if exists persion";
public DBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//这里其实是比较版本,然后升级数据库的,比如说是增加一个字段,或者删除一个字段,或者增加表
db.execSQL(DRPO_TABLE);
onCreate(db);
}
}
|
2:然后定义MyContentProvider继承ContentProvider,并且在类加载时候初始化UriMatcher匹配,以及授权AUTHORITY,同时,这个ContentProvider需要在AndroidManifest.xml中进行注册,并添加授权。
代码如下:
代码如下 |
复制代码 |
package com.dongzi;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.text.TextUtils;
public class MyContentProvider extends ContentProvider {
DBHelper dbHelper=null;
//MIME类型
static final String PERSIONS_TYPE="vnd.android.cursor.dir/person";
static final String PERSION_ITEM_TYPE="vnd.android.cursor.item/person";
//返回码
static final int CODES=2;
static final int CODE=1;
//授权
static final String AUTHORITY="com.dongzi"; //授权
static final UriMatcher uriMatcher; //Uri匹配
static { //注册匹配的Uri以及返回码
uriMatcher=new UriMatcher(UriMatcher.NO_MATCH); //不匹配任何路径返回-1
uriMatcher.addURI(AUTHORITY, "persion", CODES); //匹配content://com.dongzi/persion 返回2
uriMatcher.addURI(AUTHORITY, "persion/#", CODE); //匹配content://com.dongzi/persion/1234 返回1
}
private void init(){
//为Uri添加ID
Uri uri=Uri.parse("content://"+AUTHORITY+"/persion");
ContentUris.withAppendedId(uri, 1234);
//生成后的Uri为:content://com.dongzi/person/1234
//获取Uri后面的ID
long id=ContentUris.parseId(Uri.parse("content://com.dongzi/person/1234"));
//得到ID为:1234
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
//该方法用于供外部应用从ContentProvider删除数据。
SQLiteDatabase db=dbHelper.getWritableDatabase();
int count=0;
switch(uriMatcher.match(uri)){
case CODES:
count = db.delete(DBHelper.DB_NAME, selection, selectionArgs);
break;
case CODE:
// 下面的方法用于从URI中解析出id,对这样的路径content://com.dongzi/persion/1234
// 进行解析,返回值为10
long id = ContentUris.parseId(uri);
String where = "id=" + id;// 删除指定id的记录
where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";// 把其它条件附加上
count = db.delete(DBHelper.DB_NAME, where, selectionArgs);
break;
default:throw new IllegalArgumentException("throw Uri:"+uri.toString());
}
db.close();
return count;
}
@Override
public String getType(Uri uri) {
//该方法用于返回当前Url所代表数据的MIME类型。
switch(uriMatcher.match(uri)){
case CODES:
return PERSIONS_TYPE; //这里CODES代表集合,故返回的是集合类型的MIME
case CODE:
return PERSION_ITEM_TYPE;
default:throw new IllegalArgumentException("throw Uri:"+uri.toString());
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
//该方法用于供外部应用往ContentProvider添加数据。
SQLiteDatabase db= dbHelper.getWritableDatabase();
long id=0;
//匹配Uri
switch(uriMatcher.match(uri)){
//返回码
case CODES:
id=db.insert(DBHelper.TABLE, DBHelper.TABLE_COLUMN_NAME, values);// 返回的是记录的行号,主键为int,实际上就是主键值
return ContentUris.withAppendedId(uri, id);
case CODE:
id=db.insert(DBHelper.TABLE, DBHelper.TABLE_COLUMN_NAME, values);// 返回的是记录的行号,主键为int,实际上就是主键值
String path = uri.toString();
return Uri.parse(path.substring(0, path.lastIndexOf("/"))+id); // 替换掉id
default:throw new IllegalArgumentException("throw Uri:"+uri.toString());
}
}
@Override
public boolean onCreate() {
//在其它应用第一次访问它时被创建。
dbHelper =new DBHelper(getContext());
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
//该方法用于供外部应用从ContentProvider中获取数据。
SQLiteDatabase db=dbHelper.getWritableDatabase();
Cursor cursor=null;
switch(uriMatcher.match(uri)){
case CODES:
cursor=db.query(DBHelper.DB_NAME, projection, selection, selectionArgs, null, null, sortOrder);
break;
case CODE:
//下面的方法用于从URI中解析出id,对这样的路径content://com.dongzi/persion/1234
// 进行解析,返回值为10
long id = ContentUris.parseId(uri);
String where = "id=" + id;// 获取指定id的记录
where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";// 把其它条件附加上
cursor=db.query(DBHelper.DB_NAME, projection, where, selectionArgs, null, null, sortOrder);
break;
default:break;
}
return cursor;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
//该方法用于供外部应用更新ContentProvider中的数据。
return 0;
}
}
|
如果我们基本了解了上述说的基础知识,那么这些代码不难看懂,其实也非常简单,不直接操作DBHelper类,而是通过ContentProvider间接操作,而操作ContentProvider又是太通过
ContentResolver这个类,实现不同应用都可以访问这些数据。