安卓四大组件及Fragment(实操总结)
一、Activity
简介
- Activity可为用户提供可视化界面
- 在app中只要看得见的几乎都要依赖于Activity
- Activity生命周期(Activity栈)
使用流程
声明
在AndroidManifest.xml配置文件中声明(android studio会自动生成)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.qg.rdcdictionary">
<uses-permission android:name="android.permission.INTERNET" />
...
<application
...
<activity android:name=".taskword.WordActivity" />
<activity android:name=".tasknewbook.NewBookActivity" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
设计视图及加载
在res->layout的xml文件中设计视图布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!--可设置的布局-->
</RelativeLayout>
加载视图文件(一般在创建活动时AS会自动设置好Activity对应布局)
public class MainActivity extends AppCompatActivity {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
...
}
初始化控件
初始化控件在onCreate函数里面(button textView ImageView ViewPager TabLayout DataBaseHelper adapter onclickListener)
public class MainActivity extends AppCompatActivity {
private TabLayout myTab;
private ViewPager2 myPager2;
private ImageView bookIv;
private DatabaseHelper mDatabaseHelper;
List<String> titles=new ArrayList<>();
List<Fragment> fragments=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDatabaseHelper = new DatabaseHelper(this,"Directory.db",null,1);
myTab = findViewById(R.id.tab_layout);
myPager2 = findViewById(R.id.view_pager);
bookIv = findViewById(R.id.book_iv);
//添加Fragment进去
fragments.add(new SearchFragment());
fragments.add(new DayFragment());
fragments.add(new TranslateFragment());
//实例化适配器
MyViewPager2Adapter myAdapter=new MyViewPager2Adapter(getSupportFragmentManager(),getLifecycle(),fragments);
//设置适配器
myPager2.setAdapter(myAdapter);
//TabLayout和Viewpager2进行关联
new TabLayoutMediator(myTab, myPager2, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
tab.setText(titles.get(position));
}
}).attach();
bookIv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this, NewBookActivity.class);
startActivity(intent);
}
});
}
}
生命周期的应用
注意 进行解绑 在onstop里面 解除服务绑定,对其他类的持有等等
@Override
protected void onStop() {
super.onStop();
if (!executorService.isShutdown()) {
executorService.shutdownNow();
}
}
活动间的通信Intent
活动间的切换及通信 :Intent的应用
- 切换 一般用显式Intent
- 上一级的活动
参数:context 跳转到下一个活动的class
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
startActivity(intent);
- 下一级的活动
Intent intent = getIntent();
- 结束或者返回上一个活动(back键)
finish();
- 数据传递
- 用Extra
//发送端
Intent intent = new Intent(getContext(), WordActivity.class);
intent.putExtra("word", data);//参数:暗号 要传递的数据
intent.putExtra("isSave", 0);
//接收端
word = intent.getStringExtra("word"); //参数:暗号
isSaved = intent.getIntExtra("isSave", 0);//参数:暗号 没有接收到数据的预赋值
- 返回数据给上一个活动
//第一个活动
Intent intent = new Intent(FirstActivity.this,SecondActivity.class);
startActivityForResult(intent,1);
//重写onActivityResult方法
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == RESULT_OK){
String returnedData = data.getStringExtra("data_return");
}
}
//第二个活动
Intent intent = new Intent();
intent.putExtra("data_return","Hello");
setResult(RESULT_OK,intent);//参数 返回码:RESULT_OK / RESULT_CANCELED
finish();
//如果用户是按返回键返回的
@Override
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra("data_return","Hello");
setResult(RESULT_OK,intent);
finish();
}
- 用Bundle传递类(序列化和反序列化)
序列化类要实现Serializable接口
public class User implements Serializable {
}
在intnet的使用时加入
//发送端
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
Bundle bundle = new Bundle();
bundle.putSerializable("data",user);
intent.putExtras(bundle);
startActivity(intent);
//接收端
Intent intent = this.getIntent();
User user = (User) intent.getSerializableExtra("user");
补充IntentFilter
- 使用隐式启动时需要加上IntentFilter进行过滤
属性 | 作用 |
action | 表示Intent对象要完成的动作 |
data | 表示Intent对象要完成的动作 |
category | 表示为action添加的额外信息 |
- 匹配规则
action属性
标签中间可以有多个action属性,但是当使用隐式Intent启动时,只要Intnt携带的action与其中一个< intent-filter >标签中action的声明相同即可
<intent-filter>
<action android:name="android.intent.action.EDIT">
</intent-filter>
Intent intent = new Intent("android.intent.action.EDIT");
startIntent(intent);
data属性
标签中间可以有多个data属性,每个data属性可以指定数据MIME类型和URI。MIME类型可以表示image/ipeg、video/*等媒体类型。
隐式Intent携带的data数据只要与IntentFilter中的任意一个data声明相同即可
<intent-filter>
<data android:mimeType="video/mpeg" android:scheme="http">
</intent-filter>
data标签中可以设置以下标签
隐式Intent的应用
Intent intent = new Intent(Intent.ACTION_VIEW);
//Intent.ACTION_VIEW是系统内置动作
intent.setData(Uri.parse"http://www.baidu.com");
//Uri.parse将网址解析为Uri对象
startActivity(intent);
Intent intent = new Intent(Intent.ACTION_DIAL);
//Intent.ACTION_DIAL是系统内置动作
intent.setData(Uri.parse"tel:10086");
startActivity(intent);
category属性
隐式Intent中声明的category全部能够与某一个IntentFilter中的category匹配才算匹配成功。IntentFilter中罗列的category属性数量必须大于或者等于隐式Intent携带的category属性数量时,category属性才能匹配成功
"android.intent.category.DEFAULT"是默认的category
<intent-filter>
<category android:name="android.intent.category.DEFAULT">
</intent-filter>
可动态添加category
Intent intent = new Intent("android.intent.action.EDIT");
intent.addCategory("com.example.activity.MY_CATEGORY");
startIntent(intent);
二、Server
简介
- 一般用作后台 进行耗时操作的处理 如下载或者进行后台播放等等
- 生命周期
基本使用流程
定义
像新建Activity那样新建Service AS会自动在AndroidManifest.xml中注册
启动
- 启动有两种方式 startService和bindService
startService只是启动Service,启动它的组件(如Activity)和Service并没有关联,只有当Service调用stopSelf或者其他组件调用stopService服务才会终止。
bindService方法启动Service,其他组件可以通过回调获取Service的代理对象和Service交互,而这两方也进行了绑定,当启动方销毁时,Service也会自动进行unBind操作,当发现所有绑定都进行了unBind时才会销毁Service。
- startService
//启动
Intent startIntent = new Intent(this,MusicService.class);
startService(startIntent);
//停止
Intent stopIntent = new Intent(this,MusicService.class);
stopService(stopIntent);
- bindService(常用)
//ServiceConnection connection;
//绑定服务
Intent bindIntent = new Intent(SearchActivity.this, MusicService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);
//解除绑定
unbindService(connection);
绑定数据及操作
- 在Myservice类里面新建Binder类并覆写onBinder
(在MusicBinder类里面的函数可以在Activity中调用)
public class MusicService extends Service {
...
private MusicBinder mMusicBinder = new MusicBinder();
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mMusicBinder;
}
public class MusicBinder extends Binder {
public MusicService getService(){
return MusicService.this;
}
public void playClickMusic(List<MusicBean> data, int position){
new Thread(new Runnable() {
@Override
public void run() {
MusicBean musicBean = data.get(position);
setMusicPlayer(musicBean);
Log.d(TAG,"searchMusicPlay path = "+ musicBean.getPath());
}
}).start();
}
....
}
- 在Activity中可以调用
public class SearchActivity extends AppCompatActivity {
//声明binder类
private MusicService.MusicBinder musicBinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.searching_activity);
...
Intent startIntent = new Intent(SearchActivity.this, MusicService.class);
startService(startIntent);
playingBean = Data.get(position);
//实例化ServiceConnection类
ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
musicBinder = (MusicService.MusicBinder) service;
//与服务绑定时建立联系 调用服务binder里面的方法
musicBinder.playClickMusic(Data, position);
}
@Override
public void onServiceDisconnected(ComponentName name) {
//解绑时也可以调用
}
};
Intent bindIntent = new Intent(SearchActivity.this, MusicService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);//把connection
}
}
IntentService
内置开启线程和自动关闭功能
- 标准的service写法 执行完某个耗时操作后自己停止
public class MusicService extends Service {
...
public int onStartCommand(Intent intent, int flags, int startId) {//启动后台服务
super.onStartCommand(intent, flags, startId);
new Thread(()->{
//具体操作逻辑
stopSelf();//任务执行完后需要停止服务
}).start();
return super.onStartCommand(intent, flags, startId);
}
要回到主线程更新UI
//在Activity中
runOnUiThread(new Runnable() {
@Override
public void run() {
//更新UI
}
});
//在Fragment中
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
//更新UI
}
});
- 使用IntentService
- 新建MyIntentService类继承自IntentService
- 构造方法 一定要有 如果是无参则调用父类构造器 名字为子线程的名字,用于区分线程
- onHandleIntent方法里面可以加入耗时操作等具体逻辑
public class MyIntentService extends IntentService {
public MyIntentService() {
super("MyIntentService");
}
public MyIntentService(String name) {
super(name);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
if (intent != null) {
//进行耗时操作
}
}
}
}
- 启动服务
与显式启动service只有跳转对象的不同
intent.setClass(this,MyIntentService.class);
线程池的使用
简介
- 便于线程管理
- 复用线程减少消耗
一般步骤
(可以结合下面的常用例子结合)
- 创建线程池
- java.util.concurrent.Executors 线程池的工厂类 里面的方法可以用来创建线程,不同线程池的方法不一样
- java.util.concurrent.ExecutorService接口,用接口接收创建的线程
- 提交子线程
- 实现Runnable接口,重写run方法,设置线程任务
- 调用ExecutorService中的方法进行提交
- 回到主线程更新UI
用Handler
几种线程池的使用
- FixedThreadPool (可重用固定线程数)
//创建
executorService = Executors.newFixedThreadPool(3);
//使用
executorService.excute(()->{
// 执行耗时操作代码
Handler uiThread = new Handler(Looper.getMainLooper());
uiThread.post(()->{
//
});
});
- CachedThreadPool (按需创建)
//创建
executorService = Executors.newCachedThreadPool();
//使用同上
- SingleThreadPool(单个核线的fixed)
//创建
executorService = Executors.newSingleThreadExecutor();
//使用同上
- ScheduledThreadPool(定时延时执行)
参数
- 第一个是runnable子线程任务
- 第二个是延长的时间
- 第三个是提交周期 TimeUnit.SECONDS/DAYS等等
//创建
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);
scheduledThreadPool.schedule(()->{
// 执行耗时操作代码
Handler uiThread = new Handler(Looper.getMainLooper());
uiThread.post(()->{
//更新UI
});
},10, TimeUnit.SECONDS);
常用例子(替代AsyncTask)
public class SearchActivity extends AppCompatActivity{
private ExecutorService executorService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.searching_activity);
//创建固定线程数量的线程池 参数为线程数量
executorService = Executors.newFixedThreadPool(3);
executorService.submit(new Runnable() {
@Override
public void run() {
// 执行耗时操作代码
//执行完耗时代码回到主线程更新UI
Handler uiThread = new Handler(Looper.getMainLooper());
uiThread.post(new Runnable() {
@Override
public void run() {
//
}
});
}
});
}
}
lanmda表达式简易写法
public class SearchActivity extends AppCompatActivity{
private ExecutorService executorService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.searching_activity);
executorService = Executors.newFixedThreadPool(3);
executorService.submit(()->{
// 执行耗时操作代码
Handler uiThread = new Handler(Looper.getMainLooper());
uiThread.post(()->{
//
});
});
}
}
Broadcast Receiver
简介
- 广播是一种广泛运用的在应用程序之间传输信息的机制,广播接收器是对发送出来的广播进行过滤接受并响应的一类组件
- 可以使用广播接收器来让应用对一个外部时间做出响应。例如,当电话呼入这个外部事件到来时或当下载一个程序成功完成时,仍然可以利用广播接收器进行处理。
- 快捷创建广播 :Exported表示是否允许该广播接受去接收本程序之外的广播,Enabled表示是否启用这个广播接收器
系统全局广播使用流程
广播注册
- 广播注册有静态和动态
- 静态在AndroidManifest中注册(AS快捷方式创建new->other->Broadcast Receiver会自动生成)
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
</receiver>
- 动态在Avtivity中注册,是否关闭与Activity相关联(现在的安卓都要动态注册)
在用到广播的Activity中动态注册
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
registerReceiver(new MyBroadcastReceiver(), new IntentFilter("com.example.broadcasttest.MY_BROADCAST"));//加入过滤条件
}
发送广播
发送广播用Intent
- 自定义广播
Intent intent=new Intent("com.example.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);
- 发送有序广播
在注册时给广播接收器设置优先级
在Activity中只改发送那个行代码,多了一个与权限相关的参数
Intent intent=new Intent("com.example.broadcast.MY_BROADCAST");
sendBroadcast(intent,null);
<receiver
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.broadcast.MY_BROADCAST"/>
</intent-filter>
</receiver>
获得接收广播的优先权后的接收器可以选择是否继续传播该广播
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"received in MyReceiver",Toast.LENGTH_SHORT).show();
abortBroadcast();//表示拦截 不允许其他接收器接收
}
}
接收广播
- 创建一个类继承自BroadcastReceiver(快捷方式自动生成)
- 重写onReceive()
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//具体逻辑
Toast.makeText(context,"receive in MyBroadcastReceiver",Toast.LENGTH_SHORT).show();
}
}
本地广播使用流程
解决安全性问题,只允许在程序应用内传递,广播接收器也只能接收本程序发出的广播
与全局广布不同之处主要在于用LocalBroadcastManager对广播进行管理
//声明LocalBroadcastManager
private LocalBroadcastManager localBroadcastManager;
//获取实例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//注册广播 参数的receiver和intentFilter可以分开实例化,也可以直接实例化
localBroadcastManager.registerReceiver(MyReceiver,intentFilter3);
localBroadcastManager.registerReceiver(new MyBroadcastReceiver(), new IntentFilter("com.example.broadcasttest.MY_BROADCAST"));
//注销广播
localBroadcastManager.unregisterReceiver(localReceiver);
四、Content Provider
简介
- 主要用于在不同的应用程序之间实现数据共享
- 统一数据访问方式
- ContentProvider用于保存和获取数据,并使其对所有应用程序可见,这是不同应用程序间共享数据的唯一方式
使用流程
访问其他程序中的数据
主要基于ContentResolver(内容解析者)
要用到的知识
- Uri的解析(内容URI)
由authority、path、id组成:authority一般采用程序包命名;path用于对同一个程序中不同表的区分,id区分不同数据
content://com.example.app.provider/tabel1/999
content://com.example.app.provider/tabel2/100
Uri uri = Uri.parse("content://com.example.app.provider/tabel1");
- courser的使用
//查询
Cursor cursor = getContentResolver().query(
uri,
projection,
selection,
selectionArgs,
sortOrder);
//读取
if(cursor!=null){
while(cursor.moveToNext()){
String column = cursor.getString(cursor.getColumnIndex("colum1"));
}
cursor.close();
}
- 插入
ContentValues values = new ContentValues();
values.put("column1","text");
values.put("column2",1);
getContentResolver().insert(uri,values);
- 更新(清空)
ContentValues values = new ContentValues();
values.put("column1","");
getContentResolver().update(uri,values,"column1 = ? and column2 = ?",new String[]{"text","1"});
- 删除
getContentResolver().delete(uri,values,"column2 = ?",{"1"});
读取联系人实例
- 申请权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
- 向用户获取授权 (判断+重写onRequestPermissionsResult方法)
if(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_CONTACTS},1);
}else {
//查询联系人
readContacts();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode){
case 1:
if(grantResults.length > 0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
//查询联系人
readContacts();
}else {
Toast.makeText(this,"You denied the permission",Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
- 查询
联系人的查询有固定的uri字符串
private void readContacts(){
Cursor cursor = null;
try {
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null);
if (cursor !=null){
while (cursor.moveToNext()){
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
//对数据的操作 可加入集合等等
}
//列表适配器更新
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (cursor!=null){
cursor.close();
}
}
}
小结
访问其他程序中数据的应用
还可以访问本地音乐 本地文件 本地照片 本地视频 等等本地的数据,都是差不多的流程,只是uri字符串不一样
创建自己的内容提供器
定义匹配的规则,重写六个方法,与数据库使用相结合
- 快捷方式创建 new->other->contect proider(自动注册)
URI Authorities :包名.provider
com.example.darkCloudApp.provider
- 在MyContectProvider类中定义匹配的常量
内容URI格式有两种 以路径结尾表示访问表中所有数据,以id结尾表示访问该表相应id的数据,用通配符分别匹配
- /* 表示匹配任意长度的任意字符 content://com.example.darkCloudApp.provider/*(匹配任意表)
- /# 表示匹配任意长度的数字content://com.example.darkCloudApp.provider/tabel/#(匹配任意一行数据)
借助uriMatcher进行匹配
- addURI 把authorties path id 传进去
- 调用match()可以将一个uri对象传入,返回值是某个能够匹配这个uri对象所对应的自定义代码,利用这个代码可以判断用户想访问什么数据
public class MyContentProvider extends ContentProvider {
//这里的AUTHORITY就是我们在AndroidManifest.xml中配置的authorities
private static final String AUTHORITY = "com.example.darkCloudApp.provider";
//匹配成功后的匹配码 不同类型对应不同的码
private static final int TABLE_DIR = 1;
private static final int TABLE_ITEM = 2;
private static final Uri NOTIFY_URI = Uri.parse("content://" + AUTHORITY + "/tabel");
//声明uriMatch
private static final UriMatcher uriMatcher;
//在静态代码块中添加要匹配的 Uri
static {
//匹配不成功返回NO_MATCH(-1)
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "tabel", TABLE_DIR);// 匹配tabel表中所有数据
uriMatcher.addURI(AUTHORITY, "tabel/#", TABLE_ITEM);// 匹配tabel中单条数据
}
- onCreate
@Override
public boolean onCreate() {
//创建数据库
return false;
}
- query
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
switch (uriMatch.match(uri)){
case TABLE_DIR:
//数据库操作查询table表中所有数据
break;
case TABLE_ITEM:
//数据库操作查询table表中所有数据
break;
default:
break;
}
...
}
- delete
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
//打开数据库
int deletedRows = 0;
switch (uriMatch.match(uri)){
case TABLE_DIR:
//数据库操作删除table表中所有数据
deletedRows = db.delete("表名",selection,selectionArgs);
break;
case TABLE_ITEM:
String bookId = uri.getPathSegments().get(1);
//数据库操作查询table表中某条数据
break;
default:
break;
}
return deletedRows;
}
- insert
@Override
public Uri insert(Uri uri, ContentValues values) {
//打开数据库
Uri uriReturn = null;
switch (uriMatch.match(uri)){
case TABLE_DIR:
case TABLE_ITEM:
long newBookId = db.insert("表名",null,values);
uriReturn = Uri.parse(AUTHORITY+newBookId);
break;
default:
break;
}
return uriReturn;
}
- updata
与delete类似 把delete换成updata
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
//打开数据库
int upDataRows = 0;
switch (uriMatch.match(uri)){
case TABLE_DIR:
//数据库操作更新table表中所有数据
upDataRows = db.update("表名",selection,selectionArgs);
break;
case TABLE_ITEM:
String bookId = uri.getPathSegments().get(1);
//数据库操作更新table表中某条数据
break;
default:
break;
}
return upDataRows;
}
- getType
每个uri对象对应一个MIME类型的格式
@Override
public String getType(Uri uri) {
//按格式拼接 return对应MIME类型的字符串
}
五、Fragment
简介
- 可以嵌入在活动中的UI片段
- 好处:可以兼顾平板
- 与活动的通信
- 在活动中获取碎片
RightFragment rightFragment=(RightFragment)getFragmentManager().findFragmentById(R.id.right_fragment)
- 在碎片中获取活动
MainActivity activity=(MainActivity)getActivity();
使用流程
基础使用
- 快捷创建(AS自动注册 生成对应xml布局文件和类)
- Activity的布局文件
像添加控件一样添加Fragment
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_out_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/bg3"
>
<fragment
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/left_fragment"
android:name="com.suzy.fragmenttestone.LeftFragment"
android:layout_weight="1"/>
<fragment
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/right_fragment"
android:name="com.suzy.fragmenttestone.RightFragment"
android:layout_weight="1"/>
</RelativeLayout>
- Fragment布局文件
跟其他布局文件一样 可以设置碎片中的控件
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".city_main.CityWeatherFragment"
android:layout_gravity="center"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/frag_tv_currenttemp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="3℃"
android:textSize="70sp"
android:textStyle="bold" />
...
</RelativeLayout>
</FrameLayout>
- Fragment类中加载Fragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_city_weather, container, false);
//进行fragment内控件的初始化 设置监听等的操作
return view;
}
其他应用
与viewPager2、TabLayout实现联动
- MainActivity布局
像加入控件一样加入TabLayout和Viewpager2
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toBottomOf="@+id/tab_layout"
android:layout_below="@+id/tab_layout"
/>
<ImageView
android:id="@+id/book_iv"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:src="@drawable/ic_book"/>
</RelativeLayout>
- Fragment的布局文件(自由发挥)
其中一个Fragement
顶部相对布局中含一张图和文本
中间是一张图
底部是一张小图
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".taskday.DayFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/day_top_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/day_play_iv"
android:layout_width="30dp"
android:layout_height="30dp"
android:src="@drawable/ic_play"
android:layout_centerVertical="true"/>
<TextView
android:id="@+id/day_sentence_tv"
style="@style/TitleText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@+id/day_play_iv" />
</RelativeLayout>
<ImageView
android:id="@+id/day_picture_iv"
android:layout_width="440dp"
android:layout_height="560dp"
android:layout_gravity="center_horizontal"
/>
</LinearLayout>
</FrameLayout>
- Fragment类
跟普通的Activity类差不多
public class DayFragment extends Fragment {
private View view;
private TextView sentenceTv;
private ImageView playIv, pictureIv;
private String playPath;
MediaPlayer player = new MediaPlayer();
public DayFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//加载视图
view = inflater.inflate(R.layout.fragment_day, container, false);
//初始化
initView();
//设置播放的监听
playIv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try {
player.reset();
player.setDataSource(playPath);
player.prepare();
player.start();
} catch (IOException e) {
e.printStackTrace();
}
}
});
return view;
}
private void initView() {
//加载控件
playIv = view.findViewById(R.id.day_play_iv);
pictureIv = view.findViewById(R.id.day_picture_iv);
sentenceTv = view.findViewById(R.id.day_sentence_tv);
//初始化控件
sentenceTv.setText("I feel I stand in a desert with my hands outstretched, and you are raining down upon me.");
playPath = "https://staticedu-wps.cache.iciba.com/audio/349d814dccb823f3263a8be842b6ac71.mp3";
pictureIv.setImageResource(R.mipmap.picture);
}
}
- MainActivity类
public class MainActivity extends AppCompatActivity {
private TabLayout myTab;
private ViewPager2 myPager2;
private ImageView bookIv;
private DatabaseHelper mDatabaseHelper;
List<String> titles=new ArrayList<>();
List<Fragment> fragments=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//加载控件
myTab = findViewById(R.id.tab_layout);
myPager2 = findViewById(R.id.view_pager);
bookIv = findViewById(R.id.book_iv);
//添加标题
titles.add("查词");
titles.add("每日一句");
titles.add("翻译");
//添加Fragment进去
fragments.add(new SearchFragment());
fragments.add(new DayFragment());
fragments.add(new TranslateFragment());
//实例化适配器
MyViewPager2Adapter myAdapter=new MyViewPager2Adapter(getSupportFragmentManager(),getLifecycle(),fragments);
//设置适配器
myPager2.setAdapter(myAdapter);
//TabLayout和Viewpager2进行关联
new TabLayoutMediator(myTab, myPager2, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
tab.setText(titles.get(position));
}
}).attach();
}
}
- ViewPager2适配器
与frament集合绑定 让位置与fragment对应上
public class MyViewPager2Adapter extends FragmentStateAdapter {
List<Fragment> fragments;
public MyViewPager2Adapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle, List<Fragment> fragments) {
super(fragmentManager, lifecycle);
this.fragments = fragments;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return fragments.get(position);
}
@Override
public int getItemCount() {
return fragments.size();
}
}
//添加Fragment进去
fragments.add(new SearchFragment());
fragments.add(new DayFragment());
fragments.add(new TranslateFragment());
//实例化适配器
MyViewPager2Adapter myAdapter=new MyViewPager2Adapter(getSupportFragmentManager(),getLifecycle(),fragments);
//设置适配器
myPager2.setAdapter(myAdapter);
//TabLayout和Viewpager2进行关联
new TabLayoutMediator(myTab, myPager2, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
tab.setText(titles.get(position));
}
}).attach();
}
}
- ViewPager2适配器
与frament集合绑定 让位置与fragment对应上
public class MyViewPager2Adapter extends FragmentStateAdapter {
List<Fragment> fragments;
public MyViewPager2Adapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle, List<Fragment> fragments) {
super(fragmentManager, lifecycle);
this.fragments = fragments;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return fragments.get(position);
}
@Override
public int getItemCount() {
return fragments.size();
}
}