I want to fetch articles from a feed and display them in TextViews, and I have been told to use IntentService to fetch the feed from the Internet so the app doesn't freeze, but I don't really get how to use it, and searching Google doesn't give any good examples.
Could someone explain this please? This is my IntentService sofar:
Code:
private class FetchFeed extends IntentService {
public FetchFeed() {
super("Lifehacker Fetch Feed");
// TODO Auto-generated constructor stub
}
@Override
protected void onHandleIntent(Intent intent) {
List<Message> messages = null;
try{
BaseFeedParser parser = new BaseFeedParser();
messages = parser.parse();
List<String> titles = new ArrayList<String>(messages.size());
for (Message msg : messages){
titles.add(msg.getTitle());
}
} catch (Throwable t){
Log.e("AndroidNews",t.getMessage(),t);
}
}
}
Related
Hi,
I am trying to write simple cache class. Class uses SoftReference in order to avoid killing application.
Code:
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
public class MemoryCache {
// singleton implemtation
private static MemoryCache instance = null;
protected MemoryCache() { }
public static MemoryCache getInstance() {
if(instance == null) {
instance = new MemoryCache();
}
return instance;
}
//
private Map<String, SoftReference<Object>> cachedItems = new HashMap<String, SoftReference<Object>>();
public void saveCacheItem(String itemId, Object objForCache) {
cachedItems.put(itemId, new SoftReference<Object>(objForCache));
}
public Object getCacheItem(String itemId) {
if(cacheItemExists(itemId)) {
return cachedItems.get(itemId).get();
}
else {
return null;
}
}
public Boolean cacheItemExists(String itemId) {
if(cachedItems.containsKey(itemId)) {
if(cachedItems.get(itemId) != null ) {
return true;
}
}
return false;
}
public void deleteCacheItem(String itemId) {
if(cachedItems.containsKey(itemId)) {
cachedItems.remove(itemId);
}
}
}
However, referenced objects are cleaned too early. Even though cached item is a class with just few attributes, its lifespan is very short.
I tested this functionality only on android emulator.
Does my class cause problem or garbage collector/vm?
I am writing an IRC Client, and so far as long as I dont send the app to the background and try to restore it it works fine. Tabs for multiple channels, the connected socket is in a bound service (started separately via INTENT and a startService call), etc and so on.
However, whenever I send the app to the background, then bring it back forward, the socket closes. I would have the same issue with screen rotation but I found the config setting that stops it from going through destroy/create on rotation. If I figure this out I may actually get rid of that since the issue will have been solved.
The other issue I seem to be having is that it takes a long time to re-bind to the service, and I have no idea why (the initial binding and startup is pretty quick, but re-binding to it seems to take forever, and when It does re-bind, the socket is closed).
Here are the code samples that I feel to be relevant, let me know if there's something more specific you want to see.
Code:
//This is the Service in question
public class ConnectionService extends Service{
private BlockingQueue<String> MessageQueue;
public final IBinder myBind = new ConnectionBinder();
public class ConnectionBinder extends Binder {
ConnectionService getService() {
return ConnectionService.this;
}
}
private Socket socket;
private BufferedWriter writer;
private BufferedReader reader;
private IRCServer server;
private WifiManager.WifiLock wLock;
private Thread readThread = new Thread(new Runnable() {
@Override
public void run() {
try {
String line;
while ((line = reader.readLine( )) != null) {
//message parsing stuff
}
}
catch (Exception e) {}
}
});
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(MessageQueue == null)
MessageQueue = new LinkedBlockingQueue<String>();
return Service.START_STICKY;
}
@Override
public IBinder onBind(Intent arg0) {
return myBind;
}
@Override
public boolean stopService(Intent name) {
try {
socket.close();
wLock.release();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return super.stopService(name);
}
@Override
public void onDestroy()
{//I put this here so I had a breakpoint in place to make sure this wasn't firing instead of stopService
try {
socket.close();
wLock.release();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onDestroy();
}
public void SendMessage(String message)
{
try {
writer.write(message + "\r\n");
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public String readLine()
{//this is called by the activity which consumes the service. Its just an accessor to MessageQueue
try {
if(!isConnected())
return null;
else
return MessageQueue.take();
} catch (InterruptedException e) {
return "";
}
}
public boolean ConnectToServer(IRCServer newServer)
{
try {
//create a new message queue (connecting to a new server)
MessageQueue = new LinkedBlockingQueue<String>();
//lock the wifi
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
wLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "LockTag");
wLock.acquire();
server = newServer;
//connect to server
socket = new Socket();
socket.setKeepAlive(true);
socket.setSoTimeout(60000);
socket.connect(new InetSocketAddress(server.NAME, Integer.parseInt(server.PORT)), 10000);
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//run basic login scripts.
String line;
while ((line = reader.readLine( )) != null) {
//server initialization stuff
}
//start the reader thread AFTER the primary login!!!
CheckStartReader();
if(server.START_CHANNEL == null || server.START_CHANNEL == "")
{
server.WriteCommand("/join " + server.START_CHANNEL);
}
//we're done here, go home everyone
} catch (NumberFormatException e) {
return false;
} catch (IOException e) {
return false;
}
return true;
}
private void queueMessage(String line) {
try {
MessageQueue.put(line);
} catch (InterruptedException e) {
}
}
public boolean isConnected()
{
return socket.isConnected();
}
public void CheckStartReader()
{
if(this.isConnected() && !readThread.isAlive())
readThread.start();
}
}
Code:
//Here are the relevant portions of the hosting Activity that connects to the service
//NOTE: THE FOLLOWING CODE IS PART OF THE ACTIVITY, NOT THE SERVICE
private ConnectionService conn;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
conn = ((ConnectionService.ConnectionBinder)service).getService();
//debug toast
Toast.makeText(main_tab_page.this, "Connected", Toast.LENGTH_SHORT)
.show();
synchronized (_serviceConnWait) {
_serviceConnWait.notify();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
conn = null;//does this even run? Breakpoint here
}
};
@Override
protected void onSaveInstanceState(Bundle state){
super.onSaveInstanceState(state);
state.putParcelable("Server", server);
state.putString("Window", CurrentTabWindow.GetName());
//have to unbind, othewise we get that leaked service exception
unbindService(mConnection);
}
@Override
protected void onDestroy()
{
super.onDestroy();
if(this.isFinishing())
stopService(new Intent(this, ConnectionService.class));
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_tab_page);
localTabHost = (TabHost)findViewById(R.id.tabHostMain);
localTabHost.setup();
localTabHost.setOnTabChangedListener(new tabChange());
_serviceConnWait = new Object();
if(savedInstanceState == null)
{//initial startup, coming from Intent to start
//get server definition
server = (IRCServer)this.getIntent().getParcelableExtra(IRC_WINDOW);
server.addObserver(this);
AddTabView(server);
//this should only run the first time, all other calls to OnCreate should have something in SavedInstanceState
startService(new Intent(this, ConnectionService.class));
}
else
{
server = (IRCServer)savedInstanceState.getParcelable("Server");
String windowName = savedInstanceState.getString("Window");
//Add Needed Tabs
//Server
if(!(windowName.equals(server.GetName())))
AddTabView(server);
//channels
for(IRCChannel c : server.GetAllChannels())
if(!(windowName.equals(c.GetName())))
AddTabView(c);
//reset each view's text (handled by tabChange)
if(windowName.equals(server.GetName()))
SetCurrentTab(server.NAME);
else
SetCurrentTab(windowName);
ResetMainView(CurrentTabWindow.GetWindowTextSpan());
//Rebind to service
BindToService(new Intent(this, ConnectionService.class));
}
}
@Override
protected void onStart()
{
super.onStart();
final Intent ServiceIntent = new Intent(this, ConnectionService.class);
//check start connection service
final Thread serverConnect = new Thread(new Runnable() {
@Override
public void run() {
if(!BindToService(ServiceIntent))
return;
server.conn = conn;
conn.ConnectToServer(server);
server.StartReader();
if(server.START_CHANNEL != null && !server.START_CHANNEL.equals(""))
{
IRCChannel chan = server.FindChannel(server.START_CHANNEL);
if(chan != null)
{
AddTabView(chan);
}
else
{
server.JoinChannel(server.START_CHANNEL);
chan = server.FindChannel(server.START_CHANNEL);
AddTabView(chan);
}
}
}
});
serverConnect.start();
}
private boolean BindToService(Intent ServiceIntent)
{
int tryCount = 0;
bindService(ServiceIntent, mConnection, Context.BIND_AUTO_CREATE);
while(conn == null && tryCount < 10)
{
tryCount++;
try {
synchronized (_serviceConnWait) {
_serviceConnWait.wait(1500);
}
}
catch (InterruptedException e) {
//do nothing
}
}
return conn != null;
}
Logcat...well...there isn't really any exception thrown, the code runs just fine...except that it closes the socket. I suppose that counts as an exception. Whenever I run the socket write command It throws a "Socket Closed" exception at me. No other crash involved.
Hello,
I am a first time poster new to Android app development so please bear with me. I am currently working off of two great TCP/IP Client examples. My goal is to create a simple TCP/IP Client that connects to a server and, once a connection is established, continuously updates a TextView with strings passed from the server. If the user presses a button, the client sends a stop command to the server and I would ultimately like to expand the TextView into a graph with the converted string values. I am able to establish the connection to the server and send the stop command from the client but my attempts at adding the read capability have, so far, been unsuccessful with the app crashing as soon as it starts up.
Since it is my first time posting, I am not allowed to link the examples I am using. If anyone is interested in seeing them, however, they are posts from the android-er blog titled: "Android Server/Client example - client side using Socket" and "Bi-directional communication between Client and Server, using ServerSocket, Socket, DataInputStream and DataOutputStream".
Here is the code in my MainActivity:
Code:
package com.example.androidclient;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
TextView textResponse;
TextView textIn;
EditText editTextAddress, editTextPort;
Button buttonConnect, buttonStopTest, buttonDisconnect;
Socket socket = null;
DataInputStream incomingString = null;
DataOutputStream terminalLetter = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);
editTextAddress = (EditText)findViewById(R.id.address);
editTextPort = (EditText)findViewById(R.id.port);
buttonConnect = (Button)findViewById(R.id.connect);
buttonDisconnect = (Button)findViewById(R.id.disconnect);
buttonStopTest = (Button)findViewById(R.id.stop_test);
textResponse = (TextView)findViewById(R.id.response);
textIn = (TextView)findViewById(R.id.text_in);
buttonConnect.setOnClickListener(buttonConnectOnClickListener);
buttonStopTest.setOnClickListener(buttonStopTestOnClickListener);
buttonDisconnect.setOnClickListener(buttonDisconnectOnClickListener);
}
OnClickListener buttonConnectOnClickListener = new OnClickListener(){
//setOnClickListener sets a callback to be invoked when the button is clicked
@Override
public void onClick(View arg0) {
//Clicking button (Connect) calls a MyClientTask defined below.
MyClientTask myClientTask = new
MyClientTask(editTextAddress.getText().toString(),
Integer.parseInt(editTextPort.getText().toString()));
myClientTask.execute();
}
};
OnClickListener buttonStopTestOnClickListener = new OnClickListener(){
//setOnClickListener sets a callback to be invoked when the button is clicked
@Override
public void onClick(View arg0) {
try {
terminalLetter = new DataOutputStream(socket.getOutputStream());
terminalLetter.writeByte('b');
terminalLetter.writeByte('\n');
terminalLetter.close();
socket.close();
}
catch (IOException e) {
System.err.println("Couldn't get I/O for the connection.");
}
}
};
OnClickListener buttonDisconnectOnClickListener = new OnClickListener(){
//setOnClickListener sets a callback to be invoked when the button is clicked
@Override
public void onClick(View arg0) {
try {
socket.close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
public class MyClientTask extends AsyncTask<Void, Void, Void> {
String IPaddress;
int Port;
String response = "";
MyClientTask(String addr, int port){
IPaddress = addr;
Port = port;
}
@Override
protected Void doInBackground(Void... arg0) {
//Took socket declaration from here.
try {
//Taking relevant parameters and applying them to socket
socket = new Socket(IPaddress, Port);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
byte[] buffer = new byte[1024];
int bytesRead;
InputStream inputStream = socket.getInputStream();
incomingString = new DataInputStream(socket.getInputStream());
textIn.setText(incomingString.readUTF());
/*
* notice:
* inputStream.read() will block if no data return
*/
while ((bytesRead = inputStream.read(buffer)) != -1){
byteArrayOutputStream.write(buffer, 0, bytesRead);
response += byteArrayOutputStream.toString("UTF-8");
}
}
catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "UnknownHostException: " + e.toString();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
response = "IOException: " + e.toString();
}
finally{
if(socket != null){
try {
socket.close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return null;
}
@Override
protected void onPostExecute(Void result) {
textResponse.setText(response);
super.onPostExecute(result);
}
}
}
I put the commands for reading data from the server and writing it to the TextView with the code that sets up the connection to the socket. The idea was that it would be the next step after the connection is established but I realize that it looks like I am only reading once. I tried adding a while loop and bringing it out of the doInBackground. In each case, all I got was the whole app crashing on me. It looks fairly straight forward in the example but there the connection is automatic, not triggered and I have not been able to modify the code successfully.
I am still new to Android and this feels like it is an important part of app development so I am hoping someone in the community can help me understand where the section of code relevant to reading data (continuously) should be placed in relation to the rest.
Best,
Yusif Nurizade
P.S. I was going to include the fragment but, since the post is long enough, I chose to omit it. I can share upon request and the logcat.
Hello guys,
I have a list of fragments created and I want to delete these fragment by long pressing on them. However, before doing so I want dialog fragment to pop up and offer the user the choice to delete or not. I have created the two fragments but I can't get the data across each other. I can't give functionality to the 'OK' button. Here is my code:
Code:
public class CourseListFragment extends Fragment implements
OnItemClickListener, OnItemLongClickListener {
public static final String ARG_ITEM_ID = "course_list";
public static final String YES_NO = "modify";
Activity activity;
ListView courseListView;
ArrayList<Course> courses;
CourseListAdapter courseListAdapter;
CourseDAO courseDAO;
private GetEmpTask task;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = getActivity();
courseDAO = new CourseDAO(activity);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.schedule_fragment_course_list,
container, false);
findViewsById(view);
task = new GetEmpTask(activity);
task.execute((Void) null);
courseListView.setOnItemClickListener(this);
courseListView.setOnItemLongClickListener(this);
return view;
}
private void findViewsById(View view) {
courseListView = (ListView) view.findViewById(R.id.list_course);
}
@Override
public void onItemClick(AdapterView<?> list, View view, int position,
long id) {
Course course = (Course) list.getItemAtPosition(position);
if (course != null) {
Bundle arguments = new Bundle();
arguments.putParcelable("selectedCourse", course);
CustomCourseDialogFragment customEmpDialogFragment = new CustomCourseDialogFragment();
customEmpDialogFragment.setArguments(arguments);
customEmpDialogFragment.show(getFragmentManager(),
CustomCourseDialogFragment.ARG_ITEM_ID);
}
}
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
// Show dialogFragment
FragmentManager fm = getActivity().getSupportFragmentManager();
CheckDialogFragment dialog = new CheckDialogFragment();
dialog.show(fm, YES_NO);
Course employee = (Course) parent.getItemAtPosition(position);
// Use AsyncTask to delete from database
courseDAO.deleteEmployee(employee);
courseListAdapter.remove(employee);
return true;
}
public class GetEmpTask extends AsyncTask<Void, Void, ArrayList<Course>> {
private final WeakReference<Activity> activityWeakRef;
public GetEmpTask(Activity context) {
this.activityWeakRef = new WeakReference<Activity>(context);
}
@Override
protected ArrayList<Course> doInBackground(Void... arg0) {
ArrayList<Course> courseList = courseDAO.getCourses();
return courseList;
}
@Override
protected void onPostExecute(ArrayList<Course> empList) {
if (activityWeakRef.get() != null
&& !activityWeakRef.get().isFinishing()) {
courses = empList;
if (empList != null) {
if (empList.size() != 0) {
courseListAdapter = new CourseListAdapter(activity,
empList);
courseListView.setAdapter(courseListAdapter);
} else {
Toast.makeText(activity, "No Course Records",
Toast.LENGTH_LONG).show();
}
}
}
}
}
/*
* This method is invoked from MainActivity onFinishDialog() method. It is
* called from CustomEmpDialogFragment when an employee record is updated.
* This is used for communicating between fragments.
*/
public void updateView() {
task = new GetEmpTask(activity);
task.execute((Void) null);
}
@Override
public void onResume() {
getActivity().setTitle("Course Schedule");
getActivity().getActionBar().setTitle("Course Schedule");
super.onResume();
}
}
//Dialog Fragment
Code:
public class CheckDialogFragment extends DialogFragment {
CourseListAdapter courseListAdapter;
CourseDAO courseDAO;
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// TODO Auto-generated method stub
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
.setTitle("Do you want to delete?")
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
}
})
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
dialog.cancel();
}
});
return builder.create();
}
}
I have problems trying to get the data from onItemLongClick() of CourseListFragment to CourseListFragment. Any help would be greatly appreciated.
My need: I want to extract the links of websites that appear on Google search result page and display them in a textView. The Google search may vary according to the user's needs. The purpose of this (app) is to get the most related, nearest results for the user.
The mechanism is when the user inputs their search words and clicked on the button, the links that are extracted should appear on the textView.
Errors: I don't get an error in the code or any results on the textView.
My Question: Where have I gone wrong? How can I correct it? Is there any other way to do this?
TestHomeFragment.java
public class TestHomeFragment extends Fragment {
ImageButton b_search;
TextView search_webview;
String userLocation = "Sri Lanka";
TextView textView;
List<String> sriLankanUrls;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.test_home_fragment, container, false);
// --------------------------- Search Mechanism -----------------------------------------//
sriLankanUrls = new ArrayList<>();
b_search.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
String searchQuery="buy "+et_search.getText().toString()+ " in " + userLocation ;
new GoogleSearchScraperTask().execute();
}
}); return view;
}
private class GoogleSearchScraperTask extends AsyncTask<Void, Void, StringBuilder> {
@Override
protected StringBuilder doInBackground(Void... voids) {
StringBuilder resultBuilder = new StringBuilder();
try {
// Specify the Google search query
String searchQuery="buy "+et_search.getText().toString()+ " in " + userLocation ;
// Fetch the search results page
Document doc = Jsoup.connect("https://www.google.com/search?q=" + searchQuery).get();
// Extract sentences containing "https://"
Elements searchResults = doc.select("div.g");
for (Element result : searchResults) {
String snippet = result.select("span.st").text();
if (snippet.contains("http")) {
resultBuilder.append(snippet).append("\n");
}
}
} catch (IOException e) {
e.printStackTrace();
}return resultBuilder;
}
@Override
protected void onPostExecute(StringBuilder resultBuilder) {
super.onPostExecute(resultBuilder);
// Set the scraped sentences in the TextView
textView.setText(resultBuilder.toString());
}
}
}