I am creating app that can run 2 process at the time (saving to database / sending to api) but , i was encountering issue from my treading.This is my code upon my threading:
this is my code:
public void timerToSaveSend() {
Thread t1 = new Thread() {
#Override
public void run() {
saving();
}
};
t1.start();
Thread t2 = new Thread(){
#Override
public void run() {
sending();
}
};
t2.start();
}
private void sending() {
//dataSendApi
handler10 = new Handler();
handler10.postDelayed(new Runnable() {
#Override
public void run() {
try {
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl("http://" + ADDRESS + ":" + PORT)
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
API locate = retrofit.create(API.class);
Call<MapDetails> call = locate.mapDetailLocation(data);
call.enqueue(new Callback<MapDetails>() {
#Override
public void onResponse(Call<MapDetails> call,
Response<MapDetails> response) {
String portString = String.valueOf(portss);
}
#Override
public void onFailure(Call call, Throwable t) {
Log.d("Message: ", "Data not sent, please check your
network connection.");
}
});
} catch (Exception e) {
Toast.makeText(NavDrawerFleet.this, "Disconnected from Internet, Please Configure Settings", Toast.LENGTH_SHORT).show();
restFailed();
}
}
}, 10000);
}
private void saving() {
//4SECOND
handler2 = new Handler();
handler2.postDelayed(new Runnable() {
#Override
public void run() {
DatabaseHelper databaseHelper = new DatabaseHelper(getApplicationContext());
SQLiteDatabase db = databaseHelper.getWritableDatabase();
well2 = String.valueOf(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", java.util.Locale.getDefault()).format(new java.util.Date()));
boolean accepted = databaseHelper.saveLocationToLocalDatabase(gg, hidelat.getText().toString(), hidelon.getText().toString(), well2, "1", "9090", db);
failedCount.setText(String.valueOf(retryList.size()));
lat2 = hidelat.getText().toString();
lon2 = hidelon.getText().toString();
MapDetails mapDetails = new MapDetails(gg, hidelat.getText().toString(), hidelon.getText().toString(), well2, "1", 9090);
data.add(mapDetails);
retry2 = new NotSentModuleGetterSetter(hidelat.getText().toString(), hidelon.getText().toString(), well2);
retryList.add(retry2);
retrylist_adapter.notifyDataSetChanged();
if (accepted == true)
Log.w("Data Entered: ", "1st Copy");
}
}, 2000);
saving();
}
and this is my error encountered:
PS. I was wondering that my code is to totally not working though i want also other possible code implementation with this one, like asynctask to work with this multiple process + with threading in a single meathod.
For threading, please consider using RxJava. It would be as simple as this
Observable.fromCallable(new Callable<Object>() {
#Override public Object call() throws Exception {
saving();
return null;
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Object>() {
#Override public void onSubscribe(Disposable d) {
}
#Override public void onNext(Object o) {
}
#Override public void onError(Throwable e) {
}
#Override public void onComplete() {
}
});
Check this link out on how to integrate RxJava into your project https://github.com/ReactiveX/RxAndroid
Related
I have this issue with Volley library requests. I make calls to API and since they have to be updated very often I implemented timers. After some time it throws me error:"Throwing OutOfMemoryError “pthread_create (1040KB stack) failed: Try again. I used the method which was suggested in this post: Throwing OutOfMemoryError "pthread_create (1040KB stack) failed: Try again" when doing asynchronous posts using Volley , but for me it did not work, the data coming from API stopped updating. I thought it might be something with timers or it is just something I am doing wrong using Volley.
If you have any idea, feel welcome to share.
My printer class
public void setMenuInformation(String url, Context context, final VolleyCallback callback) {
Log.d("API", "Currently calling URL " + url);
if (eRequestQueue == null) {
eRequestQueue = Volley.newRequestQueue(context);
eRequestQueue.add(new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
String temp = response.substring(2, response.length() - 2);
Log.d("API", "Current menu" + response);
byte msgArray[];
try {
msgArray = temp.getBytes("ISO-8859-1");
currentMenu = msgArray[0];
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
menuInformation = response;
callback.onSuccess(menuInformation);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("API", "Current menu Nope ");
callback.onFailure(error);
}
}));
}
}
Main Activity:
myPrinterDetails.setMenuInformation("http://" + nsdServiceInfo.getHost() + "/GetCurrentMenu",
MainActivity.this, new PrinterNew.VolleyCallback() {
#Override
public void onSuccess(String result) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.d("NSD", "Current menu response succeded and added to array " + nsdServiceInfo);
//services.add(myPrinterDetails);
mAdapter.notifyDataSetChanged();
}
});
Log.d("NSD", "CurrentMenu " + myPrinterDetails.getMenuInformation());
myTimer.schedule(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
myPrinterDetails.setMenuInformation("http://" + nsdServiceInfo.getHost() + "/GetCurrentMenu", MainActivity.this, new PrinterNew.VolleyCallback() {
#Override
public void onSuccess(String result) {
Log.d("NSD", "Current menu response added to timer " + nsdServiceInfo);
mAdapter.notifyDataSetChanged();
}
#Override
public void onFailure(Object response) {
Log.d("NSD", "Current menu timer failed");
}
});
}
});
}
}, 0, 2000);
}
#Override
public void onFailure(Object response) {
Log.d("NSD", "Current menu response failed");
}
});
}
};
}
I have web request helper class in my app using OKHttp3 via standard async method call. everything just work fine, but in my Splash Activity just for first run (after new installation) web request calling not work! but if I close the app and run again everything work fine.
here is my call back interface:
public interface WebResult<T> {
void onValue(T value);}
here is calling method
public void getStatus(final WebResult result) {
urlBuilder.addQueryParameter("action", "test");
urlBuilder.addQueryParameter("reqbody", cd.toJSON());
String url = urlBuilder.build().toString();
Request request = new Request.Builder()
.header("Authorization", AuthKey)
.url(url)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
setHasError(true);
setMsg(e.getMessage());
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
} else {
iAct.runOnUiThread(new Runnable() {
public void run() {
try {
String s = response.body().string();
ServerStat r = new ServerStat();
r.fromJSON(s);
result.onValue(r);
return;
} catch (IOException e) {
}
}
});
}
}
});
}
and its my splash activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
WebHelper wh = new WebHelper(context);
wh.getStatus(new WebResult() {
#Override
public void onValue(Object value) {
ServerStat r = (ServerStat) value;
if (r.getErrorCode() == 0) {
Toast.makeText(context, r.getErrorMsg(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, r.getErrorMsg(), Toast.LENGTH_LONG).show();
}
}
});
}
I replaced OKHttp3 with google Volley and it's work in my case!
I need to save in Realm a JSON that I've saved in Assets folder.
So I've decided to do it in this way:
private void putCountryIntoRealm()
{
Observable.create(new Observable.OnSubscribe<String>()
{
public void call(Subscriber<? super String> subscriber)
{
try
{
InputStream is = getActivity().getAssets().open("countries.json");
Reader inRead = new InputStreamReader(is);
Gson gson = new Gson();
JsonReader reader = new JsonReader(inRead);
reader.setLenient(true);
reader.beginArray();
while (reader.hasNext())
{
CountryObject ct = gson.fromJson(reader, CountryObject.class);
country.add(ct);
System.out.println("size ct: "+country.size());
subscriber.onNext(reader.toString());
}
reader.endArray();
reader.close();
subscriber.onCompleted();
}
catch (IOException e)
{
subscriber.onError(e);
}
}
}).subscribeOn(Schedulers.newThread())
.subscribe(new Subscriber<String>()
{
#Override
public void onCompleted()
{
getActivity().runOnUiThread(new Runnable()
{
#Override
public void run()
{
realm.executeTransactionAsync(new Realm.Transaction()
{
float total = 0;
float size = country.size();
String progressCount;
public void execute(Realm mRealm)
{
Countries countries = new Countries();
int i;
System.out.print("countries size: "+size);
for (i = 0; i < country.size(); i++)
{
total = (i/size * 100);
progressCount = String.format("%.0f",total);
countries.setId(country.get(i).getId());
countries.setCode(country.get(i).getCode());
countries.setName(country.get(i).getName());
countries.setContinent(country.get(i).getContinent());
countries.setKeywords(country.get(i).getKeywords());
countries.setWikipedia_link(country.get(i).getWikiLink());
mRealm.insertOrUpdate(countries);
getActivity().runOnUiThread(new Runnable()
{
#Override
public void run()
{
//Log.d("%",progressCount);
dialog = new ProgressDialog(getActivity());
dialog.setTitle("Salvataggio country in corso");
dialog.setMessage(progressCount+"%");
}
});
}
}
},new Realm.Transaction.OnSuccess() {
#Override
public void onSuccess()
{
Log.wtf("va","Ok");
if(dialog.isShowing())
dialog.dismiss();
}
}, new Realm.Transaction.OnError()
{
#Override
public void onError(Throwable error)
{
error.printStackTrace();
}
});
}
});
}
#Override
public void onError(Throwable e)
{
e.printStackTrace();
}
#Override
public void onNext(String s)
{
System.out.println(s);
}
});
}
but I have this error:
W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'long com.plenitudesrls.aviocalc.helpful.CountryObject.getId()' on a null object reference
In fact, I print logs and the size in onNext() is 245, in onCompleted() is null.
Why I have this error? I have another case where this works good.
Thanks
EDIT: it works good, the problem was a MalformedJson that cause the crash
I've this code:
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.baseUrl(GithubService.SERVICE_ENDPOINT).build();
GithubService service = retrofit.create(GithubService.class);
service.getAirport()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<List<Airport>>() {
List<Airport> airps = new ArrayList<Airport>();
#Override
public void onCompleted() {
for(final Airport air : airps) {
realm.executeTransactionAsync(new Realm.Transaction() {
#Override
public void execute(Realm mRealm) {
AirportR airport = mRealm.createObject(AirportR.class);
airport.setId(air.getId());
}
}, new Realm.Transaction.OnSuccess() {
#Override
public void onSuccess() {
Log.wtf("ok", "ok");
}
}, new Realm.Transaction.OnError() {
#Override
public void onError(Throwable error) {
Log.e("ok", "non vaaa");
}
});
}
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
}
#Override
public void onNext(List<Airport> airports) {
airps = airports;
}
});
}
});
and I need to put a download percentage because airports are so much..and so I want to put in a textview the percentage of the download (and I don't know how to do it in onNext() method) and the percentage of the realm adding in the airport...
It's possible to do?
Thanks
I used this function to show download progress, combine by rxjava and okhttp, hope it helps.
private void initOkHttpClient() {
mOkHttpClient = new OkHttpClient();
mRequest = new Request.Builder().url(URL_JSON).build();
}
private void rxPublishProgress() {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mProgressDialog.setMax(100);
mProgressDialog.setCancelable(true);
mProgressDialog.show();
mRequest = new Request.Builder().url(URL_IMAGE).build();
Observable.create(new Observable.OnSubscribe<String>() {
#Override
public void call(Subscriber<? super String> subscriber) {
try {
InputStream inputStream;
Response response = mOkHttpClient.newCall(mRequest).execute();
if (response.isSuccessful()) {
inputStream = response.body().byteStream();
long len = response.body().contentLength();
String progress = "0";
subscriber.onNext(progress);
byte[] data = new byte[1024];
long total = 0;
int count;
while ((count = inputStream.read(data)) != -1) {
total += count;
progress = String.valueOf(total * 100 / len);
subscriber.onNext(progress);
}
inputStream.close();
subscriber.onCompleted();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).subscribeOn(Schedulers.newThread()).subscribe(new Subscriber<String>() {
#Override
public void onCompleted() {
LogUtils.d("onCompleted");
mProgressDialog.dismiss();
}
#Override
public void onError(Throwable e) {
LogUtils.d(e.toString());
mProgressDialog.dismiss();
}
#Override
public void onNext(final String progress) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mProgressDialog.setProgress(Integer.parseInt(progress));
}
});
}
});
}
I am trying to use OkHTTP library. When making a call to the server and getting a successful response back. i need to update the UI.
How can this be done when doing an Async call using the enqueue()?
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
}
#Override
public void onResponse(Response response) throws IOException {
if (response.isSuccessful()) {
// NEED TO UPDATE UI HERE
}
}
});
You can refer to the following sample code, hope this helps!
public class MainActivity extends AppCompatActivity {
private static final String LOG_TAG = "OkHttp";
private TextView mTextView;
private Handler mHandler;
private String mMessage;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.textView);
mHandler = new Handler(Looper.getMainLooper());
OkHttpClient client = new OkHttpClient();
// GET request
Request request = new Request.Builder()
.url("http://...")
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
mMessage = e.toString();
Log.e(LOG_TAG, mMessage); // no need inside run()
mHandler.post(new Runnable() {
#Override
public void run() {
mTextView.setText(mMessage); // must be inside run()
}
});
}
#Override
public void onResponse(Response response) throws IOException {
mMessage = response.toString();
Log.i(LOG_TAG, mMessage); // no need inside run()
mHandler.post(new Runnable() {
#Override
public void run() {
mTextView.setText(mMessage); // must be inside run()
}
});
}
});
}
}
If your code doesn't update the UI, I would suggest you to specify the thread, since UI is on its own thread:
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
}
#Override
public void onResponse(Response response) throws IOException {
if (response.isSuccessful()) {
runOnUiThread(new Runnable() {
#Override
public void run() {
//TODO: update your UI
}
});
}
}
});
Try this:
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(new Runnable() {
#Override
public void run() {
// code to interact with UI
}
});
For the sake of having a clean code, I would suggest you not to put your entire code inside the runnable.
A simple example:
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://...").build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Request request, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Response response) throws IOException {
final String body = response.body().string();
runOnUiThread(new Runnable() {
#Override
public void run() {
updateUI(body);
}
});
}
});
}
private void updateUI(responseBody){
//TODO: update your UI
}
}