当前位置:   article > 正文

自学 android_android studio22.2.1 linux

android studio22.2.1 linux

试了两天,不管是deepin 软件仓库自带的eclipse,还是java 版的idea,怎样安装android 都不成功,反正各样的错误。最后到android官网下载了最新的集成开发软件才成功。官网网址

https://developer.android.com/studio     下载了linux 版:android-studio-2022.2.1.20-linux.tar.gz

按照安装文档轻松安装。建议,最好让电脑科学上网,因为有很多个文件是从google网站上下载的。

还有最好不要用虚拟终端输出程序结果。因为速度很慢。找一个旧手机代替,速度快得多。

下面的代码是输入框的内容显示在文本框中。

以下的程序都采用的是Empty Views Activity 模板。

发现android编程,ui界面部分只要把布局编辑器练熟就行了,难的还是代码的事件处理部份。ui的很多控件初学都用不上,只要把三四个常用的搞熟就可以练代码了。

  1. package com.example.wz;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.widget.Button;
  5. import android.widget.EditText;
  6. import android.widget.TextView;
  7. public class MainActivity extends AppCompatActivity {
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_main); //按照布局文件activity_main.xml 显示,估计此方法是不停刷新此文件的内容,所以程序不用再setContentView
  12. Button button=findViewById(R.id.button2); //android 用findViewById 取得java的控件实例
  13. EditText editText=findViewById(R.id.editTextText); //editText 对应的布局编译器中为Plain Text 文本输入框
  14. TextView textView=findViewById(R.id.textView3);
  15. button.setOnClickListener(view -> { //按键的响应
  16. String s = String.valueOf(editText.getText()); //取文本框输入内容
  17. textView.setText(s);
  18. });
  19. }
  20. }
  1. <uses-permission android:name="android.permission.INTERNET" />
  2. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

如要连接网络,必须在AndroidManifest.xml文件中加上此两句

下面的代码是连接服务器

  1. package com.example.wz;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.widget.Button;
  5. import android.widget.EditText;
  6. import android.widget.TextView;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. import java.io.ObjectInputStream;
  10. import java.net.Socket;
  11. public class MainActivity extends AppCompatActivity {
  12. @Override
  13. protected void onCreate(Bundle savedInstanceState) {
  14. super.onCreate(savedInstanceState);
  15. setContentView(R.layout.activity_main); //按照布局文件activity_main.xml 显示,估计此方法是不停刷新此文件的内容,所以程序多次setContentView()。
  16. Button button=findViewById(R.id.button2); //android 用findViewById 取得java的控件实例
  17. EditText editText=findViewById(R.id.editTextText); //editText 对应的布局编译器中为Plain Text 文本输入框
  18. TextView textView=findViewById(R.id.textView3);
  19. button.setOnClickListener(view -> { //按键的响应
  20. // String s = String.valueOf(editText.getText()); //取文本框输入内容
  21. // textView.setText("接收数据");
  22. try {
  23. Socket socket=new Socket("192.168.43.61",3000);
  24. InputStream inputStream=socket.getInputStream();
  25. ObjectInputStream objectInputStream=new ObjectInputStream(inputStream);
  26. String s=objectInputStream.readUTF();
  27. textView.setText(s);
  28. socket.close();
  29. } catch (IOException e) {
  30. throw new RuntimeException(e);
  31. }
  32. });
  33. }
  34. }

注意:try  catch语句要注释掉throw new RunimeException(e);这句,否则一有错,程序就退出。有这个基础程序框架,就可以试试把java程序搬到手机上。

还有setContentView()方法,估计安卓系统是定时不停地刷新桌面显示控件,有点像java的Timer,所以程序不用多次用此方法,一次就行了。

android 线程间传递数据,不能用java 线程的传递方法,如静态类变量就不能用。

  1. package com.example.wz;
  2. import androidx.annotation.NonNull;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.os.Bundle;
  5. import android.os.Handler;
  6. import android.os.Looper;
  7. import android.os.Message;
  8. import android.widget.Button;
  9. import android.widget.EditText;
  10. import android.widget.TextView;
  11. import java.io.IOException;
  12. import java.io.InputStream;
  13. import java.io.ObjectInputStream;
  14. import java.net.Socket;
  15. public class MainActivity extends AppCompatActivity {
  16. static Handler handler;
  17. static TextView textView;
  18. @Override
  19. protected void onCreate(Bundle savedInstanceState) {
  20. super.onCreate(savedInstanceState);
  21. setContentView(R.layout.activity_main);
  22. Button button = findViewById(R.id.button);
  23. EditText editText = findViewById(R.id.editTextText);
  24. textView = findViewById(R.id.textView);
  25. Handler.Callback hc=new Handler.Callback() {
  26. @Override
  27. public boolean handleMessage(@NonNull Message msg) { //这里必须调用handle类的镶嵌类Handle.Callback的handleMessage方法。
  28. int t=msg.arg1;
  29. textView.setText(String.valueOf(t));
  30. return false;
  31. }
  32. };
  33. handler =new Handler(Looper.myLooper(),hc);
  34. button.setOnClickListener(view -> {
  35. Th th = new Th();
  36. th.start();
  37. });
  38. }
  39. }
  40. class Th extends Thread {
  41. int t=0;
  42. public void run() {
  43. while (true) {
  44. Message message = new Message();
  45. message.arg1=t;
  46. MainActivity.handler.sendMessage(message);
  47. t++;
  48. try {
  49. Thread.sleep(1000);
  50. } catch (InterruptedException e) {
  51. // throw new RuntimeException(e);
  52. }
  53. }
  54. }
  55. }

此种传递数据的方法,数据的产生和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版本允许您将包含将由MessageHandler 的方法处理的数据包的对象排入队列handleMessage(Message)(要求您实现 Handler 的子类)。

发布或发送到处理程序时,您可以允许项目在消息队列准备就绪后立即处理,或者指定处理前的延迟或处理的绝对时间。后两者允许您实现超时、滴答和其他基于时间的行为。

handle post() 方法,发现只能更新一次,不知道是否正确

此方法代码很简单

  1. package com.example.wz;
  2. import androidx.annotation.NonNull;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.os.Bundle;
  5. import android.os.Handler;
  6. import android.os.Looper;
  7. import android.os.Message;
  8. import android.widget.Button;
  9. import android.widget.EditText;
  10. import android.widget.TextView;
  11. import java.io.IOException;
  12. import java.io.InputStream;
  13. import java.io.ObjectInputStream;
  14. import java.net.Socket;
  15. public class MainActivity extends AppCompatActivity {
  16. static Handler handler=new Handler();
  17. static TextView textView;
  18. @Override
  19. protected void onCreate(Bundle savedInstanceState) {
  20. super.onCreate(savedInstanceState);
  21. setContentView(R.layout.activity_main);
  22. Button button = findViewById(R.id.button);
  23. EditText editText = findViewById(R.id.editTextText);
  24. textView = findViewById(R.id.textView);
  25. button.setOnClickListener(view -> {
  26. Th th = new Th();
  27. th.start();
  28. });
  29. }
  30. }
  31. class Th extends Thread {
  32. public void run() {
  33. MainActivity.handler.post(()->{
  34. MainActivity.textView.setText("hello nanning");
  35. });
  36. }
  37. }

这里的handle实例必须放在主线程中,其实把它想成java场景中的静态类变量就好理解了。

如要循环,可以这样处理,但又不能加Thread.sleep()延时

  1. class Th extends Thread { //刚实验,此post方法只能更新一次ui。如加循环,报错
  2. public void run () {
  3. while(true) {
  4. h.post(new Runnable() {
  5. public void run() {
  6. textView.setText(String.valueOf(1));
  7. }
  8. });
  9. h.post(new Runnable() {
  10. public void run() {
  11. textView.setText(String.valueOf(2));
  12. }
  13. });
  14. }
  15. }
  16. }

这个post方法虽然只能执行一次更新ui,也可编写许多场景的程序了。如连接服务器一次读取数据,输入网址读取网页文件,查询一次文件目录,如是线程不停传递数据则不能用此方法。

利用handle.post()连接服务器读取一次数据

  1. package com.example.wz;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.os.Bundle;
  4. import android.os.Handler;
  5. import android.os.Looper;
  6. import android.os.Message;
  7. import android.widget.Button;
  8. import android.widget.EditText;
  9. import android.widget.TextView;
  10. import java.io.IOException;
  11. import java.io.InputStream;
  12. import java.io.ObjectInputStream;
  13. import java.net.Socket;
  14. public class MainActivity extends AppCompatActivity {
  15. static Handler h = new Handler();
  16. static TextView textView;
  17. @Override
  18. protected void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.activity_main);
  21. Button button = findViewById(R.id.button);
  22. EditText editText = findViewById(R.id.editTextText);
  23. textView = findViewById(R.id.textView);
  24. button.setOnClickListener(view -> {
  25. Th th = new Th();
  26. th.start();
  27. });
  28. }
  29. }
  30. class Th extends Thread { //刚实验,此post方法只能更新一次ui。如加循环,报错
  31. public void run() {
  32. Socket socket= null;
  33. String s;
  34. try {
  35. socket = new Socket("192.168.2.8",3000);
  36. InputStream inputStream=socket.getInputStream();
  37. ObjectInputStream objectInputStream=new
  38. ObjectInputStream(inputStream);
  39. s=objectInputStream.readUTF();
  40. MainActivity.h.post(new Runnable() {
  41. public void run() {
  42. MainActivity.textView.setText(s);
  43. }
  44. });
  45. objectInputStream.close();
  46. } catch (IOException e) {
  47. // throw new RuntimeException(e);
  48. }
  49. }
  50. }

手机要是上网,必须要在全局文件中加这俩句

<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,再连接才会正确显示。

  1. package com.example.wz;
  2. import static android.content.Context.MODE_PRIVATE;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.os.Bundle;
  5. import android.os.Handler;
  6. import android.widget.Button;
  7. import android.widget.EditText;
  8. import android.widget.TextView;
  9. import java.io.File;
  10. import java.io.FileNotFoundException;
  11. import java.io.FileOutputStream;
  12. import java.io.IOException;
  13. public class MainActivity extends AppCompatActivity {
  14. static Handler handler=new Handler();
  15. static TextView textView;
  16. @Override
  17. protected void onCreate(Bundle savedInstanceState) {
  18. super.onCreate(savedInstanceState);
  19. setContentView(R.layout.activity_main);
  20. Button button = findViewById(R.id.button);
  21. EditText editText = findViewById(R.id.editTextText);
  22. textView = findViewById(R.id.textView);
  23. button.setOnClickListener(view -> {
  24. Th th = new Th();
  25. th.start();
  26. });
  27. }
  28. }
  29. class Th extends Thread {
  30. public void run() {
  31. String text = "hello nanning";
  32. FileOutputStream fileOutputStream = null;
  33. try {
  34. fileOutputStream = new FileOutputStream("/data/data/com.example.wz/2.txt");
  35. fileOutputStream.write(text.getBytes()); //绝对路径
  36. fileOutputStream.close();
  37. MainActivity.handler.post(()->{
  38. MainActivity.textView.setText("file over");
  39. });
  40. } catch (IOException e) {
  41. throw new RuntimeException(e);
  42. }
  43. }
  44. }

所以,现在发现想给手机编一个程序,自由上传下载图片到手机的图库是不可能的,因为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 启动新的activity

  1. package com.example.wz;
  2. import static android.content.Context.MODE_PRIVATE;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.content.Intent;
  5. import android.os.Bundle;
  6. import android.os.Handler;
  7. import android.view.View;
  8. import android.widget.Button;
  9. import android.widget.EditText;
  10. import android.widget.TextView;
  11. import java.io.File;
  12. import java.io.FileNotFoundException;
  13. import java.io.FileOutputStream;
  14. import java.io.IOException;
  15. public class MainActivity extends AppCompatActivity {
  16. static Handler handler=new Handler();
  17. static TextView textView;
  18. @Override
  19. protected void onCreate(Bundle savedInstanceState) {
  20. super.onCreate(savedInstanceState);
  21. setContentView(R.layout.activity_main);
  22. Button button = findViewById(R.id.button);
  23. EditText editText = findViewById(R.id.editTextText);
  24. textView = findViewById(R.id.textView);
  25. button.setOnClickListener(view -> {
  26. Intent intent=new Intent(MainActivity.this,MainActivity2.class); //启动新的activity
  27. startActivity(intent);
  28. });
  29. }
  30. }

建立好子activity Java程序和xml配置文件,再用intent启动 intent第一个参数为按钮所在程序的程序名,  第二个参数为要启动的程序名。所以用intent 可以跳到任何窗口,包括从子窗口跳回主窗口。为什么要加.this 和.class  , 可以是规定吧。

如果不怕复杂,可以把事件响应独立来写

  1. View.OnClickListener listener=new View.OnClickListener() {
  2. @Override
  3. public void onClick(View view) {
  4. Intent intent=new Intent(MainActivity2.this,MainActivity.class);
  5. startActivity(intent);
  6. }
  7. };
  8. button.setOnClickListener(listener);

intent  可以调用android系统的程序

下面的代码是调用android 的内置拨号程序,调用内置程序,不用自编activity。系统自动调出已固定的拨号activity。

  1. package com.example.call;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.content.Intent;
  4. import android.net.Uri;
  5. import android.os.Bundle;
  6. import android.widget.Button;
  7. import android.widget.TextView;
  8. public class MainActivity extends AppCompatActivity {
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_main);
  13. Button button=findViewById(R.id.button);
  14. TextView textView=findViewById(R.id.editTextText); //输入电话号码
  15. button.setOnClickListener(view -> {
  16. String s=textView.getText().toString();
  17. Intent intent=new Intent(Intent.ACTION_DIAL, Uri.parse("tel://"+s));
  18. startActivity(intent); //利用intent 调用android内置拨号程序
  19. });
  20. }
  21. }

到这里,就可以很好理解为什么在用某个不用钱的程序时,突然点出拚多多的程序。

activity 之间通过bundle互传数据

主窗口:

  1. package com.example.wz;
  2. import static android.content.Context.MODE_PRIVATE;
  3. import androidx.annotation.Nullable;
  4. import androidx.appcompat.app.AppCompatActivity;
  5. import android.annotation.SuppressLint;
  6. import android.content.Intent;
  7. import android.media.MediaPlayer;
  8. import android.os.Bundle;
  9. import android.os.Handler;
  10. import android.view.View;
  11. import android.widget.Button;
  12. import android.widget.EditText;
  13. import android.widget.ImageView;
  14. import android.widget.TextView;
  15. public class MainActivity extends AppCompatActivity {
  16. static Handler handler=new Handler();
  17. @Override
  18. protected void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.activity_main);
  21. Button button = findViewById(R.id.button);
  22. @SuppressLint({"MissingInflatedId", "LocalSuppress"})
  23. TextView textView=findViewById(R.id.textView);
  24. button.setOnClickListener(view -> {
  25. Bundle bundle=new Bundle();
  26. String name="wz";
  27. bundle.putString("name",name);
  28. Intent intent=new Intent(MainActivity.this,MainActivity2.class);//切换到第二窗口
  29. intent.putExtras(bundle);
  30. startActivity(intent);
  31. });
  32. Intent intent=getIntent(); //提取第二窗口传递的数据
  33. String name1=intent.getStringExtra("kk");
  34. textView.setText(name1);
  35. }
  36. }

子窗口

  1. package com.example.wz;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.annotation.SuppressLint;
  4. import android.content.Intent;
  5. import android.os.Bundle;
  6. import android.widget.Button;
  7. import android.widget.TextView;
  8. public class MainActivity2 extends AppCompatActivity {
  9. String name;
  10. @Override
  11. protected void onCreate(Bundle savedInstanceState) {
  12. super.onCreate(savedInstanceState);
  13. setContentView(R.layout.activity_main2);
  14. Intent intent=getIntent(); //提取主窗口传递的数据
  15. name=intent.getStringExtra("name");
  16. TextView textView=findViewById(R.id.textView2);
  17. textView.setText(name);
  18. @SuppressLint({"MissingInflatedId", "LocalSuppress"})
  19. Button button=findViewById(R.id.button2);
  20. button.setOnClickListener(view -> {
  21. Intent intent1=new Intent(MainActivity2.this,MainActivity.class); //切换到主窗口
  22. Bundle bundle=new Bundle(); //绑定的数据
  23. bundle.putString("kk","wl");
  24. intent1.putExtras(bundle);
  25. startActivity(intent1);
  26. });
  27. }
  28. }

用这个方法,不用调用带返回数据的startactivity方法。

android 系统内置了很多常用的activity。如打电话的activity,

--------------------------------------------------------------------------------------------------------------------------------

android  图片的接收,删除,显示,图片列表显示

图片存储有两种方式,一种是存于自身程序包内,一种是存于像册,下面的程序是处理存在程序包中的情况。

如程序都在一个窗口中显示,就不用考虑activity的问题

图片存储路径:/data/data/包名/

16fb5910fde24230815fcfb9f3f9ae56.png

接收图片的手机与发送图片的电脑,必须在同一个局域网中

 代码:

  1. package com.example.call;
  2. import android.annotation.SuppressLint;
  3. import android.app.Activity;
  4. import android.content.Context;
  5. import android.graphics.Bitmap;
  6. import android.graphics.BitmapFactory;
  7. import android.os.Bundle;
  8. import android.widget.Button;
  9. import android.widget.EditText;
  10. import android.widget.ImageView;
  11. import android.widget.TextView;
  12. import java.io.FileOutputStream;
  13. import java.io.IOException;
  14. import java.io.InputStream;
  15. import java.io.ObjectInputStream;
  16. import java.net.Socket;
  17. public class MainActivity extends Activity {
  18. TextView textView;
  19. @SuppressLint("MissingInflatedId")
  20. protected void onCreate(Bundle savedInstanceState) {
  21. super.onCreate(savedInstanceState);
  22. setContentView(R.layout.activity_main);
  23. Button button = findViewById(R.id.button);
  24. button.setText("接收");
  25. Button button2=findViewById(R.id.button2);
  26. button2.setText("播放");
  27. Button button3=findViewById(R.id.button14);
  28. button3.setText("目录");
  29. Button button4=findViewById(R.id.button3);
  30. button4.setText("删除");
  31. textView=findViewById(R.id.textView);
  32. ImageView imageView = findViewById(R.id.imageView);
  33. imageView.setImageResource(R.drawable.ic_launcher_background);
  34. EditText editText=findViewById(R.id.editTextText);
  35. button4.setOnClickListener(view -> {
  36. String name=editText.getText().toString();
  37. textView.setText(name);
  38. deleteFile(name);
  39. });
  40. button3.setOnClickListener(view -> {
  41. String[] s=fileList();
  42. String o=null;
  43. for(String k:s){
  44. o=o+k+" ";
  45. }
  46. textView.setText(o);
  47. });
  48. button2.setOnClickListener(view -> {
  49. String name=editText.getText().toString();
  50. textView.setText(name);
  51. Bitmap myBitmap = BitmapFactory.decodeFile("/data/data/com.example.call/files/"+name);
  52. imageView.setImageBitmap(myBitmap);
  53. });
  54. button.setOnClickListener(view -> {
  55. try {
  56. Socket socket=new Socket("192.168.43.61",3000);
  57. InputStream inputStream=socket.getInputStream();
  58. ObjectInputStream objectInputStream=new ObjectInputStream(inputStream);
  59. String name=objectInputStream.readUTF();
  60. byte[] b= (byte[]) objectInputStream.readObject();
  61. FileOutputStream fileOutputStream=openFileOutput(name,Context.MODE_PRIVATE);
  62. fileOutputStream.write(b);
  63. fileOutputStream.close();
  64. socket.close();
  65. } catch (IOException e) {
  66. // throw new RuntimeException(e);
  67. textView.setText("net 错误");
  68. } catch (ClassNotFoundException e) {
  69. // throw new RuntimeException(e);
  70. }
  71. });
  72. }
  73. }

上传图片

  1. import java.io.*;
  2. import java.net.ServerSocket;
  3. import java.net.Socket;
  4. public class Main {
  5. public static void main(String[] args) throws IOException {
  6. String s="/home/wzpc/3.jpg";
  7. File file=new File(s);
  8. String name=file.getName();
  9. FileInputStream fileInputStream=new FileInputStream(file);
  10. byte[] b=new byte[fileInputStream.available()];
  11. fileInputStream.read(b);
  12. ServerSocket serverSocket=new ServerSocket(3000);
  13. Socket socket=serverSocket.accept();
  14. OutputStream outputStream=socket.getOutputStream();
  15. ObjectOutputStream objectOutputStream=new ObjectOutputStream(outputStream);
  16. objectOutputStream.writeUTF(name);
  17. objectOutputStream.flush();
  18. objectOutputStream.writeObject(b);
  19. objectOutputStream.flush();
  20. socket.close();
  21. fileInputStream.close();
  22. }
  23. }

实.物图

c45343bc8918424c93c681b82d7a7cd8.jpg

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。

android 数据库

查询数据库图片,音乐,视频

"_data"    在数据库中代表文件的全路径名,它是非常重要的列名。

下面程序的cursor 的数值就是查询后数据的集合,采用循环一行一行读取列(_data)的值。

  1. package com.example.test1;
  2. import static android.content.ContentValues.TAG;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.annotation.SuppressLint;
  5. import android.content.ContentResolver;
  6. import android.database.Cursor;
  7. import android.graphics.Bitmap;
  8. import android.graphics.BitmapFactory;
  9. import android.net.Uri;
  10. import android.os.Bundle;
  11. import android.provider.MediaStore;
  12. import android.util.Log;
  13. import android.widget.ImageView;
  14. import android.widget.TextView;
  15. public class MainActivity extends AppCompatActivity {
  16. @SuppressLint("Range")
  17. @Override
  18. protected void onCreate(Bundle savedInstanceState) {
  19. super.onCreate(savedInstanceState);
  20. setContentView(R.layout.activity_main);
  21. TextView textView = findViewById(R.id.textView2);
  22. ImageView imageView = findViewById(R.id.imageView);
  23. ContentResolver contentResolver = getContentResolver(); //读数据库
  24. Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
  25. // 音频MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  26. // 视频MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
  27. Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null); //查询
  28. // int t = cursor.getColumnCount(); //数据库 列数量
  29. // String[] columnNames = cursor.getColumnNames(); //数据库全部 列名字 如query()方法的第二参数已限制列名,则columnnames=第二参数名,现在就是_data
  30. // int t1 = cursor.getColumnIndex("_data"); //返回给定 列名称的从零开始的索引,如果该列不存在,则返回-1
  31. // int t2 = cursor.getCount(); //数据库的总行数;
  32. while (cursor.moveToNext()) { // 移到数据库的下一行。
  33. /* for (String Name : columnNames) { //name数据库的某一列,columnnames 全部列名
  34. Log.d(TAG, "----------------------------");
  35. Log.d(TAG, "name--> " + Name + " value--> " + cursor.getString(cursor.getColumnIndex(Name)));
  36. Log.d(TAG, "----------------------------");
  37. }*/
  38. //因为只查询了一列"_data",可以这样简写
  39. Log.d(TAG, "----------------------------"); //在电脑的Run框中显示输出
  40. Log.d(TAG, "name-->_data " + " value--> " + cursor.getString(cursor.getColumnIndex("_data"))); //显示数据库中图片的路径,根据索引反查索引值
  41. Log.d(TAG, "----------------------------");
  42. }
  43. Bitmap bitmap = BitmapFactory.decodeFile("/storage/emulated/0/Pictures/Screenshots/Screenshot_20230701_101256_com.tencent.mobileqq.jpg"); //显示图片
  44. imageView.setImageBitmap(bitmap);
  45. }
  46. }

run框显示

7b32a9d608854b429111350bee0de706.png
 

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

  1. Cursor cursor = contentResolver.query(uri,new String[]{"_display_name","_data"}, null, null, null, null); //查询
  2. String[] s=cursor.getColumnNames();
  3. String o=null;
  4. for(String k:s){
  5. o=o+k+" ";
  6. }
  7. Log.d(TAG, "----------------------------");
  8. Log.d(TAG,o);
  9. while (cursor.moveToNext()) { // 移到数据库的下一行。
  10. Log.d(TAG,cursor.getString(cursor.getColumnIndex("_display_name")));
  11. Log.d(TAG,cursor.getString(cursor.getColumnIndex("_data"))); //显示数据库中图片的路径,根据索引反查索引值
  12. }
  13. Log.d(TAG, "----------------------------");

  查询数据库步骤:query()方法的第二个参数是字符串数组,它的元素就是数据库要查询的列名字,如_data  ,_display_name。  query方法生成的Cursor  就是要查询的列的全部行的值。提取每行采用 moveToNext()方法,取出每行的值采用:先用列名提取列在每行中的索引(getColumnIndex(列名)),再用此索引号倒查此索引的值。 

经验证,新产生的照片,如刚拍的照片,会立即填加在数据库的末端。用这个方法,可以提取出刚拍的照片。     

cursor.moveToLast();                //跳到数据库最后一行
Log.d(TAG,cursor.getString(cursor.getColumnIndex("_data")));//显示最后一行的data指向的最近写入数据库的照片。

浏览手机全部照片

  1. package com.example.test1;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.annotation.SuppressLint;
  4. import android.content.ContentResolver;
  5. import android.database.Cursor;
  6. import android.graphics.Bitmap;
  7. import android.graphics.BitmapFactory;
  8. import android.net.Uri;
  9. import android.os.Bundle;
  10. import android.provider.MediaStore;
  11. import android.widget.Button;
  12. import android.widget.ImageView;
  13. import android.widget.TextView;
  14. import java.util.ArrayList;
  15. public class MainActivity extends AppCompatActivity {
  16. int n=0;
  17. @SuppressLint("Range")
  18. @Override
  19. protected void onCreate(Bundle savedInstanceState) {
  20. super.onCreate(savedInstanceState);
  21. setContentView(R.layout.activity_main);
  22. TextView textView = findViewById(R.id.textView2);
  23. ImageView imageView = findViewById(R.id.imageView);
  24. Button button=findViewById(R.id.button3);
  25. ContentResolver contentResolver = getContentResolver(); //读数据库
  26. Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
  27. // 音频MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  28. // 视频MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
  29. Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null); //查询
  30. ArrayList<String> al=new ArrayList<>();
  31. while (cursor.moveToNext()) { // 移到数据库的下一行。
  32. String s=cursor.getString(cursor.getColumnIndex("_data"));
  33. al.add(s); //把数据库全部的图片路径存入ArrayList中
  34. }
  35. // textView.setText(String.valueOf(al.size()));
  36. button.setOnClickListener(view -> { //按钮按一下,浏览一张图片
  37. n++;
  38. Bitmap bitmap=BitmapFactory.decodeFile(al.get(n));
  39. imageView.setImageBitmap(bitmap);
  40. });
  41. }
  42. }

感觉这个小程序的图片浏览加载速度快与手机的图片浏览app。

自动播放手机数据库图片

此程序相当重要,涉及到线程之间的数据交换,ui的定时更新

  1. package com.example.test1;
  2. import androidx.annotation.NonNull;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.annotation.SuppressLint;
  5. import android.content.ContentResolver;
  6. import android.database.Cursor;
  7. import android.graphics.Bitmap;
  8. import android.graphics.BitmapFactory;
  9. import android.net.Uri;
  10. import android.os.Bundle;
  11. import android.os.Handler;
  12. import android.os.Looper;
  13. import android.os.Message;
  14. import android.provider.MediaStore;
  15. import android.widget.Button;
  16. import android.widget.ImageView;
  17. import android.widget.TextView;
  18. import java.util.ArrayList;
  19. public class MainActivity extends AppCompatActivity {
  20. int n=0;
  21. @SuppressLint("Range")
  22. @Override
  23. protected void onCreate(Bundle savedInstanceState) {
  24. super.onCreate(savedInstanceState);
  25. setContentView(R.layout.activity_main);
  26. TextView textView = findViewById(R.id.textView2);
  27. ImageView imageView = findViewById(R.id.imageView);
  28. Button button=findViewById(R.id.button3);
  29. ContentResolver contentResolver = getContentResolver(); //读数据库
  30. Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
  31. // 音频MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  32. // 视频MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
  33. Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null); //查询
  34. ArrayList<String> al=new ArrayList<>();
  35. while (cursor.moveToNext()) { // 移到数据库的下一行。
  36. String s = cursor.getString(cursor.getColumnIndex("_data"));
  37. al.add(s); //把数据库全部的图片路径存入ArrayList
  38. }
  39. Handler.Callback hc=new Handler.Callback() {
  40. @Override
  41. public boolean handleMessage(@NonNull Message msg) { //这里必须调用handle类的镶嵌类Handle.Callback的handleMessage方法。
  42. int t=msg.arg1;
  43. Bitmap bitmap = BitmapFactory.decodeFile(al.get(t));
  44. imageView.setImageBitmap(bitmap);
  45. return false;
  46. }
  47. };
  48. Handler handler =new Handler(Looper.myLooper(),hc);
  49. new Thread(()->{
  50. while(true) {
  51. Message message = new Message();
  52. message.arg1=n;
  53. handler.sendMessage(message);
  54. n++;
  55. try {
  56. Thread.sleep(1000);
  57. } catch (InterruptedException e) {
  58. // throw new RuntimeException(e);
  59. }
  60. }
  61. }).start();
  62. }
  63. }

此程序可以作为ui循环或定时更新的模板。

编程发现:android 主方法线程中,不能用for循环等方法为ui的各种显示控件赋值来完成ui的更新

必须采用上述hendle类来完成。

为什么要这样,我理解是因为android的主线程不能有占长时间运行的代码。如果必须有这种长耗时代码,必须把这种代码移到一新线程中。再把数据通过message传回主线程

android 读取数据库的权限问题

华为畅享20 ART-AL00m     用的是android 10 ,除了在全局文件中加入权限外,还要在

application段中加入这句
android:requestLegacyExternalStorage="true"
如果不在程序中加入动态权限,那么一定要在手机的设置中开启你的程序的存储权限。

华为nova8  不用加这句可运行。加了也不影响。还有如果发现程序不运行,多是手机的存储权限关闭,在手机设置中开启就可以了。nova8 很少有关闭权限的情况,畅享20经常发生。

android  数据库音频

以上介绍了几种播放方式,可以说各有优劣。
本文写的不够详细,只是大概的介绍一下几种播放方式。在此做下简单的总结。

对于延迟度要求不高,并且希望能够更全面的控制音乐的播放,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

  1. package com.example.wz;
  2. import android.annotation.SuppressLint;
  3. import android.media.MediaPlayer;
  4. import android.net.Uri;
  5. import android.os.Bundle;
  6. import androidx.appcompat.app.AppCompatActivity;
  7. public class MainActivity extends AppCompatActivity {
  8. MediaPlayer mediaPlayer; //必须onCreate()方法前先定义MediaPlayer,否则华为手机只能播放音乐1-2秒就停止,不知道为啥
  9. @SuppressLint({"MissingInflatedId", "Range"})
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_main);
  13. Uri u=Uri.parse("/storage/emulated/0/qqmusic/song/阳山伟伟 - 星辰 (Original Mix) [mqms2].flac");
  14. mediaPlayer = MediaPlayer.create(this.getApplicationContext(),u);
  15. mediaPlayer.start();
  16. }
  17. }
必须onCreate()方法前先定义MediaPlayer,否则华为手机只能播放音乐1-2秒就停止,不知道为啥,这个解决方法是在网络发现的。其他手机没有试过。

播放音频要在全局文件中加入这两种权限

    <uses-permission android:name="android.permission.INTERNET" />   
    <uses-permission android:name="android.permission.WAKE_LOCK" />
还有一点,因为所以程序都没有写动态权限,所以必须要在手机的设置中为程序赋予读写存储的权限
    
下面是android官网使用的代码,最好用这种代码,因为上面的三行代码在畅享20中不能运行。

主线程使用这种prepare()方式为同步播放,影响ui的更新,最好另起一子线程

  1. Uri myUri = ....; // initialize Uri here
  2. MediaPlayer mediaPlayer = new MediaPlayer();
  3. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  4. mediaPlayer.setDataSource(getApplicationContext(), myUri);
  5. mediaPlayer.prepare();
  6. mediaPlayer.start();

另起一子线程播放

  1. new Thread(()->{
  2. Uri u=Uri.parse(al.get(2));
  3. mediaPlayer = new MediaPlayer();
  4. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  5. try {
  6. mediaPlayer.setDataSource(getApplicationContext(),u);
  7. mediaPlayer.prepare(); //同步播发,影响ui的更新,如采用同步播放音乐,最好另开一子线程
  8. mediaPlayer.start();
  9. } catch (IOException e) {
  10. throw new RuntimeException(e);
  11. }
  12. }).start();

主线程异步播放

官网代码

  1. public class MyService extends Service implements MediaPlayer.OnPreparedListener {
  2. private static final String ACTION_PLAY = "com.example.action.PLAY";
  3. MediaPlayer mediaPlayer = null;
  4. public int onStartCommand(Intent intent, int flags, int startId) {
  5. ...
  6. if (intent.getAction().equals(ACTION_PLAY)) {
  7. mediaPlayer = ... // initialize it here
  8. mediaPlayer.setOnPreparedListener(this);
  9. mediaPlayer.prepareAsync(); // prepare async to not block main thread
  10. }
  11. }
  12. /** Called when MediaPlayer is ready */
  13. public void onPrepared(MediaPlayer player) {
  14. player.start();
  15. }
  16. }

主线程异步播放实用代码

  1. Uri u=Uri.parse(al.get(1));
  2. mediaPlayer = new MediaPlayer();
  3. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  4. try {
  5. mediaPlayer.setDataSource(this.getApplicationContext(),u);
  6. mediaPlayer.prepareAsync(); //这句必须放在setDataSource的后面,否则报错
  7. } catch (IOException e) {
  8. throw new RuntimeException(e);
  9. }
  10. mediaPlayer.setOnPreparedListener(mediaPlayer1 -> { //音乐异步准备完成播放,为什么是mediaPlay1,不清楚,程序自动显示的
  11. mediaPlayer.start();
  12. });

顺序播放数据库所有音乐,此程序相当重要,主要理解监控音乐是否完成的线程

  1. package com.example.test1;
  2. import androidx.appcompat.app.AppCompatActivity;
  3. import android.annotation.SuppressLint;
  4. import android.content.ContentResolver;
  5. import android.database.Cursor;
  6. import android.media.AudioManager;
  7. import android.media.MediaPlayer;
  8. import android.net.Uri;
  9. import android.os.Bundle;
  10. import android.provider.MediaStore;
  11. import android.widget.Button;
  12. import android.widget.ImageView;
  13. import android.widget.TextView;
  14. import java.io.IOException;
  15. import java.util.ArrayList;
  16. public class MainActivity extends AppCompatActivity {
  17. static int is=0; //音乐播放完成标志位
  18. MediaPlayer[] mp;
  19. MediaPlayer mediaPlayer;
  20. int n=0;
  21. @SuppressLint("Range")
  22. @Override
  23. protected void onCreate(Bundle savedInstanceState) {
  24. super.onCreate(savedInstanceState);
  25. setContentView(R.layout.activity_main);
  26. TextView textView = findViewById(R.id.textView2);
  27. ImageView imageView = findViewById(R.id.imageView);
  28. Button button=findViewById(R.id.button3);
  29. ContentResolver contentResolver = getContentResolver(); //读数据库
  30. // Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
  31. Uri uri=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  32. // 视频MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
  33. Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null); //查询
  34. ArrayList<String> al=new ArrayList<>();
  35. while (cursor.moveToNext()) { // 移到数据库的下一行。
  36. String s = cursor.getString(cursor.getColumnIndex("_data"));
  37. al.add(s); //把数据库全部的图片路径存入ArrayList
  38. }
  39. class Th extends Thread{
  40. public void run() {
  41. is=0; //播放开始 清标志位
  42. mediaPlayer = new MediaPlayer();
  43. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  44. try {
  45. mediaPlayer.setDataSource(al.get(n));
  46. mediaPlayer.prepareAsync(); //这句必须放在setDataSource的后面,否则报错
  47. } catch (IOException e) {
  48. throw new RuntimeException(e);
  49. }
  50. mediaPlayer.setOnPreparedListener(mediaPlayer1 -> { //音乐异步准备完成播放,为什么是mediaPlay1,不清楚,程序自动显示的
  51. mediaPlayer.start();
  52. });
  53. mediaPlayer.setOnCompletionListener(mediaPlayer1 -> {
  54. is=1; //播放完成置标志位
  55. });
  56. }
  57. }
  58. button.setOnClickListener(view ->{ //按键启动播放音乐
  59. Th th=new Th();
  60. th.start();
  61. });
  62. //------重点---------------------------------------------------------
  63. new Thread(()->{ //新开一线程,一直监控标志位is
  64. while(true) { //is=1,表示音乐播放完成,播放线程已关闭
  65. if (is == 1) {
  66. n++; //跳到下一首音乐路径
  67. Th th = new Th(); //新开一播放音乐线程
  68. th.start();
  69. }
  70. try {
  71. Thread.sleep(2000); //防线程误启动时间,也是两首音乐的间隔时间
  72. } catch (InterruptedException e) {
  73. throw new RuntimeException(e);
  74. }
  75. }
  76. }).start();
  77. }
  78. }

android 视频

Android中,我们有三种方式来实现视频的播放:

1、使用其自带的播放器。指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型。

2、使用VideoView来播放。在布局文件中使用VideoView结合MediaController来实现对其控制。

3、使用MediaPlayer类和SurfaceView来实现,这种方式很灵活。

播放数据库视频

自动顺序播放手机全部视频

  1. package com.example.test1;
  2. import static android.content.ContentValues.TAG;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.annotation.SuppressLint;
  5. import android.content.ContentResolver;
  6. import android.database.Cursor;
  7. import android.media.AudioManager;
  8. import android.media.MediaPlayer;
  9. import android.net.Uri;
  10. import android.os.Bundle;
  11. import android.provider.MediaStore;
  12. import android.util.Log;
  13. import android.view.SurfaceHolder;
  14. import android.view.SurfaceView;
  15. import android.widget.Button;
  16. import java.io.IOException;
  17. import java.util.ArrayList;
  18. public class MainActivity extends AppCompatActivity {
  19. SurfaceHolder surfaceHolder;
  20. int n=0;
  21. static int is=0;
  22. MediaPlayer mediaPlayer;
  23. @SuppressLint("Range")
  24. @Override
  25. protected void onCreate(Bundle savedInstanceState) {
  26. super.onCreate(savedInstanceState);
  27. setContentView(R.layout.activity_main);
  28. @SuppressLint({"WrongViewCast", "MissingInflatedId", "LocalSuppress"})
  29. SurfaceView surfaceView=findViewById(R.id.surfaceView);
  30. Button button=findViewById(R.id.button3);
  31. ContentResolver contentResolver = getContentResolver(); //读数据库
  32. // Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
  33. // Uri uri=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  34. Uri uri=MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
  35. Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null); //查询
  36. ArrayList<String> al=new ArrayList<>();
  37. while (cursor.moveToNext()) { // 移到数据库的下一行。
  38. String s = cursor.getString(cursor.getColumnIndex("_data"));
  39. al.add(s); //把数据库全部的图片路径存入ArrayList
  40. Log.d(TAG,s);
  41. }
  42. Runnable r=()->{
  43. is=0;
  44. mediaPlayer = new MediaPlayer();
  45. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  46. try {
  47. mediaPlayer.setDataSource(al.get(n));
  48. mediaPlayer.prepare();
  49. } catch (IOException e) {
  50. throw new RuntimeException(e);
  51. }
  52. surfaceHolder = surfaceView.getHolder(); //播放视频增加这两句
  53. mediaPlayer.setDisplay(surfaceHolder); //播放视频增加这两句
  54. mediaPlayer.start();
  55. mediaPlayer.setOnCompletionListener(mediaPlayer1 -> {
  56. is=1;
  57. mediaPlayer.release(); //释放,关闭mediaPlay
  58. });
  59. };
  60. button.setOnClickListener(view -> { //启动开始播放
  61. Thread thread=new Thread(r);
  62. thread.start();
  63. });
  64. new Thread(()->{
  65. while(true){
  66. if(is==1){
  67. n++;
  68. Thread thread=new Thread(r);
  69. thread.start();
  70. }
  71. try {
  72. Thread.sleep(2000);
  73. } catch (InterruptedException e) {
  74. throw new RuntimeException(e);
  75. }
  76. }
  77. }).start();
  78. }
  79. }

新开子窗口用于显示视频,activity 之间传递文件路径名

主窗口代码

  1. package com.example.test1;
  2. import static android.content.ContentValues.TAG;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.annotation.SuppressLint;
  5. import android.content.ContentResolver;
  6. import android.content.Intent;
  7. import android.database.Cursor;
  8. import android.media.MediaPlayer;
  9. import android.net.Uri;
  10. import android.os.Bundle;
  11. import android.provider.MediaStore;
  12. import android.util.Log;
  13. import android.view.SurfaceHolder;
  14. import android.view.SurfaceView;
  15. import android.widget.Button;
  16. import java.util.ArrayList;
  17. public class MainActivity extends AppCompatActivity {
  18. SurfaceHolder surfaceHolder;
  19. int n=0;
  20. static int is=0;
  21. MediaPlayer mediaPlayer;
  22. @SuppressLint("Range")
  23. @Override
  24. protected void onCreate(Bundle savedInstanceState) {
  25. super.onCreate(savedInstanceState);
  26. setContentView(R.layout.activity_main);
  27. @SuppressLint({"WrongViewCast", "MissingInflatedId", "LocalSuppress"})
  28. SurfaceView surfaceView=findViewById(R.id.surfaceView);
  29. Button button=findViewById(R.id.button3);
  30. ContentResolver contentResolver = getContentResolver(); //读数据库
  31. // Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
  32. // Uri uri=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  33. Uri uri=MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
  34. Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null); //查询
  35. ArrayList<String> al=new ArrayList<>();
  36. while (cursor.moveToNext()) { // 移到数据库的下一行。
  37. String s = cursor.getString(cursor.getColumnIndex("_data"));
  38. al.add(s); //把数据库全部的图片路径存入ArrayList
  39. Log.d(TAG,s);
  40. }
  41. button.setOnClickListener(view -> {
  42. n++;
  43. Bundle bundle=new Bundle();
  44. String path=al.get(n); //为子窗口传递显示文件路径
  45. bundle.putString("lj",path);
  46. Intent intent=new Intent(MainActivity.this,Sp.class);
  47. intent.putExtras(bundle);
  48. startActivity(intent);
  49. });
  50. }
  51. }

子窗口代码

  1. package com.example.test1;
  2. import androidx.annotation.NonNull;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.annotation.SuppressLint;
  5. import android.content.Intent;
  6. import android.media.AudioManager;
  7. import android.media.MediaPlayer;
  8. import android.os.Bundle;
  9. import android.view.SurfaceHolder;
  10. import android.view.SurfaceView;
  11. import java.io.IOException;
  12. public class Sp extends AppCompatActivity {
  13. SurfaceHolder surfaceHolder;
  14. MediaPlayer mediaPlayer;
  15. @Override
  16. protected void onCreate(Bundle savedInstanceState) {
  17. super.onCreate(savedInstanceState);
  18. setContentView(R.layout.activity_sp);
  19. @SuppressLint({"MissingInflatedId", "LocalSuppress"})
  20. SurfaceView surfaceView=findViewById(R.id.surfaceView2);
  21. Intent intent=getIntent();
  22. String path=intent.getStringExtra("lj"); //取得主窗口传递的路径
  23. mediaPlayer = new MediaPlayer();
  24. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  25. try {
  26. mediaPlayer.setDataSource(path);
  27. mediaPlayer.prepareAsync();
  28. } catch (IOException e) {
  29. throw new RuntimeException(e);
  30. }
  31. surfaceHolder = surfaceView.getHolder(); //播放视频增加这两句
  32. surfaceHolder.addCallback(new SurfaceHolder.Callback() { //最好用callback此方法显示,否则太多报错
  33. @Override
  34. public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder) {
  35. mediaPlayer.setDisplay(surfaceHolder); //播放视频增加这两句
  36. }
  37. @Override
  38. public void surfaceChanged(@NonNull SurfaceHolder surfaceHolder, int i, int i1, int i2) {
  39. }
  40. @Override
  41. public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder) {
  42. }
  43. });
  44. mediaPlayer.setOnPreparedListener(mediaPlayer1 -> {
  45. mediaPlayer.start();
  46. });
  47. mediaPlayer.setOnCompletionListener(mediaPlayer1 -> {
  48. mediaPlayer.release();
  49. });
  50. }
  51. //-------------------返回关闭视频---------------------------------------
  52. public void onBackPressed() { //监听返回键,如返回则关闭视频
  53. super.onBackPressed();
  54. mediaPlayer.release();
  55. }
  56. }

顺序播放或者按文件序号点播视频

  1. package com.example.test1;
  2. import static android.content.ContentValues.TAG;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.annotation.SuppressLint;
  5. import android.content.ContentResolver;
  6. import android.content.Intent;
  7. import android.database.Cursor;
  8. import android.media.MediaPlayer;
  9. import android.net.Uri;
  10. import android.os.Bundle;
  11. import android.provider.MediaStore;
  12. import android.util.Log;
  13. import android.view.KeyEvent;
  14. import android.view.SurfaceHolder;
  15. import android.view.SurfaceView;
  16. import android.view.View;
  17. import android.widget.Button;
  18. import android.widget.EditText;
  19. import android.widget.TextView;
  20. import java.util.ArrayList;
  21. import java.util.HashMap;
  22. import java.util.Map;
  23. public class MainActivity extends AppCompatActivity {
  24. SurfaceHolder surfaceHolder;
  25. String outpath;
  26. String outname;
  27. String xs;
  28. int n=0;
  29. int no=0;
  30. MediaPlayer mediaPlayer;
  31. TextView textView;
  32. EditText editText;
  33. ArrayList<String> al;
  34. Bundle bundle=new Bundle();
  35. @SuppressLint("Range")
  36. @Override
  37. protected void onCreate(Bundle savedInstanceState) {
  38. super.onCreate(savedInstanceState);
  39. setContentView(R.layout.activity_main);
  40. Button button=findViewById(R.id.button3);
  41. editText=findViewById(R.id.editTextText);
  42. editText.setText("");
  43. textView=findViewById(R.id.textView2);
  44. textView.setText("");
  45. ContentResolver contentResolver = getContentResolver(); //读数据库
  46. // Uri uri =MediaStore.Images.Media.EXTERNAL_CONTENT_URI; //读外部存储数据库 _data 代表图片文件的全路径
  47. // Uri uri=MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  48. Uri uri=MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
  49. Cursor cursor = contentResolver.query(uri, new String[]{"_data","_display_name"}, null, null, null, null); //查询
  50. al=new ArrayList<>();
  51. Map<Integer,String> map=new HashMap<>();
  52. while (cursor.moveToNext()) { // 移到数据库的下一行。
  53. String s = cursor.getString(cursor.getColumnIndex("_data"));
  54. String name=cursor.getString(cursor.getColumnIndex("_display_name"));
  55. al.add(s);
  56. outname=outname+name+" ";
  57. xs=xs+String.valueOf(no)+": "+name+" ";
  58. map.put(no,s);
  59. no++;
  60. }
  61. textView.setText(xs);
  62. //----------按键启动顺序播放-----------------------------------------
  63. button.setOnClickListener(view -> {
  64. n++;
  65. // Bundle bundle=new Bundle();
  66. String path=al.get(n);
  67. bundle.putString("lj",path);
  68. Intent intent=new Intent(MainActivity.this,Sp.class);
  69. intent.putExtras(bundle);
  70. startActivity(intent);
  71. });
  72. //-----------按键监听,实现输入文件序号单个播放---------------------------------------------------------------
  73. editText.setOnKeyListener(new View.OnKeyListener() { //正对输入框editText的按键监听
  74. @Override
  75. public boolean onKey(View v, int keyCode, KeyEvent event) {
  76. if(event.getAction() == KeyEvent.ACTION_DOWN) {
  77. switch (keyCode) {
  78. case KeyEvent.KEYCODE_ENTER: //监控 按下回车键
  79. String in= editText.getText().toString();
  80. int index=Integer.valueOf(in);
  81. String path= map.get(index);
  82. bundle.putString("lj",path);
  83. Intent intent=new Intent(MainActivity.this,Sp.class);
  84. intent.putExtras(bundle);
  85. startActivity(intent);
  86. return true;
  87. }
  88. }
  89. return false;
  90. }
  91. });
  92. }
  93. }

子窗口代码不变

使用发现,利用新线程监控播放线程不稳定

改进后的顺序音乐播放

  1. package com.example.test1;
  2. import androidx.annotation.NonNull;
  3. import androidx.appcompat.app.AppCompatActivity;
  4. import android.annotation.SuppressLint;
  5. import android.content.AsyncQueryHandler;
  6. import android.content.ContentResolver;
  7. import android.database.Cursor;
  8. import android.media.AudioManager;
  9. import android.media.MediaPlayer;
  10. import android.net.Uri;
  11. import android.os.Bundle;
  12. import android.os.Handler;
  13. import android.os.Looper;
  14. import android.os.Message;
  15. import android.provider.MediaStore;
  16. import android.view.View;
  17. import android.widget.Button;
  18. import android.widget.EditText;
  19. import android.widget.TextView;
  20. import java.io.IOException;
  21. import java.util.ArrayList;
  22. public class Yy extends AppCompatActivity {
  23. TextView textView;
  24. TextView textView1;
  25. EditText editText;
  26. Button button1;
  27. Button button2;
  28. Button button3;
  29. Button button4;
  30. int n = 0;
  31. int is = 0;
  32. ArrayList<String> al = new ArrayList<>();
  33. MediaPlayer mediaPlayer = new MediaPlayer();
  34. @SuppressLint({"MissingInflatedId", "Range"})
  35. @Override
  36. protected void onCreate(Bundle savedInstanceState) {
  37. super.onCreate(savedInstanceState);
  38. setContentView(R.layout.activity_yy);
  39. textView = findViewById(R.id.textView2);
  40. textView1 = findViewById(R.id.textView3);
  41. textView1.setTextSize(24);
  42. editText = findViewById(R.id.editTextText);
  43. editText.setText("");
  44. button1 = findViewById(R.id.button6);
  45. button1.setText("顺序播放");
  46. button2 = findViewById(R.id.button7);
  47. button2.setText("停止选播");
  48. button3 = findViewById(R.id.button8);
  49. button3.setText("进一首");
  50. button4 = findViewById(R.id.button9);
  51. button4.setText("退一首");
  52. ContentResolver contentResolver = getContentResolver();
  53. Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
  54. Cursor cursor = contentResolver.query(uri, new String[]{"_data"}, null, null, null, null);
  55. String o = null;
  56. while (cursor.moveToNext()) {
  57. @SuppressLint("Range")
  58. String s = cursor.getString(cursor.getColumnIndex("_data"));
  59. al.add(s);
  60. o = o + s + " ";
  61. }
  62. textView.setText(o);
  63. textView1.setText("音乐序号"+String.valueOf(cursor.getCount()));
  64. //------顺序全部播放--------------------------------------------------------
  65. button1.setOnClickListener(new View.OnClickListener() {
  66. @Override
  67. public void onClick(View view) {
  68. Handler.Callback hc = new Handler.Callback() {
  69. @Override
  70. public boolean handleMessage(@NonNull Message message) {
  71. int t=message.arg1;
  72. textView1.setText("音乐序号:"+String.valueOf(t));
  73. mediaPlayer = new MediaPlayer();
  74. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  75. try {
  76. mediaPlayer.setDataSource(al.get(t));
  77. mediaPlayer.prepareAsync(); //这句必须放在setDataSource的后面,否则报错
  78. } catch (IOException e) {
  79. throw new RuntimeException(e);
  80. }
  81. mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  82. @Override
  83. public void onPrepared(MediaPlayer mediaPlayer) {
  84. mediaPlayer.start();
  85. }
  86. });
  87. return false;
  88. }
  89. };
  90. Handler handler=new Handler(Looper.getMainLooper(),hc);
  91. new Thread(()->{
  92. Message message = new Message();
  93. message.arg1 = n;
  94. handler.sendMessage(message);
  95. while(true){
  96. if(mediaPlayer!=null) {
  97. mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
  98. @Override
  99. public void onCompletion(MediaPlayer mediaPlayer) {
  100. n++;
  101. Message message = new Message();
  102. message.arg1 = n;
  103. handler.sendMessage(message);
  104. }
  105. });
  106. }
  107. }
  108. }).start();
  109. }
  110. });
  111. //---------暂停音乐播放,并选播,填如要开始播放的序号------------------------
  112. button2.setOnClickListener(view -> {
  113. if(mediaPlayer.isPlaying()){
  114. mediaPlayer.release();
  115. }
  116. String in=editText.getText().toString();
  117. n=Integer.valueOf(in);
  118. });
  119. //----------进一首开始顺序播放---------------------------------------------
  120. button3.setOnClickListener(view -> {
  121. if(mediaPlayer.isPlaying()){
  122. mediaPlayer.release();
  123. }
  124. Handler.Callback hc = new Handler.Callback() {
  125. @Override
  126. public boolean handleMessage(@NonNull Message message) {
  127. int t=message.arg1;
  128. textView1.setText("音乐序号:"+String.valueOf(t));
  129. mediaPlayer = new MediaPlayer();
  130. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  131. try {
  132. mediaPlayer.setDataSource(al.get(t));
  133. mediaPlayer.prepareAsync(); //这句必须放在setDataSource的后面,否则报错
  134. } catch (IOException e) {
  135. throw new RuntimeException(e);
  136. }
  137. mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  138. @Override
  139. public void onPrepared(MediaPlayer mediaPlayer) {
  140. mediaPlayer.start();
  141. }
  142. });
  143. return false;
  144. }
  145. };
  146. Handler handler=new Handler(Looper.getMainLooper(),hc);
  147. new Thread(()->{
  148. n=n+1;
  149. Message message = new Message();
  150. message.arg1 = n;
  151. handler.sendMessage(message);
  152. while(true){
  153. if(mediaPlayer!=null) {
  154. mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
  155. @Override
  156. public void onCompletion(MediaPlayer mediaPlayer) {
  157. n++;
  158. Message message = new Message();
  159. message.arg1 = n;
  160. handler.sendMessage(message);
  161. n++;
  162. }
  163. });
  164. }
  165. }
  166. }).start();
  167. });
  168. //-----------退一首开始顺序播放--------------------------------------------------
  169. button4.setOnClickListener(view -> {
  170. if(mediaPlayer.isPlaying()){
  171. mediaPlayer.release();
  172. }
  173. Handler.Callback hc = new Handler.Callback() {
  174. @Override
  175. public boolean handleMessage(@NonNull Message message) {
  176. int t=message.arg1;
  177. textView1.setText("音乐序号:"+String.valueOf(t));
  178. mediaPlayer = new MediaPlayer();
  179. mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
  180. try {
  181. mediaPlayer.setDataSource(al.get(t));
  182. mediaPlayer.prepareAsync(); //这句必须放在setDataSource的后面,否则报错
  183. } catch (IOException e) {
  184. throw new RuntimeException(e);
  185. }
  186. mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  187. @Override
  188. public void onPrepared(MediaPlayer mediaPlayer) {
  189. mediaPlayer.start();
  190. }
  191. });
  192. return false;
  193. }
  194. };
  195. Handler handler=new Handler(Looper.getMainLooper(),hc);
  196. new Thread(()->{
  197. n=n-1;
  198. Message message = new Message();
  199. message.arg1 = n;
  200. handler.sendMessage(message);
  201. while(true){
  202. if(mediaPlayer!=null) {
  203. mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
  204. @Override
  205. public void onCompletion(MediaPlayer mediaPlayer) {
  206. n++;
  207. Message message = new Message();
  208. message.arg1 = n;
  209. handler.sendMessage(message);
  210. n++;
  211. }
  212. });
  213. }
  214. }
  215. }).start();
  216. });
  217. //-=====================================================================================
  218. }
  219. @Override
  220. public void onBackPressed () {
  221. super.onBackPressed();
  222. mediaPlayer.release();
  223. mediaPlayer = null;
  224. }
  225. }

android 按键事件响应

返回键响应
  1. //-------------------返回关闭视频---------------------------------------
  2. public void onBackPressed() { //监听返回键,如返回则关闭视频
  3. super.onBackPressed();
  4. mediaPlayer.release();
  5. }

文本输入框的按键响应

  1. editText.setOnKeyListener(new View.OnKeyListener() { //针对文本输入框的按键事件
  2. @Override
  3. public boolean onKey(View view, int i, KeyEvent keyEvent) {
  4. if(keyEvent.getAction()==KeyEvent.ACTION_DOWN){ //当按键按下
  5. if(i==KeyEvent.KEYCODE_ENTER){ //当键值为回车键
  6. textView.setText("ok");
  7. }
  8. }
  9. return false;
  10. }
  11. });

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/930846
推荐阅读
相关标签
  

闽ICP备14008679号