Я занимаюсь разработкой приложения для Android, в котором пользователи могут сообщать о проблемах (загружать в виде данных json) и загружать файлы изображений (файлы, связанные с проблемой) на сервер.Приложение работает нормально, если оно подключено к Интернету.К сожалению, этого недостаточно для меня, у него должна быть возможность сохранять эти изображения и загружать их позже, когда мобильный телефон снова будет в сети.
Итак, я создал сервис, который постоянно пытается загружать данные (я знаю,это не лучшая конструкция, чтобы заставить все это работать, но это единственное решение, которое я мог придумать, я довольно новичок во всем этом программировании), когда первый запрос не удался.И вот проблема, это работает, когда дело доходит до данных, но не в случае изображений, через несколько секунд после сохранения изображения приложение вылетает, оставляя мне java.lang.OutOfMemoryError
.
Я использую okhttp2.5 для подключения и пространство через sqlite для хранения данных.
Вот код интереса:
Класс ErrorActivity:
public class ErrorActivity extends AppCompatActivity {
private static final int REQUEST_PICK_IMAGE = 3;
UploadService mUploadservice;
boolean mBound = false;
//... Giving permissions, other variables...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_error);
Button btnReport = findViewById(R.id.btnReport);
btnReport.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
reportdefiency();
} catch (JSONException e) {
e.printStackTrace();
}
}
});
//...
}
@Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(ErrorActivity.this,
UploadService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
unbindService(mConnection);
mBound = false;
}
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder
service) {
UploadService.LocalBinder binder =
(UploadService.LocalBinder) service;
mUploadservice = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBound=false;
}
};
public void reportdefiency(){
//call static inner class AsyncTask, to avoid memory leak
//and avoid UI unresponsiveness
new ImgTask(this).execute();
//...
}
private static class ImgTask extends AsyncTask<Void, Void, Void>{
private WeakReference<ErrorActivity> activityWeakReference;
ImgTask(ErrorActivity context){
activityWeakReference = new WeakReference<>(context);
}
@Override
protected Void doInBackground(Void...voids) {
ErrorActivity activity = activityWeakReference.get();
if(activity == null || activity.isFinishing()) return null;
activity.uploadmultipleimages();
return null;
}
}
public void uploadmultipleimages(){
// check if any images are picked to upload and so on...
// create multipart body part ...
// .....................
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setConnectTimeout(30, TimeUnit.SECONDS);
okHttpClient.setReadTimeout(30, TimeUnit.SECONDS);
//create the requestbody
RequestBody rb =multipartBuilder
.type(MultipartBuilder.FORM)
.build();
Request request = new Request.Builder()
.url("http://blabla/bla/api"
+suburlblabla).post(rb).build();
}
//new variables, because inner
// class needs final fields
final List<byte[]> byteslist = fileinbytes;
//if fails -> save it and start service
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
//a list contains the image to save
final List<OffImage> offImageList = new
ArrayList<>();
File[] files = new File[pictureUriArray.size()];
for(int i=0; i<pictureUriArray.size();i++){
//convert and store in Offimage class
//which is also an @Entity in SQLite
//adding files to list, checked->works...
}
// DB = SQLite database, singleton pattern, insert
// images to table
DB.getInstance(getApplicationContext())
.daoAccess().insertoffimages(offImageList);
//if activity bounded to service, upload it...
if(mBound){
mUploadservice.uploaddefimagedata();
}
}
});
}
}
UploadService
public class UploadService extends Service {
// Users can save images multiple times on Erroractivity
// this int will register the number of calls from activity.
// Each call will be a request in an infinite loop to upload
// the images. But a change in this counter will indicate
// okhttp call to end the loop and start another, because more
// images added to the queue list, hence must query sqlite
// again and create another request with the refreshed list
// images in byte[] format
private static int defimagejobcounter = 0;
public void uploaddefimagedata(){
List<OffImage> offImageList =
DB.getInstance(getApplicationContext())
.daoAccess()
.selectalloffimages();
if(offImageList!=null){
if(offImageList.size()>0){
// increase the counter to indicate to a previous call
// to abandon its operation (See later)
defimagejobcounter++;
createmultipartrequests(offImageList);
}
}
}
private void createmultipartrequests(List<Offimage> listoflists){
// for cycle to create each request
for(int i = 0; listoflists.size(); i++){
//creating requestbody, multipart, etc....
uploadeqimage(requestBody, listoflists.get(0).getEqID(),
defimagejobcounter);
}
}
private void uploadeqimage(final RequestBody requestBody, final int
eqid, final int oldcounter){
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setConnectTimeout(20, TimeUnit.SECONDS);
okHttpClient.setReadTimeout(20, TimeUnit.SECONDS);
Request request = new
Request.Builder().url("http://blabla/bla/api"
+suburlblabla).post(requestBody).build();
okHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
// retry if request fails, AND no other calls yet
// from Activity
if(defiencyimagejobcounter==oldcounter){
uploadeqimage(requestBody, eqid, oldcounter);
}
}
@Override
public void onResponse(Response response){
if(response.isSuccessful()){
DB.getInstance(getApplicationContext())
.daoAccess().deletealleqimages();
defimagejobcounter = 0;
Log.d(TAG, "Image(s) uploaded.");
}
}
});
}
Есть какие-нибудь предложения, как избежать ошибки памяти okhttp диспетчера?Любая помощь приветствуется.