为何使用assets
resource资源可以存储声音文件,可以通过ID来获取它。将类似的声音文件存储为资源后,我们就可以按特定的方式使用它们了,如根据设备的语言及系统版本调用不同的声音资源。
如果使用Android资源系统一个个去处理,效率会很低。assets可以看作随应用打包的微型文件系统,支持任意层次的文件目录结构。
创建BeatBox应用
创建布局文件
主布局文件fragment_beat_box.xml用于生成RecyclerView布局。
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_beat_box_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
声音按钮布局文件list_item_sound.xml用于RecyclerView的列表项,作为列表项的按钮显示。
<Button
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list_item_sound_button"
android:layout_width="match_parent"
android:layout_height="120dp"
tools:text="声音名">
</Button>
实例化布局文件
BeatBoxFragment.java
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_beat_box, container, false);
RecyclerView recyclerView = view.findViewById(R.id.fragment_beat_box_recycler_view);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 3));
recyclerView.setAdapter(new SoundAdapter(mBeatBox.getSounds()));
return view;
}
创建SoundHolder
创建一个使用list_item_sound.xml布局的ViewHolder。
BeatBoxFragment.java
private class SoundHolder extends RecyclerView.ViewHolder {
private Button mButton;
private Sound mSound;
public SoundHolder(LayoutInflater layoutInflater, ViewGroup container) {
super(layoutInflater.inflate(R.layout.list_item_sound, container, false));
mButton = itemView.findViewById(R.id.list_item_sound_button);
}
//绑定sound
public void bindSound(Sound sound) {
mSound = sound;
mButton.setText(mSound.getName());
}
}
创建SoundAdapter
创建一个绑定了SoundHolder的Adapter。
BeatBoxFragment.java
private class SoundAdapter extends RecyclerView.Adapter<SoundHolder> {
private List<Sound> mSounds;
public SoundAdapter(List<Sound> sounds) {
mSounds = sounds;
}
@NonNull
@Override
public SoundHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(getActivity());
return new SoundHolder(inflater, parent);
}
@Override
public void onBindViewHolder(@NonNull SoundHolder soundHolder, int position) {
Sound sound = mSounds.get(position);
soundHolder.bindSound(sound);
Log.d(TAG, "绑定了第 " + position + " 个sound...");
}
@Override
public int getItemCount() {
return mSounds.size();
}
}
使用SoundAdapter
BeatBoxFragment.java
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//...
recyclerView.setAdapter(new SoundAdapter(mBeatBox.getSounds()));
return view;
}
填充BeatBoxActivity
SingleFragmentActivity.java
public abstract class SingleFragmentActivity extends AppCompatActivity {
protected abstract Fragment createFragment();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragment_container);
if (fragment == null) {
fragment = createFragment();
/**
* 创建一个新的fragment事务,加入一个添加操作,然后提交该事务
*/
fm.beginTransaction().add(R.id.fragment_container, fragment).commit();
}
}
}
BeatBoxActivity.java
public class BeatBoxActivity extends SingleFragmentActivity {
@Override
protected Fragment createFragment() {
return BeatBoxFragment.newInstance();
}
}
导入assets
- 右键单击app模块,选择New => Folder => Assets Folder,清楚Change Folder Location选项,保持Target Source Set选项为main;
- 然后右键单击assets目录,选择New => Directory,创建sample_sounds子目录,将声音资源文件复制到此目录。
处理assets
创建BeatBox类
BeatBox.java
public class BeatBox {
private static final String TAG = "BeatBox";
private static final String SOUNDS_FOLDER = "sample_sounds";
private AssetManager mAssets;
private List<Sound> mSounds = new ArrayList<>();
public BeatBox(Context context) {
mAssets = context.getAssets();
loadSounds();
}
//获取asset资源
private void loadSounds() {
String[] soundNames;
try {
//取得assets中的资源清单
soundNames = mAssets.list(SOUNDS_FOLDER);
Log.i(TAG, "取得 " + soundNames.length + " 个声音资源。");
}
catch (IOException ioe) {
Log.e(TAG, "无法取得assets资源清单。");
return;
}
for (String filename : soundNames) {
String assetPath = SOUNDS_FOLDER + "/" + filename;
Sound sound = new Sound(assetPath);
mSounds.add(sound);
}
}
public List<Sound> getSounds() {
return mSounds;
}
}
在访问assets时,可以不用关心究竟是用哪个Context对象。而且在实际开发的任何场景下,所有context中的AssetManager管理的都是同一套assets资源。
可以使用AssetsManager.list(String)方法列出指定目录中的所有文件名。
创建BeatBox实例
BeatBoxFragment.java
private BeatBox mBeatBox;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBeatBox = new BeatBox(getActivity());
}
使用assets
创建Sound对象
Sound.java
public class Sound {
private String mAssetPath;
private String mName;
public Sound(String assetPath) {
mAssetPath = assetPath;
String[] components = assetPath.split("/");
String filename = components[components.length - 1];
mName = filename.replace(".wav", "");
}
public String getAssetPath() {
return mAssetPath;
}
public String getName() {
return mName;
}
}
创建Sound列表
创建Sound类之后,就可以在BeatBox类中创建并初始化Sound列表(见「导入assets」)。
绑定Sound
在SoundHolder中添加代码绑定Sound(见「创建SoundHolder」)。
绑定Sound列表
让SoundAdapter与Sound数组关联起来(见「创建SoundAdapter」)。
设置Adapter
最后,在onCreateView(…)方法中传入BeatBox声音资源(见「使用SoundAdapter」)。