Keeping a Client Socket alive between activities using a Service - java

I want to enter an IP address and port of a server using editText in Android studio. When a "connect" button is pressed, the entered information should be saved and be accessible to other activities. I have used the SharedPreferences method for saving the acquired data to be accessible across activities (Is this the best way to do so?). The successful creation of a client socket (handled in the service) is checked in the Connect activity (attached below) by means of (!client.isClosed()).
My problem is that whenever the activity reaches the check in the Connect.java activity, the isclosed is nullified. I assume that the client Socket is thus destroyed when it was created in the Service and called in the Connect.java activity.
Is there a way to create the Socket and keep it alive to be used by various other activities- I require the socket to be kept alive to receive/send messages to a server which will determine to which activity the App should transition. The method of creating and closing sockets in every activity will not work as it will be registered as a new user on the server side- firmware on a module I have no access to.
Any examples/documentation/help would be greatly appreciated.
I am very new to Android App development and Java so please be gentle if my questions are stupid :-)
Thank you very much for any assistance.
This is the service for handling the socket creation.
import android.app.IntentService;
import android.content.Intent;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.StrictMode;
import android.util.Log;
import java.io.IOException;
import java.net.Socket;
public class SocketService extends IntentService
{
public Socket client;
public String ClientIP;
public Integer ClientPORT=0;
public SocketService()
{
super("SocketService");
}
#Override
protected void onHandleIntent(Intent Socketintent)
{
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
SharedPreferences savednotes= getSharedPreferences("Socket_NAME",
Context.MODE_MULTI_PROCESS);
ClientIP=savednotes.getString("IP_NAME",null); // Get the IP address
ClientPORT=savednotes.getInt("PORT_NAME",0); // Get the Port number
try
{
Log.d("IP", "Master IP address:" + ClientIP); // Debug to see
variables in Shared preferences
Log.d("PORT", "Port number: " + ClientPORT); // Debug to see
variables in Shared preferences
if ((ClientIP) != null)
{
if ((ClientPORT) != null)
{
client = new Socket(ClientIP, ClientPORT); // Create the Socket
}
}
} catch (IOException e)
{
e.printStackTrace();
try {
client.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
This is the Connect.java activity:
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.StrictMode;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.PrintWriter;
import java.net.Socket;
public class Connect extends AppCompatActivity
{
public Socket client;
private EditText etIP, etPORT;
private TextView status,IPs;
private Button buttonCON;
public int port=0;
public String IP;
SharedPreferences savednotes;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
StrictMode.ThreadPolicy policy = new
StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
setContentView(R.layout.activity_connect);
etIP = (EditText)findViewById(R.id.editTextIP);
etPORT = (EditText)findViewById(R.id.editText2);
buttonCON= (Button)findViewById(R.id.buttonCON);
status= (TextView)findViewById(R.id.textStatus);
IPs=(TextView)findViewById(R.id.textViewIP);
status.setText("Disconnected");
buttonCON.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
port = Integer.parseInt(etPORT.getText().toString());
IP= etIP.getText().toString();
IPs.setText(IP);
savednotes=
getApplicationContext().getSharedPreferences("Socket_NAME",
Context.MODE_MULTI_PROCESS);
SharedPreferences.Editor editor= savednotes.edit();
editor.putString("IP_NAME",IP);
editor.apply();
editor.putInt("PORT_NAME",port);
editor.apply();
Intent Socketintent= new Intent(Connect.this, SocketService.class);
startService(Socketintent);
int i = 0xFF00EE00;
status.setTextColor(i);
status.setText("Connected");
if (!client.isClosed())
{
Intent relay= new Intent(Connect.this, Relay.class);
startActivity(relay);
finish();
}
}
});
}
}

An IntentService is not a suitable solution for your objective. An IntentService is destroyed as soon as onHandleIntent() returns.
Most likely, you do not need any sort of Service here. A Service is for when you want to be doing work when you have no UI in the foreground, and that does not sound like your case here ("Keeping a Client Socket alive between activities"). An ordinary Java singleton would work, so long as you are very careful not to introduce memory leaks.
The method of creating and closing sockets in every activity will not work as it will be registered as a new user on the server side- firmware on a module I have no access to.
Bear in mind that your process does not live forever. Eventually, you will need to create a new socket.

Related

Trying to send data over WiFi to an ESP32 from an Android app - Data seemingly not sending

I'm more OK with the C++ on the ESP32 (arduino IDE) than I am with the Java of the Android app so I think the problem is laying with the Java code not actually sending any data.
Here is expected behaviour:
ESP32 initiates as an access point (they have all have WiFi chips so can be programmed as so)
Android devices goes to network settings and connects to the ESP32 hotspot/access point
Android device goes back to the app and presses a button to send a string of data
ESP32 is listening for any data ending with '\n' to then blink an onboard LED. In the case of my Java code the code for sending is using the PrintWriter class and the println method (meaning any data sent will have '\n' as a suffix
I made the APK today and installed it on an android phone, fired up the ESP32 and checked the serial monitor to make sure the IP is the same as what I have specified in the Java code, the port (80) is also the same.
I connect to the ESP32 from my Android device and go back to the app, press the button and nothing happens. The serial monitor in the Arduino IDE for the ESP32 is also showing nothing (it should print the received data).
So I'll paste the Java code, which is where I think the error might be. As you can see I am trying to send "Hello ESP32" as a string.
package com.benledmatrix.esp32controloverwifi;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set up a button to send data when clicked
Button sendButton = findViewById(R.id.send_button);
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sendData();
}
});
}
private void sendData() {
// Set up a thread to send the data in the background
new Thread(new Runnable() {
#Override
public void run() {
try {
// Connect to the ESP32's IP address and port
Socket socket = new Socket("192.168.4.1", 80);
PrintWriter out = new PrintWriter(socket.getOutputStream());
// Send the data
out.println("Hello, ESP32!");
out.flush();
// Close the connection
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
And here is the Arduino C++ code that is on the ESP32
#include <WiFi.h>
const char* ssid = "ESP32 HotSpot";
const char* password = "password";
WiFiServer server(80); // Create a server on port 80
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password);
Serial.print("IP address: ");
Serial.println(WiFi.softAPIP());
server.begin(); // Start the server
pinMode(2, OUTPUT); // Set onboard LED as an output
}
void loop() {
WiFiClient client = server.available(); // Listen for incoming clients
if (client) { // If a client connects
String data = client.readStringUntil('\n'); // Read the data from the client
Serial.println(data); // Print the data to the serial monitor
if (data == "Hello, ESP32!") { // If the data is "Hello, ESP32!"
// Flash the onboard LED twice
for (int i = 0; i < 2; i++) {
digitalWrite(2, HIGH);
delay(200);
digitalWrite(2, LOW);
delay(200);
}
} else {
// Flash the onboard LED once
digitalWrite(2, HIGH);
delay(200);
digitalWrite(2, LOW);
delay(200);
}
client.stop(); // Disconnect the client
}
}
And just in case I am being a complete div here is the XML code for the button :D you never know
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/send_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="#008080"
android:text="Send Data" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Sorry for such a dump but as I'm not that experienced with Android I thought it best to put everything in there. It compiles fine and no bugs found but just doesn't do the desired action.
If someone has an idea I will try it.
Many thanks
Ben
After much research I have a functioning code that, when pressing the "Send Data" button on the Android app, it blinks the onboard LED of the ESP32 twice to signify it has received the string. Very happy!
In the end the reason was I did not have any permission to use the internet. I used the USB debugging and put in some log.d and it showed me I didn't have access to use the internet so putting in that permission and some toast messages to check the permission fixed it.
C++ and XML code remained the same but in the Android XML manifest file I added:
<uses-permission android:name="android.permission.INTERNET" />
And the final Java code is as follows:
package com.benledmatrix.esp32controloverwifi;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
public class MainActivity extends AppCompatActivity {
private static final int PERMISSION_REQUEST_CODE = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Check for Internet permission for SDK 23 or higher
if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.INTERNET)) {
//rationale to display why the permission is needed
Toast.makeText(this, "The app needs access to the Internet to send data to the ESP32", Toast.LENGTH_SHORT).show();
}
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.INTERNET}, PERMISSION_REQUEST_CODE);
}
// Set up a button to send data when clicked
Button sendButton = findViewById(R.id.send_button);
sendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
sendData();
}
});
}
//Check for result of permissions and feedback accordingly
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, you can perform the network operation here
Log.d("Permission", "Granted");
} else {
// Permission denied, show a message to the user
Log.d("Permission", "Denied");
Toast.makeText(this, "Permission denied, you cannot perform network operations", Toast.LENGTH_SHORT).show();
}
}
}
private void sendData() {
// Set up a thread to send the data in the background
new Thread(new Runnable() {
#Override
public void run() {
try {
// Connect to the ESP32's IP address and port
Log.d("Sending Data", "Button Pressed, connecting to ESP32.....");
Socket socket = new Socket("192.168.4.1", 80);
PrintWriter out = new PrintWriter(socket.getOutputStream());
// Send the data
out.println("Hello, ESP32!");
out.flush();
Log.d("Sending Data", "Data Sent!");
// Close the connection
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
Log.e("Sending Data", "Error Sending Data: "+e.getMessage());
}
}
}).start();
}
}
Of course any further advice on things I perhaps don't need or improvements I could make would be great.
Many thanks
Ben

How to create service Detaction call always running after killed app over api 26 in android studio java

i am using this code
and this code running if app active in screen
and if closed the code is not running
how to fix this like truecaller app is running in background if killed app
package com.islamelwakeel.detectcall;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.Gravity;
import android.widget.Toast;
public class CallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
showToast(context,"Call started...");
}
else if(intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_IDLE)){
showToast(context,"Call ended...");
}
else if(intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)){
showToast(context,"Incoming call...");
Log.d("call","Incoming call...");
}
}
void showToast(Context context,String message){
Toast toast=Toast.makeText(context,message,Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER,0,0);
toast.show();
}
}
My service was also killed. I tried many methods, but I discovered one method that worked. I used a service that receives calls from the system to check if my service is still running. If it doesn't work, start it. New Service. For example, NotificationListenerService will have it. There will be some events all the time. And I can write code to restart my service there
Ex.
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
if(!isMyserviceRunning){
startService();
}
}

Android Socket Connection Test [duplicate]

This question already has answers here:
NetworkOnMainThreadException [duplicate]
(5 answers)
Closed 6 years ago.
I'm trying to test if my Android App is connecting to a Rpi hot spot. I'm following this guide for the client code.
I want to have a toast message pop up depending on the state of socket.isConnected() when I hit a button. However, I think each time I try and implement it, I run into Network on the main thread problems. How could I change the following code to add a simple "if(true), send toast message" using the isConnected method in the onClick?
Thank you for any help!
package mrxhaleenterprise.sockettest;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
private Socket socket;
private static final int SERVERPORT = 39169;
private static final String SERVER_IP = "172.24.1.1";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new ClientThread()).start();
}
public void onClick(View view) {
try {
EditText et = (EditText) findViewById(R.id.EditText01);
String str = et.getText().toString();
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
out.println(str);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
class ClientThread implements Runnable {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
onClick is called on main Thread.So you are writing to socket(Network Operation) on main thread which is causing problem. Your below code should run on background thread.
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
out.println(str);
I want to have a toast message pop up depending on the state of socket.isConnected() when I hit a button.
No you don't. Once you've constructed that Socket, it is connected, and that method won't magically start returning false if the connection goes down. You need to maintain your own state of the connection, depending on whether you've encountered an IOException or end of stream on it. More probably you don't want the button at all, you want to pop up an error dialogue when the disconnect happens.

Bluetooth Sends Sensor Data Only once

So for my research, I have to send accelometer data to an arduino mega as a constant stream. I have the module connected to the arduino via serial. However, when I ran the code, it only runs once. I tried to place the Bluetooth connect part of the code inside my on accuracy change part of my code, but it keeps freezing the device. Here's my code:
package com.example.arduino_bluetooth2;
//=================================================================================================
//Imports
//=================================================================================================
import java.io.IOException;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;
import android.os.Bundle;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.Menu;
import android.widget.TextView;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
public class MainActivity extends Activity implements SensorEventListener {
// Setup necessary sensor objects
private Sensor acc;
private SensorManager sm;
private TextView t1;
private double value;
// Bluetooth Object
private BluetoothAdapter bAdapter;
private BluetoothDevice device;
private BluetoothSocket mmServerSocket;
private OutputStream btoutput;
private static final UUID SPP_UUID = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
private static final int DISCOVERY_REQUEST = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
accelerometer_initialization();
bluetooth_initialization();
}
// Setsup the accelerometer object
private void accelerometer_initialization() {
sm = (SensorManager) getSystemService(SENSOR_SERVICE);
acc = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sm.registerListener(this, acc, SensorManager.SENSOR_DELAY_NORMAL);
}
// Setup bluetooth object
private void bluetooth_initialization() {
bAdapter = BluetoothAdapter.getDefaultAdapter();
startActivityForResult(new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE),
DISCOVERY_REQUEST);
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter);
bAdapter.startDiscovery();
}
#Override
public void onSensorChanged(SensorEvent event) {
value = event.values[0];
}
#Override
public void onAccuracyChanged(Sensor arg0, int arg1) {
}
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) {
device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (new String(device.getName()).equals("BT UART")) {
bAdapter.cancelDiscovery();
try {
BluetoothSocket test = null;
test = device
.createInsecureRfcommSocketToServiceRecord(SPP_UUID);
mmServerSocket = test;
mmServerSocket.connect();
String message = Double.toString(value);
byte[] send = message.getBytes();
btoutput = mmServerSocket.getOutputStream();
btoutput.write(send);
btoutput.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
};
}
I am not sure you should creating and connecting the bluetooth socket in the broadcast receiver. I do the bluetooth connection management in the onResume() of the activity.
Also I use a thread to manage getting data from the serial data connection between the arduino and the device, it is spawned off and runs continuously in the background. There is a write method to send data out that i call from the activity
/* Call this from the main activity to send data to the remote device */
public void write(String message) {
System.out.println("...Data to send: " + message + "...");
byte[] msgBuffer = message.getBytes();
try {
mmOutStream.write(msgBuffer);
} catch (IOException e) {
System.out.println("...Error data send: " + e.getMessage() + "...");
}
}
then the run() method of the tread takes care of getting data back
See my answer in this thread for an example
Error with receiving xml strings via bluetooth in Android
Good luck!
Check out this page from arduino: http://arduino.cc/en/Reference/Loop
The problem is that it only goes once because it is not in a loop that continues forever until the device is shut off or told otherwise.

android.os.NetworkOnMainThreadException -- Twitter Client for Android

I using a tutorial from tutsplus.com on building a twitter client for Android. I've built the entire application and when I run it, the following error appears in logcat for Eclipse.
android.os.NetworkOnMainThreadException -- reading a few things, it has to deal with the API level I'm calling. Currently I'm building for 4.0.3 which is API 15. After API 11, you are not allowed to do network calls in the same thread as the UI. The reason behind this is not to stall or crash the UI. Networking calls must be in an AsyncTask or Service.
Long and short of my question/problem/issue is that the tutorial maker is of no help to correct the problem, so that's why I'm here. I'm posting the code below, in hopes that someone can help me move the network portion into an AsyncTask or Service.
package com.jasonsdesign.tweetxy;
import twitter4j.ProfileImage;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.AccessToken;
import twitter4j.auth.RequestToken;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
public class TweetxyActivity extends Activity implements OnClickListener {
/**developer account key for this app*/
public final static String TWIT_KEY = "";
/**developer secret for the app*/
public final static String TWIT_SECRET = "";
/**app url*/
public final static String TWIT_URL = "tweetxy-android:///";
private String LOG_TAG = "TweetxyActivity";
/**Twitter instance*/
private Twitter tweetxyTwitter;
/**request token for accessing user account*/
private RequestToken tweetxyRequestToken;
/**shared preferences to store user details*/
private SharedPreferences tweetxyPrefs;
/**main view for the home timeline*/
private ListView homeTimeline;
/**database helper for update data*/
private TweetxyDataHelper timelineHelper;
/**update database*/
private SQLiteDatabase timelineDB;
/**cursor for handling data*/
private Cursor timelineCursor;
/**adapter for mapping data*/
private UpdateAdapter timelineAdapter;
/**broadcast receiver for when new updates are available*/
private BroadcastReceiver tweetxyStatusReceiver;
//set the profile image display
ProfileImage.ImageSize imageSize = ProfileImage.NORMAL;
/*
* onCreate behaves differently on first run and subsequent runs
* - if first run take to Twitter sign in page to grant the app permission
* - subsequent runs fetch and present the user home timeline
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//get the preferences
tweetxyPrefs = getSharedPreferences("TweetxyPrefs", 0);
//find out if the user preferences are set
if(tweetxyPrefs.getString("user_token", null)==null) {
//no user preferences so prompt to sign in
setContentView(R.layout.main);
//get a twitter instance for authentication
tweetxyTwitter = new TwitterFactory().getInstance();
//pass developer key and secret
tweetxyTwitter.setOAuthConsumer(TWIT_KEY, TWIT_SECRET);
//try to get request token
try
{
//get authentication request token
tweetxyRequestToken = tweetxyTwitter.getOAuthRequestToken(TWIT_URL);
}
catch(TwitterException te) { Log.e(LOG_TAG, "TE "+te.getMessage()); }
//setup button for click listener
Button signIn = (Button)findViewById(R.id.signin);
signIn.setOnClickListener(this);
}
else
{
//user preferences are set - get timeline
setupTimeline();
}
}
/**
* Click listener handles sign in and tweet button presses
*/
public void onClick(View v) {
//find view
switch(v.getId()) {
//sign in button pressed
case R.id.signin:
//take user to twitter authentication web page to allow app access to their twitter account
String authURL = tweetxyRequestToken.getAuthenticationURL();
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authURL)));
break;
//user has pressed tweet button
case R.id.tweetbtn:
//launch tweet activity
startActivity(new Intent(this, TweetxyTweet.class));
break;
default:
break;
}
}
/*
* onNewIntent fires when user returns from Twitter authentication Web page
*/
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//get the retrieved data
Uri twitURI = intent.getData();
//make sure the url is correct
if(twitURI!=null && twitURI.toString().startsWith(TWIT_URL))
{
//is verification - get the returned data
String oaVerifier = twitURI.getQueryParameter("oauth_verifier");
//attempt to retrieve access token
try
{
//try to get an access token using the returned data from the verification page
AccessToken accToken = tweetxyTwitter.getOAuthAccessToken(tweetxyRequestToken, oaVerifier);
//add the token and secret to shared prefs for future reference
tweetxyPrefs.edit()
.putString("user_token", accToken.getToken())
.putString("user_secret", accToken.getTokenSecret())
.commit();
//display the timeline
setupTimeline();
}
catch (TwitterException te)
{ Log.e(LOG_TAG, "Failed to get access token: "+te.getMessage()); }
}
}
/**
* setupTimeline displays the user's main home Twitter timeline
*/
private void setupTimeline() {
//set the layout
setContentView(R.layout.timeline);
//setup onclick listener for tweet button
LinearLayout tweetClicker = (LinearLayout)findViewById(R.id.tweetbtn);
tweetClicker.setOnClickListener(this);
//retrieve the timeline
try
{
//get reference to the list view
homeTimeline = (ListView)findViewById(R.id.homeList);
//instantiate database helper
timelineHelper = new TweetxyDataHelper(this);
//get the database
timelineDB = timelineHelper.getReadableDatabase();
//query the database, most recent tweets first
timelineCursor = timelineDB.query("home", null, null, null, null, null, "update_time DESC");
//manage the updates using a cursor
startManagingCursor(timelineCursor);
//instantiate adapter
timelineAdapter = new UpdateAdapter(this, timelineCursor);
//apply the adapter to the timeline view
//this will make it populate the new update data in the view
homeTimeline.setAdapter(timelineAdapter);
//instantiate receiver class for finding out when new updates are available
tweetxyStatusReceiver = new TwitterUpdateReceiver();
//register for updates
registerReceiver(tweetxyStatusReceiver, new IntentFilter("TWITTER_UPDATES"));
//start the service for updates now
this.getApplicationContext().startService(new Intent(this.getApplicationContext(), TimelineService.class));
}
catch(Exception te) { Log.e(LOG_TAG, "Failed to fetch timeline: "+te.getMessage()); }
}
/**
* Class to implement broadcast receipt for new updates
*/
class TwitterUpdateReceiver extends BroadcastReceiver
{
/**
* When new updates are available, a broadcast is received here
*/
#Override
public void onReceive(Context context, Intent intent) {
//delete db rows
int rowLimit = 100;
if(DatabaseUtils.queryNumEntries(timelineDB, "home")>rowLimit) {
String deleteQuery = "DELETE FROM home WHERE "+BaseColumns._ID+" NOT IN " +
"(SELECT "+BaseColumns._ID+" FROM home ORDER BY "+"update_time DESC " +
"limit "+rowLimit+")";
timelineDB.execSQL(deleteQuery);
}
timelineCursor = timelineDB.query("home", null, null, null, null, null, "update_time DESC");
startManagingCursor(timelineCursor);
timelineAdapter = new UpdateAdapter(context, timelineCursor);
homeTimeline.setAdapter(timelineAdapter);
}
}
/*
* When the class is destroyed, close database and service classes
*/
#Override
public void onDestroy() {
super.onDestroy();
try
{
//stop the updater service
stopService(new Intent(this, TimelineService.class));
//remove receiver register
unregisterReceiver(tweetxyStatusReceiver);
//close the database
timelineDB.close();
}
catch(Exception se) { Log.e(LOG_TAG, "unable to stop service or receiver"); }
}
}
What do you need besides what https://developer.android.com/reference/android/os/AsyncTask.html provides? Do you have a specific question regarding the usage of AsyncTask?
You take the offending line and put it inside doInBackground(). If it has a result you either put the result handling code in doInBackground(), if it does not manipulate the UI. If it does make changes to the UI, you put it in onPostExecute().
Then you replace the line that threw the exception with:
new MyTask().execute(param);
Keep in mind that the code after this is executed immediately.
I don't see a need for your question to be held up, most of the issues you face at the moment are solvable through the AsyncTask use that is so well documented over Here.
I'd suggest you don't use the tutorial as a framework to your app/project but rather use it as a guide to know how to set your own project up. It'll be way better if you create your own AsyncTask and use that to get data from the network as getting network related data in a main task or most tasks besides AsynTasks is usually frowned upon due to the exceptions it throws.

Categories

Resources