First I will explain the current situation.
I've 2 different threads in 2 services(read from usb port service and make web requests service). I'm starting them in onCreate of my activity like:
serialServiceIntent = new Intent(NDKSerialActivity.this, SerialService.class);
startService(serialServiceIntent);
webServiceIntent = new Intent(NDKSerialActivity.this, RecordWebService.class);
startService(webServiceIntent);
There is nothing wrong with serial service but in RecordWebService when I make a request my gui stops until response comes.
The code is like that:
public class RecordWebService extends Service
{
public static final String SERVER_ADDRESS = "http://192.168.1.100:8080/MobilHM/rest";
private static final String TAG = RecordWebService.class.getSimpleName();
private RecordWebThread recordWebThread;
#Override
public void onStart(Intent intent, int startId)
{
super.onStart(intent, startId);
recordWebThread = new RecordWebThread(true);
recordWebThread.start();
}
#Override
public void onDestroy()
{
super.onDestroy();
Log.i(TAG, "RecordWebService Destroyed");
}
#Override
public IBinder onBind(Intent intent)
{
return null;
}
}
and
public class RecordWebThread extends Thread
{
private static final String TAG = RecordWebThread.class.getSimpleName();
public boolean always;
public RecordWebThread(boolean always)
{
this.always = always;
}
#Override
public void run()
{
PatientRecord patientRecord = new PatientRecord();
while (always)
{
RestClient restClient = new RestClient(RecordWebService.SERVER_ADDRESS + "/hello");
try
{
restClient.execute(RequestMethod.GET);
}
catch (Exception e1)
{
Log.e(TAG, "", e1);
}
Log.i(TAG, "Server Response Code:->" + restClient.getResponseCode());
Log.i(TAG, "Server Response:->" + restClient.getResponse());
try
{
sleep(4 * 1000);
}
catch (InterruptedException e)
{
Log.e(TAG, "Web service interrupted", e);
}
}
}
}
Also I've tried to remove sleep part and make the thread to run with timer and timer task like:
public void sendRecord()
{
scanTask = new TimerTask()
{
public void run()
{
handler.post(new Runnable()
{
public void run()
{
RestClient restClient = new RestClient(RecordWebService.SERVER_ADDRESS + "/hello");
try
{
restClient.execute(RequestMethod.GET);
}
catch (Exception e1)
{
Log.e(TAG, "", e1);
}
Log.i(TAG, "Server Response Code:->" + restClient.getResponseCode());
Log.i(TAG, "Server Response:->" + restClient.getResponse());
}
});
}
};
t.schedule(scanTask, 1000, 4000);
}
but no luck, my gui hangs when it comes to restClient.execute .
You can find RestClient.java # http://www.giantflyingsaucer.com/blog/?p=1462
How can I make my requests not block my gui thread?
Edit:
public void sendRecord()
{
scanTask = new TimerTask()
{
public void run()
{
RestClient restClient = new RestClient(RecordWebService.SERVER_ADDRESS + "/hello");
try
{
restClient.execute(RequestMethod.GET);
}
catch (Exception e1)
{
Log.e(TAG, "", e1);
}
Log.i(TAG, "Server Response Code:->" + restClient.getResponseCode());
Log.i(TAG, "Server Response:->" + restClient.getResponse());
}
};
t.schedule(scanTask, 1000, 4000);
}
Without handler, I call this in onCreate of my activity but still ui hanging.
Or you can use an IntentService which will handle the thread issues for you.
This is an example class:
public class MyService extends IntentService {
public MyService() {
super("MyService");
}
public MyService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent arg0) {
//Do what you want
}
}
Then you just call:
Intent intent = new Intent(getApplicationContext(),MyService.class);
startService(intent);
Edit:
To repeat the same thing every 4 seconds you should do something like this:
PendingIntent serviceIntent= PendingIntent.getService(context,
0, new Intent(context, MyService.class), 0);
long firstTime = SystemClock.elapsedRealtime();
AlarmManager am = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
long intervalInSec = 4;
am.setRepeating(AlarmManager.ELAPSED_REALTIME, firstTime, intervalInSec*1000, serviceIntent)
;
In your code (2d version) happens next: You create thread, and it asks UI thread to do some net interaction. Just exclude handler.post(...) while executing request. Later you can use this for simple runnable for updating your UI with results of request.
Related
I am trying to load an URL (API) after every 15 seconds in a service. Everything is working fine but when the app is killed URL is not called. I dont need any UI in my app. I just want it to work in background when the app is killed. I have been finding a solution for two days but nothing worked. Please help!
Here is my service code :
public class MyService extends Service {
Handler handler = new Handler();
Runnable runnable;
int delay = 15*1000;
String data ;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(final Intent intent, int flags, int startId) {
handler.postDelayed( runnable = new Runnable() {
public void run() {
data = (String) intent.getExtras().get("data");
Toast.makeText(MyService.this, ""+data, Toast.LENGTH_SHORT).show();
loadURL(data);
handler.postDelayed(runnable, delay);
}
}, delay);
return START_STICKY ;
}
#Override
public void onDestroy() {
handler.postDelayed( runnable = new Runnable() {
public void run() {
Toast.makeText(MyService.this, ""+data, Toast.LENGTH_SHORT).show();
loadURL(data);
handler.postDelayed(runnable, delay);
}
}, delay);
}
public void loadURL(String data){
try{
RequestFuture<JSONObject> requestFuture=RequestFuture.newFuture();
final String mURL = "http://192.168.1.12/att.php?emp_id=" + data + "&status=&submit=Insert";
JsonObjectRequest request = new JsonObjectRequest(Request.Method.POST,
mURL,new JSONObject(),requestFuture,requestFuture);
MySingleton.getInstance(this).addToRequestQueue(request);
Toast.makeText(this, "Done", Toast.LENGTH_SHORT).show();
try {
JSONObject object= requestFuture.get(10, TimeUnit.SECONDS);
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e){
Toast.makeText(this, ""+e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
Here is my MainActivity.java where I am getting an intent as a userID :
public class MainActivity extends AppCompatActivity {
String data;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
data = getIntent().getStringExtra("ID");
Intent intent = new Intent(MainActivity.this, MyService.class);
intent.putExtra("data", data);
startService(intent);
}
}
You will have to turn that background service into a foreground service, because of the limitations called Background Execution Limits that started from android Oreo.
Please check out this link for more better understanding:
https://developer.android.com/about/versions/oreo/background
I am using a service in my application in order to get data from the server and save received data in my local database.
But when I am using the application and my service will run in the background the application works too slow.
This is my service class that I used:
public class InternetService extends Service implements Loader.OnLoadCompleteListener<Cursor> {
public static final int notify = 5 * 60 * 60 * 1000; //interval between two services(Here Service run every 1 Minute)
private Handler mHandler = new Handler(); //run on another Thread to avoid crash
private Timer mTimer = null; //timer handling
private ArrayList<FileModel> failedIDDownloads = new ArrayList<>();
private static final String TAG = "BroadcastService";
public static final String BROADCAST_ACTION = "my_package";
Intent intent;
int counter = 0;
private CursorLoader cursorLoader;
private EncycDatabase encycDB;
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
intent = new Intent(BROADCAST_ACTION);
}
#Override
public void onStart(Intent intent, int startId) {
cursorLoader = new CursorLoader(this, Uri.parse(EncycDatabase.CONTENT_PROVIDER_URL),
null, null, null, null);
cursorLoader.registerListener(1, this);
cursorLoader.startLoading();
mHandler.removeCallbacks(sendUpdatesToUI);
mHandler.postDelayed(sendUpdatesToUI, 1000); // 1 second
}
#Override
public void onDestroy() {
super.onDestroy();
// Stop the cursor loader
if (cursorLoader != null) {
cursorLoader.unregisterListener(this);
cursorLoader.cancelLoad();
cursorLoader.stopLoading();
}
}
#Override
public void onLoadComplete(Loader<Cursor> loader, Cursor cursor) {
encycDB = new EncycDatabase();
try {
while (cursor.moveToNext()) {
G.TOKEN = (cursor.getString(cursor.getColumnIndex("user_session_token")));
}
populateEncyclopediaData();
Thread searchTagThread = new Thread(new Runnable() {
#Override
public void run() {
populateSearchTagsEncyc();
populateSearchTags();
}
});
G.handler.postDelayed(new Runnable() {
#Override
public void run() {
checkForDownloadFiles();
}
},10 *60* 1000);
searchTagThread.start();
} catch (Exception e) { //When happened an error in getting Token!
e.printStackTrace();
}
}
private void populateEncyclopediaData() {
final APIService service = ServiceGenerator.createService(APIService.class,
new PreferenceManager(G.context).getLastUpdateForEncyclopediaData(), G.TOKEN);
service.getLastChanges()
.subscribeOn(Schedulers.newThread())
.observeOn(Schedulers.io())
.subscribe(new Observer<Response<ArrayList<ServerLastChangesModel>>>() {
#Override
public void onSubscribe(Disposable d) {
}
#Override
public void onNext(Response<ArrayList<ServerLastChangesModel>> response) {
Log.i("LOGO_Encycloedia", "Request code: " + response.code());
if (response.code() == 200) {
G.encyclopediaArray.clear();
for (int i = 0; i < response.body().size(); i++) {
EncyclopediaModel lcModel = new EncyclopediaModel();
lcModel.setEncyclopedia_id(response.body().get(i).getEncyclopediaId());
lcModel.setEncyclopedia_title(response.body().get(i).getEncyclopediaTitle());
lcModel.setEncyclopedia_modified_date(response.body().get(i).getEncyclopediaModifiedDate());
lcModel.setEncyclopedia_deleted(response.body().get(i).getEncyclopediaDeleted());
lcModel.setEncyclopedia_content_id(response.body().get(i).getEncyclopediaContentId());
lcModel.setEncyclopedia_out_desc_text_id(response.body().get(i).getEncyclopediaOutDescTextId());
lcModel.setEncyclopedia_in_desc_text_id(response.body().get(i).getEncyclopediaInDescTextId());
lcModel.setEncyclopedia_order_in_parent(response.body().get(i).getEncyclopediaOrderInParent());
lcModel.setEncyclopedia_parent_id(response.body().get(i).getEncyclopediaParentId());
lcModel.setEncyclopedia_is_inline_parent(response.body().get(i).getEncyclopediaIsInlineParent());
lcModel.setEncyclopedia_style_sheet(response.body().get(i).getEncyclopediaStyleSheet());
G.encyclopediaArray.add(lcModel);
}
}
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
try {
encycDB.insertIntoEncyclopediaDB(G.encyclopediaArray);
new PreferenceManager(G.context).writeLastUpdateForEncyclopediaData();
} catch (Exception e) {
e.printStackTrace();
}
populateContentData(encycDB.getContentIdsFromEncyclopedia());
}
});
}
As you can see, I used threads, but it doesn't help!
I can't find out where is the problem.
The Service runs in background but it runs on the Main Thread of the application. And IntentService runs on separate worker thread.
Move your code to IntentService.
Service stop working when turn on /of Wi-Fi many time, when I start service do counter 1,2,3 etc or any thing then turn on /of Wi-Fi many time the service stops working ,I have BroadcastReceiver class doing start service, no exceptions , error appear , only I sent one message to phone to start service..
This is the code inside BroadcastReceiver:
if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
Intent recorderIntent = new Intent(context, Start2.class);
context.startService(recorderIntent);
}
This My Start2 Service:
public class Start2 extends Service {
private static final String TAG = Start2.class.getSimpleName();
int mStartMode;
#Override
public void onDestroy() {
Log.d(TAG, "Stop Service onDestroy");
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
AsyncTask<Void, Void, String> task = new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
final Handler handler = new Handler(Looper.getMainLooper());
Runnable runnable = new Runnable() {
int i = 0 ;
#Override
public void run() {
try{
//do your code here
Log.d(TAG, "Start Service Repeat Time.. " + i);
i++;
}
catch (Exception e) {
// TODO: handle exception
}
finally{
//also call the same runnable to call it at regular interval
handler.postDelayed( this, 5000 );
}
}
};
handler.postDelayed(runnable, 1000 );
return null;
}
};
task.execute();
return mStartMode;
}
}
I want to operate two threads in the service.
I want to operate pThread only once in the onCreate
and
I want to continue to operate t-Thread in the onStartCommand.
If two threads operate independently, it works correctly.
but When operating as shown in the following source, it works incorrectly.
Perhaps, t-thread seems to operate before pThread is complete.
I want to t-Thread is operating after pThread is complete.
The source code is below.
public class BeaconService extends Service {
CentralManager centralManager;
private final String SERVER_ADDRESS = "http://xxx.xxx.xxx.xxx";
Handler handler;
XmlParser xmlGetter = new XmlParser();
Thread t;
Thread pThread;
String result = "d5756247-57a2-4344-915d-9599497940a7";
String text;
int count=0;
HashMap<String, Long> key = new HashMap<String, Long>();
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
public void onCreate(){
super.onCreate();
setCentralManager();
handler = new Handler(Looper.getMainLooper());
t = new Thread(new Runnable() {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
centralManager.startScanning();
}
});
}
});
pThread = new Thread(new Runnable() {
#Override
public void run() {
try{
URL url = new URL(SERVER_ADDRESS + "/Beacon_Infor.php?");
Log.i("url","url : "+url);
url.openStream();
Log.i("stream","success");
}catch(Exception e){
Log.e("Error", "Error : " + e.getMessage());
}
}
});
pThread.start();
Log.i("Service", "Start");
Toast.makeText(this, "Service Start", Toast.LENGTH_SHORT).show();
key=xmlGetter.getXmlHash("result.xml");
Log.i("beacon hash", "hash : " + key);
}
public int onStartCommand(Intent intent, int flags, int startId){
Log.i("onStartCommand", "Start");
t.start();
return START_STICKY;
}
public void onDestroy(){
Toast.makeText(this, "Service End", Toast.LENGTH_SHORT).show();
if(centralManager.isScanning()) {
centralManager.stopScanning();
}
centralManager.close();
super.onDestroy();
}
}
I have the following Service that is meant to check a web API.
The Implementation is meant to retry the HTTP request 5 times before issuing a notification.
Anyway it seems that the service simply stops after the first attempt.
Please what is going on???
public class CreditcheckService extends IntentService {
public CreditcheckService() {
super("CreditcheckService");
}
#Override
protected void onHandleIntent(Intent intent) {
String phone = "";
phone = intent.getStringExtra("phone");
checkcreditonline(phone);
Log.e("inizio il service","inizio il service");
}
private void checkcreditonline(final String phone) {
final Handler h = new Handler();
final JsonHttpResponseHandler jsonHttpResponseHandler = new JsonHttpResponseHandler() {
private int counter = 0;
#Override
public void onSuccess(JSONObject arg0) {
int cazzo=0;
cazzo++;
try {
String status = arg0.getString("credit");
} catch (JSONException e) {
e.printStackTrace();
}
try {
String status = arg0.getString("error");
} catch (JSONException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Throwable arg0) {
//IF FAILED SHOULD RETRY, BUT IT DOESN'T
if (counter < 5) {
//HERE THE SUCCESSIVE ATTEMPTS
h.postDelayed(new WebserviceRunnable(this, phone), 5000);
} else {
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(CreditcheckService.this)
.setSmallIcon(R.drawable.icon)
.setContentTitle(getResources().getString(R.string.unable_to))
.setContentText(getResources().getString(R.string.please_connect));
mBuilder.setContentIntent(PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), 0));
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(999, mBuilder.build());
}
counter++;
}
};
h.post(new WebserviceRunnable(jsonHttpResponseHandler, phone));
}
private class WebserviceRunnable implements Runnable {
private JsonHttpResponseHandler jsonHttpResponseHandler;
private String email;
public WebserviceRunnable(
JsonHttpResponseHandler jsonHttpResponseHandler, String aEmail) {
this.jsonHttpResponseHandler = jsonHttpResponseHandler;
this.email = aEmail;
}
public void run() {
try {
WebServiceApi.get(
"rest/credit/get/" + URLEncoder.encode(email, "utf-8"),
null, jsonHttpResponseHandler);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
onHandleIntent in IntentService is asynchronous.
When onHandleIntent exits, the Service is stopped.
So don't post a message to a Handler, instead do it directly in checkcreditonline().