I have this class:
public class FacebookShare extends Activity implements DialogListener {
Facebook facebook = new Facebook("199622693386109");
Bitmap bitmap;
byte [] data;
#Override
public void onCreate(Bundle savedInstanceState)
{
Bundle parameters = new Bundle();
parameters.putString("message", "Test Photo");
parameters.putByteArray("picture", data);
facebook.dialog(this, "stream.publish", parameters, this);
facebook.authorize(this, new DialogListener()
{
public void onComplete(Bundle values) {}
public void onFacebookError(FacebookError error) {}
public void onError(DialogError e) {}
public void onCancel() {}
});
}
}
but if I run this code, my app crashes. Please help.
parameters.putByteArray("picture", data);
data is your byte array of image....
and follow this link i did answer in this question....
we can upload photos using Facebook graph API with Multipart.
I am using retrofit library for network call
public interface ApiInterface {
#Multipart
#POST("/{id}/photos")
Call<UserModelResponse> uploadPhoto(#Part MultipartBody.Part image, #Path("id")String pageId, #Query("access_token") String token);
}
can upload multiple images
public class ApiCall {
private ApiInterface apiService;
private Context context;
public ApiCall(Context context) {
this.context = context;
}
public ApiInterface getRetroFitService() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Gson gson = new GsonBuilder().create();
Retrofit builder = new Retrofit.Builder()
.baseUrl("https://graph.facebook.com")
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
apiService = builder.create(ApiInterface.class);
return apiService;
}
public void uploadImageToFBPage(String pageId, ArrayList<Parcelable> path) throws IOException {
for (Parcelable parcelable : path) {
MultipartBody.Part body = prepareFilePart("source", (Uri) parcelable);
SharedPreferences sharedPreferences = context.getSharedPreferences(PREFERENCE, Context.MODE_PRIVATE);
String token = sharedPreferences.getString("token", "");
Call<UserModelResponse> call = apiService.uploadPhoto(body, pageId, token);
call.enqueue(new Callback<UserModelResponse>() {
#Override
public void onResponse
(Call<UserModelResponse> call, Response<UserModelResponse> response) {
if (response.errorBody() == null) {
Toast.makeText(context, "Image upload Success", Toast.LENGTH_SHORT).show();
} else {
onFailure(call, new Exception());
}
}
#Override
public void onFailure(Call<UserModelResponse> call, Throwable t) {
Toast.makeText(context, "Image upload Fail", Toast.LENGTH_SHORT).show();
}
});
}
}
#NonNull
private MultipartBody.Part prepareFilePart(String partName, Uri fileUri) {
// https://github.com/iPaulPro/aFileChooser/blob/master/aFileChooser/src/com/ipaulpro/afilechooser/utils/FileUtils.java
// use the FileUtils to get the actual file by uri
File file = FileUtils.getFile(context, fileUri);
// create RequestBody instance from file
RequestBody requestFile = RequestBody.create(MediaType.parse(context.getContentResolver().getType(fileUri)), file);
// MultipartBody.Part is used to send also the actual file name
return MultipartBody.Part.createFormData(partName, file.getName(), requestFile);
}
}
Related
I am using android as my front-end application and Spring boot as server part. I am using android retrofit library to connect with server.
When user logs onto server, he gets response like this.
So how do I extract "accessToken" and "tokenType" from body response?
Here is my login method in android:
private void login(LoginRequest loginRequest) {
OkHttpClient.Builder okHttpClientBuilder = new OkHttpClient.Builder();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
okHttpClientBuilder.addInterceptor(logging);
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClientBuilder.build());
Retrofit retrofit = builder.build();
RestAPI client = retrofit.create(RestAPI.class);
Call<LoginRequest> call = client.signIn(loginRequest);
call.enqueue(new Callback<LoginRequest>() {
#Override
public void onResponse(Call<LoginRequest> call, Response<LoginRequest> response) {
if (response.code() == 200) {
Toast.makeText(getApplicationContext(), response.body().toString(),
Toast.LENGTH_LONG).show();
Intent i = new Intent(LoginActivity.this, PostsActivity.class);
//response.body should be somewhere here
startActivity(i);
}else{
Toast.makeText(getApplicationContext(), "Uneti podaci nisu dobri",
Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<LoginRequest> call, Throwable t) {
}
});
}
This is my LoginRequest class
public class LoginRequest {
private String username;
private String password;
public LoginRequest(String username, String password) {
this.username = username;
this.password = password;
}
}
Create model class for response like below
public class Token {
#SerializedName("tokenType")
private String tokenType;
#SerializedName("accessToken")
private String accessToken;
public String getTokenType() {
return tokenType;
}
public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
}
Then change the Api return type to Call<Token>
Accordingly you also need to modify the call
call.enqueue(new Callback<Token>() {
#Override
public void onResponse(Call<Token> call, Response<Token> response) {
if(response.isSuccessful()) {
Token token = response.body();
}
}
#Override
public void onFailure(Call<Token> call, Throwable t) {
}
});
I have a method that makes a call to my server using Retrofit:
public class MainActivity extends AppCompatActivity {
// ... activity methods here, removed for simplicity ...
// Used to subscribe to a user given their userId
public void subscribeToUser(int userId) {
final ApiInterface apiService = ApiClient.createService(ApiInterface.class);
Call<BasicResponse> call = apiService.subscribe(userId);
call.enqueue(new Callback<BasicResponse>() {
#Override
public void onResponse(Call<BasicResponse> call, Response<BasicResponse> response) {
if (response.isSuccessful()) {
Toast.makeText(MainActivity.this, "Success", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(MainActivity.this, "Failed", Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<BasicResponse> call, Throwable t) {
Log.e(TAG, t.toString());
}
});
}
}
I now need to use this same method (subscribeToUser()) in another activity, but it doesn't make sense to copy and paste the method into the other activity. Then I would just have the same code twice.
So can I put the method into one place and have it let the activities know whether or not the call succeeded or failed? How should I organize this?
Here is my ApiClient.java class:
public class ApiClient {
public static final String API_BASE_URL = "http://www.website.com/api/";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
public static <S> S createService(Class<S> serviceClass, final String authToken) {
if (authToken != null) {
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", "Bearer " + authToken)
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
}
OkHttpClient client = httpClient.build();
Retrofit retrofit = builder.client(client).build();
return retrofit.create(serviceClass);
}
}
And here is my ApiInterface.java class:
public interface ApiInterface {
#FormUrlEncoded
#POST("subscribe")
Call<BasicResponse> subscribe(#Field("userId") Integer userId);
}
Thanks.
In my opinion, createService(ApiInterface.class) shouldn't be invoked multiple times. It's not necessary and slows down your application. You can try to create UserService with singleton pattern as below:
public class UserService {
private UserService userService;
final ApiInterface apiService;
//Contructor private to prevent init object from outside directly.
private UserService() {
apiService = ApiClient.createService(ApiInterface.class);
}
//use this method when you need to use UserService
public static UserService getInstance() {
if(userService == null) {
userService = new UserService();
}
}
// Used to subscribe to a user given their userId
public void subscribeToUser(int userId, ServiceCallBack serviceCallBack) {
final ApiInterface apiService = ApiClient.createService(ApiInterface.class);
Call<BasicResponse> call = apiService.subscribe(userId);
call.enqueue(new Callback<BasicResponse>() {
#Override
public void onResponse(Call<BasicResponse> call, Response<BasicResponse> response) {
if (response.isSuccessful()) {
Toast.makeText(MainActivity.this, "Success", Toast.LENGTH_LONG).show();
serviceCallBack.successful(response);
} else {
Toast.makeText(MainActivity.this, "Failed", Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<BasicResponse> call, Throwable t) {
Log.e(TAG, t.toString());
serviceCallBack.fail(t);
}
});
}
//this is callback interface, help you know whether success from outside.
interface ServiceCallBack {
void successful(Response response);
void fail(Throwable t);
}
}
How to use:
UserService.getInstance(1, new ServiceCallBack(){
#Override
public void successful(Response response) {
//process successful
}
#Override
public void fail(Throwable t) {
//process fail
}
});
Now you can put all methods relate to User api to UserService class to reuse.
I have a function to request upload image with Retrofit like this
void uploadPhoto(File file) {
RequestBody photo = RequestBody.create(MediaType.parse("application/image"), file);
RequestBody body = new MultipartBuilder()
.type(MultipartBuilder.FORM)
.addFormDataPart("photo", file.getName(), photo)
.build();
fragment.showProgressDialog(fragment.loading);
fragment.getApi().uploadPhoto(PrefHelper.getString(PrefKey.TOKEN), body)
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Observer<GenericResponse>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
fragment.dismissProgressDialog();
Timber.e(e.getMessage());
}
#Override
public void onNext(GenericResponse response) {
fragment.dismissProgressDialog();
if (response.getCode() == 1) {
fragment.showSuccessDialog("Saving success", false);
userInfo();
}
}
});
}
and for the example, I have a button to upload image in my fragment
#OnClick(R.id.btnChangePicture)
void onChangePictureClicked() {
}
What code should i put in
OnChangePictureClicked
So i can choose an image from gallery and then I request it to API.
void uploadPhoto(File file)
Thanks
Transform your image to an array of bytes and then create an Object Dto like the example below and send it to the server through Retrofit.
#Data
public class SetProfileImageRequestDto {
#SerializedName("Token")
private String token;
#SerializedName("Stream")
private byte[] image;
}
Retrofit Api Service:
#POST("SetProfileImage/")
Observable<ResultResponseDto> setProfileImage(#Body SetProfileImageRequestDto profileImageRequestDto);
Hope it works.
Create a Uri object in Activity or fragment.
private Uri selectedImage;
After that, You will get gallery result in onActivityResult.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data) {
selectedImage = data.getData();
}
}
Then in your onChangePictureClicked method.
#OnClick(R.id.btnChangePicture)
void onChangePictureClicked() {
if(selectedImage !=null){
uploadPhoto(new File(selectedImage.getPath()));
}
}
You can use multipart with retrofit please look this example of image upload using retrofit, its best for you.
its working for me.
//Create Upload Server Client
ApiService service = RetroClient.getApiService();
//File creating from selected URL
File file = new File(imagePath);
// create RequestBody instance from file
RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part body =
MultipartBody.Part.createFormData("uploaded_file", file.getName(), requestFile);
Call<Result> resultCall = service.uploadImage(body);
resultCall.enqueue(new Callback<Result>() {
#Override
public void onResponse(Call<Result> call, Response<Result> response) {
progressDialog.dismiss();
// Response Success or Fail
if (response.isSuccessful()) {
if (response.body().getResult().equals("success"))
Snackbar.make(parentView, R.string.string_upload_success, Snackbar.LENGTH_LONG).show();
else
Snackbar.make(parentView, R.string.string_upload_fail, Snackbar.LENGTH_LONG).show();
} else {
Snackbar.make(parentView, R.string.string_upload_fail, Snackbar.LENGTH_LONG).show();
}
/**
* Update Views
*/
imagePath = "";
textView.setVisibility(View.VISIBLE);
imageView.setVisibility(View.INVISIBLE);
}
#Override
public void onFailure(Call<Result> call, Throwable t) {
progressDialog.dismiss();
}
});
http://www.pratikbutani.com/2016/06/android-upload-image-file-using-retrofit-2-0/
I am now using retrofit,OkHttp and facebook sdk to make facebook registration.But I have problems in my register method "Fail:: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $".Could you look at that please?Here is my code.This is facebook resigter event.
loginButton.registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
#Override
public void onSuccess(LoginResult loginResult) {
GraphRequest request = GraphRequest.newMeRequest(
loginResult.getAccessToken(),
new GraphRequest.GraphJSONObjectCallback() {
#Override
public void onCompleted(
JSONObject object,
GraphResponse response) {
try {
user_id = response.getJSONObject().get("id") + "";
Log.i("User id", user_id);
register(user_id);
setProfile();
} catch (JSONException e) {
e.printStackTrace();
}
try {
response.getJSONObject().get("id");
} catch (JSONException e) {
e.printStackTrace();
}
}
});
Bundle parameters = new Bundle();
parameters.putString("fields", "id,name,email,gender, birthday");
request.setParameters(parameters);
request.executeAsync();
}
#Override
public void onCancel() {
}
#Override
public void onError(FacebookException error) {
}
});
This is my register method.
public void register(String id){
String pic_link="https://graph.facebook.com/" + id + "/picture?type=large";
Call<HashMap<String,String>> register= Login_api.createService(Login_service.class).register(id,pic_link);
register.enqueue(new Callback<HashMap<String, String>>() {
#Override
public void onResponse(Response<HashMap<String, String>> response, Retrofit retrofit) {
Log.i("SUCCESS:","MOTHER FUCKER");
}
#Override
public void onFailure(Throwable t) {
Log.i("Fail:",t.getMessage());
}
});
}
This is my api class
public class Login_api {
private static Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://192.168.0.111")
.addConverterFactory(GsonConverterFactory.create())
.client(new MyOkHttp());
public Login_api(){
}
public static <S> S createService(Class<S> serviceClass) {
Retrofit retrofit = builder.build();
return retrofit.create(serviceClass);
}
}
And this is my Service interface
public interface Login_service {
#FormUrlEncoded
#POST("androidapi/public/post/store")
Call<HashMap<String,String>> register(
#Field("user_name") String user_name,
#Field("profile_pic") String profile_pic
);
}
Hard to say for sure without more stack trace, but I'd say that you are not responding with valid JSON on your backend (http://192.168.0.111), since the error message you're getting is when Gson finds something other than a { as the first char in the response.
I am new to android retrofit and need to upload image file using multipart request format.
I was able to upload successfully using iphone multipart request.
However, had trouble with android retrofit.
I use https and token bearer authorization.
#Multipart
#POST("/Api/ApiSales/UploadImages")
void uploadImage(#Part("File") TypedFile file,
Callback<Response> callback);
RestAdapter.Builder builder = new RestAdapter.Builder().setEndpoint(appController.getInstance().getURL());
builder.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader("Authorization", appController.getInstance().getAuthTokenString());
}
});
builder.setLogLevel(RestAdapter.LogLevel.FULL);
RestAdapter restAdapter = builder.build();
RetrofitService service = restAdapter.create(RetrofitService.class);
service.uploadImage(new TypedFile("image/png",toFile), new Callback<retrofit.client.Response>() {
#Override
public void success(retrofit.client.Response response, retrofit.client.Response response2) {
Log.i(TAG, response.toString());
}
#Override
public void failure(RetrofitError error) {
Log.e(TAG, error.toString());
}
});
I got following error:
retrofit.RetrofitError: Write error: ssl=0x5ef8ad40: I/O error during system call, Connection reset by peer
I set up server for http request, still got error:
retrofit.RetrofitError: sendto failed: ECONNRESET (Connection reset by peer)
I think your interface should be like this.
#Multipart
#POST("/Api/ApiSales/UploadImages")
void uploadImage(#Header("Authorization") String user,
#Part("File") TypedFile file, Callback<Response> callback);
you should first get your real image path from onActivityResult
final String imagePath = getRealPathFromURI(imageUri);
and the getRealPathFromURI will be like this.
private String getRealPathFromURI(Uri contentUri) {
String[] projection = {MediaStore.Images.Media.DATA};
CursorLoader loader = new CursorLoader(this, contentUri, projection, null, null, null);
Cursor cursor = loader.loadInBackground();
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
String result = cursor.getString(column_index);
cursor.close();
return result;
}
and the intialize of your TypedFile
File photoFile = new File(imagePath);// image will be your real path
String mimeType = getMimeType(imagePath);
TypedFile photoTypedFile;
if (mimeType != null) {
photoTypedFile = new TypedFile(mimeType, photoFile);
} else {
photoTypedFile = new TypedFile("image/jpg", photoFile);
}
and your intialize of your Restadapter will be the same except adding headers and your call will be like.
RetrofitService service = restAdapter.create(RetrofitService.class);
service.uploadImage("yourAuthorization", photoTypedFil, new Callback<retrofit.client.Response>() {
#Override
public void success(retrofit.client.Response response, retrofit.client.Response response2) {
Log.i(TAG, response.toString());
}
#Override
public void failure(RetrofitError error) {
Log.e(TAG, error.toString());
}
});