java - 如何在点击服务器并等待响应时在android中放置一个线程安全的进度条?

标签 java android android-asynctask thread-safety background-process

我有一个应用程序,我在其中录制 Activity 中的音频。用户有一个开始录制和停止录制按钮来执行此操作。一旦用户单击停止录制按钮,它会将录制的 mp3 文件发送到服务器(编码字符串),服务器对其进行处理并收到响应。我想执行以下任务:

  1. 由于这个过程很长,我想在一个单独的线程中执行此操作(最好)。
  2. 发送和接收响应的过程将使用进度条显示。
  3. 用户在等待时应该能够导航到其他屏幕(即当前 Activity 可能会被破坏)

我尝试在将 mp3 发送到服务器的函数之前和之后使用 Toast 消息。但是没有同步,有时 msg 来得早,有时来得晚。这就是为什么需要一个适当的进度条。如何做到这一点? AsyncTask 可以与我想要在 (3) 中实现的目标一起使用吗?或者我应该使用其他形式的多线程。请帮助。下面是 Activity

(请忽略缩进,我无法修复堆栈溢出的代码:

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.provider.MediaStore;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import org.apache.commons.io.FileUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import java.io.BufferedReader;
import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;


import java.util.ArrayList;
import java.util.List;

public class RecordActivity extends AppCompatActivity {
private static final String LOG_TAG = "AudioRecordTest";
private static String msg = "default";

public final static String Result_MESSAGE = "in.innovatehub.ankita_mehta.tinyears.ResultMESSAGE";

private static final int REQUESTCODE_RECORDING = 109201;
private Button mRecorderApp = null;

private static String mFileName = "music.mp3";
private static String mFilePath =     String.valueOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS + "/TinyEars/"));

private MediaRecorder mRecorder = null;
private MediaPlayer mPlayer = null;

private ImageButton mRecordImageButton = null;
private ImageButton mPlayImageButton = null;

boolean mStartRecording = true;
boolean mStartPlaying = true;

private Button mShowStatsButton = null;

private static final String TAG = "RecordActivity";

private Handler handler = new Handler();
final Runnable updater = new Runnable() {
public void run() {
handler.postDelayed(this, 1);
if(mRecorder!=null) {
int maxAmplitude = mRecorder.getMaxAmplitude();

if (maxAmplitude != 0) {
// visualizerView.addAmplitude(maxAmplitude);
}
}
else{

}
}
};

private void onRecord(boolean start) {
if (start) {
startRecording();
} else {
stopRecording();
}
}

private void onPlay(boolean start) {
if (start) {
startPlaying();
} else {
stopPlaying();
}
}

private void startPlaying() {
mPlayer = new MediaPlayer();
try {
mPlayer.setDataSource(mFilePath+"/"+mFileName);
mPlayer.prepare();
mPlayer.start();
mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
Log.i("Completion Listener", "Song Complete");
stopPlaying();
mRecordImageButton.setEnabled(true);
}
});

} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
}

private void stopPlaying() {
if (mPlayer != null) {
mPlayer.reset();
mPlayer.release();
mPlayer = null;
mPlayImageButton.setImageResource(R.drawable.playicon);
//  mStartPlaying = true;
} else {
mPlayImageButton.setImageResource(R.drawable.pauseicon);
//   mStartPlaying = false;
}
}

private void startRecording() {
AudioRecordTest(String.valueOf(System.currentTimeMillis()));
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setOutputFile(mFilePath+"/"+mFileName);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
try {
mRecorder.prepare();
} catch (IOException e) {
Log.e(LOG_TAG, "prepare() failed");
}
try {
mRecorder.start();
Toast.makeText(getApplicationContext(), "Recording started", Toast.LENGTH_LONG).show();
} catch (Exception e) {
Log.e(LOG_TAG, "start() failed");
}
}

private void stopRecording() {
if (mRecorder != null) {
mRecorder.stop();
mRecorder.release();
Toast.makeText(getApplicationContext(), "Audio recorded successfully",Toast.LENGTH_LONG).show();
mRecorder = null;
mRecordImageButton.setImageResource(R.drawable.micicon);
// mStartRecording = true;
} else {
mRecordImageButton.setImageResource(R.drawable.stopicon);
// mStartRecording = false;
}
}

public void AudioRecordTest(String text) {
boolean exists = (new File(mFilePath+"/"+mFileName)).exists();
if (!exists) {
new File(mFileName).mkdirs();
}
//  mFileName += "audiorecordtest.mp3";
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_record);

Log.d(TAG,"HERE IS FILE PATH"+mFilePath+"/"+mFileName);

mRecordImageButton = (ImageButton) findViewById(R.id.imageButton2);
mPlayImageButton = (ImageButton) findViewById(R.id.imageButton3);
mShowStatsButton = (Button) findViewById(R.id.showMeStats);
mRecorderApp = (Button) findViewById(R.id.recorderApp);

AudioRecordTest("00000");

mRecordImageButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
onRecord(mStartRecording);
if (mStartRecording) {
mRecordImageButton.setImageResource(R.drawable.stopicon);
mPlayImageButton.setEnabled(false);
//setText("Stop recording");
} else {
mRecordImageButton.setImageResource(R.drawable.micicon);
mPlayImageButton.setEnabled(true);
mShowStatsButton.setEnabled(true);
mShowStatsButton.setVisibility(View.VISIBLE);
Toast.makeText(getApplicationContext(),"Hold on... we are getting the results!",Toast.LENGTH_SHORT).show();
pressedSavBtn();
Toast.makeText(getApplicationContext(),"Parsing done ... now you may see the results!",Toast.LENGTH_SHORT).show();
//setText("Start recording");
}
mStartRecording = !mStartRecording;
}
});
mPlayImageButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
onPlay(mStartPlaying);
if (mStartPlaying) {
mPlayImageButton.setImageResource(R.drawable.pauseicon);
mRecordImageButton.setEnabled(false);
mShowStatsButton.setEnabled(false);
//setText("Stop playing");
} else {
mPlayImageButton.setImageResource(R.drawable.playicon);
mRecordImageButton.setEnabled(true);
mShowStatsButton.setEnabled(false);
//setText("Start playing");
}
mStartPlaying = !mStartPlaying;
}
});
//Calling recorder ...
mRecorderApp.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
if (isAvailable(getApplicationContext(), intent)) {
startActivityForResult(intent, REQUESTCODE_RECORDING);
}
}
});
mShowStatsButton = (Button)  findViewById(R.id.showMeStats);
mShowStatsButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
sendResults(msg);
}
});

}

public void pressedSavBtn(){
try {
thread.start();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
mShowStatsButton.setVisibility(View.VISIBLE);
}
}

public void writeToFile(String data)
{
// Get the directory for the user's public pictures directory.
final File path = new File(mFilePath+"/");
// Make sure the path directory exists.
if(!path.exists())
{
// Make it, if it doesn't exit
path.mkdirs();
}
final File file = new File(path, "config.txt");
// Save your stream, don't forget to flush() it before closing it.
try
{
file.createNewFile();
FileOutputStream fOut = new FileOutputStream(file);
OutputStreamWriter myOutWriter = new OutputStreamWriter(fOut);
myOutWriter.append(data);

myOutWriter.close();

fOut.flush();
fOut.close();
}
catch (IOException e)
{
Log.e("Exception", "File write failed: " + e.toString());
}
}

private static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append((line + "\n"));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}

Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {

//THIS IS FILE ENCODING CODE
File file = new File(mFilePath+"/"+mFileName);
byte[] bytes = FileUtils.readFileToByteArray(file);
String encoded = Base64.encodeToString(bytes, 0);
Log.d("~~~~~~~~ Encoded: ", encoded);
writeToFile(encoded);

//THIS IS URL CONN CODE
String link = "http://192.168.50.0:9000/divide_result";
URL url = new URL(link);
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(link);
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("Name", "StackOverFlow"));
nameValuePairs.add(new BasicNameValuePair("Date", encoded));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
String sb = convertStreamToString(response.getEntity().getContent());
Log.d(TAG,"MESSAGE NOW"+sb);
Log.d(TAG, sb);
msg = sb.toString();

} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
} catch (IOException e) {
// TODO Auto-generated catch block
}
} catch (Exception e) {
e.printStackTrace();
}
}
});

public void sendResults(String res){
Log.d(TAG, "Inside on create, Navigating to Result Screen Activity!");
Intent intent = new Intent(getApplicationContext(), ResultsScreenActivity.class);
intent.putExtra(Result_MESSAGE, res);
startActivity(intent);
}

public static boolean isAvailable(Context ctx, Intent intent) {
final PackageManager mgr = ctx.getPackageManager();
List<ResolveInfo> list = mgr.queryIntentActivities(intent,PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}

protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == REQUESTCODE_RECORDING) {
if (resultCode == RESULT_OK) {
Uri audioUri = intent.getData();
// make use of this MediaStore uri
// e.g. store it somewhere
}
else {
// react meaningful to problems
}
}
else {
super.onActivityResult(requestCode,
resultCode, intent);
}
}

@Override
public void onPause() {
super.onPause();
if (mRecorder != null) {
mRecorder.release();
mRecorder = null;
}
if (mPlayer != null) {
mPlayer.release();
mPlayer = null;
}
thread.stop();
}

@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacks(updater);
if(mRecorder!=null) {
mRecorder.stop();
mRecorder.reset();
mRecorder.release();
}
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
handler.post(updater);
}
}

下面还有layout-xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_record"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center|center_horizontal"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:screenOrientation="portrait"
    android:orientation="vertical"
    tools:context="in.innovatehub.mobile.ankita_mehta.tinyears.RecordActivity">
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/linearLayout_record"
        android:orientation="vertical"
        android:gravity="center">

        <ImageButton
            android:id="@+id/imageButton2"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_gravity="center"
            android:scaleType="fitXY"
            android:src="@drawable/micicon" />

        <ImageButton
            android:id="@+id/imageButton3"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_gravity="center"
            android:scaleType="fitXY"
            android:src="@drawable/playicon" />

        <Button
            android:id="@+id/showMeStats"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:visibility="gone"
            android:onClick="loadStats"
            android:text="@string/showMeStats" />

        <Button
            android:id="@+id/recorderApp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="invisible"
            android:gravity="center"
            android:text="@string/UseRecorderApp" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/loadStatsLinearLayout"
        android:gravity="center"
        android:visibility="gone"
        android:orientation="vertical">

        <TextView
            android:id="@+id/loadingMessage"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="@string/loadingMessage"
            />

        <ProgressBar
            android:id="@+id/downloadProgress"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:indeterminate="true"
            />
    </LinearLayout>
</LinearLayout>

最佳答案

您可以使用 IntentService将您的内容上传到服务器。默认情况下,它在单独的线程上运行并且不受 Activity 限制。然后使用广播接收器将结果传回任何 Activity 。你可以找到一个例子 here .

对于进度条,你可以创建一个通知和show the progress bar there ,这不会阻止您的应用程序的用户界面。

关于java - 如何在点击服务器并等待响应时在android中放置一个线程安全的进度条?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40798970/

相关文章:

java - 使用 CommonsMultipartFile 将文件转换为 MultipartFile

android - 使用 Facebook 登录的网站和 native Android 应用程序之间的访问 token 不同?

android - 将改造 1 模块升级到改造 2

android - 使用 AsyncTask 的图像是并行下载还是顺序下载?

android - 在 Android 中取消 Asynctask 的正确方法

Java Json 解析器

java - 如何将环境变量添加到 android Runtime.getRuntime().exec 命令中?

java - 处理多个插入的最佳方法

java - 无法从 Assets 文件夹中填充的 sqlite 数据库获取数据

php - AsyncTask Android 中的 Http 请求