赞
踩
https://developer.android.com/studio 下载了linux 版:android-studio-2022.2.1.20-linux.tar.gz
按照安装文档轻松安装。建议,最好让电脑科学上网,因为有很多个文件是从google网站上下载的。
还有最好不要用虚拟终端输出程序结果。因为速度很慢。找一个旧手机代替,速度快得多。
下面的代码是输入框的内容显示在文本框中。
以下的程序都采用的是Empty Views Activity 模板。
发现android编程,ui界面部分只要把布局编辑器练熟就行了,难的还是代码的事件处理部份。ui的很多控件初学都用不上,只要把三四个常用的搞熟就可以练代码了。
- package com.example.wz;
-
- import androidx.appcompat.app.AppCompatActivity;
- import android.os.Bundle;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
-
- public class MainActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main); //按照布局文件activity_main.xml 显示,估计此方法是不停刷新此文件的内容,所以程序不用再setContentView
-
- Button button=findViewById(R.id.button2); //android 用findViewById 取得java的控件实例
- EditText editText=findViewById(R.id.editTextText); //editText 对应的布局编译器中为Plain Text 文本输入框
- TextView textView=findViewById(R.id.textView3);
-
- button.setOnClickListener(view -> { //按键的响应
- String s = String.valueOf(editText.getText()); //取文本框输入内容
- textView.setText(s);
- });
- }
- }
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
如要连接网络,必须在AndroidManifest.xml文件中加上此两句
下面的代码是连接服务器
- package com.example.wz;
-
- import androidx.appcompat.app.AppCompatActivity;
- import android.os.Bundle;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
-
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.ObjectInputStream;
- import java.net.Socket;
-
- public class MainActivity extends AppCompatActivity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main); //按照布局文件activity_main.xml 显示,估计此方法是不停刷新此文件的内容,所以程序多次setContentView()。
-
- Button button=findViewById(R.id.button2); //android 用findViewById 取得java的控件实例
- EditText editText=findViewById(R.id.editTextText); //editText 对应的布局编译器中为Plain Text 文本输入框
- TextView textView=findViewById(R.id.textView3);
-
- button.setOnClickListener(view -> { //按键的响应
- // String s = String.valueOf(editText.getText()); //取文本框输入内容
- // textView.setText("接收数据");
- try {
- Socket socket=new Socket("192.168.43.61",3000);
- InputStream inputStream=socket.getInputStream();
- ObjectInputStream objectInputStream=new ObjectInputStream(inputStream);
- String s=objectInputStream.readUTF();
- textView.setText(s);
- socket.close();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
- });
- }
- }
注意:try catch语句要注释掉throw new RunimeException(e);这句,否则一有错,程序就退出。有这个基础程序框架,就可以试试把java程序搬到手机上。
还有setContentView()方法,估计安卓系统是定时不停地刷新桌面显示控件,有点像java的Timer,所以程序不用多次用此方法,一次就行了。
android 线程间传递数据,不能用java 线程的传递方法,如静态类变量就不能用。
- package com.example.wz;
-
- import androidx.annotation.NonNull;
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
-
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.ObjectInputStream;
- import java.net.Socket;
-
- public class MainActivity extends AppCompatActivity {
- static Handler handler;
- static TextView textView;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Button button = findViewById(R.id.button);
- EditText editText = findViewById(R.id.editTextText);
- textView = findViewById(R.id.textView);
-
- Handler.Callback hc=new Handler.Callback() {
- @Override
- public boolean handleMessage(@NonNull Message msg) { //这里必须调用handle类的镶嵌类Handle.Callback的handleMessage方法。
- int t=msg.arg1;
- textView.setText(String.valueOf(t));
- return false;
- }
- };
- handler =new Handler(Looper.myLooper(),hc);
- button.setOnClickListener(view -> {
- Th th = new Th();
- th.start();
- });
- }
- }
- class Th extends Thread {
- int t=0;
- public void run() {
- while (true) {
- Message message = new Message();
- message.arg1=t;
- MainActivity.handler.sendMessage(message);
- t++;
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // throw new RuntimeException(e);
- }
- }
- }
- }
-
-
-
-
此种传递数据的方法,数据的产生和ui显示是异步的。我理解有点像map 的键值对,这个ss就是键,接照键的对应关系,线程先把值存在”map”中,ui再取出此值显示。这样理解好记忆。
安卓的主线程最好只处现ui代码和事件响应代码,其他的java逻辑算法代码都不要放在主线程中,java代码最好放在响应事件的代码块中,或者放在其他子线程中。而且响应事件的代码耗时不能太久,更不能放循环等待的语句,如有这种耗时的代码,必须放在新线程中,用事件响应启动此线程。如按钮单击启动耗时线程。
其实这也是一个android编程通用方法,把ui代码放在主线程中,其他的一切逻辑代码另开一个线程完成,主线程用一个事件响应启动这个新线程,新线程的数据通过上面程序的方法传给主线程完成显示。这样处理事后容易理解看清思路。这是我自己的看法。当然你也可以在主线程中混编,只要能通过不报错。
看jdk学Handle
Handler 允许您发送和处理Message
与线程关联的 Runnable 对象MessageQueue
。每个 Handler 实例都与一个线程和该线程的消息队列相关联。当您创建一个新的处理程序时,它会绑定到一个Looper
. 它会将消息和可运行对象传递到该 Looper 的消息队列,并在该 Looper 的线程上执行它们。
Handler 有两个主要用途:(1) 安排消息和可运行对象在未来某个时间点执行;(2) 将要在与您自己的线程不同的线程上执行的操作排队。
调度消息是通过 post(Runnable)
、postAtTime(java.lang.Runnable, long)
、 postDelayed(Runnable, Object, long)
、sendEmptyMessage(int)
、 sendMessage(Message)
、sendMessageAtTime(Message, long)
和 sendMessageDelayed(Message, long)
方法完成的。post版本允许您将 Runnable 对象入队,以便在接收到消息队列时调用它们;sendMessage版本允许您将包含将由Message
Handler 的方法处理的数据包的对象排入队列handleMessage(Message)
(要求您实现 Handler 的子类)。
发布或发送到处理程序时,您可以允许项目在消息队列准备就绪后立即处理,或者指定处理前的延迟或处理的绝对时间。后两者允许您实现超时、滴答和其他基于时间的行为。
handle post() 方法,发现只能更新一次,不知道是否正确
此方法代码很简单
- package com.example.wz;
-
- import androidx.annotation.NonNull;
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
-
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.ObjectInputStream;
- import java.net.Socket;
-
- public class MainActivity extends AppCompatActivity {
- static Handler handler=new Handler();
- static TextView textView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Button button = findViewById(R.id.button);
- EditText editText = findViewById(R.id.editTextText);
- textView = findViewById(R.id.textView);
-
- button.setOnClickListener(view -> {
- Th th = new Th();
- th.start();
- });
- }
- }
- class Th extends Thread {
- public void run() {
- MainActivity.handler.post(()->{
- MainActivity.textView.setText("hello nanning");
- });
- }
- }
-
-
-
-
这里的handle实例必须放在主线程中,其实把它想成java场景中的静态类变量就好理解了。
如要循环,可以这样处理,但又不能加Thread.sleep()延时
- class Th extends Thread { //刚实验,此post方法只能更新一次ui。如加循环,报错
- public void run () {
- while(true) {
- h.post(new Runnable() {
- public void run() {
- textView.setText(String.valueOf(1));
- }
- });
- h.post(new Runnable() {
- public void run() {
- textView.setText(String.valueOf(2));
- }
- });
- }
- }
- }
这个post方法虽然只能执行一次更新ui,也可编写许多场景的程序了。如连接服务器一次读取数据,输入网址读取网页文件,查询一次文件目录,如是线程不停传递数据则不能用此方法。
利用handle.post()连接服务器读取一次数据
- package com.example.wz;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
-
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.ObjectInputStream;
- import java.net.Socket;
-
- public class MainActivity extends AppCompatActivity {
- static Handler h = new Handler();
- static TextView textView;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Button button = findViewById(R.id.button);
- EditText editText = findViewById(R.id.editTextText);
- textView = findViewById(R.id.textView);
-
- button.setOnClickListener(view -> {
- Th th = new Th();
- th.start();
- });
- }
- }
- class Th extends Thread { //刚实验,此post方法只能更新一次ui。如加循环,报错
- public void run() {
- Socket socket= null;
- String s;
- try {
- socket = new Socket("192.168.2.8",3000);
- InputStream inputStream=socket.getInputStream();
- ObjectInputStream objectInputStream=new
- ObjectInputStream(inputStream);
- s=objectInputStream.readUTF();
- MainActivity.h.post(new Runnable() {
- public void run() {
- MainActivity.textView.setText(s);
- }
- });
- objectInputStream.close();
- } catch (IOException e) {
- // throw new RuntimeException(e);
- }
- }
- }
-
-
手机要是上网,必须要在全局文件中加这俩句
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
=========================================================================
android 文件
参考出处:https://blog.csdn.net/huweiliyi/category_8913738.html
raw目录
asserts目录
data/data/包名
sdcard目录
其中raw下的和asserts下的文件可以以资源文件的形式读取,这些目录的数据只能读取,不能写入,两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制。
data/data/包名和sdcard目录文件可读可写。其中data/data/包名目录不需要申请权限,sdcard目录需要申请权限
读取文件要在全局文件中加这两句
<!--文件读写权限--> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
data/data/(包名) 目录文件读写
将数据以普通文件的形式保存在 /data/data/包名中,该方法不需要申请权限。
存放在数据区(/data/data/包名)的文件可以使用openFileOutput和openFileInput进行操作。这两个类只能在主线程中使用。
data/data/包名/shared_prefs
存放SharedPreferences数据
data/data/包名/databases
存放数据库数据
data/data/包名/files
存放普通数据
data/data/包名/cache
存放缓存文件
开发IDE 右边有一个Device File Explorer 用它可以浏览手机的整个目录结构
可以用它看/data/data/ 有啥文件,再读取。
建立文件,发现只能在/data/data/本包名/下创建文件,在其他地方都报错。所以就不存在查找其他目录内容的必要,反正生成的文件必定在自己本程序的包名下。
还发现android的openFileOutput 不能在子线程中使用,只能在主线程中用。所以android的主线程也可编辑非ui代码。但主线程各种代码太多太杂,不好理解分析。网上一大批文章代码,本可以顺序写的,却搞几个类或方法跳过去跳过来,让人看的思路都中断了。
还有如用ide中的Device File Explorer检验是否生成文件,执行程序后必须断开连接手机终端usb,再连接才会正确显示。
- package com.example.wz;
-
- import static android.content.Context.MODE_PRIVATE;
- import androidx.appcompat.app.AppCompatActivity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
-
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- public class MainActivity extends AppCompatActivity {
- static Handler handler=new Handler();
- static TextView textView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Button button = findViewById(R.id.button);
- EditText editText = findViewById(R.id.editTextText);
- textView = findViewById(R.id.textView);
-
- button.setOnClickListener(view -> {
- Th th = new Th();
- th.start();
- });
- }
- }
- class Th extends Thread {
- public void run() {
- String text = "hello nanning";
- FileOutputStream fileOutputStream = null;
- try {
- fileOutputStream = new FileOutputStream("/data/data/com.example.wz/2.txt");
- fileOutputStream.write(text.getBytes()); //绝对路径
- fileOutputStream.close();
- MainActivity.handler.post(()->{
- MainActivity.textView.setText("file over");
- });
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
-
-
-
-
所以,现在发现想给手机编一个程序,自由上传下载图片到手机的图库是不可能的,因为android的权限太多太大。自编程序只有在自己的包内操作的权限。所以想到手机root解锁,是不是就是把全手机的文件都改成可以读写?
注意用openFileOutput openFileInput 的路径名是相对路径,不能用绝对路径,否则报错。
android 文件类 FileOutputStream FileInputStream 用绝对路径
openFileOutput openFileInput 用相对路径
文件存储只能在这两个目录下进行
data/data/包名 //不要读取权限
sdcard目录 //要读取权限
openFile* 两个类的权限:
MODE_PRIVATE //默认:私有
MODE_APPEND //在文件中追加
MODE_WORLD_READABLE //其他程序可以读
MODE_WORLD_WRITEABLE //其他程序可以写
android 文件方法: //文件路径都是相对路径
openFileInput
openFileOutput
getFileStreamPath //取文件路径
deleteFile //删除
fileList // 列出本包files的文件
=======================================================
直观理解,activity就是手机屏幕的一个窗口。
主activity 启动新的activity
- package com.example.wz;
-
- import static android.content.Context.MODE_PRIVATE;
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.content.Intent;
- import android.os.Bundle;
- import android.os.Handler;
- import android.view.View;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
-
- import java.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- public class MainActivity extends AppCompatActivity {
- static Handler handler=new Handler();
- static TextView textView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Button button = findViewById(R.id.button);
- EditText editText = findViewById(R.id.editTextText);
- textView = findViewById(R.id.textView);
-
- button.setOnClickListener(view -> {
- Intent intent=new Intent(MainActivity.this,MainActivity2.class); //启动新的activity
- startActivity(intent);
- });
- }
- }
-
-
-
-
-
建立好子activity Java程序和xml配置文件,再用intent启动 intent第一个参数为按钮所在程序的程序名, 第二个参数为要启动的程序名。所以用intent 可以跳到任何窗口,包括从子窗口跳回主窗口。为什么要加.this 和.class , 可以是规定吧。
如果不怕复杂,可以把事件响应独立来写
- View.OnClickListener listener=new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Intent intent=new Intent(MainActivity2.this,MainActivity.class);
- startActivity(intent);
- }
- };
- button.setOnClickListener(listener);
intent 可以调用android系统的程序
下面的代码是调用android 的内置拨号程序,调用内置程序,不用自编activity。系统自动调出已固定的拨号activity。
- package com.example.call;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.content.Intent;
- import android.net.Uri;
- import android.os.Bundle;
- import android.widget.Button;
- import android.widget.TextView;
-
- public class MainActivity extends AppCompatActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Button button=findViewById(R.id.button);
- TextView textView=findViewById(R.id.editTextText); //输入电话号码
-
- button.setOnClickListener(view -> {
- String s=textView.getText().toString();
- Intent intent=new Intent(Intent.ACTION_DIAL, Uri.parse("tel://"+s));
- startActivity(intent); //利用intent 调用android内置拨号程序
- });
- }
- }
到这里,就可以很好理解为什么在用某个不用钱的程序时,突然点出拚多多的程序。
activity 之间通过bundle互传数据
主窗口:
- package com.example.wz;
-
- import static android.content.Context.MODE_PRIVATE;
-
- import androidx.annotation.Nullable;
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.annotation.SuppressLint;
- import android.content.Intent;
- import android.media.MediaPlayer;
- import android.os.Bundle;
- import android.os.Handler;
- import android.view.View;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.ImageView;
- import android.widget.TextView;
-
-
- public class MainActivity extends AppCompatActivity {
- static Handler handler=new Handler();
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Button button = findViewById(R.id.button);
- @SuppressLint({"MissingInflatedId", "LocalSuppress"})
- TextView textView=findViewById(R.id.textView);
- button.setOnClickListener(view -> {
- Bundle bundle=new Bundle();
- String name="wz";
- bundle.putString("name",name);
- Intent intent=new Intent(MainActivity.this,MainActivity2.class);//切换到第二窗口
- intent.putExtras(bundle);
- startActivity(intent);
- });
- Intent intent=getIntent(); //提取第二窗口传递的数据
- String name1=intent.getStringExtra("kk");
- textView.setText(name1);
- }
- }
-
-
-
-
-
子窗口
- package com.example.wz;
-
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.annotation.SuppressLint;
- import android.content.Intent;
- import android.os.Bundle;
- import android.widget.Button;
- import android.widget.TextView;
-
- public class MainActivity2 extends AppCompatActivity {
- String name;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main2);
- Intent intent=getIntent(); //提取主窗口传递的数据
- name=intent.getStringExtra("name");
- TextView textView=findViewById(R.id.textView2);
- textView.setText(name);
-
- @SuppressLint({"MissingInflatedId", "LocalSuppress"})
- Button button=findViewById(R.id.button2);
- button.setOnClickListener(view -> {
- Intent intent1=new Intent(MainActivity2.this,MainActivity.class); //切换到主窗口
- Bundle bundle=new Bundle(); //绑定的数据
- bundle.putString("kk","wl");
- intent1.putExtras(bundle);
- startActivity(intent1);
- });
- }
- }
用这个方法,不用调用带返回数据的startactivity方法。
android 系统内置了很多常用的activity。如打电话的activity,
--------------------------------------------------------------------------------------------------------------------------------
图片存储有两种方式,一种是存于自身程序包内,一种是存于像册,下面的程序是处理存在程序包中的情况。
如程序都在一个窗口中显示,就不用考虑activity的问题
图片存储路径:/data/data/包名/
接收图片的手机与发送图片的电脑,必须在同一个局域网中
代码:
- package com.example.call;
-
- import android.annotation.SuppressLint;
- import android.app.Activity;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.os.Bundle;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.ImageView;
- import android.widget.TextView;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.ObjectInputStream;
- import java.net.Socket;
-
- public class MainActivity extends Activity {
- TextView textView;
- @SuppressLint("MissingInflatedId")
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Button button = findViewById(R.id.button);
- button.setText("接收");
- Button button2=findViewById(R.id.button2);
- button2.setText("播放");
- Button button3=findViewById(R.id.button14);
- button3.setText("目录");
- Button button4=findViewById(R.id.button3);
- button4.setText("删除");
-
- textView=findViewById(R.id.textView);
- ImageView imageView = findViewById(R.id.imageView);
- imageView.setImageResource(R.drawable.ic_launcher_background);
- EditText editText=findViewById(R.id.editTextText);
-
- button4.setOnClickListener(view -> {
- String name=editText.getText().toString();
- textView.setText(name);
- deleteFile(name);
- });
-
- button3.setOnClickListener(view -> {
- String[] s=fileList();
- String o=null;
- for(String k:s){
- o=o+k+" ";
- }
- textView.setText(o);
- });
-
- button2.setOnClickListener(view -> {
- String name=editText.getText().toString();
- textView.setText(name);
- Bitmap myBitmap = BitmapFactory.decodeFile("/data/data/com.example.call/files/"+name);
- imageView.setImageBitmap(myBitmap);
-
- });
-
- button.setOnClickListener(view -> {
-
- try {
- Socket socket=new Socket("192.168.43.61",3000);
- InputStream inputStream=socket.getInputStream();
- ObjectInputStream objectInputStream=new ObjectInputStream(inputStream);
- String name=objectInputStream.readUTF();
- byte[] b= (byte[]) objectInputStream.readObject();
- FileOutputStream fileOutputStream=openFileOutput(name,Context.MODE_PRIVATE);
- fileOutputStream.write(b);
- fileOutputStream.close();
- socket.close();
-
- } catch (IOException e) {
- // throw new RuntimeException(e);
- textView.setText("net 错误");
- } catch (ClassNotFoundException e) {
- // throw new RuntimeException(e);
- }
- });
- }
- }
上传图片
- import java.io.*;
- import java.net.ServerSocket;
- import java.net.Socket;
-
- public class Main {
- public static void main(String[] args) throws IOException {
- String s="/home/wzpc/3.jpg";
- File file=new File(s);
- String name=file.getName();
- FileInputStream fileInputStream=new FileInputStream(file);
- byte[] b=new byte[fileInputStream.available()];
- fileInputStream.read(b);
-
- ServerSocket serverSocket=new ServerSocket(3000);
- Socket socket=serverSocket.accept();
- OutputStream outputStream=socket.getOutputStream();
- ObjectOutputStream objectOutputStream=new ObjectOutputStream(outputStream);
- objectOutputStream.writeUTF(name);
- objectOutputStream.flush();
- objectOutputStream.writeObject(b);
- objectOutputStream.flush();
- socket.close();
- fileInputStream.close();
- }
- }
-
-
-
-
实.物图
android 四个核心组件:Activity Service Content.Provider BroadcastReceiver
在 activity 主程序的onCreate(Bundel bundle)中,可以直接引用android 的Actitvty,Intent,Content三个类的全部方法。如Content类的openFileoutput(). 不用创造实例。可以这样写:this.方法名。
android.App.Activity 继承与android.Content.Context. 所以这两个类的方法都可以直接引用
onCreate(Bundle) 是初始化 Activity 的地方。 最重要的是,在这里您通常会使用定义 UI 的布局资源调用 setContentView(int),并使用 findViewById(int) 检索该 UI 中需要以编程方式交互的小部件
onPause() 是处理用户暂停与 Activity 的主动交互的地方。 此时应提交用户所做的任何更改(通常提交给保存数据的 ContentProvider)。 在此状态下,活动在屏幕上仍然可见。
要与 Context.startActivity() 一起使用,所有 Activity 类都必须在其包的 AndroidManifest.xml 中具有相应的 <activity> 声明。
现在理一下:view UI的各个组成部件,如按钮的外观,event 事件响应
activity 由多个view组*成activity窗口。
Intent 主要是切换activity窗口
Context.Provider 主要是用来保存数据
ContentProvider的作用是为不同的应用之间数据共享,提供统一的接口,我们知道安卓系统中应用内部的数据是对外隔离的,要想让其它应用能使用自己的数据(例如通讯录)这个时候就用到了ContentProvider。
"_data" 在数据库中代表文件的全路径名,它是非常重要的列名。
下面程序的cursor 的数值就是查询后数据的集合,采用循环一行一行读取列(_data)的值。
- package com.example.test1;
-
- import static android.content.ContentValues.TAG;
- import androidx.appcompat.app.AppCompatActivity;
- import android.annotation.SuppressLint;
- import android.content.ContentResolver;
- import android.database.Cursor;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.net.Uri;
- import android.os.Bundle;
- import android.provider.MediaStore;
- import android.util.Log;
- import android.widget.ImageView;
- import android.widget.TextView;
-
- public class MainActivity extends AppCompatActivity {
-
- @SuppressLint("Range")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- TextView textView = findViewById(R.id.textView2);
- ImageView imageView = findViewById(R.id.imageView);
-
- ContentResolver contentResolver = getContentResolver(); //读数据库
- Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
- // 音频MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- // 视频MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null); //查询
- // int t = cursor.getColumnCount(); //数据库 列数量
- // String[] columnNames = cursor.getColumnNames(); //数据库全部 列名字 如query()方法的第二参数已限制列名,则columnnames=第二参数名,现在就是_data
- // int t1 = cursor.getColumnIndex("_data"); //返回给定 列名称的从零开始的索引,如果该列不存在,则返回-1。
- // int t2 = cursor.getCount(); //数据库的总行数;
-
- while (cursor.moveToNext()) { // 移到数据库的下一行。
-
- /* for (String Name : columnNames) { //name数据库的某一列,columnnames 全部列名
- Log.d(TAG, "----------------------------");
- Log.d(TAG, "name--> " + Name + " value--> " + cursor.getString(cursor.getColumnIndex(Name)));
- Log.d(TAG, "----------------------------");
- }*/
- //因为只查询了一列"_data",可以这样简写
- Log.d(TAG, "----------------------------"); //在电脑的Run框中显示输出
- Log.d(TAG, "name-->_data " + " value--> " + cursor.getString(cursor.getColumnIndex("_data"))); //显示数据库中图片的路径,根据索引反查索引值
- Log.d(TAG, "----------------------------");
- }
- Bitmap bitmap = BitmapFactory.decodeFile("/storage/emulated/0/Pictures/Screenshots/Screenshot_20230701_101256_com.tencent.mobileqq.jpg"); //显示图片
- imageView.setImageBitmap(bitmap);
- }
- }
Uri:
Uri uri = MediaStore.Images.Media.INTERNAL_CONTENT_URI;
图片MediaStore.Images.Media.EXTERNAL_CONTENT_URI
音频MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
视频MediaStore.Video.Media.EXTERNAL_CONTENT_URI
查询文件名,和文件路径。文件名:_display_name 文件路径 : _data
- Cursor cursor = contentResolver.query(uri,new String[]{"_display_name","_data"}, null, null, null, null); //查询
- String[] s=cursor.getColumnNames();
- String o=null;
- for(String k:s){
- o=o+k+" ";
- }
- Log.d(TAG, "----------------------------");
- Log.d(TAG,o);
- while (cursor.moveToNext()) { // 移到数据库的下一行。
- Log.d(TAG,cursor.getString(cursor.getColumnIndex("_display_name")));
- Log.d(TAG,cursor.getString(cursor.getColumnIndex("_data"))); //显示数据库中图片的路径,根据索引反查索引值
- }
- Log.d(TAG, "----------------------------");
查询数据库步骤:query()方法的第二个参数是字符串数组,它的元素就是数据库要查询的列名字,如_data ,_display_name。 query方法生成的Cursor 就是要查询的列的全部行的值。提取每行采用 moveToNext()方法,取出每行的值采用:先用列名提取列在每行中的索引(getColumnIndex(列名)),再用此索引号倒查此索引的值。
经验证,新产生的照片,如刚拍的照片,会立即填加在数据库的末端。用这个方法,可以提取出刚拍的照片。
cursor.moveToLast(); //跳到数据库最后一行 Log.d(TAG,cursor.getString(cursor.getColumnIndex("_data")));//显示最后一行的data指向的最近写入数据库的照片。
浏览手机全部照片
- package com.example.test1;
- import androidx.appcompat.app.AppCompatActivity;
- import android.annotation.SuppressLint;
- import android.content.ContentResolver;
- import android.database.Cursor;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.net.Uri;
- import android.os.Bundle;
- import android.provider.MediaStore;
- import android.widget.Button;
- import android.widget.ImageView;
- import android.widget.TextView;
- import java.util.ArrayList;
-
- public class MainActivity extends AppCompatActivity {
- int n=0;
- @SuppressLint("Range")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- TextView textView = findViewById(R.id.textView2);
- ImageView imageView = findViewById(R.id.imageView);
- Button button=findViewById(R.id.button3);
-
- ContentResolver contentResolver = getContentResolver(); //读数据库
- Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
- // 音频MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- // 视频MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null); //查询
- ArrayList<String> al=new ArrayList<>();
- while (cursor.moveToNext()) { // 移到数据库的下一行。
- String s=cursor.getString(cursor.getColumnIndex("_data"));
- al.add(s); //把数据库全部的图片路径存入ArrayList中
- }
- // textView.setText(String.valueOf(al.size()));
- button.setOnClickListener(view -> { //按钮按一下,浏览一张图片
- n++;
- Bitmap bitmap=BitmapFactory.decodeFile(al.get(n));
- imageView.setImageBitmap(bitmap);
- });
- }
- }
感觉这个小程序的图片浏览加载速度快与手机的图片浏览app。
此程序相当重要,涉及到线程之间的数据交换,ui的定时更新
- package com.example.test1;
- import androidx.annotation.NonNull;
- import androidx.appcompat.app.AppCompatActivity;
- import android.annotation.SuppressLint;
- import android.content.ContentResolver;
- import android.database.Cursor;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.net.Uri;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- import android.provider.MediaStore;
- import android.widget.Button;
- import android.widget.ImageView;
- import android.widget.TextView;
- import java.util.ArrayList;
-
- public class MainActivity extends AppCompatActivity {
- int n=0;
- @SuppressLint("Range")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- TextView textView = findViewById(R.id.textView2);
- ImageView imageView = findViewById(R.id.imageView);
- Button button=findViewById(R.id.button3);
-
- ContentResolver contentResolver = getContentResolver(); //读数据库
- Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
- // 音频MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- // 视频MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null); //查询
- ArrayList<String> al=new ArrayList<>();
- while (cursor.moveToNext()) { // 移到数据库的下一行。
- String s = cursor.getString(cursor.getColumnIndex("_data"));
- al.add(s); //把数据库全部的图片路径存入ArrayList
- }
-
- Handler.Callback hc=new Handler.Callback() {
- @Override
- public boolean handleMessage(@NonNull Message msg) { //这里必须调用handle类的镶嵌类Handle.Callback的handleMessage方法。
- int t=msg.arg1;
- Bitmap bitmap = BitmapFactory.decodeFile(al.get(t));
- imageView.setImageBitmap(bitmap);
- return false;
- }
- };
- Handler handler =new Handler(Looper.myLooper(),hc);
-
- new Thread(()->{
- while(true) {
- Message message = new Message();
- message.arg1=n;
- handler.sendMessage(message);
- n++;
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // throw new RuntimeException(e);
- }
- }
- }).start();
- }
- }
此程序可以作为ui循环或定时更新的模板。
编程发现:android 主方法线程中,不能用for循环等方法为ui的各种显示控件赋值来完成ui的更新
必须采用上述hendle类来完成。
为什么要这样,我理解是因为android的主线程不能有占长时间运行的代码。如果必须有这种长耗时代码,必须把这种代码移到一新线程中。再把数据通过message传回主线程
android 读取数据库的权限问题
华为畅享20 ART-AL00m 用的是android 10 ,除了在全局文件中加入权限外,还要在
application段中加入这句 android:requestLegacyExternalStorage="true" 如果不在程序中加入动态权限,那么一定要在手机的设置中开启你的程序的存储权限。
华为nova8 不用加这句可运行。加了也不影响。还有如果发现程序不运行,多是手机的存储权限关闭,在手机设置中开启就可以了。nova8 很少有关闭权限的情况,畅享20经常发生。
以上介绍了几种播放方式,可以说各有优劣。
本文写的不够详细,只是大概的介绍一下几种播放方式。在此做下简单的总结。
对于延迟度要求不高,并且希望能够更全面的控制音乐的播放,MediaPlayer比较适合
声音短小,延迟度小,并且需要几种声音同时播放的场景,适合使用SoundPool
对于简单的播放,不需要复杂控制的播放,可以给使用AsyncPlayer,所有操作均在子线程不阻塞UI
播放大文件音乐,如WAV无损音频和PCM无压缩音频,可使用更底层的播放方式AudioTrack。它支持流式播放,可以读取(可来自本地和网络)音频流,却播放延迟较小。
ps:据我测试AudioTrack直接支持WAV和PCM,其他音频需要解码成PCM格式才能播放。(其他无损格式没有尝试,有兴趣可以使本文提供的例子测试一下)
.jet的音频比较少见(有的游戏中在使用),可使用专门的播放器JetPlayer播放
对于系统类声音的播放和操作,Ringtone更适合(主要是掌握好RingtoneManager)
————————————————
版权声明:本文为CSDN博主「一个有梦想的屌丝程序员」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u013366008/article/details/76577372
- package com.example.wz;
- import android.annotation.SuppressLint;
- import android.media.MediaPlayer;
- import android.net.Uri;
- import android.os.Bundle;
- import androidx.appcompat.app.AppCompatActivity;
-
- public class MainActivity extends AppCompatActivity {
- MediaPlayer mediaPlayer; //必须onCreate()方法前先定义MediaPlayer,否则华为手机只能播放音乐1-2秒就停止,不知道为啥
- @SuppressLint({"MissingInflatedId", "Range"})
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Uri u=Uri.parse("/storage/emulated/0/qqmusic/song/阳山伟伟 - 星辰 (Original Mix) [mqms2].flac");
- mediaPlayer = MediaPlayer.create(this.getApplicationContext(),u);
- mediaPlayer.start();
- }
- }
-
-
-
-
-
-
必须onCreate()方法前先定义MediaPlayer,否则华为手机只能播放音乐1-2秒就停止,不知道为啥,这个解决方法是在网络发现的。其他手机没有试过。
播放音频要在全局文件中加入这两种权限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> 还有一点,因为所以程序都没有写动态权限,所以必须要在手机的设置中为程序赋予读写存储的权限 下面是android官网使用的代码,最好用这种代码,因为上面的三行代码在畅享20中不能运行。
主线程使用这种prepare()方式为同步播放,影响ui的更新,最好另起一子线程
- Uri myUri = ....; // initialize Uri here
- MediaPlayer mediaPlayer = new MediaPlayer();
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- mediaPlayer.setDataSource(getApplicationContext(), myUri);
- mediaPlayer.prepare();
- mediaPlayer.start();
- new Thread(()->{
- Uri u=Uri.parse(al.get(2));
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- try {
- mediaPlayer.setDataSource(getApplicationContext(),u);
- mediaPlayer.prepare(); //同步播发,影响ui的更新,如采用同步播放音乐,最好另开一子线程
- mediaPlayer.start();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }).start();
主线程异步播放
官网代码
- public class MyService extends Service implements MediaPlayer.OnPreparedListener {
- private static final String ACTION_PLAY = "com.example.action.PLAY";
- MediaPlayer mediaPlayer = null;
-
- public int onStartCommand(Intent intent, int flags, int startId) {
- ...
- if (intent.getAction().equals(ACTION_PLAY)) {
- mediaPlayer = ... // initialize it here
- mediaPlayer.setOnPreparedListener(this);
- mediaPlayer.prepareAsync(); // prepare async to not block main thread
- }
- }
-
- /** Called when MediaPlayer is ready */
- public void onPrepared(MediaPlayer player) {
- player.start();
- }
- }
主线程异步播放实用代码
- Uri u=Uri.parse(al.get(1));
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- try {
- mediaPlayer.setDataSource(this.getApplicationContext(),u);
- mediaPlayer.prepareAsync(); //这句必须放在setDataSource的后面,否则报错
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- mediaPlayer.setOnPreparedListener(mediaPlayer1 -> { //音乐异步准备完成播放,为什么是mediaPlay1,不清楚,程序自动显示的
- mediaPlayer.start();
- });
- package com.example.test1;
-
- import androidx.appcompat.app.AppCompatActivity;
- import android.annotation.SuppressLint;
- import android.content.ContentResolver;
- import android.database.Cursor;
- import android.media.AudioManager;
- import android.media.MediaPlayer;
- import android.net.Uri;
- import android.os.Bundle;
- import android.provider.MediaStore;
- import android.widget.Button;
- import android.widget.ImageView;
- import android.widget.TextView;
- import java.io.IOException;
- import java.util.ArrayList;
-
- public class MainActivity extends AppCompatActivity {
- static int is=0; //音乐播放完成标志位
- MediaPlayer[] mp;
- MediaPlayer mediaPlayer;
- int n=0;
- @SuppressLint("Range")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- TextView textView = findViewById(R.id.textView2);
- ImageView imageView = findViewById(R.id.imageView);
- Button button=findViewById(R.id.button3);
-
- ContentResolver contentResolver = getContentResolver(); //读数据库
- // Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
- Uri uri=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- // 视频MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null); //查询
- ArrayList<String> al=new ArrayList<>();
- while (cursor.moveToNext()) { // 移到数据库的下一行。
- String s = cursor.getString(cursor.getColumnIndex("_data"));
- al.add(s); //把数据库全部的图片路径存入ArrayList
- }
- class Th extends Thread{
- public void run() {
- is=0; //播放开始 清标志位
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- try {
- mediaPlayer.setDataSource(al.get(n));
- mediaPlayer.prepareAsync(); //这句必须放在setDataSource的后面,否则报错
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- mediaPlayer.setOnPreparedListener(mediaPlayer1 -> { //音乐异步准备完成播放,为什么是mediaPlay1,不清楚,程序自动显示的
- mediaPlayer.start();
- });
- mediaPlayer.setOnCompletionListener(mediaPlayer1 -> {
- is=1; //播放完成置标志位
- });
- }
- }
-
- button.setOnClickListener(view ->{ //按键启动播放音乐
- Th th=new Th();
- th.start();
- });
- //------重点---------------------------------------------------------
- new Thread(()->{ //新开一线程,一直监控标志位is
- while(true) { //is=1,表示音乐播放完成,播放线程已关闭
- if (is == 1) {
- n++; //跳到下一首音乐路径
- Th th = new Th(); //新开一播放音乐线程
- th.start();
- }
- try {
- Thread.sleep(2000); //防线程误启动时间,也是两首音乐的间隔时间
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
-
- }).start();
- }
- }
在Android中,我们有三种方式来实现视频的播放:
1、使用其自带的播放器。指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型。
2、使用VideoView来播放。在布局文件中使用VideoView结合MediaController来实现对其控制。
3、使用MediaPlayer类和SurfaceView来实现,这种方式很灵活。
播放数据库视频
自动顺序播放手机全部视频
- package com.example.test1;
-
- import static android.content.ContentValues.TAG;
- import androidx.appcompat.app.AppCompatActivity;
- import android.annotation.SuppressLint;
- import android.content.ContentResolver;
- import android.database.Cursor;
- import android.media.AudioManager;
- import android.media.MediaPlayer;
- import android.net.Uri;
- import android.os.Bundle;
- import android.provider.MediaStore;
- import android.util.Log;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- import android.widget.Button;
- import java.io.IOException;
- import java.util.ArrayList;
-
- public class MainActivity extends AppCompatActivity {
- SurfaceHolder surfaceHolder;
- int n=0;
- static int is=0;
- MediaPlayer mediaPlayer;
- @SuppressLint("Range")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- @SuppressLint({"WrongViewCast", "MissingInflatedId", "LocalSuppress"})
- SurfaceView surfaceView=findViewById(R.id.surfaceView);
- Button button=findViewById(R.id.button3);
-
- ContentResolver contentResolver = getContentResolver(); //读数据库
- // Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
- // Uri uri=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- Uri uri=MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null); //查询
- ArrayList<String> al=new ArrayList<>();
- while (cursor.moveToNext()) { // 移到数据库的下一行。
- String s = cursor.getString(cursor.getColumnIndex("_data"));
- al.add(s); //把数据库全部的图片路径存入ArrayList
- Log.d(TAG,s);
- }
-
- Runnable r=()->{
- is=0;
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- try {
- mediaPlayer.setDataSource(al.get(n));
- mediaPlayer.prepare();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- surfaceHolder = surfaceView.getHolder(); //播放视频增加这两句
- mediaPlayer.setDisplay(surfaceHolder); //播放视频增加这两句
- mediaPlayer.start();
- mediaPlayer.setOnCompletionListener(mediaPlayer1 -> {
- is=1;
- mediaPlayer.release(); //释放,关闭mediaPlay
- });
- };
-
- button.setOnClickListener(view -> { //启动开始播放
- Thread thread=new Thread(r);
- thread.start();
- });
- new Thread(()->{
- while(true){
- if(is==1){
- n++;
- Thread thread=new Thread(r);
- thread.start();
- }
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- }).start();
- }
- }
主窗口代码
-
- package com.example.test1;
-
- import static android.content.ContentValues.TAG;
- import androidx.appcompat.app.AppCompatActivity;
- import android.annotation.SuppressLint;
- import android.content.ContentResolver;
- import android.content.Intent;
- import android.database.Cursor;
- import android.media.MediaPlayer;
- import android.net.Uri;
- import android.os.Bundle;
- import android.provider.MediaStore;
- import android.util.Log;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- import android.widget.Button;
- import java.util.ArrayList;
-
- public class MainActivity extends AppCompatActivity {
- SurfaceHolder surfaceHolder;
- int n=0;
- static int is=0;
- MediaPlayer mediaPlayer;
- @SuppressLint("Range")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- @SuppressLint({"WrongViewCast", "MissingInflatedId", "LocalSuppress"})
- SurfaceView surfaceView=findViewById(R.id.surfaceView);
- Button button=findViewById(R.id.button3);
-
- ContentResolver contentResolver = getContentResolver(); //读数据库
- // Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
- // Uri uri=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- Uri uri=MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null); //查询
- ArrayList<String> al=new ArrayList<>();
- while (cursor.moveToNext()) { // 移到数据库的下一行。
- String s = cursor.getString(cursor.getColumnIndex("_data"));
- al.add(s); //把数据库全部的图片路径存入ArrayList
- Log.d(TAG,s);
- }
-
- button.setOnClickListener(view -> {
- n++;
- Bundle bundle=new Bundle();
- String path=al.get(n); //为子窗口传递显示文件路径
- bundle.putString("lj",path);
- Intent intent=new Intent(MainActivity.this,Sp.class);
- intent.putExtras(bundle);
- startActivity(intent);
-
- });
- }
- }
-
子窗口代码
- package com.example.test1;
-
- import androidx.annotation.NonNull;
- import androidx.appcompat.app.AppCompatActivity;
- import android.annotation.SuppressLint;
- import android.content.Intent;
- import android.media.AudioManager;
- import android.media.MediaPlayer;
- import android.os.Bundle;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- import java.io.IOException;
-
- public class Sp extends AppCompatActivity {
- SurfaceHolder surfaceHolder;
- MediaPlayer mediaPlayer;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_sp);
- @SuppressLint({"MissingInflatedId", "LocalSuppress"})
- SurfaceView surfaceView=findViewById(R.id.surfaceView2);
-
- Intent intent=getIntent();
- String path=intent.getStringExtra("lj"); //取得主窗口传递的路径
-
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
-
- try {
- mediaPlayer.setDataSource(path);
- mediaPlayer.prepareAsync();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- surfaceHolder = surfaceView.getHolder(); //播放视频增加这两句
- surfaceHolder.addCallback(new SurfaceHolder.Callback() { //最好用callback此方法显示,否则太多报错
- @Override
- public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
- mediaPlayer.setDisplay(surfaceHolder); //播放视频增加这两句
- }
- @Override
- public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {
- }
- @Override
- public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
- }
- });
- mediaPlayer.setOnPreparedListener(mediaPlayer1 -> {
- mediaPlayer.start();
- });
- mediaPlayer.setOnCompletionListener(mediaPlayer1 -> {
- mediaPlayer.release();
- });
-
- }
- //-------------------返回关闭视频---------------------------------------
- public void onBackPressed() { //监听返回键,如返回则关闭视频
- super.onBackPressed();
- mediaPlayer.release();
- }
-
- }
-
- package com.example.test1;
-
- import static android.content.ContentValues.TAG;
- import androidx.appcompat.app.AppCompatActivity;
- import android.annotation.SuppressLint;
- import android.content.ContentResolver;
- import android.content.Intent;
- import android.database.Cursor;
- import android.media.MediaPlayer;
- import android.net.Uri;
- import android.os.Bundle;
- import android.provider.MediaStore;
- import android.util.Log;
- import android.view.KeyEvent;
- import android.view.SurfaceHolder;
- import android.view.SurfaceView;
- import android.view.View;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
-
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Map;
-
- public class MainActivity extends AppCompatActivity {
- SurfaceHolder surfaceHolder;
- String outpath;
- String outname;
- String xs;
- int n=0;
- int no=0;
- MediaPlayer mediaPlayer;
- TextView textView;
- EditText editText;
- ArrayList<String> al;
- Bundle bundle=new Bundle();
- @SuppressLint("Range")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- Button button=findViewById(R.id.button3);
- editText=findViewById(R.id.editTextText);
- editText.setText("");
- textView=findViewById(R.id.textView2);
- textView.setText("");
-
- ContentResolver contentResolver = getContentResolver(); //读数据库
- // Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
- // Uri uri=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- Uri uri=MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- Cursor cursor = contentResolver.query(uri, new String[]{"_data","_display_name"}, null, null, null, null); //查询
- al=new ArrayList<>();
- Map<Integer,String> map=new HashMap<>();
-
- while (cursor.moveToNext()) { // 移到数据库的下一行。
- String s = cursor.getString(cursor.getColumnIndex("_data"));
- String name=cursor.getString(cursor.getColumnIndex("_display_name"));
- al.add(s);
- outname=outname+name+" ";
- xs=xs+String.valueOf(no)+": "+name+" ";
- map.put(no,s);
- no++;
- }
- textView.setText(xs);
- //----------按键启动顺序播放-----------------------------------------
- button.setOnClickListener(view -> {
- n++;
- // Bundle bundle=new Bundle();
- String path=al.get(n);
- bundle.putString("lj",path);
- Intent intent=new Intent(MainActivity.this,Sp.class);
- intent.putExtras(bundle);
- startActivity(intent);
- });
- //-----------按键监听,实现输入文件序号单个播放---------------------------------------------------------------
- editText.setOnKeyListener(new View.OnKeyListener() { //正对输入框editText的按键监听
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- if(event.getAction() == KeyEvent.ACTION_DOWN) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_ENTER: //监控 按下回车键
- String in= editText.getText().toString();
- int index=Integer.valueOf(in);
- String path= map.get(index);
- bundle.putString("lj",path);
- Intent intent=new Intent(MainActivity.this,Sp.class);
- intent.putExtras(bundle);
- startActivity(intent);
- return true;
- }
- }
- return false;
- }
- });
- }
- }
-
子窗口代码不变
使用发现,利用新线程监控播放线程不稳定
改进后的顺序音乐播放
- package com.example.test1;
-
- import androidx.annotation.NonNull;
- import androidx.appcompat.app.AppCompatActivity;
-
- import android.annotation.SuppressLint;
- import android.content.AsyncQueryHandler;
- import android.content.ContentResolver;
- import android.database.Cursor;
- import android.media.AudioManager;
- import android.media.MediaPlayer;
- import android.net.Uri;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Looper;
- import android.os.Message;
- import android.provider.MediaStore;
- import android.view.View;
- import android.widget.Button;
- import android.widget.EditText;
- import android.widget.TextView;
-
- import java.io.IOException;
- import java.util.ArrayList;
-
- public class Yy extends AppCompatActivity {
- TextView textView;
- TextView textView1;
- EditText editText;
- Button button1;
- Button button2;
- Button button3;
- Button button4;
- int n = 0;
- int is = 0;
- ArrayList<String> al = new ArrayList<>();
- MediaPlayer mediaPlayer = new MediaPlayer();
-
- @SuppressLint({"MissingInflatedId", "Range"})
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_yy);
-
- textView = findViewById(R.id.textView2);
- textView1 = findViewById(R.id.textView3);
- textView1.setTextSize(24);
- editText = findViewById(R.id.editTextText);
- editText.setText("");
- button1 = findViewById(R.id.button6);
- button1.setText("顺序播放");
- button2 = findViewById(R.id.button7);
- button2.setText("停止选播");
- button3 = findViewById(R.id.button8);
- button3.setText("进一首");
- button4 = findViewById(R.id.button9);
- button4.setText("退一首");
-
- ContentResolver contentResolver = getContentResolver();
- Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
- Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null);
- String o = null;
-
- while (cursor.moveToNext()) {
- @SuppressLint("Range")
- String s = cursor.getString(cursor.getColumnIndex("_data"));
- al.add(s);
- o = o + s + " ";
- }
- textView.setText(o);
- textView1.setText("音乐序号"+String.valueOf(cursor.getCount()));
-
- //------顺序全部播放--------------------------------------------------------
- button1.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
-
- Handler.Callback hc = new Handler.Callback() {
- @Override
- public boolean handleMessage(@NonNull Message message) {
- int t=message.arg1;
- textView1.setText("音乐序号:"+String.valueOf(t));
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- try {
- mediaPlayer.setDataSource(al.get(t));
- mediaPlayer.prepareAsync(); //这句必须放在setDataSource的后面,否则报错
-
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
- @Override
- public void onPrepared(MediaPlayer mediaPlayer) {
- mediaPlayer.start();
- }
- });
- return false;
- }
- };
-
- Handler handler=new Handler(Looper.getMainLooper(),hc);
-
- new Thread(()->{
- Message message = new Message();
- message.arg1 = n;
- handler.sendMessage(message);
- while(true){
- if(mediaPlayer!=null) {
- mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
- @Override
- public void onCompletion(MediaPlayer mediaPlayer) {
- n++;
- Message message = new Message();
- message.arg1 = n;
- handler.sendMessage(message);
-
- }
- });
- }
- }
- }).start();
- }
- });
-
- //---------暂停音乐播放,并选播,填如要开始播放的序号------------------------
- button2.setOnClickListener(view -> {
- if(mediaPlayer.isPlaying()){
- mediaPlayer.release();
- }
- String in=editText.getText().toString();
- n=Integer.valueOf(in);
- });
- //----------进一首开始顺序播放---------------------------------------------
- button3.setOnClickListener(view -> {
- if(mediaPlayer.isPlaying()){
- mediaPlayer.release();
- }
- Handler.Callback hc = new Handler.Callback() {
- @Override
- public boolean handleMessage(@NonNull Message message) {
- int t=message.arg1;
- textView1.setText("音乐序号:"+String.valueOf(t));
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- try {
- mediaPlayer.setDataSource(al.get(t));
- mediaPlayer.prepareAsync(); //这句必须放在setDataSource的后面,否则报错
-
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
- @Override
- public void onPrepared(MediaPlayer mediaPlayer) {
- mediaPlayer.start();
- }
- });
- return false;
- }
- };
-
- Handler handler=new Handler(Looper.getMainLooper(),hc);
-
- new Thread(()->{
- n=n+1;
- Message message = new Message();
- message.arg1 = n;
- handler.sendMessage(message);
-
- while(true){
- if(mediaPlayer!=null) {
- mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
- @Override
- public void onCompletion(MediaPlayer mediaPlayer) {
- n++;
- Message message = new Message();
- message.arg1 = n;
- handler.sendMessage(message);
- n++;
- }
- });
- }
- }
- }).start();
-
- });
- //-----------退一首开始顺序播放--------------------------------------------------
- button4.setOnClickListener(view -> {
- if(mediaPlayer.isPlaying()){
- mediaPlayer.release();
- }
- Handler.Callback hc = new Handler.Callback() {
- @Override
- public boolean handleMessage(@NonNull Message message) {
- int t=message.arg1;
- textView1.setText("音乐序号:"+String.valueOf(t));
- mediaPlayer = new MediaPlayer();
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- try {
- mediaPlayer.setDataSource(al.get(t));
- mediaPlayer.prepareAsync(); //这句必须放在setDataSource的后面,否则报错
-
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
- @Override
- public void onPrepared(MediaPlayer mediaPlayer) {
- mediaPlayer.start();
- }
- });
- return false;
- }
- };
-
- Handler handler=new Handler(Looper.getMainLooper(),hc);
-
- new Thread(()->{
- n=n-1;
- Message message = new Message();
- message.arg1 = n;
- handler.sendMessage(message);
- while(true){
- if(mediaPlayer!=null) {
- mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
- @Override
- public void onCompletion(MediaPlayer mediaPlayer) {
- n++;
- Message message = new Message();
- message.arg1 = n;
- handler.sendMessage(message);
- n++;
- }
- });
- }
- }
- }).start();
-
- });
- //-=====================================================================================
- }
-
-
- @Override
- public void onBackPressed () {
- super.onBackPressed();
- mediaPlayer.release();
- mediaPlayer = null;
- }
-
- }
- //-------------------返回关闭视频---------------------------------------
- public void onBackPressed() { //监听返回键,如返回则关闭视频
- super.onBackPressed();
- mediaPlayer.release();
- }
文本输入框的按键响应
- editText.setOnKeyListener(new View.OnKeyListener() { //针对文本输入框的按键事件
- @Override
- public boolean onKey(View view, int i, KeyEvent keyEvent) {
- if(keyEvent.getAction()==KeyEvent.ACTION_DOWN){ //当按键按下
- if(i==KeyEvent.KEYCODE_ENTER){ //当键值为回车键
- textView.setText("ok");
- }
- }
- return false;
- }
- });
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。