So I have followed this tutorial here: https://heartbeat.fritz.ai/uploading-images-from-android-to-a-python-based-flask-server-691e4092a95e
And set up my android studio and flask server.
The problem I am facing is sending image over to flask server. I am getting this error on sending the when I click on connect to server.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.flaskserver, PID: 28524
java.lang.IllegalStateException: Could not find method connectServer(View) in a parent or ancestor Context for android:onClick attribute defined on view class com.google.android.material.button.MaterialButton
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.resolveMethod(AppCompatViewInflater.java:447)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:405)
at android.view.View.performClick(View.java:7448)
at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1119)
at android.view.View.performClickInternal(View.java:7425)
at android.view.View.access$3600(View.java:810)
at android.view.View$PerformClick.run(View.java:28305)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
I/Process: Sending signal. PID: 28524 SIG: 9
Here is my code for Android Studio:
package com.example.flaskserver;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class MainActivity extends AppCompatActivity {
String selectedImagePath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
connectServer(findViewById(R.id.connectServer));
}
@SuppressLint("SetTextI18n")
void connectServer(View v){
EditText ipv4AddressView = findViewById(R.id.IPAddress);
String ipv4Address = ipv4AddressView.getText().toString();
EditText portNumberView = findViewById(R.id.portNumber);
String portNumber = portNumberView.getText().toString();
String postUrl= "http://"+ipv4Address+":"+portNumber+"/";
ByteArrayOutputStream stream = new ByteArrayOutputStream();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
// Read BitMap by file path
Bitmap bitmap = BitmapFactory.decodeFile(selectedImagePath, options);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] byteArray = stream.toByteArray();
RequestBody postBodyImage = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("image", "androidFlask.jpg", RequestBody.create(MediaType.parse("image/*jpg"), byteArray))
.build();
TextView responseText = findViewById(R.id.responseText);
responseText.setText("Please wait ...");
postRequest(postUrl, postBodyImage);
}
void postRequest(String postUrl, RequestBody postBody) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(postUrl)
.post(postBody)
.build();
client.newCall(request).enqueue(new Callback() {
@SuppressLint("SetTextI18n")
@Override
public void onFailure(Call call, IOException e) {
// Cancel the post on failure.
call.cancel();
// In order to access the TextView inside the UI thread, the code is executed inside runOnUiThread()
runOnUiThread(() -> {
TextView responseText = findViewById(R.id.responseText);
responseText.setText("Failed to Connect to Server");
});
}
@Override
public void onResponse(Call call, final Response response) {
// In order to access the TextView inside the UI thread, the code is executed inside runOnUiThread()
runOnUiThread(() -> {
TextView responseText = findViewById(R.id.responseText);
try {
responseText.setText(response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
});
}
});
}
public void selectImage(View v) {
Intent intent = new Intent();
intent.setType("*/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, 0);
}
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
protected void onActivityResult(int reqCode, int resCode, Intent data) {
super.onActivityResult(reqCode, resCode, data);
if (resCode == RESULT_OK && data != null) {
Uri uri = data.getData();
selectedImagePath = getPath(getApplicationContext(), uri);
EditText imgPath = findViewById(R.id.imgPath);
imgPath.setText(selectedImagePath);
Toast.makeText(getApplicationContext(), selectedImagePath, Toast.LENGTH_LONG).show();
}
}
// Implementation of the getPath() method and all its requirements is taken from the StackOverflow Paul Burke's answer: https://stackoverflow.com/a/20559175/5426539
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
}
Flask:
import flask
import werkzeug
app = flask.Flask(__name__)
@app.route('/', methods = ['GET', 'POST'])
def handle_request():
imagefile = flask.request.files['image']
filename = werkzeug.utils.secure_filename(imagefile.filename)
print("\nReceived image File name : " + imagefile.filename)
imagefile.save(filename)
return "Image Uploaded Successfully"
app.run(host="0.0.0.0", port=5000, debug=True)