0

so I've created a list view in my xml file which just has the simple id/list property.

In my class, I've set the name and number parameters in from the ContactsContracts class.

I've got 2 questions, First is when I click a number/name it should be highlighted and be selected and saved unless the user unclicks it. Second question is how do I, import the contacts photo...is it just in the String Array -> ...phone.Photo_ID?

Class:

package com.example.ankhit.saveme;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Color;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;


public class UserContacts extends ListActivity {


    ListView lv;
    Cursor cursor1;
    String spref_identifier = "com.example.app";
    String entryIdentifierPrefix = "selectionState_listEntry_";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user_contacts);

        cursor1 = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,null,null,null);
        startManagingCursor(cursor1);

        String[] from = {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,ContactsContract.CommonDataKinds.Phone.NUMBER,ContactsContract.CommonDataKinds.Phone._ID};

        int[] to = {android.R.id.text1,android.R.id.text2};

        SimpleCursorAdapter listAdapter = new SimpleCursorAdapter(this,android.R.layout.simple_list_item_2,cursor1,from,to);

        setListAdapter(listAdapter);

        lv = getListView();
        lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                saveSelectedState(position, !getSelectedState(position));
                refreshList();
            }
        });

    }


    private void saveSelectedState(int entryPosition, boolean selectedState) {
        SharedPreferences.Editor spe = this.getSharedPreferences(
                spref_identifier, Context.MODE_PRIVATE).edit();
        spe.putBoolean(entryIdentifierPrefix + entryPosition, selectedState);
        spe.commit();
    }

    private boolean getSelectedState(int entryPosition) {
        SharedPreferences sp = this.getSharedPreferences(
                spref_identifier, Context.MODE_PRIVATE);
        return sp.getBoolean(entryIdentifierPrefix + entryPosition, false); // Default value is set as false. Tweak this if necessary.
    }

    private void refreshList() {
        for (int i = 0; i < lv.getCount(); i++) {
            boolean selected = getSelectedState(i);
            ((View)lv.getItemAtPosition(i)).setBackgroundColor(selected ? Color.GREEN : Color.RED); // Change colors to whatever you need.
        }
    }

    @Override
    public long getSelectedItemId() {
        return super.getSelectedItemId();
    }

    @Override
    public int getSelectedItemPosition() {
        return super.getSelectedItemPosition();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_user_contacts, menu);
        return true;
    }

    @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.
        switch (item.getItemId()) {
            case R.id.homescreen:
                homescreenItem();
                return true;
            case R.id.dashboard:
                dashboardItem();
                return true;
            case R.id.about:
                aboutItem();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    private void homescreenItem(){
        startActivity(new Intent(UserContacts.this, Home.class));
    }

    private void dashboardItem(){
        startActivity(new Intent(UserContacts.this, Dashboard.class));
    }

    private void aboutItem(){
        new AlertDialog.Builder(this)
                .setTitle("About")
                .setMessage("Welcome to Save Me! An interactive and intuitive way to protect yourself during emergency situations and keep your location privacy. Made for a Dissertation and Developed by Ankhit Sharma")
                .setNeutralButton("OK" , new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                    }
                }).show();
    }
}

Errors:

02-11 13:48:43.069    7216-7216/com.example.ankhit.saveme E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.ClassCastException: android.content.ContentResolver$CursorWrapperInner cannot be cast to android.view.View
            at com.example.ankhit.saveme.UserContacts.refreshList(UserContacts.java:75)
            at com.example.ankhit.saveme.UserContacts.access$200(UserContacts.java:21)
            at com.example.ankhit.saveme.UserContacts$1.onItemClick(UserContacts.java:52)
            at android.widget.AdapterView.performItemClick(AdapterView.java:301)
            at android.widget.AbsListView.performItemClick(AbsListView.java:1507)
            at android.widget.AbsListView$PerformClick.run(AbsListView.java:3292)
            at android.widget.AbsListView.onTouchEvent(AbsListView.java:4550)
            at android.view.View.dispatchTouchEvent(View.java:7685)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2395)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2119)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2401)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2134)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2401)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2134)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2401)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2134)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2401)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2134)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2289)
            at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1575)
            at android.app.Activity.dispatchTouchEvent(Activity.java:2470)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2237)
            at android.view.View.dispatchPointerEvent(View.java:7892)
            at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3976)
            at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3860)
            at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5122)
            at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5101)
            at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5199)
            at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
            at android.os.MessageQueue.nativePollOnce(Native Method)
            at android.os.MessageQueue.next(MessageQueue.java:125)
            at android.os.Looper.loop(Looper.java:138)
            at android.app.ActivityThread.main(ActivityThread.java:5299)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
            at dalvik.system.NativeStart.main(Native Method)

XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.example.ankhit.saveme.UserContacts">

    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</RelativeLayout>

1 Answers1

0

I was just working on a very similar task. I solved the selection of contacts and keeping their selection status using Android's SharedPreferences.

I didn't just use the savedInstanceState of the app because while it does persist throughout the lifetime of the app, it does not when the app closes entirely. The SharedPreferences can be seen as the settings of your app, and they are persistent as long as your app is installed on the device. If you only need to save the selected contacts when the app is running and it is no problem to lose information about which contacts have been selected when your app closes, just follow this tutorial.

However, if you're using SharedPreferences instead, do something like this:

Writing to SharedPreferences, where 'com.example.app' is some random string value you use throughout your app to identify a set of shared preferences:

private enum Contact { CONTACT1 /*,... More enums */ }
String spref_identifier = "com.example.app";
String spref_contact1_selected = "contact1_selected";
...

private void saveSelectedState(Contact contact, Boolean selectedState) {
    SharedPreferences.Editor spe = this.getSharedPreferences(
  spref_identifier, Context.MODE_PRIVATE).edit();
    switch (contact) {
        case CONTACT1:
            spe.putBoolean(spref_contact1_selected, selectedState);
            spe.commit();
            break;
        [...]    // Other cases.
        default:
            break;
    }

}

And to read from SharedPreferences:

private Boolean getSelectedState(Contact contact) {
    SharedPreferences sp = this.getSharedPreferences(
  spref_identifier, Context.MODE_PRIVATE);
    switch (contact) {
        case CONTACT1:
            return sp.getBoolean(spref_contact1_selected, false); // Default value is set as false. Tweak this if necessary.
        [...]    // Other cases.
        default:
            return false;
    }
}

Finally, when the user clicks on a contact, just do this:

private void onButtonClick(View view) {
    Button button = (Button) view;
    // Toggle the selected state.
    saveSelectedState(Contact.CONTACT1, !getSelectedState(Contact.CONTACT1));
    boolean selected = getSelectedState(Contact.CONTACT1);
    button.setBackgroundColor(selected ? Color.GREEN : Color.RED); // Change colors to whatever you need.
}

When you now want to get all the selected contacts, just iterate over all your items from the enum Contact and get their respective selection state. Also, don't forget to check each selection state when you app starts, i.e. in the onCreate method. This way your app represents the exact state it was in last time you used it (even if it crashed sometime during the last use!).

And for the photo, please refer to this section from the Android Developers website.

EDIT:

Change the above methods to this:

String entryIdentifierPrefix = "selectionState_listEntry_";

private void saveSelectedState(int entryPosition, boolean selectedState) {
    SharedPreferences.Editor spe = this.getSharedPreferences(
  spref_identifier, Context.MODE_PRIVATE).edit();
    spe.putBoolean(entryIdentifierPrefix + entryPosition, selectedState);
    spe.commit();
}

private boolean getSelectedState(int entryPosition) {
    SharedPreferences sp = this.getSharedPreferences(
  spref_identifier, Context.MODE_PRIVATE);
    return sp.getBoolean(entryIdentifierPrefix + entryPosition, false); // Default value is set as false. Tweak this if necessary.
}

Now, also add this method:

private void refreshList() {
    for (int i = 0; i < lv.getCount(); i++) {
        boolean selected = getSelectedState(i);
        ((View)lv.getItemAtPosition(i)).setBackgroundColor(selected ? Color.GREEN : Color.RED); // Change colors to whatever you need.
    }
}

And finally, add these lines to your onCreate()-method:

....

lv.setOnItemClickListener(new OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        saveSelectedState(position, !getSelectedState(position));
        refreshList();                
    }
});

I cannot test this code right now, but it should work. Let me know if this was understandable.

Yeehaw
  • 105
  • 2
  • 11
  • Awesome, thanks for the explanations. Could you please edit and mention where in my code shall I put these statements, Because your sharedprefrences is actually what i am looking for an needed constantly saved. So do i replace my code what is in the saved instances and just put what you've suggested...I am not sure how to incorporate this with mine...I apologise I am very new to this stuff. @Yeehaw – Ankhit Sharma Feb 10 '15 at 20:09
  • I've made edits in my code with yours, however the sprefidentifier and position are giving me errors? How can I resolve these. Appreciate your help btw :) – Ankhit Sharma Feb 10 '15 at 21:39
  • I edited my code above, in `refreshList()` it's not `position`, it's the index `i` of course. My bad, sorry for that. Also, you need to add `String spref_identifier = "com.example.app";` as an instance variable right where you define `entryIdentifierPrefix`. That should fix the problems. – Yeehaw Feb 10 '15 at 22:35
  • I've made the corrections almost everything works, however, the new onItemClickListner was giving an error until I imported the class AdapterviewOnItemClick is that correct? also the entryIdentifierPrefix is defined in the scope and is giving me an error? See my edited code above...is that correct the way everything is put in? – Ankhit Sharma Feb 10 '15 at 22:54
  • What error does it give you? I can't see anything wrong with the code. – Yeehaw Feb 11 '15 at 01:22
  • thats the thing I don't get any compile errors and when I run it no errors in the logical? but the colours don't appear when I click one of the name/numbers. So I can't tell whats saved and what isn't? Also whatever I click for example, will be saved even if the app closes? – Ankhit Sharma Feb 11 '15 at 11:20
  • You could use a [Toast](http://developer.android.com/guide/topics/ui/notifiers/toasts.html#Basics) to quickly see whether the method has been called or not. As for the error, casting it to a `View` did produce the error. Look into your xml and check what type the elements of your listView are of. This type should equal the type you're casting to in the `refreshList()`-method. – Yeehaw Feb 12 '15 at 13:38
  • Also, in general I would recommend you read and work through the tutorials from the [Android Developers website](http://developer.android.com/guide/index.html), as it seems you lack some basic understanding of how Android apps work. Just putting some code together from here and there will not help you in the long run, especially since your project is for a dissertation. – Yeehaw Feb 12 '15 at 13:41
  • I've started looking at basic tutorials and thank you for being patient with me. I've just gotten started on all of this just recently so trying to soak up as much whilst meeting deliverables. In regards to the refreshList() I check the xml file which only has one Listview element nothing else. And if I substitute it with View it compiles but same errors occur. I've posted my XML above...any idea? PS. I really do appreciate all the help :) – Ankhit Sharma Feb 12 '15 at 13:58
  • I found another way of solving this. In the `refreshList()`-method, simply use this code: `for (int i = 0; i < lv.getCount(); i++) { lv.setItemChecked(position, getSelectedState(i)); }`. For this to work as expected, you also need to use `R.layout.simple_list_item_activated_2` instead of `simple_list_item_2` in the constructor of `SimpleCursorAdapter`. Finally, to change the background color when un-/selecting, refer to [this](http://stackoverflow.com/a/6589219/2440410). – Yeehaw Feb 12 '15 at 21:42
  • Thanks it works! it selects and stays. Thanks so much! Sorry I could not up vote cause I don't have enough rep points but really appreciate the help :) I saw the custom theme link you posted. I created a xml file in my drawable folder called customhighlight which set the activated state to "true". However, where do I add the first bit? to reference my drawable file in relation to my code? the bit below I don't know where to stick and call. Some thoughts please? @drawable/my_background – Ankhit Sharma Feb 13 '15 at 03:01