(一)活动
活动的创建,以及在AndroidManifest文件中的注册。
配置主活动使用标签
并在标签里添加声明
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
活动的销毁
除了BACK按钮可以实现活动的销毁
还可以使用finish();
Toast的使用
点击按钮弹出Toast。
// 普通弹出Toast
Toast.makeText(getApplicationContext(),"Toast",Toast.LENGTH_LONG).show();
//居中显示Toast
Toast toastCenter=Toast.makeText(getApplicationContext(),"居中Toast",Toast.LENGTH_LONG);
toastCenter.setGravity(Gravity.CENTER,0,0);
toastCenter.show();
//自定义的Toast
Toast toastCustom=new Toast(getApplicationContext());
LayoutInflater inflater=LayoutInflater.from(ToastActivity.this);
View view=inflater.inflate(R.layout.layout_toast,null);
ImageView imageView=view.findViewById(R.id.iv_toast);
TextView textView=view.findViewById(R.id.tv_toast);
imageView.setImageResource(R.drawable.icon_love);
textView.setText("myToast");
toastCustom.setView(view);
toastCustom.setDuration(Toast.LENGTH_LONG);
toastCustom.show();
Intent
包含显式Intent和隐式Intent
// 显式
Intent intent=new Intent(AActivity.this,BActivity.class);
startActivity(intent);
//隐式
Intent intent=new Intent();
intent.setAction("com.example.basisproject.BActivity");
startActivity(intent);
隐式Intent更多用法
隐式Intent不用像显式Intent那样传入一个目标activity的类名,只需要传入操作的响应,也就是action;Android其中最重要的特性之一,就是一个应用可以基于“action”来切换到另一个应用。比如,你的应用想要查找地方,在地图上显示。但是不一定要创建一个activity来显示地图,可以使用Intent发起一个请求来查看地址,然后Android系统会启动一个可以显示地图的应用。
例1:拨号
Uri number = Uri.parse("tel:5551234");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
例2:查看地图
Uri location = Uri.parse("geo:38.899533,-77.036476");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
例3:打开网页
Uri website = Uri.parse("http://xxxxx.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, website);
尽管Android系统保证每一个确切的Intent都会对应apps中发起的一个请求响应(比如电话、邮件或者地图应用等),但是在调用一个Intent之前还是应该包含验证这一步骤的。如果调用了一个Intent,但是设备中并没有一个可以处理这个Intent请求响应的应用,这时候app就会崩溃了。
检验是否有适合的应用来接收Intent:创建一个PackageManager的对象,调用queryIntentActivities() 来获取activity的List容器,这个可以用来处理Intent。如果这个List不为空的话,那就说明至少有一个应用可以接这个Intent,调用Intent是安全的
Uri website = Uri.parse("http://www.baidu.com");
Intent webIntent = new Intent(Intent.ACTION_VIEW, website);
PackageManager packageManager = getPackageManager();
List activities = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
boolean isIntentSafe = activities.size() > 0;
if(isIntentSafe){
startActivity(webIntent);
}
活动之间数据的传递
1.向下一个活动传递数据
在第一个活动中:
Intent intent=new Intent(AActivity.this,BActivity.class);
Bundle bundle=new Bundle();//以bundle为载体
bundle.putString("name","colorful");//数据放入bundle
bundle.putInt("num",24);//数据放入bundle
intent.putExtras(bundle);//传入bundle
startActivity(intent);
在第二个活动中接收:
Bundle bundle=getIntent().getExtras();//bundle为载体
String name=bundle.getString("name");
int num=bundle.getInt("num");
2.返回数据给上一个活动
第一个活动:
Intent intent=new Intent(AActivity.this,BActivity.class);
startActivityForResult(intent,0);
第二个活动:
Intent intent=new Intent();
Bundle bundle1=new Bundle();
bundle1.putString("title","lif");
intent.putExtras(bundle1);
setResult(Activity.RESULT_OK,intent);
finish();//销毁
第一个活动接收返回的数据:
//接收BActivity 返回的数据
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Toast.makeText(AActivity.this,data.getExtras().getString("title"),Toast.LENGTH_LONG).show();
}
活动的生命周期
四种状态
运行状态
暂停状态
停止状态
销毁状态
7个回调方法
onCreate()。每个活动都重写了这个方法,它会在活动第一次被创建的时候调用。你应该在这个完成活动的初始化操作,比如加载布局、绑定事件等。
onStart()。这个方法在活动有不可见变为可见的时候调用。
onResume()。这个方法在活动准备好和用户进行交互的时候调用此时的活动一定位于返回栈的栈顶,并且处于运行状态。
onPause()。这个方法在系统准备去启动或者恢复另外一个活动的时候调用。我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快不然会影响新的栈顶活动的使用。
onStop()。这个方法是在活动不可见的时候调用的。它和onPause()方法的主要区别在于,如果启动的新活动是个对话框式的活动,那么onPause()法方法会得到执行,而onStop()方法不会执行。
onDestory()。这个方法在活动被销毁之前调用,之后的活动状态将变成销毁状态。
onrestart()。这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了
活动的启动模式
standard模式
这是Android默认的启动模式,在不指定的情况下都是默认该模式,该模式不会检查返回栈里是否包含该活动,而是直接创建新的活动
singleTop模式
只创建了一个活动,该模式会检查返回栈的栈顶是否存在该活动,若存在,则不创建新活动。
singleTask模式
该模式会检查整个返回栈中是否存在该活动,如果存在则直接调用,并不会生成新的活动。
singleInstance模式
在该模式下,会启动一个新的返回栈来管理该活动。
(二)UI开发
TextView
Button
EditText
ImageView
ProgressBar
AlertDialog
AlertDialog.Builder builder=new AlertDialog.Builder(DialogActivity.this);//实例化
builder.setTitle("please answer").setMessage("what about the Android?").setIcon(R.drawable.icon_love).setPositiveButton("nice", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ToastUtil.showMsg(DialogActivity.this,"positive");
}
}).setNeutralButton("neutral", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ToastUtil.showMsg(DialogActivity.this,"neutral");
}
}).setNegativeButton("bad", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ToastUtil.showMsg(DialogActivity.this,"bad");
}
}).show();
ProgressDialog
ProgressDialog progressDialog=new ProgressDialog(ProgressActivity.this);
progressDialog.setTitle("提示");
progressDialog.setMessage("loading");
progressDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
ToastUtil.showMsg(ProgressActivity.this,"cancel...");
}
});
progressDialog.setCancelable(true);
progressDialog.show();
LinearLayout
RelativeLayout
RecyclerView的使用
在dependencies闭包中添加依赖
implementation 'androidx.recyclerview:recyclerview:1.1.0'
1基本用法
布局中加入RecyclerView 控件
准备一个适配器,创建LinearAdapter类
public class LinearAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context mContext;
//构造方法
public LinearAdapter(Context context){
this.mContext=context;
}
@NonNull
@Override
//负责承载每个子项的布局
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if(viewType==0){
return new LinearViewHolder(LayoutInflater.from(mContext).inflate(R.layout.layout_linear_item,parent,false));
}else{
return new LinearViewHolder2(LayoutInflater.from(mContext).inflate(R.layout.layout_linear_item_2,parent,false));
}
}
//负责将每个子项holder绑定数据
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
if(getItemViewType(position)==0){
((LinearViewHolder)holder).textView.setText("Hello World!");//偶数位置设置文本
}else{
((LinearViewHolder2)holder).textView.setText("Hello!");//奇数位置文本
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext,"click...."+position,Toast.LENGTH_SHORT).show();
}
});//item的点击事件
}
//奇偶数位置区别
@Override
public int getItemViewType(int position) {
if(position%2==0){
return 0;
}else {
return 1;
}
}
//返回控件数目
@Override
public int getItemCount() {
return 30;
}
//自定义ViewHolder1
class LinearViewHolder extends RecyclerView.ViewHolder{
private TextView textView;
public LinearViewHolder(View itemView){
super(itemView);
textView=itemView.findViewById(R.id.tv_title);//文本
}
}
//自定义ViewHolder2
class LinearViewHolder2 extends RecyclerView.ViewHolder{
private TextView textView;
private ImageView imageView;
public LinearViewHolder2(View itemView){
super(itemView);
textView=itemView.findViewById(R.id.tv_title);//文本
imageView=itemView.findViewById(R.id.iv_image);//图
}
}
}
在Activity中:
public class LinearRecyclerViewActivity extends AppCompatActivity {
private RecyclerView mRvMain;//声明
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_linear_recycler_view);
mRvMain=findViewById(R.id.rv_main);//找到RecyclerView控件
mRvMain.setLayoutManager(new LinearLayoutManager(LinearRecyclerViewActivity.this));
mRvMain.addItemDecoration(new MyDecoration());//添加分割线
mRvMain.setAdapter(new LinearAdapter(LinearRecyclerViewActivity.this));
}
//写一个添加分割线的类
class MyDecoration extends RecyclerView.ItemDecoration{
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0,0,0,getResources().getDimensionPixelOffset(R.dimen.dividerHeight));
}
}
}
2.实现水平方向滚动
在基本用法的基础上,在Activity中的onCreate方法中加入
linearLayoutManager.setOrientation(RecyclerView.HORIZONTAL);//额外设置view方向
3.实现瀑布流效果
在基本用法的基础上,在Activity中的onCreate方法中进行修改
mRvPu=findViewById(R.id.rv_pu);
mRvPu.setLayoutManager(new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL));
mRvPu.addItemDecoration(new MyDecoration());
mRvPu.setAdapter(new StaggeredGridAdapter(PuRecyclerActivity.this));
(三)碎片
碎片的简单用法
1新建一个碎片布局
2新建一个类继承自Fragment
重写Fragment中的onCreateView方法
View view=inflater.inflate(R.layout.xxx,container,false);
return view;
动态创建碎片
1.创建待添加的碎片实例
2.获取FragmentManager,在活动中可以调用getSupportFragmentManager()得到
3.开启一个事务,调用beginTransaction开启
4向容器内添加或置换碎片,用replace()实现
5提交事务,调用commit()
FragmentManager fragmentManager=getSupportFragmentManager();
FragmentTransaction transaction=fragmentManager.beginTransaction();
transaction.replace(R.id.xxx,fragment);
transaction.commit();
在碎片中模拟返回栈
为了防止按下返回键,直接将activity退出,而是返回到上一个碎片。
FragmentManager fragmentManager=getSupportFragmentManager();
FragmentTransaction transaction=fragmentManager.beginTransaction();
transaction.replace(R.id.xxx,fragment);
transaction.addToBackStack(null);//模仿类似于返回栈的效果
transaction.commit();
碎片和活动之间进行通信
在活动中找到碎片:
AFragment fragment=(AFragment)getSupportFragmentManager().findFragmentById(R.id.xxx);
在碎片中找到活动:
Activity activity=(Activity)getActivity();
(四)广播机制
接受系统广播
定义一个内部类继承自BroadcastReceiver,并重写其父类的onReceive方法
class NetworkChangeReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
//当接收广播成功时要完成的动作/事件 }
}
创建IntentFilter的实例,并添加action
intentFilter=new IntentFilter();//创建实例
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//监听此广播
创建第一步定义的类的实例,传入参数
networkChangeReceiver=new NetworkChangeReceiver();//创建实例
registerReceiver(networkChangeReceiver,intentFilter);//注册
最后记得在活动销毁的时候取消注册
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(networkChangeReceiver);
}
发送自定义的本地广播
本地广播的优势:
1可以明确知道正在发送的广播不会离开该程序,不必担心数据泄密
2其他应用程无法将广播发送到我们应用程序的内部,不必担心有安全漏洞的隐患
3本地广播比全局广播更加高效
定义一个内部类继承自BroadcastReceiver,并重写其父类的onReceive方法
private class MyBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()){
case "com.example.update":
mtvTest.setText("finally");
break;
}
}
}
创建IntentFilter的实例,并添加action
IntentFilter intentFilter=new IntentFilter();
intentFilter.addAction("com.example.update");//监听此广播
创建第一步定义的类的实例,创建一个本地广播管理器的实例,用该实例注册
myBroadcast=new MyBroadcast();//实例化LocalBroadcastManager localBroadcastManager=LocalBroadcastManager.getInstance(this);//获取实例
localBroadcastManager.registerReceiver(myBroadcast,intentFilter);//注册
发送本地广播
Intent intent=new Intent("com.example.update");
LocalBroadcastManager.getInstance(BroadActivity2.this).sendBroadcast(intent);//发送本地广播
活动销毁的时候取消注册
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager localBroadcastManager=LocalBroadcastManager.getInstance(this);
localBroadcastManager.unregisterReceiver(myBroadcast);
}
发送标准广播
静态注册实现开机启动
发送有序广播
(五) 数据存储
SharedPreferences存储
获取SharedPreferences对象的三种方法
1Context类中的getSharedPreferences()方法
此方法接收两个参数,1是指定创建文件的名称2是指定操作模式,默认操作模式MODE_PRIVATE。
2Activity类中的getPreferences()方法
此方法接收一个参数即操作模式,创建文件时自动将当前活动的类名当作文件名
3PreferenceManager类中的getDefaultSharedPreferences()方法
接收一个Context参数,并自动使用当前应用程序的包名作为前缀命名创建的文件
存储文件的步骤
1调用SharedPreferences对象的edit()方法获取一个SharedPreferences.Editor对象。
2向SharedPreferences.Editor对象中添加数据,putBoolean,putString,putInt等等。
3调用apply方法将数据提交。
mSharedPreferences=getSharedPreferences("anything",MODE_PRIVATE);//指定文件名为anything
mEditor=mSharedPreferences.edit();
mbtnSave.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mEditor.putString("name",metName.getText().toString());
mEditor.apply();
}
});
从SharedPreferences文件中读取数据
1通过getSharedPreferences方法获取SharedPreferences对象
2调用getInt,getString,getBoolean方法获取数据
mbtnShow.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mtvContent.setText(mSharedPreferences.getString("name",""));
}
});
文件存储
内部存储不是内存,内部存储位于系统中很特殊的一个位置,当应用被卸载后,内部存储的文件夹也被删除,一个应用所创建的所有文件都在和应用包名相同的目录下。
数据的写入
Context类提供了openFileOutput(String name,ContextMode model)方法;
name指的是文件名,(不可以包含路径)
model 主要有两种模式,MODE_PRIVATE(同名文件覆盖) MODE_APPEND(同名文件夹追加)
public void save(String inputText){
FileOutputStream out=null;
BufferedWriter writer=null;
try {
out=openFileOutput("data", Context.MODE_PRIVATE);
writer=new BufferedWriter(new OutputStreamWriter(out));
writer.write(inputText);
}catch (IOException e){
e.printStackTrace();
}finally {
try {
if (writer!=null){
writer.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
数据的读取
Context.openFileInput(String name);
name是文件名
String inputText=load();
if(!TextUtils.isEmpty(inputText)){
etSomething.setText(inputText);
etSomething.setSelection(inputText.length());
}
SQLite
(参考博客:【Android】SQLite数据库基本用法详解(极简洁))
Android 提供的 SQLiteOpenHelper.java 是一个抽象类。要使用它,必须自己写一个类来继承它。
此时需要在DatabaseHelper类中实现三个方法:构造函数(以后生成数据库对象的时候要用到),onCreate,onUpgrade
构造函数
//带全部参数的构造函数,此构造函数必不可少
public DatabaseHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
}
onCreate
@Override
public void onCreate(SQLiteDatabase db) {
//创建数据库sql语句并执行
String sql = "create table user(name varchar(20))";
db.execSQL(sql);
}
创建数据库
这里我们给数据库起名为“test_db”,数据库版本号为1
//依靠DatabaseHelper带全部参数的构造函数创建数据库
DatabaseHelper dbHelper = new DatabaseHelper(MainActivity.this, "test_db",null,1);
SQLiteDatabase db = dbHelper.getWritableDatabase();
增
插入数据,首先需要new一个ContentValues,内容值对象
//创建存放数据的ContentValues对象
ContentValues values = new ContentValues();
values.put("name",insert_data);
//数据库执行插入命令
db.insert("user", null, values);
删
删除数据,这里不需要生成ContentValues对象,直接从表user中delete符合要求的内容即可
db.delete("user", "name=?", new String[]{delete_data});
改
更新数据,这里和插入数据类似,需要new一个ContentValues对象,然后放入数据,执行update
ContentValues values2 = new ContentValues();
values2.put("name", update_after_data);
db.update("user", values2, "name = ?", new String[]{update_before_data});
查
查询全部数据,这里使用了Cursor游标进行查询,游历数据同时,把数据用换行符\n连接起来,再把所有数据展示到文本显示框内
//创建游标对象
Cursor cursor = db.query("user", new String[]{"name"}, null, null, null, null, null);
//利用游标遍历所有数据对象
//为了显示全部,把所有对象连接起来,放到TextView中
String textview_data = "";
while(cursor.moveToNext()){
String name = cursor.getString(cursor.getColumnIndex("name"));
textview_data = textview_data + "\n" + name;
}
textview.setText(textview_data);
// 关闭游标,释放资源
cursor.close();
LitePal
配置LitePal
添加依赖
implementation 'org.litepal.android:java:3.0.0'
在assets目录下配置litepal.xml文件
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="test" />
<version value="1" />
<list>
</list>
</litepal>
修改AndroidManifest.xml
android:name="org.litepal.LitePalApplication"
创建数据库
使用面向对象的思想实现功能
定义一个Book类(继承自LitePalSupport类)
public class Book extends LitePalSupport {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
将Book类添加到映射模型列表里
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="test" />
<version value="1" />
<list>
<mapping class="com.example.basisproject.datastorage.Book"></mapping>
</list>
</litepal>
创建数据库
LitePal.getDatabase();
使用LitePal添加数据
Book book=new Book();
book.setName(xxx);
book.save();
使用LitePal更新数据
法1:
Book book=new Book();
book.setName(xxx);
book.save();
法2:
Book book=new Book();
book.setName(nameafter);
book.updateAll("name=?",namebefore);//约束条件
使用LitePal查询数据
List<Book> books=LitePal.findAll(Book.class);
for(Book book1:books){
result.setText(book1.getName()+"");
}