赞
踩
ContentProvider相当于一个接口,该接口的作用是对外暴露本APP的数据。
当我们想允许本应用的数据可以被别的应用进行读取,可以让本的APP实现ContentProvider类,同时注册一个URI,然后其他应用只要使用ContentResolver访问指定URI就可以操作我们APP里的数据了。
ContentProvider为数据定义一个URI,其他Application想要操作本Application中的数据时,只需要获得一个ContentResolver对象并传入相应的URI,即可操作本Application中 URI 下的数据。
需要重写onCreate( )、delete( )、getType( )、insert( )、query( )、update( )方法。
其中增删查改方法可以用来操作本应用的SQLite数据库。
package com.example.myapplication;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class MyContentProvider extends ContentProvider{
/*创建ContentProvider时调用,其他应用程序第一次访问ContentProvider时,该ContentProvider会被创建出来,立即回调该方法
*/
@Override
public boolean onCreate() {
return false;
}
/*根据ContentProvider传来的属性字段查询数据库中指定条件下的数据
projection:要查询的列名
selection:where子句的内容
selectionArgs:selection中对应的参数
sortOrder:排序规则
*/
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
return null;
}
/*用于返回指定URI代表的数据的MIME类型
*/
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
/*根据ContentProvider传来的属性字段插入contentValues中的的数据到数据库
*/
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
return null;
}
/*根据ContentProvider传来的属性字段删除数据库中where条件匹配的数据信息
*/
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
return 0;
}
/*根据ContentProvider传来的属性字段更新更新where条件匹配的数据为contentValues
*/
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
return 0;
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--属性依次为:全限定类名,用于匹配的URI,是否对外暴露数据 -->
<!--只有与uri.mycontentprovider该URI有关的请求才会被该应用捕获并处理-->
<provider
android:name="com.example.myapplication.MyContentProvider"
android:authorities="uri.mycontentprovider"
android:exported="true"/>
</application>
</manifest>
每个对外暴露数据的Application都必须有一个URI,其他Application通过该URI访问本应用的数据。
//字符串转URI
Uri uri = Uri.parse("uri.mycontentprovider");
//获取uri中数据部分存入一个List中
List<String> segments = uri.getPathSegments();
不同URI代表着不同的操作,所以当ContentProvider接收到URI时,我们需要解析URI才能知道该条URI想进行什么操作。
UriMatcher类用于匹配Uri。当应用程序通过URI访问ContentProvider时,UriMatcher用于检查URI是否符合我们预先定义好的若干条规则,如果符合某条规则,则可使用该URI,返回该条规则的匹配码。
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);//常量UriMatcher.NO_MATCH表示Uri不匹配时的返回码
ContentProvider接收到外部发来的请求URI后会根据匹配规则进行匹配。
matcher.addURI("uri.mycontentprovider", "studentall", 1);//查询所有学生记录,如果URI为:uri.mycontentprovider/studentall时会返回1
matcher.addURI("uri.mycontentprovider", "students/*", 2);//根据学号和姓名模糊查询获得多个记录。*是字符通配符,可以匹配任何字符,例如:将来可以匹配students/stuId="+stuId+"&stuName="+stuName
matcher.addURI("uri.mycontentprovider", "student/#", 3);//单个学生,需要根据studentid来判断,#是数字通配符,可以匹配任何数字,例如:将来可以匹配student/001,student/002等
matcher.addURI("uri.mycontentprovider", "insertStudent", 4);//插入学生
matcher.addURI("uri.mycontentprovider", "deleteStudent", 5);//删除单个学生,需要根据studentid来判断,#将来调用时实参使用学号来代替
matcher.addURI("uri.mycontentprovider", "updateStudent", 6);//修改学生信息
//点击”查询全部学生“按钮时,ContentResolver会执行query方法,发送URI,ContentProvider捕获到该URI后需要判断匹配规则是否符合,符合才执行查询操作
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
switch (matcher.match(Uri.parse("uri.mycontentprovider/studentall"))){
//URI符合我们设置的匹配规则
case 1:{
//查询操作
}
//URI不匹配
default:{
break;
}
}
}
});
ContentUris类用于操作Uri路径后面的ID(唯一标识符)部分。
/*
public static Uri withAppendedId (Uri contentUri, long id):用于为路径加上ID部分。
*/
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person");
Uri resultUri = ContentUris.withAppendedId(uri, 10);
//生成后的Uri为:content://cn.itcast.provider.personprovider/person/10
/*
public static long parseId (Uri contentUri)该方法用于从路径中获取ID部分。
*/
Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person/10")
long personid = ContentUris.parseId(uri);//获取的结果为:10
当外部应用需要对ContentProvider中的数据进行增删改查操作时,可以使用ContentResolver类完成。
通过Activity的静态方法获取ContentResolver对象。
ContentResolver resolver = this.getContentResolver();
ContentResolver 类提供了与ContentProvider 类相同签名的四个方法,通过给这些方法提供ContentProvider的URI使得这些方法能够调用ContenProvider中与之对应的CRUD方法,并得到返回的结果。
ContentResolver resolver = this.getContentResolver();
/*根据传入的URI查询指定条件下的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
*/
resolver.query(ContentProvider的URI,SQL参数...);
/*根据传入的URI插入contentValues对应的数据
public Uri insert(Uri uri, ContentValues values)
*/
resolver.insert(ContentProvider的URI,SQL参数...);
/*根据传入的URI删除where条件匹配的所有数据
public int delete(Uri uri, String selection, String[] selectionArgs)
*/
resolver.delete(ContentProvider的URI,SQL参数...);
/*根据传入的URI更新更新where条件匹配的数据为contentValues
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
*/
resolver.update(ContentProvider的URI,SQL参数...);
用于监听ContentProvider中单个URI下数据的变化。
在ContentProvider 能使数据发生变化的方法中 调用以下方法:
//该方法的作用是:通知注册在该URI:content://uri.mycontentprovider/studentall上的监听器:该URI上的数据发生变化
this.getContext().getContentResolver().notifyChange(Uri.parse("content://uri.mycontentprovider/studentall"), null);
需要重写构造方法和onChange方法。
class MyContentObserve extends ContentObserver{
/*
当观察到Uri代表的数据发生变化时,会触发该方法
*/
@Override
public void onChange(boolean selfChange, @Nullable Uri uri) {
//消息弹框,通知所有注册了监听的Application该URI下的数据发生变化
Toast.makeText(MainActivity.this,"来自ContentObserver的通知:ContentProvider的数据发生改变",Toast.LENGTH_LONG).show();
}
public MyContentObserve(Handler handler) {
super(handler);
}
}
在需要进行监听的位置加入下面的代码,当该URI下的数据发生变化时,ContentProvider会发送通知,然后就会被下面的代码接收到通知,接收到通知后会调用MyContentObserve的onChange方法。
//获取ContentResolver
ContentResolver resolver = this.getContentResolver();
//注册ContentObserver的监听器,当uri="content://uri.mycontentprovider/studentall"的数据有变化时,就触发,回调MyObserver对象的onChange(boolean selfChange, Uri uri)方法
contentResolver.registerContentObserver(Uri.parse("content://uri.mycontentprovider/studentall"),true,new MyContentObserve(new Handler()));
数据库位于app中,app2访问app的数据库进行增删查改。
package com.example.myapplication;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.List;
public class MyContentProvider extends ContentProvider{
//数据库对象,MyContentProvider是用来对外暴露数据库数据的
private MySQLiteOpenHelper openHelper;
//URI解析器
private UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
/*创建ContentProvider时调用,其他应用程序第一次访问ContentProvider时,该ContentProvider会被创建出来,立即回调该方法
*/
@Override
public boolean onCreate() {
//获得数据库dbHelper对象,将来用它得到SQLLiteDatabase对象
openHelper = new MySQLiteOpenHelper(this.getContext());
//设置该ContentProvider下的URI匹配规则
//当ContentResolver发送的请求为content://uri.mycontentprovider/studentall时,会执行匹配码1对应的方法
matcher.addURI("uri.mycontentprovider","studentall",1);
//当ContentResolver发送的请求为content://uri.mycontentprovider/student/......时,会执行匹配码2对应的方法
matcher.addURI("uri.mycontentprovider","student/#",2);
//当ContentResolver发送的请求为content://uri.mycontentprovider/insertStudent时,会执行匹配码3对应的方法
matcher.addURI("uri.mycontentprovider","insertStudent",3);
//当ContentResolver发送的请求为content://uri.mycontentprovider/deleteStudent时,会执行匹配码4对应的方法
matcher.addURI("uri.mycontentprovider","deleteStudent",4);
//当ContentResolver发送的请求为content://uri.mycontentprovider/updateStudent时,会执行匹配码5对应的方法
matcher.addURI("uri.mycontentprovider","updateStudent",5);
return true;
}
/*根据ContentProvider传来的属性字段查询数据库中指定条件下的数据
projection:要查询的列名
selection:where子句的内容
selectionArgs:selection中对应的参数
sortOrder:排序规则
*/
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
SQLiteDatabase database = openHelper.getWritableDatabase();
Cursor cursor = null;
//根据ContentResolver传来的URI匹配相应的匹配码,并执行匹配码下的方法
switch (matcher.match(uri)){
//匹配码1对应的方法
case 1:{
//操作本ContentProvider的数据库,根据ContentResolver传来的数据进行查询操作
cursor = database.query("student", projection, selection, selectionArgs, "", "", sortOrder);
break;
}
//匹配码2对应的方法
case 2:{
//操作本ContentProvider的数据库,根据ContentResolver传来的数据进行查询操作
cursor = database.query("student", projection, selection, selectionArgs, "", "", sortOrder);
break;
}
//不匹配时执行的默认方法,即ContentResolver想执行query方法但是匹配码对应不上,也就是请求的URI在ContentProvider中没有相应的匹配码
default:{
break;
}
}
//database.close();
//返回结果给方法调用者ContentResolver
return cursor;
}
/*用于返回指定URI代表的数据的MIME类型
*/
@Nullable
@Override
public String getType(@NonNull Uri uri) {
return null;
}
/*根据ContentProvider传来的属性字段插入contentValues中的的数据到数据库
*/
@Nullable
@Override
public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
SQLiteDatabase database = openHelper.getWritableDatabase();
//根据ContentResolver传来的URI匹配相应的匹配码,并执行匹配码下的方法
switch (matcher.match(uri)){
//匹配码3对应的方法
case 3:{
//操作本ContentProvider的数据库,根据ContentResolver传来的数据执行插入操作
database.insert("student",null,contentValues);
//发送通知给所有注册了监听的ContentResolver,告诉它们数据库中的信息发生改变
this.getContext().getContentResolver().notifyChange(Uri.parse("content://uri.mycontentprovider/studentall"), null);
break;
}
//不匹配时执行的默认方法,即ContentResolver想执行query方法但是匹配码对应不上,也就是请求的URI在ContentProvider中没有相应的匹配码
default:{
break;
}
}
//database.close();
//返回结果给方法调用者ContentResolver
return uri;
}
/*根据ContentProvider传来的属性字段删除数据库中where条件匹配的数据信息
*/
@Override
public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
SQLiteDatabase database = openHelper.getWritableDatabase();
int i =0;
//根据ContentResolver传来的URI匹配相应的匹配码,并执行匹配码下的方法
switch (matcher.match(uri)){
//匹配码4对应的方法
case 4:{
//操作本ContentProvider的数据库,根据ContentResolver传来的数据执行删除操作
i = database.delete("student", selection, selectionArgs);
//发送通知给所有注册了监听的ContentResolver,告诉它们数据库中的信息发生改变
this.getContext().getContentResolver().notifyChange(Uri.parse("content://uri.mycontentprovider/studentall"), null);
break;
}
//不匹配时执行的默认方法,即ContentResolver想执行query方法但是匹配码对应不上,也就是请求的URI在ContentProvider中没有相应的匹配码
default:{
break;
}
}
//database.close();
//返回结果给方法调用者ContentResolver
return i;
}
/*根据ContentProvider传来的属性字段更新更新where条件匹配的数据为contentValues
*/
@Override
public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String selection, @Nullable String[] selectionArgs) {
SQLiteDatabase database = openHelper.getWritableDatabase();
int i = 0;
//根据ContentResolver传来的URI匹配相应的匹配码,并执行匹配码下的方法
switch (matcher.match(uri)){
//匹配码5对应的方法
case 5:{
//操作本ContentProvider的数据库,根据ContentResolver传来的数据执行更新操作
i = database.update("student",contentValues, selection, selectionArgs);
//发送通知给所有注册了监听的ContentResolver,告诉它们数据库中的信息发生改变
this.getContext().getContentResolver().notifyChange(Uri.parse("content://uri.mycontentprovider/studentall"), null);
break;
}
//不匹配时执行的默认方法,即ContentResolver想执行query方法但是匹配码对应不上,也就是请求的URI在ContentProvider中没有相应的匹配码
default:{
break;
}
}
//database.close();
//返回结果给方法调用者ContentResolver
return i;
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--属性依次为:全限定类名,用于匹配的URI,是否对外暴露数据 -->
<!--只有与uri.mycontentprovider该URI有关的请求才会被该应用捕获并处理-->
<provider
android:name="com.example.myapplication.MyContentProvider"
android:authorities="uri.mycontentprovider"
android:exported="true"/>
</application>
</manifest>
package com.example.myapplication;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import androidx.annotation.Nullable;
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
//创建数据库mydatabase
public MySQLiteOpenHelper(@Nullable Context context) {
super(context, "mydatabase", null, 1);
}
//建表student
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL("create table student(stuId varchar(20) primary key ,stuName varchar(20) ,stuSex varchar(20) ,stuAge varchar(20))");
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
package com.example.app2;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//获取ContentResolver
ContentResolver resolver = this.getContentResolver();
//获取控件对象
EditText stuId = findViewById(R.id.stuId);
EditText stuName = findViewById(R.id.stuName);
EditText stuSex = findViewById(R.id.stuSex);
EditText stuAge = findViewById(R.id.stuAge);
ListView listview = findViewById(R.id.listview);
Button addBtn = findViewById(R.id.addbtn);
Button deleteBtn = findViewById(R.id.deletebtn);
Button selectBtn = findViewById(R.id.selectbtn);
Button updateBtn = findViewById(R.id.updatebtn);
//注册ContentObserver的监听器,当uri="content://uri.mycontentprovider/studentall"的数据有变化时,就触发,在MyObserver对象的onChang()方法
resolver.registerContentObserver(Uri.parse("content://uri.mycontentprovider/studentall"),true,new MyObserver(new Handler()));
//点击按钮插入数据
addBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ContentValues values = new ContentValues();
values.put("stuId",stuId.getText().toString());
values.put("stuName",stuName.getText().toString());
values.put("stuSex",stuSex.getText().toString());
values.put("stuAge",stuAge.getText().toString());
//发送请求,调用resolver的insert方法并传入URI,管理该URI的ContentProvider捕获到该请求后会执行对应的insert方法,返回结果给该请求(相当于该方法调用了ContentProvider中的inserrt方法)
resolver.insert(Uri.parse("content://uri.mycontentprovider/insertStudent"), values);
//消息弹框
Toast.makeText(MainActivity.this,"远程插入成功",Toast.LENGTH_LONG).show();
//将输入框数据置空
stuId.setText("");
stuName.setText("");
stuSex.setText("");
stuAge.setText("");
//唤醒查询点击事件
selectBtn.callOnClick();
}
});
//点击按钮查询数据,查询需要主键_id,这是SQLite的规定
selectBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//游标
Cursor cursor = null;
//根据ID判断查一条信息还是查所有学生信息
if (stuId.getText().toString().trim().equals("")){
//发送请求,调用resolver的query方法并传入URI,管理该URI的ContentProvider捕获到该请求后会执行对应的query方法,返回结果给该请求
cursor = resolver.query(Uri.parse("content://uri.mycontentprovider/studentall"),new String[]{"stuId as _id","stuName","stuSex","stuAge"},null,null,null);
}else{
//发送请求,调用resolver的query方法并传入URI,管理该URI的ContentProvider捕获到该请求后会执行对应的query方法,返回结果给该请求
cursor = resolver.query(Uri.parse("content://uri.mycontentprovider/student/"+stuId.getText().toString()),new String[]{"stuId as _id","stuName","stuSex","stuAge"},"_id = ?",new String[]{stuId.getText().toString()},"");
}
//将查询结果通过适配器渲染到listview控件中
SimpleCursorAdapter cursorAdapter = new SimpleCursorAdapter(MainActivity.this,R.layout.one,cursor,new String[]{"_id","stuName","stuSex","stuAge"},new int[]{R.id.oneid,R.id.onename,R.id.onesex,R.id.oneage});
listview.setAdapter(cursorAdapter);
//消息弹框
Toast.makeText(MainActivity.this,"远程查询成功",Toast.LENGTH_LONG).show();
}
});
//点击某一列表项触发该事件,将列表信息填入输入框
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
TextView id = view.findViewById(R.id.oneid);
TextView name = view.findViewById(R.id.onename);
TextView age = view.findViewById(R.id.oneage);
TextView sex = view.findViewById(R.id.onesex);
//获取数据
stuId.setText(id.getText());
stuName.setText(name.getText());
stuSex.setText(age.getText());
stuAge.setText(sex.getText());
}
});
//点击按钮删除数据
deleteBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//发送请求,调用resolver的delete方法并传入URI,管理该URI的ContentProvider捕获到该请求后会执行对应的delete方法,返回结果给该请求
resolver.delete(Uri.parse("content://uri.mycontentprovider/deleteStudent"),"stuId=?",new String[]{stuId.getText().toString()});
//消息弹框
Toast.makeText(MainActivity.this,"远程删除成功",Toast.LENGTH_LONG).show();
//清空输入框数据
stuId.setText("");
stuName.setText("");
stuSex.setText("");
stuAge.setText("");
//唤醒查询点击事件
selectBtn.callOnClick();
}
});
//修改数据
updateBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ContentValues contentValues = new ContentValues();
contentValues.put("stuName",stuName.getText().toString());
contentValues.put("stuAge",stuAge.getText().toString());
contentValues.put("stuSex",stuSex.getText().toString());
//发送请求,调用resolver的update方法并传入URI,管理该URI的ContentProvider捕获到该请求后会执行对应的delete方法,返回结果给该请求
resolver.update(Uri.parse("content://uri.mycontentprovider/updateStudent"),contentValues,"stuId=?",new String[]{stuId.getText().toString()});
//消息弹框
Toast.makeText(MainActivity.this,"远程修改成功",Toast.LENGTH_LONG).show();
//将输入框数据置空
stuId.setText("");
stuName.setText("");
stuSex.setText("");
stuAge.setText("");
//唤醒查询点击事件
selectBtn.callOnClick();
}
});
}
//监听器类,监听ContentProvider的某个URI下数据的变化
class MyObserver extends ContentObserver {
public MyObserver(Handler handler) {
super(handler);
Toast.makeText(MainActivity.this,"开始",Toast.LENGTH_LONG).show();
}
//URI下的数据发生变化时会回调该方法
public void onChange(boolean selfChange, Uri uri) {
//消息弹框,通知所有注册了监听的Application该URI下的数据发生变化
Toast.makeText(MainActivity.this,"来自ContentObserver的通知:ContentProvider的数据发生改变",Toast.LENGTH_LONG).show();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="学号:"
android:textSize="20sp"
android:gravity="center"/>
<EditText
android:id="@+id/stuId"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/border_bottom"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="姓名:"
android:textSize="20sp"
android:gravity="center"/>
<EditText
android:id="@+id/stuName"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/border_bottom"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="性别:"
android:textSize="20sp"
android:gravity="center"/>
<EditText
android:id="@+id/stuSex"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/border_bottom"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="年龄:"
android:textSize="20sp"
android:gravity="center"/>
<EditText
android:id="@+id/stuAge"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableBottom="@drawable/border_bottom"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/addbtn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="添加"/>
<Button
android:id="@+id/deletebtn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="删除"/>
<Button
android:id="@+id/updatebtn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="修改"/>
<Button
android:id="@+id/selectbtn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="查询"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="学号"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="姓名"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="性别"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="年龄"/>
</LinearLayout>
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:id="@+id/one">
<TextView
android:id="@+id/oneid"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView
android:id="@+id/onename"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView
android:id="@+id/onesex"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView
android:id="@+id/oneage"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
必须先运行app创建数据库,之后才能运行app2操作app的数据库。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。