I have a service bound to an activity. The service will access a JSON web service. I would like to create a thread within the activity that calls a member function of the bound service but I am receiving an error.
The following example functions perfectly if I don't use a thread.
Here is the activity:
import java.util.ArrayList;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class ProjectsListActivity extends ListActivity {
ApiService mService;
boolean mBound = false;
private static String TAG = "tag";
private ProgressDialog mProgressDialog = null;
private ArrayList<Project> mProjects = null;
private ProjectAdapter mAdapter;
private Runnable viewProjects;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// set the layout
setContentView(R.layout.project_list_item);
// setup the custom list adapter
mProjects = new ArrayList<Project>();
this.mAdapter = new ProjectAdapter(this, R.layout.row, mProjects);
setListAdapter(this.mAdapter);
ListView lv = getListView();
lv.setTextFilterEnabled(true);
lv.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
if (mBound) {
Project p = mProjects.get(position);
Toast.makeText(getApplicationContext(), p.getName(),
Toast.LENGTH_SHORT).show();
}
}
});
// use a thread to get the projects
viewProjects = new Runnable() {
@Override
public void run() {
getProjects();
}
};
Thread thread = new Thread(null, viewProjects, "MagentoBackground");
thread.start();
mProgressDialog = ProgressDialog.show(ProjectsListActivity.this,
"Please wait...", "Retrieving data ...", true);
}
@Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, ApiService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
}
/** Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
mService = ((ApiService.LocalBinder)service).getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
private class ProjectAdapter extends ArrayAdapter<Project> {
private ArrayList<Project> items;
public ProjectAdapter(Context context, int textViewResourceId,
ArrayList<Project> items) {
super(context, textViewResourceId, items);
this.items = items;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, parent, false);
}
Project o = items.get(position);
if (o != null) {
TextView tt = (TextView) v.findViewById(R.id.toptext);
TextView bt = (TextView) v.findViewById(R.id.bottomtext);
if (tt != null) {
tt.setText("Name: " + o.getName());
}
if (bt != null) {
bt.setText("Status: " + o.getId());
}
}
return v;
}
}
private Runnable returnRes = new Runnable() {
@Override
public void run() {
if (mProjects != null && mProjects.size() > 0) {
mAdapter.notifyDataSetChanged();
for (int i = 0; i < mProjects.size(); i++)
mAdapter.add(mProjects.get(i));
}
mProgressDialog.dismiss();
mAdapter.notifyDataSetChanged();
}
};
private void getProjects() {
try {
mProjects = mService.getUserProjects();
Log.i(TAG, "" + mProjects.size());
} catch (Exception e) {
Log.e("BACKGROUND_PROC", "Exception ["+e.getMessage()+"]", e);
}
runOnUiThread(returnRes);
}
}
Here is the service:
import java.util.ArrayList;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class ApiService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
ApiService getService() {
return ApiService.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public ArrayList<Project> getUserProjects() {
ArrayList<Project> mProjects = new ArrayList<Project>();
Project p1 = new Project();
p1.setName("Project 1");
p1.setId("Pending");
Project p2 = new Project();
p2.setName("Project 2");
p2.setId("Completed");
mProjects.add(p1);
mProjects.add(p2);
return mProjects;
}
}
The error I receive:
06-10 18:45:32.736: ERROR/BACKGROUND_PROC(285): Exception [null]
06-10 18:45:32.736: ERROR/BACKGROUND_PROC(285): java.lang.NullPointerException
06-10 18:45:32.736: ERROR/BACKGROUND_PROC(285): at ProjectsListActivity.getProjects(ProjectsListActivity.java:160)
06-10 18:45:32.736: ERROR/BACKGROUND_PROC(285): at ProjectsListActivity.access$3(ProjectsListActivity.java:158)
06-10 18:45:32.736: ERROR/BACKGROUND_PROC(285): at ProjectsListActivity$4.run(ProjectsListActivity.java:67)
06-10 18:45:32.736: ERROR/BACKGROUND_PROC(285): at java.lang.Thread.run(Thread.java:1096)
If this still doesn't make sense, essentially what I am trying to do is take the bound service example with the number generator and modify it so that the method is called within a thread in the activity. Within the example it even says, "However, if this call were something that might hang, then this request should occur in a separate thread to avoid slowing down the activity performance."
Thanks in advance for your help.