<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:id="@+id/tv_one"
android:text="@string/tv_one"
android:textColor="@color/teal_700"
android:textStyle="bold"
android:textSize="25sp"
android:background="@color/purple_200"
android:gravity="center_horizontal"
android:layout_width="200dp"
android:="200dp"/>
LinearLayout>
id:组件id
text:文本内容
gravity:文本对齐方式
layout_width:盒子宽度
layout_height:盒子高度
@string/tv_one定义在res/values/strings.xml中 可以设定字符串 通过name取值
@color/teal_700同理
android:shadowColor:设置阴影颜色,需要和shadowRadius一起使用
android:shadowRadius:设置阴影的模糊程度,设为0.1就变成字体颜色,建议3.0
android:shadowDx:设置阴影在水平方向的偏移
android:shadowDy:设置阴影在竖直方向的偏移
<TextView
android:id="@+id/tv_one"
android:layout_width="200dp"
android:layout_height="200dp"
android:gravity="center_horizontal"
android:shadowColor="@color/red"
android:shadowRadius="3.0"
android:text="@string/tv_one"
android:shadowDx="10.0"
android:shadowDy="10.0"
android:textColor="@color/teal_700"
android:textSize="25sp"
android:textStyle="bold" />
android:singleLine="true" //单行显示文本
android:ellipsize="marquee" //跑马灯显示省略文本
android:marqueeRepeatLimit="marquee_forever" //无限循环
android:focusable="true" //可以获得焦点
android:focusableInTouchMode="true"> //触屏获得焦点
获取焦点方法1.
android:clickable="true"
添加点击获得焦点
获取焦点方法2.
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean isFocused() {
return true;
}
}
重写TextView方法,默认一直获取焦点
方法3.
<requestFocus/>
加载就获取焦点
<Button
android:text="点击"
android:textColor="@color/white"
android:background="@drawable/btn_selector"
android:backgroundTint="@color/btn_color_selector"
android:layout_width="200dp"
android:layout_height="100dp"/>
@drawable可绘制图片
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_baseline_account_balance_24" android:state_pressed="true"/>
<item android:drawable="@drawable/ic_baseline_accessibility_24"/>
selector>
在drawable创建btn_selector.xml设置按压一个图片,释放一个图片
selector选择器,可以为颜色,图片等
public class MainActivity extends AppCompatActivity {
private static final String TAG="leo";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = findViewById(R.id.btn);
//点击事件
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.e(TAG, "onClick: ");
}
});
//长按事件
btn.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
Log.e(TAG, "OnLongClick: ");
return false;
}
});
//触摸事件
btn.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.e(TAG, "onTouch: "+motionEvent.getAction());
return false;
}
});
}
}
当返回值为false时,才会执行其他事件,若为true时,执行完此事件,不再接着执行
也可以自定义事件
<Button
android:text="点击"
android:textColor="@color/white"
android:background="@drawable/btn_selector"
android:backgroundTint="@color/btn_color_selector"
android:layout_width="200dp"
android:layout_height="100dp"
android:onClick="myOnclick"
android:id="@+id/btn"
/>
public void myOnclick(View view) {
Log.e(TAG, "OnLongClick: ");
}
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<EditText
android:id="@+id/et"
android:hint="请输入用户名"
android:inputType="phone"
android:textColorHint="#95a1aa"
android:layout_width="200dp"
android:layout_height="100dp"/>
<EditText
android:hint="请输入用户名"
android:inputType="textPassword"
android:textColorHint="#95a1aa"
android:drawableLeft="@drawable/ic_baseline_person_24"
android:drawablePadding="5dp"
android:background="@color/white"
android:paddingLeft="5dp"
android:layout_width="200dp"
android:layout_height="100dp"/>
<Button
android:id="@+id/btn"
android:text="获取用户名"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
LinearLayout>
hint:隐式提醒,输入内容时消失
inputType:输入文本的内容
drawableLeft:输入框的图片
drawablePadding:图片与输入值间距
paddingLeft:图标与左侧间距
android:orientation="vertical":自适应布局
通过按钮获取输入框内容
public class MainActivity extends AppCompatActivity {
private EditText et;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = findViewById(R.id.btn);
et = findViewById(R.id.et);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String text = et.getText().toString();
Log.e("leo", "输入的内容"+text);
}
});
}
}
/*
设置按钮监听,然后点击获取输入框的文本值
*/
<ImageView
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/wuxing2"
android:scaleType="fitCenter"
/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/wuxing2"
android:maxHeight="200dp"
android:maxWidth="200dp"
android:adjustViewBounds="true"
/>
android:scaleType="fitCenter" :进行图片缩放
android:maxHeight="200dp"
android:maxWidth="200dp":设置最大宽高 前提开启adjustViewBounds
android:adjustViewBounds="true":可以调整View的界限
<LinearLayout android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<ProgressBar
android:id="@+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="leonclick"
android:text="显示或者隐藏进度条" />
<ProgressBar
android:id="@+id/pd2"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:layout_width="300dp"
android:layout_height="wrap_content"/>
<Button
android:onClick="loclick"
android:text="模拟下载"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ProgressBar
android:indeterminate="true"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
android:layout_width="300dp"
android:layout_height="wrap_content"/>
LinearLayout>
style="?android:attr/progressBarStyleHorizontal":设置成水平进度条
android:indeterminate="true":将进度条设置成不加载精度的进度条
点击事件
public class MainActivity extends AppCompatActivity {
private ProgressBar progressBar;
private ProgressBar progressBar2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = findViewById(R.id.pb);
progressBar2 = findViewById(R.id.pd2);
}
public void leonclick(View view) {
if(progressBar.getVisibility()==View.GONE){
progressBar.setVisibility(View.VISIBLE);
}else{
progressBar.setVisibility(View.GONE);
}
}
public void loclick(View view) {
int progress = progressBar2.getProgress();
progress+=10;
progressBar2.setProgress(progress);
}
}
/*
progressBar.getVisibility()==View.GONE:获取进度条的显示效果是否为隐藏
progressBar2.getProgress()获取进度条的数值
*/
按钮
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发出通知"
android:onClick="sendNotification"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="取消通知"
android:onClick="cacelNotification"
/>
LinearLayout>
public class MainActivity extends AppCompatActivity {
private NotificationManager manager;
private Notification notification;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
//调用Context的getSystemService()方法获取,getSystemService()方法接收一个字符串参数用于确定获取系统那一个服务,这里是Context.NOTIFICATION_SERVICE。
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
//该手机的操作系统版本号大于等于安卓6
NotificationChannel channel = new NotificationChannel("leo", "测试通知", NotificationManager.IMPORTANCE_HIGH);//id需要和NotificationCompat的id一致 NotificationChannel的用户可见名称 和通知强度
manager.createNotificationChannel(channel);//创建通知chan链
}
Intent intent = new Intent(this, NotificationActivity.class); //通信跳转到NotificationActivity
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
//跳转到一个activity组件
notification = new NotificationCompat.Builder(this,"leo")
.setContentTitle("官方通知") //设置通知标题
.setContentText("开始学习安卓开发了") //设置通知内容
.setSmallIcon(R.drawable.ic_baseline_person_24) //设置通知小图标
.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.wuxing))//设置通知大图标
.setColor(Color.parseColor("#ff0000"))//设置小图标颜色
.setContentIntent(pendingIntent)//设置通知点击跳转
.setAutoCancel(true)//设置通知点击消失
.build();//构建
}
public void sendNotification(View view) {
manager.notify(1,notification);//点击发通知
}
public void cacelNotification(View view) {
manager.cancel(1);//点击取消通知 id和发通知id一致
}
}
NotificationActivity
package com.example.mynotification;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.Nullable;
public class NotificationActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//onCreate方法用来初始化Activity实例对象
Log.e("leo", "onCreate: 进入notificationActivity" );
}
}
需要add到related file xml中
线性布局在开发中使用最多,具有垂直方向与水平方向的布局方式,通过设置属性“android:orientation”控制方向,属性值垂直(vertical)和水平(horizontal),默认水平方向。
android:gravity:内部控件对齐方式,常用属性值有center、center_vertical、center_horizontal、top、bottom、left、right等。
这个属性在布局组件RelativeLayout、TableLayout中也有使用,FrameLayout、AbsoluteLayout则没有这个属性。
center:居中显示,这里并不是表示显示在LinearLayout的中心,当LinearLayout线性方向为垂直方向时,center表示水平居中,但是并不能垂直居中,此时等同于center_horizontal的作用;同样当线性方向为水平方向时,center表示垂直居中,等同于center_vertical。
top、bottom、left、right顾名思义为内部控件居顶、低、左、右布局。
这里要与android:layout_gravity区分开,layout_gravity是用来设置自身相对于父元素的布局。
android:layout_weight:权重,用来分配当前控件在剩余空间的大小。
使用权重一般要把分配该权重方向的长度设置为零,比如在水平方向分配权重,就把width设置为零。
相对布局可以让子控件相对于兄弟控件或父控件进行布局,可以设置子控件相对于兄弟控件或父控件进行上下左右对齐。
RelativeLayout能替换一些嵌套视图,当我们用LinearLayout来实现一个简单的布局但又使用了过多的嵌套时,就可以考虑使用RelativeLayout重新布局。
相对布局就是一定要加Id才能管理。
RelativeLayout中子控件常用属性:
1、相对于父控件,例如:android:layout_alignParentTop=“true”
android:layout_alignParentTop 控件的顶部与父控件的顶部对齐;
android:layout_alignParentBottom 控件的底部与父控件的底部对齐;
android:layout_alignParentLeft 控件的左部与父控件的左部对齐;
android:layout_alignParentRight 控件的右部与父控件的右部对齐;
2、相对给定Id控件,例如:android:layout_above=“@id/**”
android:layout_above 控件的底部置于给定ID的控件之上;
android:layout_below 控件的底部置于给定ID的控件之下;
android:layout_toLeftOf 控件的右边缘与给定ID的控件左边缘对齐;
android:layout_toRightOf 控件的左边缘与给定ID的控件右边缘对齐;
android:layout_alignBaseline 控件的baseline与给定ID的baseline对齐;
android:layout_alignTop 控件的顶部边缘与给定ID的顶部边缘对齐;
android:layout_alignBottom 控件的底部边缘与给定ID的底部边缘对齐;
android:layout_alignLeft 控件的左边缘与给定ID的左边缘对齐;
android:layout_alignRight 控件的右边缘与给定ID的右边缘对齐;
3、居中,例如:android:layout_centerInParent=“true”
android:layout_centerHorizontal 水平居中;
android:layout_centerVertical 垂直居中;
android:layout_centerInParent 父控件的中央;
帧布局或叫层布局,从屏幕左上角按照层次堆叠方式布局,后面的控件覆盖前面的控件。
该布局在开发中设计地图经常用到,因为是按层次方式布局,我们需要实现层面显示的样式时就可以
采用这种布局方式,比如我们要实现一个类似百度地图的布局,我们移动的标志是在一个图层的上面。
在普通功能的软件设计中用得也不多。层布局主要应用就是地图方面。
绝对布局中将所有的子元素通过设置android:layout_x 和 android:layout_y属性,将子元素的坐标位置固定下来,即坐标(android:layout_x, android:layout_y) ,layout_x用来表示横坐标,layout_y用来表示纵坐标。屏幕左上角为坐标(0,0),横向往右为正方,纵向往下为正方。实际应用中,这种布局用的比较少,因为Android终端一般机型比较多,各自的屏幕大小。分辨率等可能都不一样,如果用绝对布局,可能导致在有的终端上显示不全等。所有基本不会使用,这里就不多介绍了。
表格布局,适用于多行多列的布局格式,每个TableLayout是由多个TableRow组成,一个TableRow就表示TableLayout中的每一行,这一行可以由多个子元素组成。实际上TableLayout和TableRow都是LineLayout线性布局的子类。但是TableRow的参数android:orientation属性值固定为horizontal,且android:layout_width=MATCH_PARENT,android:layout_height=WRAP_CONTENT。所以TableRow实际是一个横向的线性布局,且所以子元素宽度和高度一致。
注意:在TableLayout中,单元格可以为空,但是不能跨列,意思是只能不能有相邻的单元格为空。
TableLayout常用属性:
android:shrinkColumns:设置可收缩的列,内容过多就收缩显示到第二行
android:stretchColumns:设置可伸展的列,将空白区域填充满整个列
android:collapseColumns:设置要隐藏的列
列的索引从0开始,shrinkColumns和stretchColumns可以同时设置。
子控件常用属性:
android:layout_column:第几列
android:layout_span:占据列数
作为android 4.0 后新增的一个布局,与前面介绍过的TableLayout(表格布局)其实有点大同小异;
不过新增了一些东东
①跟LinearLayout(线性布局)一样,他可以设置容器中组件的对齐方式
②容器中的组件可以跨多行也可以跨多列(相比TableLayout直接放组件,占一行相比较)
因为是android 4.0新增的,API Level 14,在这个版本以前的sdk都需要导入项目。这里不解释。
常用属性:
排列对齐:
①设置组件的排列方式: android:orientation=“” vertical(竖直,默认)或者horizontal(水平)
②设置组件的对齐方式: android:layout_gravity=“” center,left,right,buttom
设置布局为几行几列:
①设置有多少行: android:rowCount=“4” //设置网格布局有4行
②设置有多少列: android:columnCount=“4” //设置网格布局有4列
设置某个组件位于几行几列
注:都是从0开始算的哦!
①组件在第几行: android:layout_row = “1” //设置组件位于第二行
②组件在第几列: android:layout_column = “2” //设置该组件位于第三列
设置某个组件横跨几行几列(合并):
横跨几行: android:layout_rowSpan = “2” //纵向横跨2行
横跨几列: android:layout_columnSpan = “3” //横向横跨2列
android:layout_gravity="fill"填充
MainActivity
package com.example.testmenu;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//创建OptionMenu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
//加载菜单资源
getMenuInflater().inflate(R.menu.option,menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.save:
Toast.makeText(this,"保存",Toast.LENGTH_SHORT).show();
break;
case R.id.exit:
Toast.makeText(this,"退出",Toast.LENGTH_SHORT).show();
break;
}
return super.onOptionsItemSelected(item);
}
}
activity_main.xml
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:id="@+id/ctx_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="上下文菜单" />
<Button
android:id="@+id/popup_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="弹出式菜单" />
LinearLayout>
两种实现方式,一种重写onCreateContextMenu,一种使用上下文操作模式
package com.example.testmenu;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.ActionMode;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*
//注册contextmenu
registerForContextMenu(findViewById(R.id.ctx_btn));
*/
findViewById(R.id.ctx_btn).setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View view) {
startActionMode(cb);
return false;
}
});
}
/*
//创建
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
getMenuInflater().inflate(R.menu.context,menu);
}
//菜单选的操做覆盖
@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
switch(item.getItemId()){
case R.id.delet:
Toast.makeText(this,"删除",Toast.LENGTH_SHORT).show();
break;
case R.id.opera1:
Toast.makeText(this,"操作1",Toast.LENGTH_SHORT).show();
break;
case R.id.opera2:
Toast.makeText(this,"操作2",Toast.LENGTH_SHORT).show();
break;
}
return super.onContextItemSelected(item);
}
*/
//为按钮设置上下文操作模式
//实现ActionModeCallback接口
ActionMode.Callback cb=new ActionMode.Callback() {
//启动上下文操作模式时调用
@Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
Log.e("TAG", "创建");
getMenuInflater().inflate(R.menu.context,menu);
return true;
}
//在创建方法后使用
@Override
public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
return true;
}
//菜单被点击
@Override
public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
Log.e("TAG", "点击");
switch(menuItem.getItemId()){
case R.id.delet:
Toast.makeText(MainActivity.this,"删除",Toast.LENGTH_SHORT).show();
break;
case R.id.opera1:
Toast.makeText(MainActivity.this,"操作1",Toast.LENGTH_SHORT).show();
break;
case R.id.opera2:
Toast.makeText(MainActivity.this,"操作2",Toast.LENGTH_SHORT).show();
break;
}
return true;
}
//上下文操作结束时调用
@Override
public void onDestroyActionMode(ActionMode actionMode) {
Log.e("TAG", "结束");
}
};
}
context.xml
通过java创建optionmenu菜单
public boolean onCreateOptionsMenu(Menu menu) {
//加载菜单资源
// getMenuInflater().inflate(R.menu.option,menu);
//组id 菜单项id 序号 菜单名称
menu.add(1,1,1,"设置");
SubMenu sub = menu.addSubMenu(1, 2, 2, "更多");
sub.add(2,3,1,"添加");
sub.add(2,4,1,"删除");
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
/* case R.id.save:
Toast.makeText(this,"保存",Toast.LENGTH_SHORT).show();
break;
case R.id.exit:
Toast.makeText(this,"退出",Toast.LENGTH_SHORT).show();
break;*/
case 1:
Toast.makeText(this,"设置",Toast.LENGTH_SHORT).show();
break;
case 2:
Toast.makeText(this,"更多",Toast.LENGTH_SHORT).show();
break;
case 3:
Toast.makeText(this,"添加",Toast.LENGTH_SHORT).show();
break;
case 4:
Toast.makeText(this,"删除",Toast.LENGTH_SHORT).show();
break;
}
return super.onOptionsItemSelected(item);
}
Button button=findViewById(R.id.popup_btn);
findViewById(R.id.popup_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//实例化PopupMenu对象
PopupMenu menu = new PopupMenu(MainActivity.this,button);//出现在谁的下方
//加载菜单资源,利用MenuInflater将Menu资源加载到PopupMenu.getMenu()返回的对象中
menu.getMenuInflater().inflate(R.menu.popup,menu.getMenu());
//设置点击监听
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
switch (menuItem.getItemId()){
case R.id.copy:
Toast.makeText(MainActivity.this,"复制",Toast.LENGTH_SHORT).show();
break;
case R.id.paste:
Toast.makeText(MainActivity.this,"粘贴",Toast.LENGTH_SHORT).show();
break;
}
return false;
}
});
//
menu.show();
}
});
}
popup.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/copy"
android:title="复制" />
<item
android:id="@+id/paste"
android:title="粘贴" />
menu>
package com.example.dialogdemo;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//方法二
public void showNormalDialog(){
AlertDialog builder=new AlertDialog.Builder(MainActivity.this).create();
builder.setTitle("提示");
builder.setMessage("您确定退出吗?");
builder.setButton(DialogInterface.BUTTON_POSITIVE, "确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
builder.show();
}
//方法一
public void myClick(View view) {
switch (view.getId()){
case R.id.normal_dialog_btn:
AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this);
builder.setTitle("提示");
builder.setMessage("您确定退出吗?");
//设置提示按钮,以及后续操作
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
finish();
}
});
builder.setNegativeButton("取消",null);
builder.show();
/*
等价
AlertDialog alertDialog = builder.create();
alertDialog.show();
*/
break;
case R.id.diy_dialog_btn:
break;
}
}
}
方法二设置按钮时不能传空操作
设置按钮布局
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
android:background="@drawable/dialog"
xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
android:textColor="#e61414"
android:textStyle="bold|italic"
android:layout_marginTop="290dp"
android:textSize="34sp"
android:text="@string/isexit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:orientation="horizontal"
android:layout_margin="25dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="@+id/yes_btn"
android:background="@mipmap/yes"
android:layout_marginRight="20dp"
android:layout_width="70dp"
android:layout_height="50dp"/>
<Button
android:id="@+id/no_btn"
android:background="@mipmap/no"
android:layout_marginLeft="20dp"
android:layout_width="70dp"
android:layout_height="50dp"/>
LinearLayout>
LinearLayout>
package com.example.dialogdemo;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//方法二
/*
public void showNormalDialog(){
AlertDialog builder=new AlertDialog.Builder(MainActivity.this).create();
builder.setTitle("提示");
builder.setMessage("您确定退出吗?");
builder.setButton(DialogInterface.BUTTON_POSITIVE, "确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
builder.show();
}
*/
//方法一
public void myClick(View view) {
switch (view.getId()){
case R.id.normal_dialog_btn:
AlertDialog.Builder builder=new AlertDialog.Builder(MainActivity.this);
builder.setTitle("提示");
builder.setMessage("您确定退出吗?");
//设置提示按钮,以及后续操作
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
finish();
}
});
builder.setNegativeButton("取消",null);
builder.show();
/*
等价
AlertDialog alertDialog = builder.create();
alertDialog.show();
*/
break;
case R.id.diy_dialog_btn:
MyDialog myDialog = new MyDialog(this,R.style.mydialog);
myDialog.show();
break;
}
}
}
activity.xml
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:id="@+id/normal_dialog_btn"
android:text="@string/show_alter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="myClick"
/>
<Button
android:id="@+id/diy_dialog_btn"
android:text="@string/show_div_alter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="myClick"
/>
LinearLayout>
定义一个类继承dialog
public class MyDialog extends Dialog {
public MyDialog(@NonNull Context context, int themeResId) {
super(context, themeResId);
setContentView(R.layout.dialog_layout);
findViewById(R.id.yes_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
System.exit(0);
}
});
findViewById(R.id.no_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
}
}
为按钮设置样式
<style name="mydialog" parent="android:style/Theme.Dialog">
- "android:windowNoTitle"
>true
- "android:windowBackground"
>@color/white
style>
在mydialog中应用样式,为对话框添加监听器
如果按钮图片没有加载出来则修改values/themes/themes.xml中
<style name="Theme.Dialogdemo" parent="Theme.MaterialComponents.DayNight.DarkActionBar.Bridge">
只执行最上层的,如A,B,C,D,想执行B,则会添加B
顶部复用
一个栈里一个activity只能有一个如A,B,C,D启动B,就会弹出C,D
先进先出,栈的模式
独自占有一个栈,全局只有一个,如当前栈内是A,B,C,D需要启动E,则会新建栈E,如打电话
生命周期
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UhcyNQIh-1660619680017)(C:\Users\TR\AppData\Roaming\Typora\typora-user-images\image-20220814175616933.png)]
package com.example.activitylife;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate: ");
}
@Override
protected void onStart() {
super.onStart();
Log.i(TAG, "onStart: ");
}
//交互
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume: ");
}
//暂停
@Override
protected void onPause() {
super.onPause();
Log.i(TAG, "onPause: ");
}
@Override
protected void onStop() {
super.onStop();
Log.i(TAG, "onStop: ");
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: ");
}
}
线路一:正常打开到关闭一直往下
线路二:打开另外的activity到onstop()后若返回键,则会到onrestart()再重新创建
线路三:如进行浮窗类事件,则会触发onpause()返回则继续onresume
线路四:终止
补充:当actity销毁之前可以调用
@Override
public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
}
把数据存储起来,在下次程序启动的时候,可以拿到数据
当按返回键时触发
@Override
public void onBackPressed() {
super.onBackPressed();
}
两个Activry之间的传递
可以使用bundle 或则intent自带的常用类型
package com.example.activitylife;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate: ");
}
@Override
protected void onStart() {
super.onStart();
Log.i(TAG, "onStart: ");
}
//交互
@Override
protected void onResume() {
super.onResume();
Log.i(TAG, "onResume: ");
}
//暂停
@Override
protected void onPause() {
super.onPause();
Log.i(TAG, "onPause: ");
}
@Override
protected void onStop() {
super.onStop();
Log.i(TAG, "onStop: ");
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState, @NonNull PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
}
@Override
public void onBackPressed() {
super.onBackPressed();
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy: ");
}
public void myclick(View view) {
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
Bundle bundle = new Bundle();
bundle.putString("name","bundle消息");
bundle.putChar("开头",'A');
intent.putExtra("name",bundle);
startActivity(intent);
}
}
secondactivity
package com.example.activitylife;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_activity);
if(getIntent()!=null){
Bundle bundle = getIntent().getBundleExtra("name");
if(bundle!=null){
String name = bundle.getString("name");
Button button = findViewById(R.id.sec);
button.setText(name);
}
}
}
}
activity.xml
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:id="@+id/btn_onn"
android:onClick="myclick"
android:text="@string/secondactivity"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
LinearLayout>
second.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/sec"
android:textSize="35sp"
android:text="@string/seconnd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
LinearLayout>
序列化传输
传输序列化后的对象
public class User implements Serializable{
private String title;
public class BaseInfo implements Serializable{}
}
序列化的类的方法也需要序列化
public void myclick(View view) {
intent.putExtra("",new User());
}
实现关闭SecondActivity或返回时把值传给MainActivity
startActivityForResult(intent,999);
使用Result传入标识符
SecondActivity添加监听
public void seclick(View view) {
setResult(RESULT_OK);
finish();
}
MainActivity添加接收判断
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.i(TAG, "onActivityResult:启动了 ");
if(requestCode == 999 && requestCode == RESULT_OK){
Log.i(TAG, "onActivityResult: 成功了!");
setTitle("前一个页面返回啦!!");
}else {
setTitle("返回失败了!!");
}
也可直接关闭的时候传入Inent 返回的时候在public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) 的data接收
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OOK5pLfm-1660619680018)(C:\Users\dofun008\AppData\Roaming\Typora\typora-user-images\image-20220815091236288.png)]
MainActivity
package com.example.servicedemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void operate(View view) {
switch (view.getId()){
case R.id.start_:
//启动服务
Intent intent = new Intent(this,MyService.class);
startService(intent);
break;
case R.id.stop_:
//停止服务
Intent intent1 = new Intent(this,MyService.class);//无论开启几个意图还是操作同一个对象
stopService(intent1);
break;
}
}
}
activity_main.xml
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:id="@+id/start_"
android:text="启动服务"
android:onClick="operate"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/stop_"
android:text="停止服务"
android:onClick="operate"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/bind_"
android:text="绑定服务"
android:onClick="operate"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/unbind_"
android:text="解除服务"
android:onClick="operate"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
LinearLayout>
Myservice
package com.example.servicedemo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
private static final String TAG = "Ms";
public MyService() {
}
//创建
@Override
public void onCreate() {
Log.e(TAG, "onCreate: ");
super.onCreate();
}
//启动
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: " );
return super.onStartCommand(intent, flags, startId);
}
//绑定
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.e(TAG, "onBind: " );
throw new UnsupportedOperationException("Not yet implemented");
}
//解绑
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind: " );
return super.onUnbind(intent);
}
//摧毁
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy: " );
super.onDestroy();
}
}
启动服务,通过onCreate,onStartCommand方法,停止服务经过onDestroy,再次启动则会重新创建
服务对象只会存在一个,若服务已经创建,后续启动的都是同一个服务,除非先销毁它
服务的生命周期和Activity无关,除非手动关闭
package com.example.servicedemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private ServiceConnection conn=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void operate(View view) {
switch (view.getId()){
case R.id.start_:
//启动服务
Intent intent = new Intent(this,MyService.class);
startService(intent);
break;
case R.id.stop_:
//停止服务
Intent intent1 = new Intent(this,MyService.class);//无论开启几个意图还是操作同一个对象
stopService(intent1);
break;
case R.id.bind_:
//绑定服务
Intent intent2 = new Intent(this,MyService.class);
bindService(intent2, conn,BIND_AUTO_CREATE);
break;
case R.id.unbind_:
//解绑服务
unbindService(conn);
break;
}
}
}
服务不存在,执行绑定,先创建服务,再绑定服务,执行解绑,先解绑,再销毁。
服务存在,bindService只能被onBind调用,unbindService只能被onUnbind调用
注意:绑定服务不会启动服务,不会在后台启动,只绑定不启动,退出后台后,服务会销毁
IBinder:在android中用于远程操作对象的一个基本接口
//绑定
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.e(TAG, "onBind: " );
return new Binder();
}
//对于onBind方法而言,要求返回IBinder对象
//实际上,我们会自己定义一个内部类,继承Binder类
//用于绑定客户端和服务
private ServiceConnection conn=new ServiceConnection() {
//当客户端正常连接着服务时,执行服务的绑定会被调用
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e("TAG", "onServiceConnected: " );
}
//当客户端和服务的连接丢失了
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e("TAG", "onServiceDisconnected: " );
}
};
服务器解绑后无法再次绑定,然而每次重新绑定会执行
onServiceConnected()方法
所以需要IBind来传值
package com.example.servicedemo;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
//用于绑定客户端和服务
private ServiceConnection conn=new ServiceConnection() {
//当客户端正常连接着服务时,执行服务的绑定会被调用
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e("TAG", "onServiceConnected: " );
MyService.MyBinder mb= (MyService.MyBinder) iBinder;
int process = mb.getProcess();
Log.e("TAG", "当前进度是: "+process );
}
//当客户端和服务的连接丢失了
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e("TAG", "onServiceDisconnected: " );
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void operate(View view) {
switch (view.getId()){
case R.id.start_:
//启动服务
Intent intent = new Intent(this,MyService.class);
startService(intent);
break;
case R.id.stop_:
//停止服务
Intent intent1 = new Intent(this,MyService.class);//无论开启几个意图还是操作同一个对象
stopService(intent1);
break;
case R.id.bind_:
//绑定服务
Intent intent2 = new Intent(this,MyService.class);
bindService(intent2, conn,BIND_AUTO_CREATE);
break;
case R.id.unbind_:
//解绑服务
unbindService(conn);
break;
}
}
}
开启线程,传递进度
package com.example.servicedemo;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import java.util.concurrent.TimeUnit;
public class MyService extends Service {
private int i;
private static final String TAG = "Ms";
public MyService() {
}
//创建
@Override
public void onCreate() {
Log.e(TAG, "onCreate: ");
super.onCreate();
//开启一个线程。开启耗时任务,(从1到100)
new Thread(()->{
for (i = 1; i <=100; i++) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
//启动
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: " );
return super.onStartCommand(intent, flags, startId);
}
//绑定
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.e(TAG, "onBind: " );
return new MyBinder();
}
//对于onBind方法而言,要求返回IBinder对象
//实际上,我们会自己定义一个内部类,继承Binder类
class MyBinder extends Binder{
//定义自己需要的方法(实现进度监控)
public int getProcess(){
return i;
}
}
//解绑
@Override
public boolean onUnbind(Intent intent) {
Log.e(TAG, "onUnbind: " );
return super.onUnbind(intent);
}
//摧毁
@Override
public void onDestroy() {
Log.e(TAG, "onDestroy: " );
super.onDestroy();
}
}
onBind的类的返回值IBinder刚好可以作为ServiceConnection.onServiceConnected的返回值,但是由于IBinder类需要实现很多方法,不方便,于是使用他的实现类Binder类来做返回值,可以自定义自己需要的业务
不同进程之间,数据共享,数据通信
创建新的项目aidldemo1
package com.example.aidldemo1;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
ServiceConnection conn=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e("Ms", "onServiceConnected: " );
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.e("Ms", "onServiceDisconnected: " );
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void operate(View view) {
switch (view.getId()){
case R.id.start_:
//远程启动服务
//Intent intent = new Intent("com.liu.myservice");
Intent intent = new Intent();
intent.setAction("com.liu.myservice");
intent.setPackage("com.example.servicedemo");
startService(intent);
break;
case R.id.stop_:
//远程停止服务
// Intent intent1 = new Intent("com.liu.myservice");
Intent intent1 = new Intent();
intent1.setAction("com.liu.myservice");
intent1.setPackage("com.example.servicedemo");
stopService(intent1);
break;
case R.id.bind_:
//远程绑定服务
//Intent intent2 = new Intent("com.liu.myservice");
Intent intent2 = new Intent();
intent2.setAction("com.liu.myservice");
intent2.setPackage("com.example.servicedemo");
bindService(intent2, conn,BIND_AUTO_CREATE);
break;
case R.id.unbind_:
//远程解绑服务
unbindService(conn);
break;
}
}
}
给原来项目的service起别名
<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>
注意,这个Intent传值一定要显式声明
远程通信
创建aidl资源
// IMyAidlInterface.aidl
package com.example.serviceaidldemo;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
void showProgress();
}
rebuild项目
改写传值方法,因为IBinder只能同一个项目传值
MyService改写onbind
//绑定
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.e(TAG, "onBind: " );
return new IMyAidlInterface.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public void showProgress() throws RemoteException {
Log.e(TAG, "aidl显示的进度为"+i);
}
};
}
MainActivity改写
//用于绑定客户端和服务
private ServiceConnection conn=new ServiceConnection() {
//当客户端正常连接着服务时,执行服务的绑定会被调用
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Log.e("Ms", "onServiceConnected: " );
IMyAidlInterface imai = IMyAidlInterface.Stub.asInterface(iBinder);
try {
imai.showProgress();
} catch (RemoteException e) {
e.printStackTrace();
}
}
在aidldemo中创建aidl 创建下一级目录需要和主程序的包名一直
,复制aidl文件,并rebuilder
改写传输代码
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
IMyAidlInterface imit = IMyAidlInterface.Stub.asInterface(iBinder);
try {
imit.showProgress();
} catch (RemoteException e) {
e.printStackTrace();
}
}
AIDL本质是生成Java类,自己写实现,如同搭建了桥梁
创建两个项目dataproviderdemo和dataresoverdemo
在dataproviderdemo创建other ContentPovider方法
package com.example.dataproviderdemo;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
public class MyContentProvider extends ContentProvider {
public MyContentProvider() {
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Implement this to handle requests to delete one or more rows.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public String getType(Uri uri) {
// TODO: Implement this to handle requests for the MIME type of the data
// at the given URI.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO: Implement this to handle requests to insert a new row.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public boolean onCreate() {
// TODO: Implement this to initialize your content provider on startup.
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO: Implement this to handle query requests from clients.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO: Implement this to handle requests to update one or more rows.
throw new UnsupportedOperationException("Not yet implemented");
}
}
在dataresoverdemo使用dataproviderdemo暴露的方法
在MyContentProvider中onCreate方法中创建数据库
@Override
public boolean onCreate() {
// TODO: Implement this to initialize your content provider on startup.
SQLiteOpenHelper sqLiteOpenHelper=new SQLiteOpenHelper(getContext(),"stu.db",null,1) {
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
String sql="create table info_tb (_id integer primary key autoincrement,"
+"name varchar(20),"
+"age integer,"
+"gender varchar(2))";
sqLiteDatabase.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
};
db = sqLiteOpenHelper.getReadableDatabase();
//返回true
return true;
}
添加方法
case R.id.add_btn:
ContentValues values = new ContentValues();
values.put("name",name);
values.put("age",age);
values.put("gender",genderstr);
//返回值是MyContentProvider中insert传入的值
Uri uri = resolver.insert(Uri.parse("content://com.liu.myprovider"), values);//参数1:URI对象
//解析返回的uri的id
long id = ContentUris.parseId(uri);
Toast.makeText(MainActivity.this, "添加成功,新学生的学号是"+id, Toast.LENGTH_SHORT).show();
break;
contentprovider
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO: Implement this to handle requests to insert a new row.
Log.e("TAG", "调用了DataProviderDemo中的insert方法");
long id = db.insert("info_tb", null, values);
//将id追加到uri后面
return ContentUris.withAppendedId(uri,id);
}
这里resover解析uri然后传入数据,然后接收到contentprovider的ContentUris的方法携带的参数id作为添加成功的依据
查询操作
重写provider的query方法
contentprovider
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO: Implement this to handle query requests from clients.
Cursor c = db.query("info_tb", projection, selection, selectionArgs, null, null, sortOrder);
return c;
}
resover
case R.id.select_btn:
//查询、
Cursor cursor = null;
if(!idedt.equals("")){
cursor = resolver.query(uri, null, "_id=?", new String[]{idedt}, null);;
}else {
cursor = resolver.query(uri, null, null, null, null);;
}
if(cursor!=null){
SimpleCursorAdapter adapter=new SimpleCursorAdapter(this,R.layout.item,cursor,
new String[]{"_id","name","age","gender"},
new int[]{R.id.id_item,R.id.name_item,R.id.age_item,R.id.gender_item},
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);//页面更新
stulist.setAdapter(adapter);
}else {
Toast.makeText(MainActivity.this, "查无此人", Toast.LENGTH_SHORT).show();
}
break;
删除
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Implement this to handle requests to delete one or more rows.
int result = db.delete("info_tb", selection, selectionArgs);
return result;
}
case R.id.delet_btn:
//删除、
int i = resolver.delete(uri, "_id=?", new String[]{idedt});
if(i>0){
Toast.makeText(MainActivity.this, "删除成功", Toast.LENGTH_SHORT).show();
}
break;
修改操作
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO: Implement this to handle requests to update one or more rows.
int tb = db.update("info_tb", values, selection, selectionArgs);
return tb;
}
case R.id.update_btn:
//修改、
ContentValues values1 = new ContentValues();
values1.put("name",name);
values1.put("age",age);
values1.put("gender",genderstr);
int update = resolver.update(uri, values1, "_id=?", new String[]{idedt});
if (update>0){
Toast.makeText(MainActivity.this, "修改成功", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MainActivity.this, "修改失败", Toast.LENGTH_SHORT).show();
}
break;
}
在这里,已经很明显了,contentprovider为resover提供接口,resover请求contentprovider的方法,操作contentprovider的数据,然后收到其返回值
SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。
下载SQLite Expert
activity_main.xml
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<EditText
android:id="@+id/name_edt"
android:hint="姓名:"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="@+id/age_edt"
android:numeric="integer"
android:hint="年龄:"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<RadioGroup
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:text="性别:"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<RadioButton
android:id="@+id/man"
android:text="男"
android:layout_marginLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<RadioButton
android:id="@+id/woman"
android:text="女"
android:layout_marginLeft="5dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
RadioGroup>
<EditText
android:id="@+id/id_edt"
android:hint="编号"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/add_btn"
android:text="添加"
android:onClick="opera"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:onClick="opera"
android:id="@+id/select_btn"
android:text="查询"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:onClick="opera"
android:id="@+id/delet_btn"
android:text="删除"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:onClick="opera"
android:id="@+id/update_btn"
android:text="修改"
android:layout_marginLeft="5dp"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
LinearLayout>
LinearLayout>
编写按钮处理事件
package com.example.sqlitetest;
import androidx.appcompat.app.AppCompatActivity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.view.View;
import android.widget.CursorAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RadioGroup;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private EditText nameEdt,ageEdt,idEdt;
private RadioGroup genderGp;
private String genderstr="男";
private SQLiteDatabase db;
private String sql;
private ListView stulist;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
stulist=findViewById(R.id.stu_list);
nameEdt=findViewById(R.id.name_edt);
ageEdt=findViewById(R.id.age_edt);
idEdt=findViewById(R.id.id_edt);
genderGp=findViewById(R.id.gender_gp);
genderGp.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup radioGroup, int i) {
if(i==R.id.man){
//男
genderstr="男";
}else {
genderstr="女";
}
}
});
//添加、
//操作对象, 数据库名称
//如果只有一个数据库名称,那么这个数据库位置会在私有目录中 data/data
//如果带SD卡路径,那么数据库位置则会在指定的路径下
//String path = Environment.getExternalStorageDirectory() + "/stu.db";
SQLiteOpenHelper helper=new SQLiteOpenHelper(this,"test3.db",null,1) {
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
//创建
Toast.makeText(MainActivity.this, "数据库创建", Toast.LENGTH_SHORT).show();
String sql="create table test_tb1(_id integer primary key autoincrement,"
+"name varchar(20),"+
"age integer,"+"gender varchar(6) )"
;
sqLiteDatabase.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
//升级
Toast.makeText(MainActivity.this, "数据库升级", Toast.LENGTH_SHORT).show();
}
};
//获取数据库对象
//数据库存在则打开数据库,数据库不存在则打开数据库
//数据库存在,但版本号升高了,则调用数据库升级方法
db = helper.getReadableDatabase();
//查询 db.rawQuery();
//增删改创 db.execSQL();
}
public void opera(View view) {
switch (view.getId()){
case R.id.add_btn:
String name=nameEdt.getText().toString();
String age=ageEdt.getText().toString();
// String sql="insert into test_tb1 (name,age,gender) values('"+name+"',"+age+",'"+genderstr+"') ";
sql="insert into test_tb1 (name,age,gender) values(?,?,?) ";
db.execSQL(sql,new String[]{name,age,genderstr});
Toast.makeText(MainActivity.this, "添加成功", Toast.LENGTH_SHORT).show();
break;
case R.id.delet_btn:
//删除、
sql="delete from test_tb1 where _id=?";
db.execSQL(sql,new String[]{idEdt.getText().toString()});
Toast.makeText(MainActivity.this, "删除成功", Toast.LENGTH_SHORT).show();
break;
case R.id.select_btn:
//查询、
if(!idEdt.getText().toString().equals("")){
sql+="where _id="+idEdt.getText().toString();
}
sql="select * from test_tb1";
//查询结果
Cursor cursor = db.rawQuery(sql, null);
//
SimpleCursorAdapter adapter=new SimpleCursorAdapter(this,R.layout.item,cursor,
new String[]{"_id","name","age","gender"},
new int[]{R.id.id_item,R.id.name_item,R.id.age_item,R.id.gender_item},
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);//页面更新
stulist.setAdapter(adapter);
break;
case R.id.update_btn:
//修改、
sql="update test_tb1 set name=?,age=?,gender=? where _id=?";
db.execSQL(sql,new String[]{nameEdt.getText().toString(),ageEdt.getText().toString(),genderstr,idEdt.getText().toString()});
Toast.makeText(MainActivity.this, "修改成功", Toast.LENGTH_SHORT).show();
break;
}
}
}
使用了Viewlist要设置适配器
item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/name_item"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/age_item"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/id_item"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/gender_item"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
LinearLayout>
注意:
如果用的虚拟机,不要把数据库路径写在SD卡中,会闪退
需要借助SQLiteOpenHelper类然后创建数据库或者打开,
使用helper.getReadableDatabase()得到SQLiteDatabase对象,
然后可以对数据库进行增删改查等操作
添加insert()
switch (view.getId()){
case R.id.add_btn:
ContentValues values = new ContentValues();
values.put("name",name);
values.put("age",age);
values.put("gender",genderstr);
long id = db.insert("test_tb1", null, values);//表名,可以为空的列,参数
Toast.makeText(MainActivity2.this, "添加成功,新学员学号是:"+id, Toast.LENGTH_SHORT).show();
break;
第二个参数依据第三个参数而定是否为null
查询query()
case R.id.select_btn:
//查询、
//参数1:表名 参数2:列(查询全部为null或者{"*"})
// 参数3:条件(列1=? 多值为列1=? and 列2=?)参数4:条件的参数 参数5:分组
//参数6:分组条件限定 参数7:排序
Cursor cursor = db.query("test_tb1",null,null,null,null,null,null);
SimpleCursorAdapter adapter=new SimpleCursorAdapter(this,R.layout.item,cursor,
new String[]{"_id","name","age","gender"},
new int[]{R.id.id_item,R.id.name_item,R.id.age_item,R.id.gender_item},
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);//页面更新
stulist.setAdapter(adapter);
break;
删除delete()
case R.id.select_btn:
//查询、
//参数1:表名 参数2:列(查询全部为null或者{"*"})
// 参数3:条件(列1=? 多值为列1=? and 列2=?)参数4:条件的参数 参数5:分组
//参数6:分组条件限定 参数7:排序
Cursor cursor = db.query("test_tb1",null,null,null,null,null,null);
SimpleCursorAdapter adapter=new SimpleCursorAdapter(this,R.layout.item,cursor,
new String[]{"_id","name","age","gender"},
new int[]{R.id.id_item,R.id.name_item,R.id.age_item,R.id.gender_item},
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);//页面更新
stulist.setAdapter(adapter);
break;
修改
case R.id.update_btn:
//修改、
ContentValues values1 = new ContentValues();
values1.put("name",name);
values1.put("age",age);
values1.put("gender",genderstr);
int i = db.update("test_tb1", values1, "_id=?", new String[]{idedt});
if(i>0){
Toast.makeText(MainActivity2.this, "修改成功", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(MainActivity2.this, "修改失败啦", Toast.LENGTH_SHORT).show();
}
break;
}
条件查询
case R.id.select_btn:
//查询、
//参数1:表名 参数2:列(查询全部为null或者{"*"})
// 参数3:条件(列1=? 多值为列1=? and 列2=?)参数4:条件的参数 参数5:分组
//参数6:分组条件限定 参数7:排序
Cursor cursor = null;
if(!idedt.equals("")){
cursor = db.query("test_tb1",null,"_id=?",new String[]{idedt},null,null,null);
}else {
cursor = db.query("test_tb1",null,null,null,null,null,null);
}
if(cursor!=null){
SimpleCursorAdapter adapter=new SimpleCursorAdapter(this,R.layout.item,cursor,
new String[]{"_id","name","age","gender"},
new int[]{R.id.id_item,R.id.name_item,R.id.age_item,R.id.gender_item},
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);//页面更新
stulist.setAdapter(adapter);
}else {
Toast.makeText(MainActivity2.this, "查无此人", Toast.LENGTH_SHORT).show();
}
break;