简单的android游戏开发实例教程

 更新时间:2016年9月20日 20:01  点击:1666
本文章简单的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 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. 根据你网速的情况,下载安装的时间或长或短,请耐心等待。

本文章介绍了一篇关于手机开发中的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这个类,实现不同应用都可以访问这些数据。

Windows操作系统下,今天进行Android4.0安装时需要更新软件包,下载下来后自动安装出现这样一个问题:

Android2.2安装时需要更新软件包 - Elly - Elly?·

  解决办法:

  1.进入sdk的temp文件夹,下载好后会有一个tools_r15-windows.zip(版本号可能会不一样)

  2.解压此文件,如解压成tools_r15-windows

  3.进入tools_r15-windows文件夹,将tools_r15-windows里的文件复制

  4.覆盖sdk根目录的tools文件夹中的文件

[!--infotagslink--]

相关文章

  • Android子控件超出父控件的范围显示出来方法

    下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
  • Android开发中findViewById()函数用法与简化

    findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20
  • Android模拟器上模拟来电和短信配置

    如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
  • 夜神android模拟器设置代理的方法

    夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
  • android自定义动态设置Button样式【很常用】

    为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
  • Android WebView加载html5页面实例教程

    如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
  • 深入理解Android中View和ViewGroup

    深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
  • Android自定义WebView网络视频播放控件例子

    下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
  • Android用MemoryFile文件类读写进行性能优化

    java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
  • Android设置TextView竖着显示实例

    TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
  • android.os.BinderProxy cannot be cast to com解决办法

    本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20
  • vscode搭建STM32开发环境的详细过程

    这篇文章主要介绍了vscode搭建STM32开发环境的详细过程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-05-02
  • Android 实现钉钉自动打卡功能

    这篇文章主要介绍了Android 实现钉钉自动打卡功能的步骤,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下...2021-03-15
  • Android 开发之布局细节对比:RTL模式

    下面我们来看一篇关于Android 开发之布局细节对比:RTL模式 ,希望这篇文章对各位同学会带来帮助,具体的细节如下介绍。 前言 讲真,好久没写博客了,2016都过了一半了,赶紧...2016-10-02
  • Android中使用SDcard进行文件的读取方法

    首先如果要在程序中使用sdcard进行存储,我们必须要在AndroidManifset.xml文件进行下面的权限设置: 在AndroidManifest.xml中加入访问SDCard的权限如下: <!--...2016-09-20
  • Android开发之PhoneGap打包及错误解决办法

    下面来给各位简单的介绍一下关于Android开发之PhoneGap打包及错误解决办法,希望碰到此类问题的同学可进入参考一下哦。 在我安装、配置好PhoneGap项目的所有依赖...2016-09-20
  • 安卓开发之Intent传递Object与List教程

    下面我们一起来看一篇关于 安卓开发之Intent传递Object与List的例子,希望这个例子能够为各位同学带来帮助。 Intent 不仅可以传单个的值,也可以传对象与数据集合...2016-09-20
  • 用Intel HAXM给Android模拟器Emulator加速

    Android 模拟器 Emulator 速度真心不给力,, 现在我们来介绍使用 Intel HAXM 技术为 Android 模拟器加速,使模拟器运行度与真机比肩。 周末试玩了一下在Eclipse中使...2016-09-20
  • php微信公众账号开发之五个坑(二)

    这篇文章主要为大家详细介绍了php微信公众账号开发之五个坑,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2016-10-02
  • Android判断当前屏幕是全屏还是非全屏

    在安卓开发时我碰到一个问题就是需要实现全屏,但又需要我们来判断出用户是使用了全屏或非全屏了,下面我分别找了两段代码,大家可参考。 先来看一个android屏幕全屏实...2016-09-20