- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试用 Kotlin 编写一个 CallRecorder 应用程序。我想要做的是开始使用 BroadcastReceiver 启动的服务录制音频。我认为我在 MediaRecorder 初始化方面做错了什么,但我不知道是什么。
编辑:找到并解决了 MediaRecorder 问题(将文件名从“dd.MMM.yyyy-HH:mm:ss”更改为“dd.MMM.yyyy”。Android 不喜欢文件名中的冒号)。现在它给了我一个关于 IntentService 的“致命异常(exception)”。查看下面更新的堆栈跟踪。
list :
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<service android:name=".RecordService"
android:exported="false"/>
<receiver android:name=".CallReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter>
</receiver>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
主要 Activity :
class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener, ActivityCompat.OnRequestPermissionsResultCallback {
private val READ_PHONE_STATE : String = Manifest.permission.READ_PHONE_STATE
private val RECORD_AUDIO : String = Manifest.permission.RECORD_AUDIO
private val WRITE_EXTERNAL_STORAGE : String = Manifest.permission.WRITE_EXTERNAL_STORAGE
private val PERMISSION_LIST = arrayOf(READ_PHONE_STATE, RECORD_AUDIO, WRITE_EXTERNAL_STORAGE)
private val REQUEST_CODE : Int = 101
private val PERMISSION_GRANTED : Int = PackageManager.PERMISSION_GRANTED
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
/*fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}*/
checkPermissions()
val toggle = ActionBarDrawerToggle(
this, drawer_layout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
drawer_layout.addDrawerListener(toggle)
toggle.syncState()
nav_view.setNavigationItemSelectedListener(this)
}
fun checkPermissions(){
var tempPermissionList : Array<String?> = arrayOfNulls(3)
var position : Int = 0
for(permission in PERMISSION_LIST){
if(ContextCompat.checkSelfPermission(this, permission) != PERMISSION_GRANTED) tempPermissionList.set(position, permission)
position++
}
if(!tempPermissionList.isEmpty()){
ActivityCompat.requestPermissions(this, tempPermissionList, REQUEST_CODE)
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
if(requestCode == REQUEST_CODE) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
override fun onBackPressed() {
if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START)
} else {
super.onBackPressed()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
when (item.itemId) {
R.id.action_settings -> return true
else -> return super.onOptionsItemSelected(item)
}
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
// Handle navigation view item clicks here.
when (item.itemId) {
R.id.nav_camera -> {
// Handle the camera action
}
R.id.nav_gallery -> {
}
R.id.nav_slideshow -> {
}
R.id.nav_manage -> {
}
R.id.nav_share -> {
}
R.id.nav_send -> {
}
}
drawer_layout.closeDrawer(GravityCompat.START)
return true
}
记录器:
class Recorder {
val TAG : String = "RECORDER"
var mediaRecorder : MediaRecorder? = null
fun startRecording(){
if(mediaRecorder != null){
mediaRecorder!!.stop()
mediaRecorder!!.reset()
mediaRecorder!!.release()
mediaRecorder = null
}
mediaRecorder = MediaRecorder()
mediaRecorder!!.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL)
mediaRecorder!!.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
mediaRecorder!!.setOutputFile(generateFilePath())
mediaRecorder!!.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_WB)
try {
mediaRecorder!!.prepare()
} catch (e:Exception){
Log.e(TAG, "prepare() failed")
}
mediaRecorder!!.start()
}
fun stopRecording(){
if(mediaRecorder != null){
mediaRecorder!!.stop()
mediaRecorder!!.release()
mediaRecorder = null
}
}
private fun getCurrentDate() : String{
val calendar = java.util.Calendar.getInstance()
val dateFormat = SimpleDateFormat("dd.MMM.yyyy")
val date : String = dateFormat.format(calendar.time)
return date
}
private fun generateFilePath() : String{
return Environment.getExternalStorageDirectory().absolutePath + "/" + getCurrentDate() + ".3gp"
}
调用接收者:
class CallReceiver : BroadcastReceiver() {
private val TAG = "CALL_RECEIVER"
private val PHONE_STATE : String = "PHONE_STATE"
private val START_RECORDING : String = "START_RECORDING"
private val STOP_RECORDING : String = "STOP_RECORDING"
//private lateinit var mRecorder : Recorder
override fun onReceive(context: Context?, intent: Intent?) {
val phoneState : String? = intent?.getStringExtra(TelephonyManager.EXTRA_STATE)
if(phoneState.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
Toast.makeText(context, "REGISTRAZIONE INIZIATA", Toast.LENGTH_SHORT).show()
Log.d(TAG, "START RECORDING")
var intent2 = Intent(context, RecordService::class.java)
intent2.putExtra(PHONE_STATE, START_RECORDING)
context?.startService(intent2)
//if(mRecorder == null) mRecorder = Recorder()
//mRecorder.startRecording()
} else if (phoneState.equals(TelephonyManager.EXTRA_STATE_IDLE)){
Toast.makeText(context, "REGISTRAZIONE TERMINATA", Toast.LENGTH_SHORT).show()
Log.d(TAG, "STOP RECORDING")
var intent3 = Intent(context, RecordService::class.java)
intent3.putExtra(PHONE_STATE, STOP_RECORDING)
context?.startService(intent3)
//mRecorder.stopRecording()
}
}
记录服务:
class RecordService : IntentService("RecordService") {
private val PHONE_STATE : String = "PHONE_STATE"
private val START_RECORDING : String = "START_RECORDING"
private val STOP_RECORDING : String = "STOP_RECORDING"
private lateinit var mRecorder : Recorder
override fun onCreate() {
mRecorder = Recorder()
super.onCreate()
}
override fun onHandleIntent(intent: Intent?) {
when(intent?.getStringExtra(PHONE_STATE)){
START_RECORDING -> mRecorder.startRecording()
STOP_RECORDING -> mRecorder.stopRecording()
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}
堆栈跟踪:
06-25 19:11:12.889 9104-9104/com.example.luca.kallrecorder D/CALL_RECEIVER: START RECORDING
06-25 19:11:12.897 9104-9104/com.example.luca.kallrecorder D/CALL_RECEIVER: START RECORDING
06-25 19:11:12.928 9104-9123/com.example.luca.kallrecorder D/EGL_emulation: eglMakeCurrent: 0xae834c40: ver 2 0
06-25 19:11:12.930 9104-9139/com.example.luca.kallrecorder E/MediaRecorder: start failed: -2147483648
06-25 19:11:12.931 9104-9139/com.example.luca.kallrecorder E/AndroidRuntime: FATAL EXCEPTION: IntentService[RecordService]
Process: com.example.luca.kallrecorder, PID: 9104
java.lang.RuntimeException: start failed.
at android.media.MediaRecorder.start(Native Method)
at com.example.luca.kallrecorder.Recorder.startRecording(Recorder.kt:33)
at com.example.luca.kallrecorder.RecordService.onHandleIntent(RecordService.kt:25)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.os.HandlerThread.run(HandlerThread.java:61)
06-25 19:11:12.952 9104-9123/com.example.luca.kallrecorder V/RenderScript: 0xae8eb800 Launching thread(s), CPUs 4
06-25 19:11:14.891 9104-9123/com.example.luca.kallrecorder D/EGL_emulation: eglMakeCurrent: 0xae834c40: ver 2 0
06-25 19:11:14.929 9104-9123/com.example.luca.kallrecorder D/EGL_emulation: eglMakeCurrent: 0xae834c40: ver 2 0
最佳答案
正如 Mike M. 在评论中所建议的,我通过实现服务而不是 IntentService 来解决。我引用 Mike M. 的话:“IntentService... 每次 onHandleIntent() 完成后都会立即停止。”。我想一旦系统失去对 onHandleIntent() 的引用,MediaRecorder 实例就会消失。
我的应用程序还没有按预期工作,但这不是因为那个错误。实际上它现在编译和运行没有任何错误。
这是更新的 RecordService 类,实现服务:
class RecordService : Service() {
private val PHONE_STATE : String = "PHONE_STATE"
private val START_RECORDING : String = "START_RECORDING"
private val STOP_RECORDING : String = "STOP_RECORDING"
private var mRecorder : Recorder? = null
private lateinit var mServiceLooper : Looper
override fun onCreate() {
mRecorder = Recorder()
super.onCreate()
}
override fun onBind(intent: Intent?): IBinder {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
when(intent?.getStringExtra(PHONE_STATE)){
START_RECORDING -> thread { Runnable { kotlin.run { mRecorder!!.stopRecording() } } }
STOP_RECORDING -> thread { Runnable { kotlin.run { mRecorder!!.stopRecording() } } }
}
return super.onStartCommand(intent, flags, startId)
}
关于Android:IntentService 致命异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51029008/
我有一个包含很多歌曲的 ListView 。每次点击一首歌曲时,我都会调用一个 IntentService 来按顺序下载这首歌曲。 但有时我想取消下载(例如:第 5 次)。这意味着我需要停止第 5 个
我有这个 IntentService (HttpService),它从网络服务中获取原始 json 数据: public class HttpService extends IntentService
我想将回调传递给 IntentService。这是我当前的代码: 我的回调接口(interface) import android.os.Message; public interface Sampl
在我的 Android 应用程序中,我有一个带有适配器的简单 ListView 。有一个繁重的查询是用数据填充 ListView 。所以我把它放到另一个线程中运行的 IntentService 中。
我只想写一个“Hello World IntentService App”。不幸的是,我无法做到这一点。 问题: MyIntentService.enqueueWork() 方法不起作用。 Inten
我有 5 个 IntentServices,它们在与主 UI 不同的时间和单独的进程中运行。当服务完成时,它们通过 Intent 将数据发送到主进程。我想知道 5 个服务是否占用了我的应用程序过多的内
我正在构建一个应用程序,通知将在特定时间响起,如果无人看管 15 分钟,通知就会消失。当我插入设备并运行代码时它就可以工作。然而,一旦我拔掉设备并运行应用程序,通知就会起作用,但如果无人看管,它不会在
我构建了一个应用程序,它使用 IntentService 来操作应用程序的数据库和调用网络服务。 例子: 我有一个 Activity ,它是一个项目列表。此列表由 CursorAdapter 填充。每
我遇到了一个问题。 IntentService UpdateService02 偶尔会运行失败。我放入了日志条目以便进行调试,这就是我得到的... 02-28 21:37:32.461: Main -
我正在使用 IntentService 执行后台任务,例如从远程服务器更新数据。 在某些情况下,同一个请求可以被用户多次排队,但我只想执行一次(连续两次从服务器更新数据没有意义)。 是否有使用 Int
我正在使用 Android AlarmManger 安排 IntentService 在较小的间隔后运行。 这是我的 AlarmManger: static void setNextSchedule(
我的 IntentService 看起来像这样: public class MusicService extends IntentService{ final static String NA
我遇到了一个奇怪的情况,我构建的对象在方法 onHandleIntent 中返回为 null,我不知道为什么或如何解决它。 我的 Activity @Override protected vo
我搜索了很多,但我不知道如何在单击按钮时停止 IntentService。我有一个启动 IntentService 的按钮,然后 progressDialog 显示通过 ResultReceiver
我正在尝试用 Kotlin 编写一个 CallRecorder 应用程序。我想要做的是开始使用 BroadcastReceiver 启动的服务录制音频。我认为我在 MediaRecorder 初始化方
只是想阐明我对 IntentService 在达到 terminating 状态后如何由操作系统管理的理解。通过终止,我的意思是当当前 Activity 被销毁或应用程序进程被终止时,根据以下文档:
我正在使用 IntentService 访问不同的网络服务方法并更新我的 ContentProvider。我看到的问题是,有时,我向 IntentService 发送了一个新的 Intent,但是 I
我想我明白了 IntentService 类的意义。它处理一个队列,防止太多或更多的服务实例一起执行。 我发现它很有用,但是如果我从 IntentService 派生了太多具有不同用途的类,并且我希望
我有一个 IntentService,它在启动时启动并在后台保持运行。没有启动器 Activity,IntentService 由广播接收器调用。它适用于 2.3.4 和 4.0.4 设备,但不适用于
我编写了一个发送命令行的 IntentService。与我尝试对控制台进行编程的 Activity 有关。该 Activity 的目的是执行“命令提示符”,我可以在其中向服务器发送消息或从服务器接收消
我是一名优秀的程序员,十分优秀!