Android 新API 之 MediaCodec使用笔记 一

2024-02-05 10:18

本文主要是介绍Android 新API 之 MediaCodec使用笔记 一,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://blog.csdn.net/shawnkong/article/details/16337381


Android的视频编解码一直让人有点纠结,SDK竟然不提供硬件编解码的API,如果你想自己做,只能通过JNI借助第三方编解码器,其都是使用的软解码,效率很难保证,这对想做视频通话的是一个不小的打击。

好了,说到google 新提供的SDK中出现的类MediaCodec,这个api限制在API 16后,也就是Android 4.1.2后才可以使用,如果你的系统低于这个版本,是不可以使用这个类的。MediaCodec这家伙能提供给你硬件编解码功能,当然得厂商支持在下层已经,如果厂商没做好,系统会提供给你软件编解码器,反正不用你操心,可以直接就拿来用的。

使用网上有人提供的Demo,可以解码mp4文件,具体情况还没研究,先放出Github链接,直接自己抓出来就可以用,

如果懒得去抓,下面贴出代码,就一个简单的Activity,一切搞定,

“记得修改文件名,SAMPLE变量为你自己的文件名称”,

[java]  view plain copy
在CODE上查看代码片 派生到我的代码片
  1. package io.vec.demo.mediacodec;  
  2.   
  3. import java.nio.ByteBuffer;  
  4.   
  5. import android.app.Activity;  
  6. import android.media.MediaCodec;  
  7. import android.media.MediaCodec.BufferInfo;  
  8. import android.media.MediaExtractor;  
  9. import android.media.MediaFormat;  
  10. import android.os.Bundle;  
  11. import android.os.Environment;  
  12. import android.util.Log;  
  13. import android.view.Surface;  
  14. import android.view.SurfaceHolder;  
  15. import android.view.SurfaceView;  
  16.   
  17. public class DecodeActivity extends Activity implements SurfaceHolder.Callback {  
  18.     private static final String SAMPLE = Environment.getExternalStorageDirectory() + "/video.mp4";  
  19.     private PlayerThread mPlayer = null;  
  20.   
  21.     @Override  
  22.     protected void onCreate(Bundle savedInstanceState) {  
  23.         super.onCreate(savedInstanceState);  
  24.         SurfaceView sv = new SurfaceView(this);  
  25.         sv.getHolder().addCallback(this);  
  26.         setContentView(sv);  
  27.     }  
  28.   
  29.     protected void onDestroy() {  
  30.         super.onDestroy();  
  31.     }  
  32.   
  33.     @Override  
  34.     public void surfaceCreated(SurfaceHolder holder) {  
  35.     }  
  36.   
  37.     @Override  
  38.     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {  
  39.         if (mPlayer == null) {  
  40.             mPlayer = new PlayerThread(holder.getSurface());  
  41.             mPlayer.start();  
  42.         }  
  43.     }  
  44.   
  45.     @Override  
  46.     public void surfaceDestroyed(SurfaceHolder holder) {  
  47.         if (mPlayer != null) {  
  48.             mPlayer.interrupt();  
  49.         }  
  50.     }  
  51.   
  52.     private class PlayerThread extends Thread {  
  53.         private MediaExtractor extractor;  
  54.         private MediaCodec decoder;  
  55.         private Surface surface;  
  56.   
  57.         public PlayerThread(Surface surface) {  
  58.             this.surface = surface;  
  59.         }  
  60.   
  61.         @Override  
  62.         public void run() {  
  63.             extractor = new MediaExtractor();  
  64.             extractor.setDataSource(SAMPLE);  
  65.   
  66.             for (int i = 0; i < extractor.getTrackCount(); i++) {  
  67.                 MediaFormat format = extractor.getTrackFormat(i);  
  68.                 String mime = format.getString(MediaFormat.KEY_MIME);  
  69.                 if (mime.startsWith("video/")) {  
  70.                     extractor.selectTrack(i);  
  71.                     decoder = MediaCodec.createDecoderByType(mime);  
  72.                     decoder.configure(format, surface, null0);  
  73.                     break;  
  74.                 }  
  75.             }  
  76.   
  77.             if (decoder == null) {  
  78.                 Log.e("DecodeActivity""Can't find video info!");  
  79.                 return;  
  80.             }  
  81.   
  82.             decoder.start();  
  83.   
  84.             ByteBuffer[] inputBuffers = decoder.getInputBuffers();  
  85.             ByteBuffer[] outputBuffers = decoder.getOutputBuffers();  
  86.             BufferInfo info = new BufferInfo();  
  87.             boolean isEOS = false;  
  88.             long startMs = System.currentTimeMillis();  
  89.   
  90.             while (!Thread.interrupted()) {  
  91.                 if (!isEOS) {  
  92.                     int inIndex = decoder.dequeueInputBuffer(10000);  
  93.                     if (inIndex >= 0) {  
  94.                         ByteBuffer buffer = inputBuffers[inIndex];  
  95.                         int sampleSize = extractor.readSampleData(buffer, 0);  
  96.                         if (sampleSize < 0) {  
  97.                             // We shouldn't stop the playback at this point, just pass the EOS  
  98.                             // flag to decoder, we will get it again from the  
  99.                             // dequeueOutputBuffer  
  100.                             Log.d("DecodeActivity""InputBuffer BUFFER_FLAG_END_OF_STREAM");  
  101.                             decoder.queueInputBuffer(inIndex, 000, MediaCodec.BUFFER_FLAG_END_OF_STREAM);  
  102.                             isEOS = true;  
  103.                         } else {  
  104.                             decoder.queueInputBuffer(inIndex, 0, sampleSize, extractor.getSampleTime(), 0);  
  105.                             extractor.advance();  
  106.                         }  
  107.                     }  
  108.                 }  
  109.   
  110.                 int outIndex = decoder.dequeueOutputBuffer(info, 10000);  
  111.                 switch (outIndex) {  
  112.                 case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:  
  113.                     Log.d("DecodeActivity""INFO_OUTPUT_BUFFERS_CHANGED");  
  114.                     outputBuffers = decoder.getOutputBuffers();  
  115.                     break;  
  116.                 case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:  
  117.                     Log.d("DecodeActivity""New format " + decoder.getOutputFormat());  
  118.                     break;  
  119.                 case MediaCodec.INFO_TRY_AGAIN_LATER:  
  120.                     Log.d("DecodeActivity""dequeueOutputBuffer timed out!");  
  121.                     break;  
  122.                 default:  
  123.                     ByteBuffer buffer = outputBuffers[outIndex];  
  124.                     Log.v("DecodeActivity""We can't use this buffer but render it due to the API limit, " + buffer);  
  125.   
  126.                     // We use a very simple clock to keep the video FPS, or the video  
  127.                     // playback will be too fast  
  128.                     while (info.presentationTimeUs / 1000 > System.currentTimeMillis() - startMs) {  
  129.                         try {  
  130.                             sleep(10);  
  131.                         } catch (InterruptedException e) {  
  132.                             e.printStackTrace();  
  133.                             break;  
  134.                         }  
  135.                     }  
  136.                     decoder.releaseOutputBuffer(outIndex, true);  
  137.                     break;  
  138.                 }  
  139.   
  140.                 // All decoded frames have been rendered, we can stop playing now  
  141.                 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {  
  142.                     Log.d("DecodeActivity""OutputBuffer BUFFER_FLAG_END_OF_STREAM");  
  143.                     break;  
  144.                 }  
  145.             }  
  146.   
  147.             decoder.stop();  
  148.             decoder.release();  
  149.             extractor.release();  
  150.         }  
  151.     }  
  152. }  

最後再奉上我修改過的代碼,增加了選擇文件的功能.

http://download.csdn.net/detail/shawnkong/6555857



最近从事手机iOS/Android直播、视频实时美颜方面的工作。

欢迎加群交流:496010189

4
0
我的同类文章
  • c++中局部变量未初始化引发的离奇惨案~~2014-09-09
  • Ubuntu 14.04 Linux系统安装Subversion结合Eclipse的一些问题2014-04-22
  • Android NDK 开发进阶之 mk文件写法2014-01-13
  • Android 不能生产 R.java2013-11-27
  • Android Studio配置2013-10-30
  • Android NDK开发之配置 adb-bundle、eclipse 支持C/C++ 语言的JNI开发2014-05-27
  • Linphone 杂记2014-02-10
  • 编译x264 出现No working C compiler found.2013-12-23
  • Ubuntu android 开发环境搭建之eclipse篇2013-11-12
  • 关于64位 Ubuntu 13.04 安装Android Studio的一些问题及ADB驱动配置2013-10-30
更多文章

参考知识库

img
iOS知识库

img
Android知识库

img
.NET知识库

img
Java SE知识库

img
Java EE知识库

img
Java 知识库

img
Swift知识库

猜你在找
FFmpeg音视频高级开发实战 iOS&Android;
Android 5.x顶级视频课程
Android SQLite 性能优化——显示使用事务
Android底层技术:HAL驱动开发
Android基础视频教程
查看评论
15楼  IT_Transformers 2016-10-19 18:14发表 [回复]
你好,我解码以后从哪个地方可以得到每一帧的数据呢?
14楼  邪恶的鱼蛋 2016-06-27 09:14发表 [回复]
您好,我想请问一下MediaCodec 如何暂停解码,就是我点暂停,他就停留在这里,点击继续他就继续开始解码
Re:  Shawn4com 2016-07-25 18:15发表 [回复]
回复邪恶的鱼蛋:把解码线程挂起,这样解码就不会继续了
13楼  ai454121 2015-11-10 20:26发表 [回复]
LZ,您好,我发现decoder.configure(format, surface, null, 0); 中如果surface设置为null,那解码速度会比现在慢很多,这边测试差不多慢2倍,这个可能是什么原因引起的,如果不配置surface,有什么办法改进吗?
Re:  Shawn4com 2016-07-25 18:21发表 [回复]
回复ai454121:不设置surface会解码变慢么?你是从哪里看出来解码变慢了么?检查一下sleep那个地方,看是不是调用次数增多了
12楼  he_wen_jian 2015-03-05 13:13发表 [回复]
请问如何播放网络视频?
Re:  Shawn4com 2016-07-25 18:16发表 [回复]
回复he_wen_jian:这个只是简单演示解码video,如果需要播放网络视频,你还需要有接收、音频解码播放功能
11楼  amsh10421 2014-09-15 17:46发表 [回复]
extractor = new MediaExtractor(); 
extractor.setDataSource(SAMPLE); 
for (int i = 0; i < extractor.getTrackCount(); i++) 


extractor.getTrackCount(); 返回值是0 请问这个怎么修改?是我的文件没读进去么?
Re:  Shawn4com 2014-09-16 11:06发表 [回复]
回复amsh10421: 加文件读写权限了么?
10楼  sanbo_xyz 2014-06-19 18:51发表 [回复]
上传的不对。。。
Re:  Shawn4com 2014-06-20 14:54发表 [回复]
回复sanbo_xyz:什么不对?
Re:  sanbo_xyz 2014-06-23 11:21发表 [回复]
回复Shawn4com:不能正常使用。
Re:  Shawn4com 2014-06-23 16:09发表 [回复]
回复sanbo_xyz:有什么问题,能说的具体点么?我这里跑的好好的。。
9楼  newplumage 2014-04-03 15:54发表 [回复]
感谢这个例子,我能正常运行了。有两个问题
1.音频需另外解码,怎么处理?
2.视频和音频怎么同步?
请指教!!
Re:  Shawn4com 2014-04-15 10:18发表 [回复]
回复newplumage:sorry,我暂时只用来解码视频,没有测试音频,因为现在我主要不是用来做播放器。同步的话使用时间戳。
8楼  yqymmzby 2014-04-01 13:45发表 [回复]
请问音频使用MediaPlayer同步解吗?还是什么?
7楼  yubestming_job 2014-03-20 10:51发表 [回复]
你好,我想问下,我做的实时视频通话,c++那边给我传递过来的是一个Byte[]的字节数组,我怎么显示出来,在android端,求指教。QQ512573717
Re:  Shawn4com 2014-03-21 11:01发表 [回复]
回复yubestming_job: 实时流好像不支持的,我试过,没弄出来,要不你试试,如果成功了,回头跟出来?
6楼  xhcw1011 2014-02-19 09:17发表 [回复]
你好,请问我想解实时的h264的流该怎么解,我现在按照网上一些例子做出来了,但是效果很差,很模糊。基本看不到东西。
Re:  chenqingfei 2014-10-11 09:05发表 [回复]
回复xhcw1011:同感,我也是在网上搜集了一些信息,写出来的,效果比较差,
如果是非高清的,流畅度还能保证,如果是高清的,网络根本就支撑不了,而且我还做了分包,如果不分包,高清的一帧数据UDP都发不过去。这个问题真的很棘手啊。不知道微信是怎么做的。
Re:  紫枫wrongs 2014-02-28 14:36发表 [回复]
回复xhcw1011:你好,对于实时的视频,在接收端,如何解析解包呢,是不是需要将包组起来,然后解码, 请问下你解码是使用的啥方式,求助!!!
Re:  紫枫wrongs 2014-02-19 14:16发表 [回复]
回复xhcw1011:你好,请问你对h264如何进行解码的呢,我使用的是.264文件解码,可在extractor.setDataSource(fileString); 一直报异常呢
Re:  xhcw1011 2014-02-19 14:33发表 [回复]
回复紫枫wrongs:你先看下是报什么错。
Re:  紫枫wrongs 2014-02-20 10:35发表 [回复]
回复xhcw1011:播放H264错误是我的文件有问题,现在换了文件解决了,对于实时流的接收端,你是使用RTP 接收的吗 可以给个Demo参考下吗
5楼  紫枫wrongs 2014-02-17 16:48发表 [回复]
你好,下载的demo,怎么在extractor.setDataSource(SAMPLE);
一直报错呢,是不是不能支持.h264吗 ?
Re:  Shawn4com 2014-02-17 22:21发表 [回复]
回复紫枫wrongs:SAMPLE 要制定一个文件。。
Re:  紫枫wrongs 2014-02-18 10:03发表 [回复]
回复Shawn4com:sample 这个路径下的文件,是我自己编码的,使用h264的播放器都可以播放的,
Re:  Shawn4com 2014-04-14 14:43发表 [回复]
回复紫枫wrongs:sdk里面的extractor只支持mp4,avi和mkv格式的,h264的裸码解析不了的
4楼  紫枫wrongs 2014-02-13 16:48发表 [回复]
下载csdn的实例,extractor = new MediaExtractor();
extractor.setDataSource(SAMPLE);
执行到这的时候一直报错,求指点啊,
3楼  zuchgi 2014-02-11 00:46发表 [回复]
String SAMPLE = Environment.getExternalStorageDirectory() + "/encoder.h264";
extractor.setDataSource(SAMPLE);

运行到这里的时候显示找不到extractor,请问楼主要如何处理?
Re:  Shawn4com 2014-02-25 12:14发表 [回复]
回复zuchgi:贴错误信息看下。
2楼  chen7yang 2014-01-08 15:03发表 [回复] [引用] [举报]
求助:
我的代码 执行到这句时
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo,0);

就会抛 IllegalStateException ,
Re:  Shawn4com 2014-01-09 16:17发表 [回复] [引用] [举报]
回复chen7yang:据说这个api还不稳定,实际使用可能有问题。。
1楼  temofil2009 2013-12-24 11:17发表 [回复]
这样的话送到surface播出来的视频是没有audio的吧?
Re:  Shawn4com 2013-12-25 10:40发表 [回复]
回复temofil2009:是的,这个只是单解视频,音频需另外解码。。























另外一篇文章的代码,也可以看看:

代码片段(1)[全屏查看所有代码]

1. [代码][Java]代码     

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
private final String TAG = "MediaCodeSample" ;
     /** 用来解码 */
     private MediaCodec mMediaCodec;
     /** 用来读取音频文件 */
     private MediaExtractor extractor;
     private MediaFormat format;
     private String mime = null ;
     private int sampleRate = 0 , channels = 0 , bitrate = 0 ;
     private long presentationTimeUs = 0 , duration = 0 ;
     public void decode(String url)
     {
         extractor = new MediaExtractor();
         // 根据路径获取源文件
         try
         {
             extractor.setDataSource(url);
         } catch (Exception e)
         {
             Log.e(TAG, " 设置文件路径错误" + e.getMessage());
         }
         try
         {
             // 音频文件信息
             format = extractor.getTrackFormat( 0 );
             mime = format.getString(MediaFormat.KEY_MIME);
             sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
             // 声道个数:单声道或双声道
             channels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
             // if duration is 0, we are probably playing a live stream
             duration = format.getLong(MediaFormat.KEY_DURATION);
             // System.out.println("歌曲总时间秒:"+duration/1000000);
             bitrate = format.getInteger(MediaFormat.KEY_BIT_RATE);
         } catch (Exception e)
         {
             Log.e(TAG, "音频文件信息读取出错:" + e.getMessage());
             // 不要退出,下面进行判断
         }
         Log.d(TAG, "Track info: mime:" + mime + " 采样率sampleRate:" + sampleRate + " channels:" + channels + " bitrate:"
                 + bitrate + " duration:" + duration);
         // 检查是否为音频文件
         if (format == null || !mime.startsWith( "audio/" ))
         {
             Log.e(TAG, "不是音频文件 end !" );
             return ;
         }
         // 实例化一个指定类型的解码器,提供数据输出
         // Instantiate an encoder supporting output data of the given mime type
         mMediaCodec = MediaCodec.createDecoderByType(mime);
         if (mMediaCodec == null )
         {
             Log.e(TAG, "创建解码器失败!" );
             return ;
         }
         mMediaCodec.configure(format, null , null , 0 );
         mMediaCodec.start();
         // 用来存放目标文件的数据
         ByteBuffer[] inputBuffers = mMediaCodec.getInputBuffers();
         // 解码后的数据
         ByteBuffer[] outputBuffers = mMediaCodec.getOutputBuffers();
         // 设置声道类型:AudioFormat.CHANNEL_OUT_MONO单声道,AudioFormat.CHANNEL_OUT_STEREO双声道
         int channelConfiguration = channels == 1 ? AudioFormat.CHANNEL_OUT_MONO : AudioFormat.CHANNEL_OUT_STEREO;
         Log.i(TAG, "channelConfiguration=" + channelConfiguration);
         extractor.selectTrack( 0 );
         // ==========开始解码=============
         boolean sawInputEOS = false ;
         boolean sawOutputEOS = false ;
         final long kTimeOutUs = 10 ;
         MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
         while (!sawOutputEOS)
         {
             try
             {
                 if (!sawInputEOS)
                 {
                     int inputBufIndex = mMediaCodec.dequeueInputBuffer(kTimeOutUs);
                     if (inputBufIndex >= 0 )
                     {
                         ByteBuffer dstBuf = inputBuffers[inputBufIndex];
                         int sampleSize = extractor.readSampleData(dstBuf, 0 );
                         if (sampleSize < 0 )
                         {
                             Log.d(TAG, "saw input EOS. Stopping playback" );
                             sawInputEOS = true ;
                             sampleSize = 0 ;
                         } else
                         {
                             presentationTimeUs = extractor.getSampleTime();
                         }
                         mMediaCodec.queueInputBuffer(inputBufIndex, 0 , sampleSize, presentationTimeUs,
                                 sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0 );
                         if (!sawInputEOS)
                         {
                             extractor.advance();
                         }
                     } else
                     {
                         Log.e(TAG, "inputBufIndex " + inputBufIndex);
                     }
                 } // !sawInputEOS
                 // decode to PCM and push it to the AudioTrack player
                 int res = mMediaCodec.dequeueOutputBuffer(info, kTimeOutUs);
                 if (res >= 0 )
                 {
                     int outputBufIndex = res;
                     ByteBuffer buf = outputBuffers[outputBufIndex];
                     final byte [] chunk = new byte [info.size];
                     buf.get(chunk);
                     buf.clear();
                     if (chunk.length > 0 )
                     {
                         // chunk解码后的音频流
                         // TODO:处理...
                     }
                     mMediaCodec.releaseOutputBuffer(outputBufIndex, false );
                     if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0 )
                     {
                         Log.d(TAG, "saw output EOS." );
                         sawOutputEOS = true ;
                     }
                 } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
                 {
                     outputBuffers = mMediaCodec.getOutputBuffers();
                     Log.w(TAG, "[AudioDecoder]output buffers have changed." );
                 } else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)
                 {
                     MediaFormat oformat = mMediaCodec.getOutputFormat();
                     Log.w(TAG, "[AudioDecoder]output format has changed to " + oformat);
                 } else
                 {
                     Log.w(TAG, "[AudioDecoder] dequeueOutputBuffer returned " + res);
                 }
             } catch (RuntimeException e)
             {
                 Log.e(TAG, "[decodeMP3] error:" + e.getMessage());
             }
         }
         // =================================================================================
         if (mMediaCodec != null )
         {
             mMediaCodec.stop();
             mMediaCodec.release();
             mMediaCodec = null ;
         }
         if (extractor != null )
         {
             extractor.release();
             extractor = null ;
         }
         // clear source and the other globals
         duration = 0 ;
         mime = null ;
         sampleRate = 0 ;
         channels = 0 ;
         bitrate = 0 ;
         presentationTimeUs = 0 ;
         duration = 0 ;
     }




这篇关于Android 新API 之 MediaCodec使用笔记 一的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/680594

相关文章

从零教你安装pytorch并在pycharm中使用

《从零教你安装pytorch并在pycharm中使用》本文详细介绍了如何使用Anaconda包管理工具创建虚拟环境,并安装CUDA加速平台和PyTorch库,同时在PyCharm中配置和使用PyTor... 目录背景介绍安装Anaconda安装CUDA安装pytorch报错解决——fbgemm.dll连接p

Vue项目的甘特图组件之dhtmlx-gantt使用教程和实现效果展示(推荐)

《Vue项目的甘特图组件之dhtmlx-gantt使用教程和实现效果展示(推荐)》文章介绍了如何使用dhtmlx-gantt组件来实现公司的甘特图需求,并提供了一个简单的Vue组件示例,文章还分享了一... 目录一、首先 npm 安装插件二、创建一个vue组件三、业务页面内 引用自定义组件:四、dhtmlx

使用Python创建一个能够筛选文件的PDF合并工具

《使用Python创建一个能够筛选文件的PDF合并工具》这篇文章主要为大家详细介绍了如何使用Python创建一个能够筛选文件的PDF合并工具,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录背景主要功能全部代码代码解析1. 初始化 wx.Frame 窗口2. 创建工具栏3. 创建布局和界面控件4

一文详解如何在Python中使用Requests库

《一文详解如何在Python中使用Requests库》:本文主要介绍如何在Python中使用Requests库的相关资料,Requests库是Python中常用的第三方库,用于简化HTTP请求的发... 目录前言1. 安装Requests库2. 发起GET请求3. 发送带有查询参数的GET请求4. 发起PO

Java中的Cursor使用详解

《Java中的Cursor使用详解》本文介绍了Java中的Cursor接口及其在大数据集处理中的优势,包括逐行读取、分页处理、流控制、动态改变查询、并发控制和减少网络流量等,感兴趣的朋友一起看看吧... 最近看代码,有一段代码涉及到Cursor,感觉写法挺有意思的。注意是Cursor,而不是Consumer

Node.js net模块的使用示例

《Node.jsnet模块的使用示例》本文主要介绍了Node.jsnet模块的使用示例,net模块支持TCP通信,处理TCP连接和数据传输,具有一定的参考价值,感兴趣的可以了解一下... 目录简介引入 net 模块核心概念TCP (传输控制协议)Socket服务器TCP 服务器创建基本服务器服务器配置选项服

Android开发中gradle下载缓慢的问题级解决方法

《Android开发中gradle下载缓慢的问题级解决方法》本文介绍了解决Android开发中Gradle下载缓慢问题的几种方法,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、网络环境优化二、Gradle版本与配置优化三、其他优化措施针对android开发中Gradle下载缓慢的问

如何使用CSS3实现波浪式图片墙

《如何使用CSS3实现波浪式图片墙》:本文主要介绍了如何使用CSS3的transform属性和动画技巧实现波浪式图片墙,通过设置图片的垂直偏移量,并使用动画使其周期性地改变位置,可以创建出动态且具有波浪效果的图片墙,同时,还强调了响应式设计的重要性,以确保图片墙在不同设备上都能良好显示,详细内容请阅读本文,希望能对你有所帮助...

Rust中的注释使用解读

《Rust中的注释使用解读》本文介绍了Rust中的行注释、块注释和文档注释的使用方法,通过示例展示了如何在实际代码中应用这些注释,以提高代码的可读性和可维护性... 目录Rust 中的注释使用指南1. 行注释示例:行注释2. 块注释示例:块注释3. 文档注释示例:文档注释4. 综合示例总结Rust 中的注释

Linux使用cut进行文本提取的操作方法

《Linux使用cut进行文本提取的操作方法》Linux中的cut命令是一个命令行实用程序,用于从文件或标准输入中提取文本行的部分,本文给大家介绍了Linux使用cut进行文本提取的操作方法,文中有详... 目录简介基础语法常用选项范围选择示例用法-f:字段选择-d:分隔符-c:字符选择-b:字节选择--c