How do I access a variable from an intent download service? - android

I have created an intent download service and I want to pass download data to Toast and into Text in main activity. Download service should start from alarm manager repeatedly. How do I do this?
Currently, it does not show in Toast, but I have network traffic; data is downloaded but not shown.
Relevant code:
public class DownloadService extends IntentService {
public String response;
public DownloadService() {
super("DownloadService");
}
// Will be called asynchronously be Android
#Override
protected void onHandleIntent(Intent intent) {
//String urldown = intent.getStringExtra("url");
String urldown="http://......";
DefaultHttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(urldown);
try {
HttpResponse execute = client.execute(httpGet);
InputStream content = execute.getEntity().getContent();
BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
String s = "";
while ((s = buffer.readLine()) != null) {
response += s;
}
} catch (IOException e) {
e.printStackTrace();
}
Intent intentsend=new Intent("update");
intentsend.putExtra( "downdata",response);
sendBroadcast(intentsend);
}

This can be implemented with BroadcastReceiver:
In your activity, add the following code:
private BroadcastReceiver updateReceiver;
//...
#Override
protected void onResume() {
super.onResume();
updateReceiver=new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//get extras, do some stuff
}
};
IntentFilter updateIntentFilter=new IntentFilter("update");
registerReceiver(updateReceiver, updateIntentFilter);
}
#Override
protected void onPause() {
super.onPause();
if (this.updateReceiver!=null)
unregisterReceiver(updateReceiver);
}
And then, in your IntentService, just send broadcast with the same action:
Intent intent=new Intent("update");
intent.putExtra(...);
sendBroadcast(intent);

For me personally the receiver was not working so instead I created a singleton class where I was using the setter methods to set variables and the getter methods to get them to the particular activity.

Related

Error sending data using intent from class to MainActivity

In my MainActivity I need to know the state of a boolean type variable to hide or put an icon visible, but this variable is generated in another class called TcpClient which is called several times by the MainActivity, I am trying to use intent to send this variable from the TcpClient class but I have errors.
This is my code of my MainActivity:
public class MainActivity extends AppCompatActivity implements
NavigationView.OnNavigationItemSelectedListener {
private TcpClient mTcpClient;
public boolean statusWIFI = false;
.
.
public class ConnectTask extends AsyncTask<String, String, TcpClient> {
#Override
protected TcpClient doInBackground(String... message) {
mTcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
#Override
//here the messageReceived method is implemented
public void messageReceived(String message) { //we create a TCPClient object and
publishProgress(message); //this method calls the onProgressUpdate
}
});
mTcpClient.run();
return null;
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
//arrayList.add("RX: " + values[0]); //in the
arrayList we add the messaged received from server
mDumpTextView.append( values[0] );
mDumpTextView.append( "\n" );
mScrollView.smoothScrollTo( 0, mDumpTextView.getBottom() );
mAdapter.notifyDataSetChanged(); // notify the
adapter that the data set has changed. This means that new message
received
// from server was added to the list
}
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem IconWIFI = menu.findItem(R.id.bt1_wifi);
Intent intent = getIntent();
Bundle bundle = null;
bundle = getIntent().getExtras();
if (bundle !=null) {
statusWIFI = bundle.getBoolean( "mstatusWIFI");
}
if (statusWIFI == true){
IconUsbON.setVisible(true);
}else{
IconUsbON.setVisible(false);
}
return true;
}
This is the code of my TcpClient class:
public class TcpClient {
private Boolean statusWIFIX = false;
.
.
public void stopClient() {
statusWIFIX = false;
Intent intent = new Intent( this, MainActivity.class );
intent.putExtra( "mstatusWIFI", statusWIFIX );
startActivityForResult( intent, 0 );
sendMessage(Constants.CLOSED_CONNECTION+": " + Modelox);
// send message that we are closing the connection
mRun = false;
if (mBufferOut != null) {
mBufferOut.flush();
mBufferOut.close();
}
mMessageListener = null;
mBufferIn = null;
mBufferOut = null;
mServerMessage = null;
}
Here is the error; someone could tell me how to correct this
I did't see any initialization of mTcpClient, you need to initialize it like:
mTcpClient= TcpClient();
and if your variable is in TcpClient class you can access it via mTcpClient.statusWIFIX
You also need to make statusWIFIX scope to public like this:
public Boolean statusWIFIX = false;
in your TcpClient class.
You can also send data via intent but just for accessing statusWIFIX to start an activity again is not a good approach.
You must have to pass activity context into the Intent constructor. The TCPClient is not seems any activity or service.

How to get network status changes with BroadcastReceiver?

When I change from wi-fi to 3g or vice versa the my AsyncTask will cause a error. So I want to trace this and restart the loading progress(or stop and proceed the asynctask if possible) when this happens. I looked it up on google and find that the BroadcastReceiver onReceive is called when this happens. The problem now is that I still don't get the exact moment when this happens.
Oncreate
registerReceiver(mConnReceiver,new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
AsyncTask point of error(it's called on the HttpClient line):
#Override
protected String doInBackground(String... params)
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(params[0]);
try
{
if(!isCancelled())//I have set this after I found the error
{
HttpResponse response = httpclient.execute(httppost);
jsonResult = inputStreamToString(
response.getEntity().getContent()).toString();
}
}
The broadcastreceiver
private BroadcastReceiver mConnReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
boolean noConnectivity = intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
NetworkInfo changes = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
Log.w("current", "" + changes);
if(noConnectivity)
{
task.cancel(true);
task2.cancel(true);
task3.cancel(true);
}
Log.w("taskIsCanceled","" + task.isCancelled());
}
};
So I have two problems tracing the event of the error and restarting or stopping and proceeding the asynctaskes. I have 3 asynctaskes which take turns.
When I switch from 3g to wi-fi the noConnectivity boolean always returns that I have connection. While when I go from wi-fi to 3g it first returns that I dont and shortly after that I have(so that it connected).
You can use reflections to monitor mobile data changes.
public class NetworkStateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getExtras() != null){
final ConnectivityManager mConnectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
boolean mobileDataEnabled = false;
try{
Class cmClass = Class.forName(mConnectivityManager.getClass().getName());
Method method = cmClass.getDeclaredMethod("getMobileDataEnabled");
method.setAccessible(true); // Make the method callable
mobileDataEnabled = (Boolean)method.invoke(mConnectivityManager);
} catch(Exception e){
return;
}
Toast.makeText(BackroundService.this, "Data state changed", Toast.LENGTH_LONG).show();
}
}
}

Communicate with a WallpaperService

Is there any way to directly communicate with a WallpaperService from an Activity? It doesn't look like I can use the normal service communication classes because the onBind method is declared final in the WallpaperService class I'm extending. Worth noting that I'm referring to my WallpaperService not any.
Any workarounds if this isn't possible?
My solution was to use local sockets. I created an instance of a LocalServerSocket in the constructor of my wallpaper's Engine. Here's a quick implementation. Server runs on a separate thread and is directly tied to the lifecycle of MyEngine. The thread will stop when continueSocket is set to false. This happens onDestroy. Problem is that LocalServerSocket.accept() blocks until there's something to do. The workaround is to send a message to our own server so it will run through the loop again and check continueSocket (which is now false), closing the server. Check the closeSocketServer method. I have it running in onDestroy in the example but you might want to use it elsewhere like onSurfaceDestroyed and add your own sanity checks.
public class MyWallpaperService extends WallpaperService {
#Override
public Engine onCreateEngine() {
return new MyEngine();
}
private class MyEngine extends Engine {
private boolean continueSocket = true;
MyEngine() {
new Thread() {
#Override
public void run() {
try {
LocalServerSocket server = new LocalServerSocket("MyAddress");
Log.d("SERVER READY", "Server is ready.");
while(continueSocket) {
LocalSocket receiver = server.accept();
if(receiver != null) {
InputStream input = receiver.getInputStream();
byte[] data = IOUtils.toByteArray(input);
Log.d("GOT DATA", new String(data));
}
}
server.close();
} catch (IOException ex) {
Log.wtf("IOEXCEPTION", ex);
}
}
}.start();
}
#Override
public void onDestroy() {
closeSocketServer();
super.onDestroy();
}
private void closeSocketServer() {
continueSocket = false;
try {
LocalSocket socket = new LocalSocket();
socket.connect(new LocalSocketAddress("MyAddress"));
socket.getOutputStream().write(new byte[0]);
socket.getOutputStream().close();
socket.close();
} catch (IOException ex) {
//
}
}
}
}
And in my Activity it can be as simple as this...
try {
LocalSocket sender = new LocalSocket();
sender.connect(new LocalSocketAddress("MyAddress"));
String data = "Hello world!";
Log.d("SENT DATA", data);
sender.getOutputStream().write(data.getBytes());
sender.getOutputStream().close();
sender.close();
} catch (IOException ex) {
Log.wtf("IOEXCEPTION", ex);
}
Logcat ends up looking like this:
D/SERVER READY﹕ Server is ready. (when the wallpaper starts up)
D/SENT DATA﹕ Hello world! (when the activity sends data)
D/GOT DATA﹕ Hello world! (when the wallpaper gets the data)
In your WallpaperService onCreateEngine:
IntentFilter intentFilter = new IntentFilter("your.package.your.action");
MyBroadcastReceiver mReceiver = new MyBroadcastReceiver(mRenderer);
LocalBroadcastManager.getInstance(getApplicationContext())
.registerReceiver(mReceiver, intentFilter);
In mRenderer's class:
public void receiveCommand(int i) {
Log.d("got", String.valueOf(i));
}
Receiver class:
public class MyBroadcastReceiver extends BroadcastReceiver {
private final MyRenderer _mRenderer;
public MyBroadcastReceiver(MyRenderer mRenderer) {
_mRenderer = mRenderer;
}
#Override
public void onReceive(Context context, Intent intent) {
_mRenderer.receiveCommand(intent.getExtra("msg", -1));
}
}
Now call from activity:
Intent in = new Intent();
in.setAction("your.package.your.action");
in.setExtra("msg", 42);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(in);

query regarding image upload in android

When a button is clicked in my android application, it will open the camera application. When a picture is taken in the camera application, the picture is uploaded to server.
PROBLEM: When the picture is taken and "SAVE" is clicked in the camera application, it is not returning to the application until the picture is uploaded to the server.
This is because I am waiting for the Thread that is uploading the image to complete.
How to solve this problem? I want it to return to the application from the camera application and want to show a ProgressBar.
For that my procedure is :
--> Using Intent to open camera application like this:
Intent CameraIntent =new Intent("android.media.action.IMAGE_CAPTURE");
startActivityForResult(CameraIntent,CAMERA_PIC_REQUEST);
--> In the method onActivityResult(int requestCode, int resultCode, Intent data), I wrote the following code. I am encoding the image in Base64 and calling a Thread which uploads the Base64 encoded image to the server.
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==CAMERA_PIC_REQUEST)
{
ThumbNail=(Bitmap) data.getExtras().get("data");
ba=new ByteArrayOutputStream();
ThumbNail.compress(Bitmap.CompressFormat.JPEG,100,ba);
barray=ba.toByteArray();
str_img=Base64.encodeToString(barray,Base64.DEFAULT);
if(resultCode==Activity.RESULT_OK )
{
upload_image = new ThreadUploadImage(str_img);
upload_image.start();
while(upload_image.isAlive())
{
Thread.sleep(100);
}
}
}
}
ThreadUploadImage.java
public class ThreadUploadImage extends Thread {
String str_img,result;
String port=null,ip_addr=null;
public ThreadUploadImage(String str_img)
{
this.str_img=str_img;
}
public void run()
{
try
{
HttpClient client =new DefaultHttpClient();
ip_addr=StaticVariables.ip_addr;
port=StaticVariables.port;
if(ip_addr!=null && port!=null)
{
List<NameValuePair> l =new ArrayList<NameValuePair>();
l.add(new BasicNameValuePair("img_str",str_img));
post.setEntity(new UrlEncodedFormEntity(l));
HttpResponse response=client.execute(post);
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
for (String line = null; (line = reader.readLine()) != null;) {
builder.append(line).append("\n");
}
this.result = builder.toString();
Log.e("result_is",result);
} catch(Exception e) {
e.printStackTrace();
}
}
}
PROBLEM: When the picture is Taken and "SAVE" is clicked in the camera application, it is not returning to the application until the picture is uploaded to the server.
This is because I am waiting for the Thread which is uploading the image.
How to solve this problem? I want it to return to the application from the camera application and I want to show a ProgressBar.
Remove the waiting for the Thread to finish.
Remove this:
while(upload_image.isAlive())
{
Thread.sleep(100);
}
If you need to block the user from doing anything and if you need to inform him when the upload is finished, then you should put up a ProgressDialog with an indeterminate progress indicator (i.e. spinning wait icon).
When the Thread is complete, then you need to inform you Activity via simple callback or broadcast and dismiss() the ProgressDialog.
Callback Example:
public static interface MyCallback {
public void finished(final boolean success);
}
Your Activity 'implements' MyCallback:
public class MyActivity implements MyCallback {
...
public void finished(final boolean success) {
if(success) {
// Upload was successful!
} else {
// Upload failed.
}
}
}
Your ThreadUploadImage class must own a MyCallback object, and it must get set as a parameter in the constructor. Then, when the Thread finishes, you should call mCallback.finished().
public class ThreadUploadImage extends Thread {
String str_img,result;
String port=null,ip_addr=null;
final MyCallback mCallback;
public ThreadUploadImage(String str_img, final MyCallback callback)
{
this.str_img=str_img;
mCallback = callback;
}
public void run()
{
try
{
HttpClient client =new DefaultHttpClient();
...
Log.e("result_is",result);
mCallback.finished(true);
} catch(Exception e) {
e.printStackTrace();
mCallback.finished(false);
}
}
}

Android Local Service Architecture

I'm trying to implement a service to handle the communication with the server for the following code. I don't know much about the design architecture for these.
Here is my service class
public class BgService extends Service {
private static final String TAG = BgService.class.getSimpleName();
private Timer timer;
SendJsonRequest sjr;
private TimerTask updateTask = new TimerTask(){
#Override
public void run(){
try{
SendJsonRequest sjr = new SendJsonRequest();
sjr.carMake();
Log.i(TAG, "LOOK AT ME");
}
catch(Exception e){
Log.w(TAG,e);
}
}
};
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate(){
super.onCreate();
Log.i(TAG, "Service creating");
timer = new Timer("Server listening timer");
timer.schedule(updateTask, 1000L, 60*1000L);
}
#Override
public void onDestroy(){
super.onDestroy();
Log.i(TAG, "Service Destroying");
timer.cancel();
timer = null;
}
}
Here is my SendJsonRequest class
public class SendJsonRequest{
private static final String TAG = "SendJsonRequest";
private static String URL = "xxxxxxxxx";
private static String infoRec;
public static void createJsonObj(String path, Map x){
infoRec = CreateJsonRequest.jsonRequest(URL+path, x );
System.out.println(infoRec);
}
public static void carMake(){
String path = "/CarMake";
Map<String, Object> z = new HashMap<String,Object>();
z.put("Name", "Ford");
z.put("Model", "Mustang");
createJsonObj(path, z);
}
}
Here is my CreateJsonObject class
public class CreateJsonRequest {
public static String jsonRequest(String URL, Map<String,Object> params){
try{
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(URL);
JSONObject holder = new JSONObject();
for (Map.Entry<String, Object> m : params.entrySet()){
try {
holder.put(m.getKey(), m.getValue());
}
catch (JSONException e) {
Log.e("Hmmmm", "JSONException : "+e);
}
}
StringEntity se;
se = new StringEntity(holder.toString());
httpPost.setEntity(se);
httpPost.setHeader("Accept", "text/json");
httpPost.setHeader("Content-type", "text/json");
HttpResponse response = (HttpResponse) httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
if(entity != null){
InputStream is = entity.getContent();
Header contentEncoding = response.getFirstHeader("Content-Encoding");
String result= convertToString(is);
is.close();
System.out.println(result);
return result;
}
}
catch(Exception e)
{
e.printStackTrace();
}
return null;
}
Sorry for the massive amount of code. How I implemented my service is obviously not correct, I just have no clue where to start to get a service handling the json requests to the server. Thanks in advance.
To be more clear, this did work on a button click, now I'm trying to get it to all run in the background with the service. So I guess my question is what goes where in the service?
My activity successfully starts the service, the service would work and print "look at me" to the logcat every minute. Then I added the try{ sjr.carMake()} and it catches an exception.
You can use a broadcast receiver. This is a way to have your code start at certain times indicated by Android OS - for example, you can have it start when Android finished booting up (this is where I run my services usually.
The best way is to use the AlarmManager class, and tell your service how often to run.
Tell us more about what you're trying to do, and what the problem is, and we can give you a more concise answer...
UPDATE:
Have you created an entry in the manifest.xml file for the service?
UPDATE
Here is how I'm doing it in my application. This is your "hook" to the OS. It's going to fire when it finishes booting (don't forget to make in entry in the manifest for this!)
public class TmBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent bootintent) {
try{
Log.i("Taskmotion-ROBOT", "Robot Broadcast signal received on Boot. Trying to start Alarm scheduler");
Intent mServiceIntent = new Intent(context, ServiceAlarm.class);
context.startService(mServiceIntent);
}
catch(Exception e)
{
Log.i("Taskmotion", "Failed to start service...");
}
}
}
This Broadcast receiver calls a service that implements the AlarmManager class. The alarm manager sets up a schedule to run my service at a specified interval. Note that the alarms are deleted when the phone is shut down - but then recreated again when process is repeated as the phone boots back up and runs the BroadcastReceiver again.
public class ServiceAlarm extends Service {
private PendingIntent mAlarmSender;
#Override
public void onCreate() {
try{
Log.i("Taskmotion-ROBOT", "Setting Service Alarm Step 1");
mAlarmSender = PendingIntent.getService(this.getApplicationContext(),
0, new Intent(this.getApplicationContext(), BackgroundService.class), 0);
}
catch(Exception e)
{
Log.i("Taskmotion-ROBOT", "Problem at 1 :" + e.toString());
}
long firstTime = SystemClock.elapsedRealtime();
Log.i("Taskmotion-ROBOT", "Setting Service Alarm Step 2");
// Schedule the alarm!
AlarmManager am = (AlarmManager)getSystemService(ALARM_SERVICE);
am.setRepeating(AlarmManager.ELAPSED_REALTIME,
firstTime, AlarmManager.INTERVAL_HOUR, mAlarmSender);
this.stopSelf();
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
I haven't refactored this code yet, it was my first go at it. I see now that I'm looking at it again that I could probably do the scheduling inside the BroadcastReceiver, but for the sake of getting you something that works, I'll continue.
As indicated by AlarmManager.INTERVAL_HOUR, my service will run once an hour. The service that I want to run is defined in the pendingIntent (BackgroundService.class). This is where you put your own service class.
I reworked your service class for you, and removed the timer (functionality replaced by the BroadcastReceiver & AlarmManager).
public class BgService extends Service {
private static final String TAG = BgService.class.getSimpleName();
SendJsonRequest sjr;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate(){
super.onCreate();
Log.i(TAG, "Service creating");
//DO YOUR WORK WITH YOUR JSON CLASS HERE
//**************************************
//Make sure to call stopSelf() or your service will run in the background, chewing up
//battery life like rocky mountain oysters!
this.stopSelf();
}
#Override
public void onDestroy(){
super.onDestroy();
}
}

Categories

Resources