In my apps,i will provide checkbox dynamically and above one button for get selected i am providing,if you click the button it has to fetch the checked data what we given in an listview.But right now after clicking button select,the application has stopped.
Mainactivity.java
public class MainActivity extends Activity implements FetchDataListener,OnClickListener
{
private static final int ACTIVITY_CREATE=0;
private ProgressDialog dialog;
ListView lv;
private List<Application> items;
private Button btnGetSelected;
//private ProjectsDbAdapter mDbHelper;
//private SimpleCursorAdapter dataAdapter;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_item);
//mDbHelper = new ProjectsDbAdapter(this);
//mDbHelper.open();
//fillData();
//registerForContextMenu(getListView());
lv =(ListView)findViewById(R.id.list);
btnGetSelected = (Button) findViewById(R.id.btnget);
btnGetSelected.setOnClickListener(this);
initView();
}
private void initView()
{
// show progress dialog
dialog = ProgressDialog.show(this, "", "Loading...");
String url = "http://dry-brushlands-3645.herokuapp.com/posts.json";
FetchDataTask task = new FetchDataTask(this);
task.execute(url);
//mDbHelper.open();
//Cursor projectsCursor = mDbHelper.fetchAllProjects();
//startManagingCursor(projectsCursor);
// Create an array to specify the fields we want to display in the list (only TITLE)
//String[] from = new String[]{ProjectsDbAdapter.KEY_TITLE};
// and an array of the fields we want to bind those fields to (in this case just text1)
//int[] to = new int[]{R.id.text1};
/* Now create a simple cursor adapter and set it to display
SimpleCursorAdapter projects =
new SimpleCursorAdapter(this, R.layout.activity_row, projectsCursor, from, to);
setListAdapter(projects);
*/
// create the adapter using the cursor pointing to the desired data
//as well as the layout information
/*dataAdapter = new SimpleCursorAdapter(
this, R.layout.activity_row,
projectsCursor,
from,
to,
0);
setListAdapter(dataAdapter);
*/
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
//getMenuInflater().inflate(R.menu.activity_main, menu);
super.onCreateOptionsMenu(menu);
MenuInflater mi = getMenuInflater();
mi.inflate(R.menu.activity_main, menu);
return true;
}
#Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
createProject();
return super.onMenuItemSelected(featureId, item);
}
private void createProject() {
Intent i = new Intent(this, ProjectEditActivity.class);
startActivityForResult(i, ACTIVITY_CREATE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
initView();
}
#Override
public void onFetchComplete(List<Application> data)
{
// dismiss the progress dialog
if ( dialog != null )
dialog.dismiss();
// create new adapter
ApplicationAdapter adapter = new ApplicationAdapter(this, data);
// set the adapter to list
lv.setAdapter(adapter);
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
CheckBox chk = (CheckBox) view.findViewById(R.id.checkbox);
Application bean = items.get(position);
if (bean.isSelected()) {
bean.setSelected(false);
chk.setChecked(false);
} else {
bean.setSelected(true);
chk.setChecked(true);
}
}
});
}
// Toast is here...
private void showToast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
#Override
public void onFetchFailure(String msg)
{
// dismiss the progress dialog
if ( dialog != null )
dialog.dismiss();
// show failure message
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}
#Override
public void onClick(View v) {
StringBuffer sb = new StringBuffer();
// Retrive Data from list
for (Application bean : items) {
if (bean.isSelected()) {
sb.append(bean.getContent());
sb.append(",");
}
}
showAlertView(sb.toString().trim());
}
private void showAlertView(String str) {
AlertDialog alert = new AlertDialog.Builder(this).create();
if (TextUtils.isEmpty(str)) {
alert.setTitle("Not Selected");
alert.setMessage("No One is Seleceted!!!");
} else {
// Remove , end of the name
String strContactList = str.substring(0, str.length() - 1);
alert.setTitle("Selected");
alert.setMessage(strContactList);
}
alert.setButton("Ok", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alert.show();
}
#Override
public void onBackPressed() {
AlertDialog alert_back = new AlertDialog.Builder(this).create();
alert_back.setTitle("Quit?");
alert_back.setMessage("Are you sure want to Quit?");
alert_back.setButton("No", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alert_back.setButton2("Yes", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
MainActivity.this.finish();
}
});
alert_back.show();
}
#Override
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
// TODO Auto-generated method stub
}
This is my adapter closs,Applicationadapter.java
public class ApplicationAdapter extends ArrayAdapter<Application>
{
private List<Application> items;
private LayoutInflater inflator;
public ApplicationAdapter(Context context, List<Application> items)
{
super(context, R.layout.activity_row, items);
this.items = items;
inflator = LayoutInflater.from(getContext());
}
#Override
public int getCount()
{
return items.size();
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder = null;
//View v = convertView;
if ( convertView == null )
{
convertView = inflator.inflate(R.layout.activity_row, null);
LayoutInflater li = LayoutInflater.from(getContext());
//convertView = inflator.inflate(R.layout.app_custom_list, null);
holder = new ViewHolder();
holder.text1 = (TextView) convertView.findViewById(R.id.text1);
holder.chk = (CheckBox) convertView.findViewById(R.id.checkbox);
holder.chk
.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton view,
boolean isChecked) {
int getPosition = (Integer) view.getTag();
items.get(getPosition).setSelected(view.isChecked());
}
});
convertView.setTag(holder);
convertView.setTag(R.id.text1, holder.text1);
convertView.setTag(R.id.checkbox, holder.chk);
}else {
holder = (ViewHolder) convertView.getTag();
}
Application app = items.get(position);
holder.chk.setTag(position);
holder.text1.setText(Html.fromHtml(items.get(position).getContent()));
holder.chk.setChecked(items.get(position).isSelected());
if ( app != null )
{
TextView titleText = (TextView) convertView.findViewById(R.id.titleTxt);
if ( titleText != null )
titleText.setText(Html.fromHtml(app.getContent()).toString());
//titleText.setText(app.getContent());
//holder.chk.setChecked(((View) Html.fromHtml(app.getContent())).isSelected());
}
return convertView;
}
static class ViewHolder {
public TextView text1;
public CheckBox chk;
}
//return convertView;
}
Here i mention my logcat error also.
06-04 10:07:49.857: E/AndroidRuntime(2454): FATAL EXCEPTION: main
06-04 10:07:49.857: E/AndroidRuntime(2454): java.lang.NullPointerException
06-04 10:07:49.857: E/AndroidRuntime(2454): at com.example.jsonandroid.MainActivity.onClick(MainActivity.java:174)
06-04 10:07:49.857: E/AndroidRuntime(2454): at android.view.View.performClick(View.java:4202)
06-04 10:07:49.857: E/AndroidRuntime(2454): at android.view.View$PerformClick.run(View.java:17340)
06-04 10:07:49.857: E/AndroidRuntime(2454): at android.os.Handler.handleCallback(Handler.java:725)
06-04 10:07:49.857: E/AndroidRuntime(2454): at android.os.Handler.dispatchMessage(Handler.java:92)
06-04 10:07:49.857: E/AndroidRuntime(2454): at android.os.Looper.loop(Looper.java:137)
06-04 10:07:49.857: E/AndroidRuntime(2454): at android.app.ActivityThread.main(ActivityThread.java:5039)
06-04 10:07:49.857: E/AndroidRuntime(2454): at java.lang.reflect.Method.invokeNative(Native Method)
06-04 10:07:49.857: E/AndroidRuntime(2454): at java.lang.reflect.Method.invoke(Method.java:511)
06-04 10:07:49.857: E/AndroidRuntime(2454): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
06-04 10:07:49.857: E/AndroidRuntime(2454): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
06-04 10:07:49.857: E/AndroidRuntime(2454): at dalvik.system.NativeStart.main(Native Method)
After clicking the btngetselected,apps has stopped
this is my Application.java
public class Application {
private String content;
private boolean selected;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public boolean isSelected() {
return selected;
}
public void setSelected(boolean selected) {
this.selected = selected;
}
}
In my code,i am using asynctask for fetching data,here i attached that code also.
public class FetchDataTask extends AsyncTask<String, Void, String>
{
private final FetchDataListener listener;
private String msg;
public FetchDataTask(FetchDataListener listener)
{
this.listener = listener;
}
#Override
protected String doInBackground(String... params)
{
if ( params == null )
return null;
// get url from params
String url = params[0];
try
{
// create http connection
HttpClient client = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
// connect
HttpResponse response = client.execute(httpget);
// get response
HttpEntity entity = response.getEntity();
if ( entity == null )
{
msg = "No response from server";
return null;
}
// get response content and convert it to json string
InputStream is = entity.getContent();
return streamToString(is);
}
catch ( IOException e )
{
msg = "No Network Connection";
}
return null;
}
#Override
protected void onPostExecute(String sJson)
{
if ( sJson == null )
{
if ( listener != null )
listener.onFetchFailure(msg);
return;
}
try
{
// convert json string to json object
JSONObject jsonObject = new JSONObject(sJson);
JSONArray aJson = jsonObject.getJSONArray("post");
// create apps list
List<Application> apps = new ArrayList<Application>();
for ( int i = 0; i < aJson.length(); i++ )
{
JSONObject json = aJson.getJSONObject(i);
Application app = new Application();
app.setContent(json.getString("content"));
// add the app to apps list
apps.add(app);
}
//notify the activity that fetch data has been complete
if ( listener != null )
listener.onFetchComplete(apps);
}
catch ( JSONException e )
{
e.printStackTrace();
msg = "Invalid response";
if ( listener != null )
listener.onFetchFailure(msg);
return;
}
}
/**
* This function will convert response stream into json string
*
* #param is
* respons string
* #return json string
* #throws IOException
*/
public String streamToString(final InputStream is) throws IOException
{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try
{
while ( (line = reader.readLine()) != null )
{
sb.append(line + "\n");
}
}
catch ( IOException e )
{
throw e;
}
finally
{
try
{
is.close();
}
catch ( IOException e )
{
throw e;
}
}
return sb.toString();
}
}
06-04 10:07:49.857: E/AndroidRuntime(2454): java.lang.NullPointerException
06-04 10:07:49.857: E/AndroidRuntime(2454): at com.example.jsonandroid.MainActivity.onClick(MainActivity.java:174)
This error is very clear , you have a nullPointerException at onClick, check this line: Application bean : items I think there's the null pointer.
Assuming onFetchComplete is what populates your data, and is called before
for (Application bean : items) {
is called, you need to populate your items there. So,
#Override
public void onFetchComplete(List<Application> data) {
this.items = data;
But without seeing all of your code it is hard to tell what is happening.
The below line inside onClick is the source for your problem:
for (Application bean : items) {
...
}
here "items" is not initialized. hence NullpointerException.
you must initialize it somewhere like this:
private ArrayList<Application> items = new ArrayList<Application>();
and then have some data in that list to carry out necessary operation.
Related
if i using extends Activity it works normally. But when i move the code to fragment extends Fragment the progress bar is never stop and the data is never show up and there is no error to.
Frag_Country_List.java
public class Frag_Country_List extends Fragment implements DB_FetchDataListener {
private String CountryFlag;
private String CountryName;
private ProgressDialog dialog;
private GridView myGridview;
public Frag_Country_List() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.frag_country_list, container, false);
}
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
// do your variables initialisations here except Views!!!
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
return true;
}
public void onViewCreated(#NonNull View view, Bundle savedInstanceState){ super.onViewCreated(view, savedInstanceState);
myGridview = (GridView)view.findViewById(R.id.countryGridView);
initView();
/*myGridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
OpenDialog();
}
});*/
}
private void initView() {
dialog = ProgressDialog.show(this.getContext(), "", "Loading...");
String url = "http://example.com/get_country.php";
DB_FetchDataTask task = new DB_FetchDataTask(this);
task.execute(url);
}
#Override
public void onFetchComplete(List<DB_Application> data) {
if(dialog != null) dialog.dismiss();
DB_ApplicationAdapter adapter = new DB_ApplicationAdapter(this.getContext(), data);
myGridview.setAdapter(adapter);
}
#Override
public void onFetchFailure(String msg) {
if(dialog != null) dialog.dismiss();
Toast.makeText(this.getContext(), msg, Toast.LENGTH_LONG).show();
}
}
DB_FetchDataTask.java
public class DB_FetchDataTask extends AsyncTask<String, Void, String>{
private final DB_FetchDataListener listener;
private String msg;
public DB_FetchDataTask(DB_FetchDataListener listener) {
this.listener = listener;
}
#Override
protected String doInBackground(String... params) {
if(params == null) return null;
// get url from params
String url = params[0];
try {
// create http connection
HttpClient client = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
// connect
HttpResponse response = client.execute(httpget);
// get response
HttpEntity entity = response.getEntity();
if(entity == null) {
msg = "No response from server";
return null;
}
// get response content and convert it to json string
InputStream is = entity.getContent();
return streamToString(is);
}
catch(IOException e){
msg = "No Network Connection";
}
return null;
}
#Override
protected void onPostExecute(String sJson) {
if(sJson == null) {
if(listener != null) listener.onFetchFailure(msg);
return;
}
try {
// convert json string to json array
JSONArray aJson = new JSONArray(sJson);
// create apps list
List<DB_Application> apps = new ArrayList<DB_Application>();
for(int i=0; i<aJson.length(); i++) {
JSONObject json = aJson.getJSONObject(i);
DB_Application app = new DB_Application();
app.setCountry(json.getString("_country"));
app.setFlag(json.getString("_flag"));
// add the app to apps list
apps.add(app);
}
//notify the activity that fetch data has been complete
if(listener != null) listener.onFetchComplete(apps);
} catch (JSONException e) {
msg = "Invalid response";
if(listener != null) listener.onFetchFailure(msg);
return;
}
}
/**
* This function will convert response stream into json string
* #param is respons string
* #return json string
* #throws IOException
*/
public String streamToString(final InputStream is) throws IOException{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
}
catch (IOException e) {
throw e;
}
finally {
try {
is.close();
}
catch (IOException e) {
throw e;
}
}
return sb.toString();
}
}
tell me if you need more information.
Logcat
11-27 13:54:06.007 1934-1994/com.mysql.sample E/Surface: getSlotFromBufferLocked: unknown buffer: 0xaaa89aa0
11-27 13:54:06.177 1934-1934/com.mysql.sample E/SysUtils: ApplicationContext is null in ApplicationStatus
11-27 13:54:06.185 1934-1934/com.mysql.sample E/libEGL: validate_display:255 error 3008 (EGL_BAD_DISPLAY)
11-27 13:54:06.185 1934-1934/com.mysql.sample E/libEGL: validate_display:255 error 3008 (EGL_BAD_DISPLAY)
11-27 13:54:06.215 1934-1934/com.mysql.sample E/DataReductionProxySettingListener: No DRP key due to exception:java.lang.ClassNotFoundException: com.android.webview.chromium.Drp
Try moving your onViewCreated code to onCreateView method:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.frag_country_list, container, false);
myGridview = (GridView)view.findViewById(R.id.countryGridView);
initView();
return view;
}
My Main Activity has three tabs. Each tab is a fragment. Now if you change the theme (white and dark are available), the activity is being recreated so that the change takes effect. But the app crashes.
How I deal with the fragments:
if (savedInstanceState == null) {
pageadapter = new SectionsPageAdapter(getSupportFragmentManager());
rFragMore = new RoomlistFragmentMore();
rFragMyRooms = new RoomlistFragmentMyRooms();
rFragFavs = new RoomlistFragmentFavorites();
} else {
rFragMyRooms = (RoomlistFragmentMyRooms)pageadapter.getItem(0);
rFragFavs = (RoomlistFragmentFavorites)pageadapter.getItem(1);
rFragMore = (RoomlistFragmentMore)pageadapter.getItem(2);
pageadapter.clearAdapter();
pageadapter = new SectionsPageAdapter(getSupportFragmentManager());
}
How I set up the Adapter:
private void setupViewPager(ViewPager viewPager) {
pageadapter.addFragment(rFragMyRooms, getResources().getString(R.string.myrooms));
pageadapter.addFragment(rFragFavs, getResources().getString(R.string.favorites));
pageadapter.addFragment(rFragMore, getResources().getString(R.string.more));
viewPager.setAdapter(pageadapter);
}
My Adapter:
public class SectionsPageAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
public void clearAdapter() {
mFragmentList.clear();
mFragmentTitleList.clear();
}
public SectionsPageAdapter(FragmentManager fm) {
super(fm);
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
#Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
#Override
public int getCount() {
return mFragmentList.size();
}
}
And the Error Log:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.io.FileInputStream android.content.Context.openFileInput(java.lang.String)' on a null object reference
at com.yannick.mychatapp.RoomlistFragmentMore.readFromFile(RoomlistFragmentMore.java:246)
at com.yannick.mychatapp.RoomlistFragmentMore.addRoomToList(RoomlistFragmentMore.java:121)
at com.yannick.mychatapp.RoomlistFragmentMore.access$000(RoomlistFragmentMore.java:46)
at com.yannick.mychatapp.RoomlistFragmentMore$1.onDataChange(RoomlistFragmentMore.java:79)
at com.google.firebase.database.core.ValueEventRegistration.fireEvent(com.google.firebase:firebase-database##16.0.4:75)
at com.google.firebase.database.core.view.DataEvent.fire(com.google.firebase:firebase-database##16.0.4:63)
at com.google.firebase.database.core.view.EventRaiser$1.run(com.google.firebase:firebase-database##16.0.4:55)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
EDIT: the code of RoomlistFragmentMore
public class RoomlistFragmentMore extends Fragment {
private ListView listView;
private List<HashMap<String, String>> listItems = new ArrayList<>();
private String raumname, theme;
private static String userID = "";
private SimpleAdapter adapter;
private DatabaseReference root = FirebaseDatabase.getInstance().getReference().getRoot().child("rooms");
private ArrayList<Room> raumliste = new ArrayList<>();
private TextView keinraumgefunden;
private String[] kat;
private static final String TAG = "RoomlistFragmentMore";
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.roomlist_fragment_more,container,false);
listView = view.findViewById(R.id.listView);
keinraumgefunden = view.findViewById(R.id.keinraumgefunden);
kat = getResources().getStringArray(R.array.categories);
theme = readFromFile("mychatapp_theme.txt");
adapter = new SimpleAdapter(getActivity(), listItems, R.layout.listlayout,
new String[]{"name", "kat", "lock", "newest"},
new int[]{R.id.raumname, R.id.raumkat, R.id.raumlock, R.id.raumdatum});
listView.setAdapter(adapter);
root.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
addRoomToList(dataSnapshot);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(getActivity(), R.string.nodatabaseconnection, Toast.LENGTH_SHORT).show();
}
});
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
int position = listView.getPositionForView(view);
String roomname = listItems.get(position).values().toArray()[0].toString();
Room room = findRoom(raumliste, roomname);
request_password(room, position);
}
});
adapter.registerDataSetObserver(new DataSetObserver() {
#Override
public void onChanged() {
if (raumliste.isEmpty()) {
keinraumgefunden.setText(R.string.noroomfound);
} else {
keinraumgefunden.setText("");
}
}
});
return view;
}
private void addRoomToList(DataSnapshot dataSnapshot) {
HashMap<String, String> raeume = new HashMap<>();
raumliste.clear();
for(DataSnapshot uniqueKeySnapshot : dataSnapshot.getChildren()){
String name = uniqueKeySnapshot.getKey();
for(DataSnapshot roomSnapshot : uniqueKeySnapshot.getChildren()){
Room room = roomSnapshot.getValue(Room.class);
room.setRaumname(name);
if (!room.getPasswd().equals(readFromFile("mychatapp_raum_" + name + ".txt"))) {
raeume.put(name, kat[Integer.parseInt(room.getCaty())]+"/"+"\uD83D\uDD12"+"/");
raumliste.add(room);
}
break;
}
}
listItems.clear();
Iterator it = raeume.entrySet().iterator();
while (it.hasNext()){
HashMap<String, String> resultsMap = new HashMap<>();
Map.Entry pair = (Map.Entry)it.next();
resultsMap.put("name", pair.getKey().toString());
String daten = pair.getValue().toString();
String caty = daten.substring(0, daten.indexOf("/"));
String lock = daten.substring(daten.indexOf("/")+1, daten.lastIndexOf("/"));
String time = daten.substring(daten.lastIndexOf("/")+1, daten.length());
String newestTime = "";
int index = 0;
resultsMap.put("kat", caty);
resultsMap.put("lock", lock);
resultsMap.put("newest", newestTime);
if (time.equals("")) {
listItems.add(resultsMap);
} else {
listItems.add(index, resultsMap);
}
}
adapter.notifyDataSetChanged();
}
private void request_password(final Room room, final int position) {
LayoutInflater inflater = LayoutInflater.from(getContext());
View view = inflater.inflate(R.layout.enter_room, null);
raumname = room.getRaumname();
userID = readFromFile("mychatapp_userid.txt");
final EditText input_field = view.findViewById(R.id.room_password);
AlertDialog.Builder builder;
if (theme.equals(getResources().getStringArray(R.array.themes)[1])) {
builder = new AlertDialog.Builder(new ContextThemeWrapper(getActivity(), R.style.AlertDialogDark));
} else {
builder = new AlertDialog.Builder(getActivity());
}
builder.setTitle(R.string.pleaseenterpassword);
builder.setView(view);
builder.setCancelable(false);
builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
}
});
builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
View view = ((AlertDialog) dialogInterface).getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager)getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
dialogInterface.cancel();
}
});
final AlertDialog alert = builder.create();
alert.setOnShowListener(new DialogInterface.OnShowListener() {
#Override
public void onShow(DialogInterface dialog) {
Button b = alert.getButton(AlertDialog.BUTTON_POSITIVE);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (input_field.getText().toString().trim().equals(room.getPasswd())) {
Intent tabIntent = new Intent("tab");
LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(tabIntent);
Intent intent = new Intent(getActivity(), ChatActivity.class);
intent.putExtra("room_name", room.getRaumname());
intent.putExtra("user_id",userID);
updateRoomList(position);
writeToFile(room.getPasswd(),"mychatapp_raum_" + raumname + ".txt");
alert.cancel();
startActivity(intent);
} else {
Toast.makeText(getActivity(), R.string.wrongpassword, Toast.LENGTH_SHORT).show();
}
}
});
}
});
alert.show();
}
public Room findRoom(ArrayList<Room> raumliste, String raumname) {
for (Room room : raumliste) {
if (room.getRaumname().equals(raumname)) {
return room;
}
}
return null;
}
public void writeToFile(String text, String datei) {
Context context = getActivity();
try {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(context.openFileOutput(datei, Context.MODE_PRIVATE));
outputStreamWriter.write(text);
outputStreamWriter.close();
}
catch (IOException e) {
Log.e("Exception", "File write failed: " + e.toString());
}
}
public String readFromFile(String datei) {
Context context = getActivity();
String erg = "";
try {
InputStream inputStream = context.openFileInput(datei);
if ( inputStream != null ) {
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String receiveString = "";
StringBuilder stringBuilder = new StringBuilder();
while ( (receiveString = bufferedReader.readLine()) != null ) {
stringBuilder.append(receiveString);
}
inputStream.close();
erg = stringBuilder.toString();
}
}
catch (FileNotFoundException e) {
Log.e("login activity", "File not found: " + e.toString());
} catch (IOException e) {
Log.e("login activity", "Can not read file: " + e.toString());
}
return erg;
}
private void updateRoomList(int position) {
listItems.remove(position);
adapter.notifyDataSetChanged();
}
}
The NullPointerException occured while onDataChange() was executed (you can see this by reading the stack trace). More specifically, readFromFile() needs a valid Context to open a file.
Since your app crashed we know that getActivity() did return null. How can this happen?
You add the ValueEventListener in onCreateView(). At this point in time, the Fragment has a valid Context (see the documentation for an explanation of the Lifecycle), so all is well for the moment.
But since you do not remove the ValueEventListener, it will continue to fire even if the Fragment is temporarily not attached to the Activity because the user swiped to the next page. The Fragment won't be garbage collected because you keep it in a list and reuse it.
This approach is basically ok if you implement null checks to avoid accessing the Activity, the Context or Views in general while they are not present. Of course, you could consider a stronger separation of the data and the View layer as suggested in this guide to app architecture
So im trying to update a list with the information provided from a server communicated by JSON.
This is the class doing the communication:
package com.example.simon_000.buddy;
public class TCPConnection {
private RunOnThread thread;
private Receive receive;
private MainActivity ma;
private Socket socket;
private DataInputStream input;
private DataOutputStream output;
private InetAddress address;
private int connectionPort;
private String ip;
private Exception exception;
public static String id;
public static ArrayList<members> memberList = new ArrayList<members>();
public static ArrayList<String> groupsList = new ArrayList<String>();
public static ArrayList<String> namesList = new ArrayList<String>();
public TCPConnection(String ip, int connectionPort, MainActivity ma) {
this.ip = ip;
this.connectionPort = connectionPort;
thread = new RunOnThread();
this.ma = ma;
}
public void connect() {
thread.start();
thread.execute(new Connect());
}
public void disconnect() {
thread.execute(new Disconnect());
}
public void send(String expression) {
thread.execute(new Send(expression));
}
private class Receive extends Thread {
public void run() {
String result;
try {
while (receive != null) {
result = (String) input.readUTF();
newMessage(result);
}
} catch (Exception e) { // IOException, ClassNotFoundException
receive = null;
}
}
}
public void newMessage(final String answer) {
ma.runOnUiThread(new Runnable() {
public void run() {
String message = answer;
String type;
JSONObject jObj = null;
try {
Log.d("TEST", message);
jObj = new JSONObject(message);
type = jObj.getString("type");
if (type.equals("groups")) {
recevieGroups(jObj);
}
else if (type.equals("register")) {
recevieID(jObj);
}
else if (type.equals("members")) {
receiveMembers(jObj);
}
else if (type.equals("location")) {
receiveLocations(jObj);
} else if (type.equals("locations")) {
receiveLocations(jObj);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
});
}
public void receiveLocations(JSONObject jObj) throws JSONException {
// { ”type”:”locations”, ”group”:”NAME”, ”locations”:[ {”member”:”NAME”, ”longitude”:”LONGITUDE”, ”latitude”:”LATITUDE” }, … ] }
JSONArray jArray = jObj.getJSONArray("locations");
for (int i = 0; i < jArray.length(); i++) {
members m = new members();
JSONObject jRealObject = jArray.getJSONObject(i);
m.setName(jRealObject.getString("member"));
m.setLongitude(Double.parseDouble(jRealObject.getString("longitude")));
m.setLatitude(Double.parseDouble(jRealObject.getString("latitude")));
memberList.add(m);
Log.d("TEST", " memberNAMES : " + m.getName()+" lng: "+ m.getLongitude()+" lat: "+m.getLatitude());
}
ma.updateMapMarkers(memberList);
}
public void receiveMembers(JSONObject jObj) throws JSONException {
// { “type”:”members”, “group”:”NAME”, “members”:[ {“member”:”NAME”},…] }
JSONArray jArray = jObj.getJSONArray("members");
for (int i = 0; i < jArray.length(); i++) {
String n;
JSONObject jRealObject = jArray.getJSONObject(i);
n = jRealObject.getString("member");
Log.d("TEST", " MembernamesBEFORE_ADD : " + n );
namesList.add(n);
Log.d("TEST", " memberNAMES : " + n);
}
}
public void recevieID(JSONObject jObj) throws JSONException {
id = (jObj.getString("id"));
Log.d("TEST", " ID : " + id);
}
public void recevieGroups(JSONObject jObj) throws JSONException {
JSONArray jArray = jObj.getJSONArray("groups");
for (int i = 0; i < jArray.length(); i++) {
String g;
JSONObject jRealObject = jArray.getJSONObject(i);
g = (jRealObject.getString("group"));
groupsList.add(g);
Log.d("TEST", " groupNames : " + g);
}
}
public Exception getException() {
Exception result = exception;
exception = null;
return result;
}
private class Connect implements Runnable {
public void run() {
try {
Log.d("TCPConnection", "Connect-run");
address = InetAddress.getByName(ip);
Log.d("TCPConnection-Connect", "Skapar socket");
socket = new Socket(address, connectionPort);
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
output.flush();
Log.d("TCPConnection-Connect", "Strömmar klara");
newMessage("CONNECTED");
receive = new Receive();
receive.start();
} catch (Exception e) { // SocketException, UnknownHostException
Log.d("TCPConnection-Connect", e.toString());
exception = e;
newMessage("EXCEPTION");
}
}
}
public class Disconnect implements Runnable {
public void run() {
try {
if (socket != null)
socket.close();
if (input != null)
input.close();
if (output != null)
output.close();
thread.stop();
newMessage("CLOSED");
} catch (IOException e) {
exception = e;
newMessage("EXCEPTION");
}
}
}
public class Send implements Runnable {
private String exp;
public Send(String exp) {
this.exp = exp;
}
public void run() {
try {
output.writeUTF(exp);
output.flush();
} catch (IOException e) {
exception = e;
newMessage("EXCEPTION");
}
}
}
}
This is the "Controller":
package com.example.simon_000.buddy;
public class MainActivity extends Activity
implements NavigationDrawerFragment.NavigationDrawerCallbacks {
/**
* Fragment managing the behaviors, interactions and presentation of the navigation drawer.
*/
private NavigationDrawerFragment mNavigationDrawerFragment;
/**
* Used to store the last screen title. For use in {#link #restoreActionBar()}.
*/
private CharSequence mTitle;
private myMap tempMapfragment = new myMap();
private Menu menu;
private String inetAddress = "195.178.232.7";
private Integer port = 7117;
private TCPConnection connect;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startNavDrawer();
connect = new TCPConnection(inetAddress, port, this);
connect.connect();
}
public void myPosition(String id, double LONGITUDE, double LATITUDE) {
StringWriter stringWriter = new StringWriter();
JsonWriter writer = new JsonWriter(stringWriter);
try {
writer.beginObject().name("type").value("location").name("id").value(id).name("longitude").value(LONGITUDE).name("latitude").value(LATITUDE).endObject();
} catch (IOException e) {
e.printStackTrace();
}
connect.send(stringWriter.toString());
}
public void getMembers(String group) {
StringWriter stringWriter = new StringWriter();
JsonWriter writer = new JsonWriter(stringWriter);
try {
writer.beginObject().name("type").value("members").name("group").value(group).endObject();
} catch (IOException e) {
e.printStackTrace();
}
connect.send(stringWriter.toString());
}
public void getGroups() {
// Aktuella grupper
// { ”type”:”groups” }
// { “type”:”groups”, ”groups”:[ {”group”:”NAME”}, …] }
StringWriter stringWriter = new StringWriter();
JsonWriter writer = new JsonWriter(stringWriter);
try {
writer.beginObject().name("type").value("groups").endObject();
} catch (IOException e) {
e.printStackTrace();
}
connect.send(stringWriter.toString());
}
public void registerGroup(String groupName, String userName) {
StringWriter stringWriter = new StringWriter();
JsonWriter writer = new JsonWriter(stringWriter);
try {
writer.beginObject().name("type").value("register").name("group").value(groupName).name("member").value(userName).endObject();
} catch (IOException e) {
e.printStackTrace();
}
connect.send(stringWriter.toString());
}
public void updateMapMarkers(ArrayList<members> memberList) {
for(members m: memberList){
tempMapfragment.addMarker(m);
}
}
#Override
protected void onDestroy() {
super.onDestroy();
connect.disconnect();
}
private void startNavDrawer() {
mNavigationDrawerFragment = (NavigationDrawerFragment)
getFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
#Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
communication fragment2 = new communication();
switch (position) {
case 0:
// fragment1
// use fragment transaction and add the fragment to the container
fragmentTransaction.replace(R.id.container, fragment2);
fragmentTransaction.commit();
break;
case 1:
// fragment2
fragmentTransaction.replace(R.id.container, tempMapfragment);
fragmentTransaction.commit();
break;
case 2:
// fragment2
break;
default:
// fragment1
// use fragment transaction and add the fragment to the container
fragmentTransaction.replace(R.id.container, fragment2);
fragmentTransaction.commit();
}
}
public void onSectionAttached(int number) {
switch (number) {
case 1:
mTitle = getString(R.string.title_section1);
break;
case 2:
mTitle = getString(R.string.title_section2);
break;
case 3:
mTitle = getString(R.string.title_section3);
break;
}
}
public void restoreActionBar() {
ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(mTitle);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
this.menu = menu;
if (!mNavigationDrawerFragment.isDrawerOpen()) {
// Only show items in the action bar relevant to this screen
// if the drawer is not showing. Otherwise, let the drawer
// decide what to show in the action bar.
getMenuInflater().inflate(R.menu.main, menu);
restoreActionBar();
return true;
}
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//Setting maptype
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
private static final String ARG_SECTION_NUMBER = "section_number";
/**
* Returns a new instance of this fragment for the given section
* number.
*/
public static PlaceholderFragment newInstance(int sectionNumber) {
PlaceholderFragment fragment = new PlaceholderFragment();
Bundle args = new Bundle();
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
fragment.setArguments(args);
return fragment;
}
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
return rootView;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((MainActivity) activity).onSectionAttached(
getArguments().getInt(ARG_SECTION_NUMBER));
}
}
}
This is the fragment, its in the part where i open a Dialog onclick.
package com.example.simon_000.buddy.Fragments;
public class communication extends Fragment {
private ListView list;
private EditText groupet;
private EditText nameet;
private ListView memberList;
private Button btsend, btUpdate;
private GroupAdapter Groupadapter;
private NameAdapter Nameadapter;
public communication() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_communication, container, false);
getGroupInfo();
initiateVariables(view);
return view;
}
private void initiateVariables(View view) {
list = (ListView) view.findViewById(R.id.grouplistView);
// groupsList = new ArrayList<String>();
// namesList = new ArrayList<String>();
groupet = (EditText) view.findViewById(R.id.etgroupName);
nameet = (EditText) view.findViewById(R.id.etUsername);
btsend = (Button) view.findViewById(R.id.btSend);
btUpdate = (Button) view.findViewById(R.id.btUpdate);
groupet.setText("MadKim");
Groupadapter = new GroupAdapter(getActivity(), R.layout.row, TCPConnection.groupsList);
list.setAdapter(Groupadapter);
list.setOnItemClickListener(new listListener());
btsend.setOnClickListener(new Listener());
btUpdate.setOnClickListener(new ListenerUpdate());
}
public void getGroupInfo(){
((MainActivity)getActivity()).getGroups();
}
private class Listener implements View.OnClickListener {
#Override
public void onClick(View view) {
// sc.startThreadCommunication();
String group = groupet.getText().toString();
String name = nameet.getText().toString();
// sending query to server
if(group.isEmpty() || name.isEmpty() ){
Toast.makeText(getActivity(), "You need to fill in all the fields.", Toast.LENGTH_LONG).show();
}else {
((MainActivity)getActivity()).registerGroup(groupet.getText().toString(), nameet.getText().toString());
getGroupInfo();
Groupadapter.notifyDataSetChanged();
//hides keyboard
nameet.clearFocus();
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(nameet.getWindowToken(), 0);
//show user info
Toast.makeText(getActivity(), "Successfully registered to: "+groupet.getText().toString()+
" with username: "+nameet.getText().toString(), Toast.LENGTH_LONG).show();
groupet.setText("");
nameet.setText("");
}
}
}
private class ListenerUpdate implements View.OnClickListener {
#Override
public void onClick(View view) {
getGroupInfo();
Groupadapter = new GroupAdapter(getActivity(), R.layout.row, TCPConnection.groupsList);
list.setAdapter(Groupadapter);
Groupadapter.notifyDataSetChanged();
}
}
//REVENUES list onClick LISTENER
private class listListener implements AdapterView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
// ListView Clicked item index
int itemPosition = position;
Nameadapter.notifyDataSetChanged();
((MainActivity)getActivity()).getMembers(TCPConnection.groupsList.get(itemPosition).toString());
Nameadapter.notifyDataSetChanged();
//open selected finanse and show more information
Dialog d = new Dialog(getActivity());
String title = getResources().getString(R.string.dialogTitle);
d.setTitle(title);
d.setCanceledOnTouchOutside(true);
//inserting xml file in Dialog
LayoutInflater factory = LayoutInflater.from(getActivity());
View infoLayout = factory.inflate(R.layout.dialog, null);
memberList = (ListView) infoLayout.findViewById(R.id.memberList);
Button updatebt = (Button) infoLayout.findViewById(R.id.updateDialogBt);
updatebt.setOnClickListener(new updateDialogListener());
d.setContentView(infoLayout);
Nameadapter = new NameAdapter(getActivity(), R.layout.rownames, TCPConnection.namesList);
memberList.setAdapter(Nameadapter);
Nameadapter.notifyDataSetChanged();
d.show();
}
private class updateDialogListener implements View.OnClickListener {
#Override
public void onClick(View view) {
Nameadapter = new NameAdapter(getActivity(), R.layout.rownames, TCPConnection.namesList);
memberList.setAdapter(Nameadapter);
Nameadapter.notifyDataSetChanged();
}
}
}
}
This is my error:
10-27 17:49:00.168 24903-24903/com.example.simon_000.buddy E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.simon_000.buddy, PID: 24903
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131034141, class android.widget.ListView) with Adapter(class com.example.simon_000.buddy.customs.GroupAdapter)]
at android.widget.ListView.layoutChildren(ListView.java:1555)
at android.widget.AbsListView.onTouchUp(AbsListView.java:3624)
at android.widget.AbsListView.onTouchEvent(AbsListView.java:3436)
at android.view.View.dispatchTouchEvent(View.java:7713)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2210)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1945)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2216)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1959)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2329)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1568)
at android.app.Activity.dispatchTouchEvent(Activity.java:2458)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2277)
at android.view.View.dispatchPointerEvent(View.java:7893)
at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:3950)
at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3829)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3395)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3445)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3414)
at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3521)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3422)
at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3578)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3395)
at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3445)
at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3414)
at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3422)
at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3395)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5535)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5515)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5486)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5615)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:138)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:5146)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.j
Your adapter.notifyDataSetChanged() must be called from the UI thread. At present it's called from a background thread.
So instead of:
adapter.notifyDataSetChanged();
You should write:
yourActivity.runOnUiThread(new Runnable(){
public void run() {
adapter.notifyDataSetChanged();
}
});
When calling the method from a background thread.
This allows the ListView to update properly with the data attached to the adapter that has been changed.
I'm attempting to populate a ListView with XML Data by using an ArrayList - which I've been able to accomplish thus far - the issue is the ArrayList does not seem to populate the ListView with data beyond the first item in the listView and I'm unsure why.
Screenshot
XML Data:
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<response>
<cmd>getVideos</cmd>
<success>1</success>
<NumberOfVideos>4</NumberOfVideos>
<Videos>
<Video>
<VideoName>sample_iPod</VideoName>
<VideoDesc/>
<VideoUrl>
http://mobile.example.com/api/wp-content/uploads/sites/6/2014/01/api/1/06087297988b.m4v
</VideoUrl>
<VideoTags/>
</Video>
<Video>
<VideoName>sample_mpeg4</VideoName>
<VideoDesc/>
<VideoUrl>
http://mobile.example.com/api/wp-content/uploads/sites/6/2014/01/api/1/b5ed9e7100e2.mp4
</VideoUrl>
<VideoTags/>
</Video>
<Video>
<VideoName>sample_sorenson</VideoName>
<VideoDesc/>
<VideoUrl>
http://mobile.example.com/api/wp-content/uploads/sites/6/2014/01/api/1/2a8e64b24997.mov
</VideoUrl>
<VideoTags/>
</Video>
<Video>
<VideoName>sample_iTunes</VideoName>
<VideoDesc/>
<VideoUrl>
http://mobile.example.com/api/wp-content/uploads/sites/6/2014/01/api/1/6c7f65254aad.mov
</VideoUrl>
<VideoTags/>
</Video>
</Videos>
</response>
CustomListViewAdapter.java
public class CustomListViewAdapter extends ArrayAdapter<Cmd> {
Activity context;
List<Cmd> videos;
public CustomListViewAdapter(Activity context, List<Cmd> videos) {
super(context, R.layout.list_item2, videos);
this.context = context;
this.videos = videos;
}
/*private view holder class*/
private class ViewHolder {
ImageView imageView;
TextView txtSuccess;
TextView txtCmd;
TextView txtPrice;
}
public Cmd getItem(int position) {
return videos.get(position);
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
LayoutInflater inflater = context.getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(R.layout.list_item2, null);
holder = new ViewHolder();
holder.txtSuccess = (TextView) convertView.findViewById(R.id.success);
holder.txtCmd = (TextView) convertView.findViewById(R.id.cmd);
holder.txtPrice = (TextView) convertView.findViewById(R.id.price);
holder.imageView = (ImageView) convertView.findViewById(R.id.thumbnail);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Cmd cmd = (Cmd) getItem(position);
holder.txtSuccess.setText(cmd.getSuccess());
holder.txtCmd.setText(cmd.getCmd());
// holder.imageView.setImageBitmap(cmd.getImageBitmap());
holder.txtPrice.setText(cmd.getVideoName() + "");
return convertView;
}
}
SAXParserAsyncTaskActivity.java
public class SAXParserAsyncTaskActivity extends Activity implements
OnClickListener, OnItemClickListener {
Button button;
ListView listView;
List<Cmd> videos = new ArrayList<Cmd>();
CustomListViewAdapter listViewAdapter;
static final String URL = "http://mobile.example.com/api/xml.php?cmd=getVideos&username=fake&password=";
public static final String LIBRARY = "Library";
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.parser_main);
findViewsById();
button.setOnClickListener(this);
listView.setOnItemClickListener(this);
GetXMLTask task = new GetXMLTask(this);
task.execute(new String[] { URL });
}
private void findViewsById() {
button = (Button) findViewById(R.id.button);
listView = (ListView) findViewById(R.id.cmdList);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
}
#Override
public void onClick(View view) {
// GetXMLTask task = new GetXMLTask(this);
// task.execute(new String[] { URL });
}
// private inner class extending AsyncTask
private class GetXMLTask extends AsyncTask<String, Void, List<Cmd>> {
private Activity context;
public GetXMLTask(Activity context) {
this.context = context;
}
protected void onPostExecute(List<Cmd> videos) {
listViewAdapter = new CustomListViewAdapter(context, videos);
listView.setAdapter(listViewAdapter);
}
/*
* uses HttpURLConnection to make Http request from Android to download
* the XML file
*/
private String getXmlFromUrl(String urlString) {
StringBuffer output = new StringBuffer("");
try {
InputStream stream = null;
URL url = new URL(urlString);
URLConnection connection = url.openConnection();
HttpURLConnection httpConnection = (HttpURLConnection) connection;
httpConnection.setRequestMethod("GET");
httpConnection.connect();
if (httpConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
stream = httpConnection.getInputStream();
BufferedReader buffer = new BufferedReader(
new InputStreamReader(stream));
String s = "";
while ((s = buffer.readLine()) != null)
output.append(s);
}
} catch (Exception ex) {
ex.printStackTrace();
}
return output.toString();
}
#Override
protected List<Cmd> doInBackground(String... urls) {
List<Cmd> videos = null;
String xml = null;
for (String url : urls) {
xml = getXmlFromUrl(url);
InputStream stream = new ByteArrayInputStream(xml.getBytes());
videos = SAXXMLParser.parse(stream);
for (Cmd cmd : videos) {
String videoName = cmd.getVideoName();
// String getVideos = cmd.getVideos();
String getVideo = cmd.getVideo();
String getVideoURL = cmd.getVideoURL();
String getNumberOfVideos = cmd.getNumberOfVideos();
Bitmap bitmap = null;
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 1;
try {
bitmap = BitmapFactory.decodeStream(
new URL(videoName).openStream(), null,
bmOptions);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// stream.close();
return videos;
}
}
}
Cmd.java
public class Cmd implements ListAdapter {
private String success;
private String cmd;
List<Cmd> videos;
private String video;
private String numberofvideos;
private String videoname;
private String videourl;
private LayoutInflater mInflater;
Button fav_up_btn1;
Button fav_dwn_btn1;
Context my_context;
// private Bitmap imageBitmap;
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// If convertView wasn't null it means we have already set it to our
// list_item_user_video so no need to do it again
if (convertView == null) {
// This is the layout we are using for each row in our list
// anything you declare in this layout can then be referenced below
convertView = mInflater.inflate(R.layout.list_item_user_video,
parent, false);
}
// We are using a custom imageview so that we can load images using urls
ImageView thumb = (ImageView) convertView
.findViewById(R.id.userVideoThumbImageView);
//thumb.setScaleType(ScaleType.FIT_XY);
TextView title = (TextView) convertView
.findViewById(R.id.userVideoTitleTextView);
TextView uploader = (TextView) convertView
.findViewById(R.id.userVideouploaderTextView);
TextView viewCount = (TextView) convertView
.findViewById(R.id.userVideoviewsTextView);
uploader.setText(videos.get(position).getTitle());
viewCount.setText(videos.get(position).getviewCount() + " views");
fav_up_btn1 = (Button) convertView.findViewById(R.id.fav_up_btn1);
fav_up_btn1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
boolean favIsUp = fav_up_btn1
.getBackground()
.getConstantState()
.equals(my_context.getResources()
.getDrawable(R.drawable.fav_up_btn1)
.getConstantState());
// set the background
fav_up_btn1
.setBackgroundResource(favIsUp ? R.drawable.fav_dwn_btn1
: R.drawable.fav_up_btn1);
}
});
// Get a single video from our list
final Cmd video = videos.get(position);
// Set the image for the list item
// / thumb.setImageDrawable(video.getThumbUrl());
//thumb.setScaleType(ScaleType.FIT_XY);
// Set the title for the list item
title.setText(video.getTitle());
uploader.setText("by " + video.getUploader() + " | ");
return convertView;
}
public String getUploader() {
// TODO Auto-generated method stub
return null;
}
public String getviewCount() {
// TODO Auto-generated method stub
return null;
}
public CharSequence getTitle() {
// TODO Auto-generated method stub
return null;
}
public String getCmd() {
return cmd;
}
public void setCmd(String cmd) {
this.cmd = cmd;
}
public String getSuccess() {
return success;
}
public void setSuccess(String success) {
this.success = success;
}
public String getNumberOfVideos() {
return numberofvideos;
}
public void setNumberOfVideos(String numberofvideos) {
this.numberofvideos = numberofvideos;
}
public List<Cmd> getVideos() {
return videos;
}
public void setVideos(List<Cmd> videos) {
this.videos = videos;
}
public String getVideo() {
return video;
}
public void setVideo(String video) {
this.video = video;
}
public String getVideoName() {
return videoname;
}
public void setVideoName(String videoname) {
this.videoname = videoname;
}
public String getVideoURL() {
return videourl;
}
public void setVideoURL(String videourl) {
this.videourl = videourl;
}
#Override
public int getCount() {
return videos.size();
}
#Override
public Object getItem(int position) {
return videos.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
// TODO Auto-generated method stub
return position;
}
#Override
public int getViewTypeCount() {
// TODO Auto-generated method stub
return 0;
}
#Override
public boolean hasStableIds() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isEmpty() {
// TODO Auto-generated method stub
return false;
}
#Override
public void registerDataSetObserver(DataSetObserver observer) {
// TODO Auto-generated method stub
}
#Override
public void unregisterDataSetObserver(DataSetObserver observer) {
// TODO Auto-generated method stub
}
#Override
public boolean areAllItemsEnabled() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isEnabled(int position) {
// TODO Auto-generated method stub
return false;
}
public String getId() {
// TODO Auto-generated method stub
return null;
}
}
SAXXMLParser.java
public class SAXXMLParser {
public static List<Cmd> parse(InputStream is) {
List<Cmd> response = null;
try {
// create a XMLReader from SAXParser
XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser()
.getXMLReader();
// create a SAXXMLHandler
SAXXMLHandler saxHandler = new SAXXMLHandler();
// store handler in XMLReader
xmlReader.setContentHandler(saxHandler);
// the process starts
xmlReader.parse(new InputSource(is));
// get the `Video list`
response = saxHandler.getResponse();
} catch (Exception ex) {
Log.d("XML", "SAXXMLParser: parse() failed");
ex.printStackTrace();
}
// return video list
return response;
}
}
SAXXMLHandler.java
public class SAXXMLHandler extends DefaultHandler {
private List<Cmd> videos;
private String tempVal;
// to maintain context
private Cmd cmd;
public SAXXMLHandler() {
videos = new ArrayList<Cmd>();
}
public List<Cmd> getResponse() {
return videos;
}
// Event Handlers
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// reset
tempVal = "";
if (qName.equalsIgnoreCase("cmd")) {
// create a new instance of cmd
cmd = new Cmd();
}
}
public void characters(char[] ch, int start, int length)
throws SAXException {
tempVal = new String(ch, start, length);
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
if (qName.equalsIgnoreCase("videos")) {
// add it to the list
videos.add(cmd);
} else if (qName.equalsIgnoreCase("success")) {
cmd.setSuccess(tempVal);
} else if (qName.equalsIgnoreCase("numberofvideos")) {
cmd.setNumberOfVideos(tempVal);
} else if (qName.equalsIgnoreCase("videos")) {
cmd.setVideos(videos);
} else if (qName.equalsIgnoreCase("video")) {
cmd.setVideo(tempVal);
} else if (qName.equalsIgnoreCase("videoname")) {
cmd.setVideoName(tempVal);
} else if (qName.equalsIgnoreCase("videourl")) {
cmd.setVideoURL(tempVal);
}
}
}
parser_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="#+id/button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="#string/button" />
<ListView
android:id="#+id/cmdList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
XML Screenshot
P.S.
If any additional information is required - please let me know (I will be at my desk working on this for the next few hours and will gladly answer any questions and accept any answers promptly)
In SAXXMLHandler.java's endElement() method you only add the cmd to the videos list if qName.equalsIgnoreCase("videos").
In all other cases you modify the cmd but you dont actually add it to the list. You want to add a videos.add(cmd) statement in the else if blocks as well so all the cmd's get added to the list.
This mistake right here is the cause of your List<Cmd> videos only having one item and thus only showing one item in your listview.
I'm calling the object here.
public class TestDetails extends ListActivity {
protected TextView testNameText;
protected SQLiteDatabase db;
protected TextView testvalueText;
protected List<TestAction> actions;
protected TestItemAdapter adapter;
protected int testId;
protected int categoryId;
#Override
//adds options menu
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.list_search: onSearchRequested();
break;
}
return true;
}
//end of add options menu
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_details);
// Get the intent, verify the action and get the query
db = (new DatabaseHelper(this)).getWritableDatabase();
Intent intent1 = getIntent();
SimpleSearch SSearch = new SimpleSearch();
if (Intent.ACTION_SEARCH.equals(intent1.getAction())) {
String query = intent1.getStringExtra(SearchManager.QUERY);
SSearch.testSearch(query);
}
testId = getIntent().getIntExtra("EMPLOYEE_ID", 0);
SQLiteDatabase db = (new DatabaseHelper(this)).getWritableDatabase();
Cursor cursor = db.rawQuery("SELECT emp._id, emp.firstName, emp.lastName, emp.title, emp.officePhone, emp.cellPhone, emp.email, emp.managerId, mgr.firstName managerFirstName, mgr.lastName managerLastName FROM employee emp LEFT OUTER JOIN employee mgr ON emp.managerId = mgr._id WHERE emp._id = ?",
new String[]{""+testId});
if (cursor.getCount() == 1)
{
cursor.moveToFirst();
testNameText = (TextView) findViewById(R.id.employeeName);
testNameText.setText(cursor.getString(cursor.getColumnIndex("firstName")) + " " + cursor.getString(cursor.getColumnIndex("lastName")));
actions = new ArrayList<TestAction>();
String officePhone = cursor.getString(cursor.getColumnIndex("officePhone"));
if (officePhone != null) {
actions.add(new TestAction("Call office", officePhone, TestAction.ACTION_CALL));
}
String cellPhone = cursor.getString(cursor.getColumnIndex("cellPhone"));
if (cellPhone != null) {
actions.add(new TestAction("Call mobile", cellPhone, TestAction.ACTION_CALL));
actions.add(new TestAction("SMS", cellPhone, TestAction.ACTION_SMS));
}
String email = cursor.getString(cursor.getColumnIndex("email"));
if (email != null) {
actions.add(new TestAction("Email", email, TestAction.ACTION_EMAIL));
}
categoryId = cursor.getInt(cursor.getColumnIndex("managerId"));
if (categoryId>0) {
actions.add(new TestAction("View manager", cursor.getString(cursor.getColumnIndex("managerFirstName")) + " " + cursor.getString(cursor.getColumnIndex("managerLastName")), TestAction.ACTION_VIEW));
}
cursor = db.rawQuery("SELECT count(*) FROM employee WHERE managerId = ?",
new String[]{""+testId});
cursor.moveToFirst();
int count = cursor.getInt(0);
if (count>0) {
actions.add(new TestAction("View direct reports", "(" + count + ")", TestAction.ACTION_REPORTS));
}
adapter = new TestItemAdapter();
setListAdapter(adapter);
}
}
class TestItemAdapter extends ArrayAdapter<TestAction> {
TestItemAdapter() {
super(TestDetails.this, R.layout.action_list_item, actions);
}
#Override
public boolean areAllItemsEnabled() {
return false;
}
public boolean isEnabled(int position) {
return false;
}
public View getView(int position, View convertView, ViewGroup parent) {
TestAction action = actions.get(position);
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.action_list_item, parent, false);
TextView label = (TextView) view.findViewById(R.id.label);
label.setText(action.getLabel());
TextView data = (TextView) view.findViewById(R.id.data);
data.setText(action.getData());
return view;
}
}
}
This is the class from which I'm calling the object.(part of the class)
public class SimpleSearch extends ListActivity {
protected SQLiteDatabase db;
protected Cursor cursor;
protected ListAdapter adapter;
protected String query;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
db = (new DatabaseHelper(this)).getWritableDatabase();
// Get the intent, verify the action and get the query
Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
testSearch(query);
}
else TestListAll();
}
But I'm getting a force close on running the application. Stack trace shows the error to be in SSearch.testSearch(query); statement. What am I missing here?
Stack trace:
app_vercode:1
device_model:umts_jordan
build_version:1.11.18
condition:1
processName:com.simple.search
pid:3529
uid:10063
tag:null
shortMsg:java.lang.NullPointerException
longMsg:java.lang.NullPointerException: Unable to start activity ComponentInfo{com.simple.search/com.simple.search.TestDetails}: java.lang.NullPointerException
stackTrace:java.lang.RuntimeException: Unable to start activity ComponentInfo{com.simple.search/com.simple.search.TestDetails}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1664)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1680)
at android.app.ActivityThread.access$1500(ActivityThread.java:117)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3703)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at com.simple.search.SimpleSearch.testSearch(SimpleSearch.java:68)
at com.simple.search.TestDetails.onCreate(TestDetails.java:59)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1628)
... 11 more
Most likely the line
String query = intent1.getStringExtra(SearchManager.QUERY);
Is assigning a null value to query - are you sure the correct extra is there? I usually get extras in this manner:
public static final String TAG = "MyActivity";
public static final String DATA_KEY = "DataKey";
public static final String MY_CUSTOM_ACTION = "MyCustomSearchAction";
public void onCreate(Bundle savedInstanceState) {
Intent intent1 = getIntent();
SimpleSearch SSearch = new SimpleSearch();
if (intent1.getAction().equals(MY_CUSTOM_ACTION)
&& intent1.hasExtra(SearchManager.QUERY)
&& intent.hasExtra(DATA_KEY)) {
String query = intent1.getStringExtra(SearchManager.QUERY);
DataObject data = intent1.getParcelableExtra(DATA_KEY);
if (query != null && data != null)
SSearch.testSearch(query, data);
else {
//invalid query
Log.d(TAG,"Activity started with invalid query data - closing");
this.finish();
return;
}
} else {
//Invalid Intent
Log.d(TAG,"Activity started with invalid intent - closing");
this.finish();
return;
}
}
A data object can look like this:
public class DataObject implements Parcelable {
public String someData;
public String someMoreData;
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(someData);
dest.writeString(someMoreDate);
}
//Constructor for parceler
public DataObject(Parcel src) {
someData = src.readString();
someMoreData = src.readString();
}
public static final Parcelable.Creator<DataObject> CREATOR =
new Parcelable.Creator<DataObject>() {
public DataObject createFromParcel(Parcel in) {
return new DataObject(in);
}
public DataObject[] newArray(int size) {
return new DataObject[size];
}
};
}
To start your activity just go:
DataObject data = new DataObject();
data.someData = "test";
data.someMoreData = "test2";
Intent intent = new Intnent(this, MyActivity.class);
intent.setAction(MyActivity.MY_CUSTOM_ACTION);
intent.putExtra(MyActivity.DATA_KEY,data);
intent.putExtra(SearchManager.QUERY, "Query");
startActivity(intent);