2017年6月24日 星期六

Android:Content Provider範例

Content Provider 內容提供者,是Andoird提供應用程式存取資料的機制,Android提供許多類型的內容,像是聯絡人名稱、電話、手機上的圖片等,皆是以Content Provider提供存取。


以下例子是以存取手機上的聯絡人為範例


要存取聯絡人必須取得權限,請在AndroidMainifest.xml裡新增

 
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />

PS:在Andoird 6.0之後,如果在AndroidMainifest加入的是危險權限,會執行的應用程式裡要求使用者允許存取資料

MainActivity.xml:


 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.user.contentprovidertest.MainActivity"
    android:orientation="vertical"
    android:gravity="center">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="查詢聯絡人資料"
        android:id="@+id/btnread"/>
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="新增聯絡人資料"
        android:id="@+id/btninsert"/>

</LinearLayout>

MainActivity.java:
 
import android.content.Intent;
import android.content.pm.PackageManager;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import static android.Manifest.permission.READ_CONTACTS;
import static android.Manifest.permission.WRITE_CONTACTS;

public class MainActivity extends AppCompatActivity {

    private  int REQUEST_CONTACTS = 1;
    private Button btnread,btninsert;



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

        findviewById();

        //檢查使用者是否已經允許了權限
        int permission = ActivityCompat.checkSelfPermission(this, READ_CONTACTS);
        if (permission != PackageManager.PERMISSION_GRANTED){
            //如果未取得權限,向使用者要求允許
            ActivityCompat.requestPermissions(this,new String[]{READ_CONTACTS,WRITE_CONTACTS},REQUEST_CONTACTS);
        }
        else {
            //如果已有權限,進行下面工作
            btnread.setOnClickListener(btnlistener);
        }

    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        btnread.setOnClickListener(btnlistener);
    }

    private void findviewById() {
        btnread = (Button)findViewById(R.id.btnread);
        btninsert = (Button)findViewById(R.id.btninsert);
        btnread.setOnClickListener(btnlistener);
        btninsert.setOnClickListener(btnlistener);

    }
    private View.OnClickListener btnlistener = new View.OnClickListener()
    {
        @Override
        public void onClick(View v) {
            if (v.getId()==R.id.btnread){
                startActivity(new Intent(MainActivity.this,readContent.class));
            }
            if (v.getId()==R.id.btninsert){
                startActivity(new Intent(MainActivity.this,insertContent.class));
            }
        }
    };
}

insertContent.xml:

 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.user.contentprovidertest.insertContent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="姓名 :"/>
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/edtname"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="電話 :"/>
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/edtphone"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center">
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="新增"
            android:id="@+id/btninsert"/>
        
    </LinearLayout>
</LinearLayout>

insertContent.java:
 
import android.content.ContentProviderOperation;
import android.content.DialogInterface;
import android.content.OperationApplicationException;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import java.util.ArrayList;

public class insertContent extends AppCompatActivity {

    private EditText edtname,edtphone;
    private Button btninsert;

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

        findviewById();

    }

    private void findviewById() {
        edtname = (EditText)findViewById(R.id.edtname);
        edtphone = (EditText)findViewById(R.id.edtphone);
        btninsert = (Button)findViewById(R.id.btninsert);
        btninsert.setOnClickListener(btnlistener);
    }

    private View.OnClickListener btnlistener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ArrayList list = new ArrayList(); //建立一個集合,存放操作指令
            int index = list.size();

            //新增一個資料操作,並加到操作集合中,資料對象是RawContacts,新增成功後會得到ID值
            list.add(ContentProviderOperation
                    .newInsert(ContactsContract.RawContacts.CONTENT_URI)
                    .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE,null)
                    .withValue(ContactsContract.RawContacts.ACCOUNT_NAME,null).build());

            //此段主要是寫入聯絡人姓名
            list.add(ContentProviderOperation
                    .newInsert(ContactsContract.Data.CONTENT_URI)
                    .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID,index)
                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                    .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,edtname.getText().toString().trim()).build());

            //利用第一個新增RawContacts操作後得到的ID值,建立新增到Phone的電話號碼操作
            list.add(ContentProviderOperation
                    .newInsert(ContactsContract.Data.CONTENT_URI)
                    .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID,index)
                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                    .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER,edtphone.getText().toString().trim())
                    .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE).build());

            try {
                getContentResolver().applyBatch(ContactsContract.AUTHORITY,list);
                new AlertDialog.Builder(insertContent.this)
                        .setMessage("新增成功")
                        .setPositiveButton("確定", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                edtphone.setText("");
                                edtname.setText("");
                            }
                        })
                        .show();
            } catch (RemoteException e) {
                e.printStackTrace();
            } catch (OperationApplicationException e) {
                e.printStackTrace();
            }
        }
    };
}

readContent.xml:

 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.user.contentprovidertest.readContent">

    <ListView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/listread"></ListView>

</RelativeLayout>

readContent.java:
 
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.provider.ContactsContract;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;

import java.util.ArrayList;

public class readContent extends AppCompatActivity {

    private ListView listread;
//    SimpleCursorAdapter adapter;

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

        listread = (ListView) findViewById(R.id.listread);
        listread.setOnItemClickListener(listlistener);
        query();

    }

    private void query() {

        ContentResolver resolver = getContentResolver();

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
            String[] projection = {ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER};
            //query(欲查詢的Uri,查詢回傳的表格欄位,SQL的Where語法,where中的參數,排序ASC OR DESC)
            Cursor cursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projection, null, null, null, null);

            ArrayList alname = new ArrayList();
            ArrayList alphone = new ArrayList();
            while (cursor.moveToNext()) {
                alname.add(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)));
                alphone.add(cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
            }

            ArrayList listMockData = new ArrayList();

            for (int i = 0; i < alname.size(); i++) {

                listItem newsData = new listItem();
                newsData.setName((String) alname.get(i));
                newsData.setPhone((String) alphone.get(i));
                listMockData.add(newsData);
            }
            listread.setAdapter(new listAdapter(readContent.this,listMockData));

            //            while (cursor.moveToNext()){
            //                int id = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID));
            //                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
            //                Log.d("TAG",id+"/"+name);
            //            }


//            adapter = new SimpleCursorAdapter(this,
//                    android.R.layout.simple_list_item_2,
//                    cursor,
//                    new String[]{ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER},
//                    new int[]{android.R.id.text1,android.R.id.text2},
//                    1);
//            listread.setAdapter(adapter);

        }

    }

    private AdapterView.OnItemClickListener listlistener = new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView adapterView, View view, int position, long id) {


            listItem bs = (listItem) adapterView.getItemAtPosition(position);
            Intent it = new Intent();
            it.setClass(readContent.this, updateContacts.class);
            Bundle bd = new Bundle();
            bd.putString("name", bs.getName());
            bd.putString("phone",bs.getPhone());
            it.putExtras(bd);
            startActivity(it);

        }
    };

    //當update完資料後,回到readContacts時,刷新listview
    protected void onRestart(){
        super.onRestart();
        query();
    }
}

updateContacts.xml:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.user.contentprovidertest.updateContacts"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="姓名 :"/>
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/edtname"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="電話 :"/>
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/edtphone"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center">
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="更新"
            android:id="@+id/btnupdate"/>
        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="刪除"
            android:id="@+id/btndelete"/>

    </LinearLayout>
    
</LinearLayout>

updateContacts.java:

import android.content.ContentProviderOperation;
import android.content.DialogInterface;
import android.content.OperationApplicationException;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import java.util.ArrayList;

public class updateContacts extends AppCompatActivity {

    private EditText edtname,edtphone;
    private Button btnupdate,btndelete;
    String name;

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

        findviewById();

        Bundle bd = getIntent().getExtras();
        name = bd.getString("name");
        String phone = bd.getString("phone");
        edtname.setText(name);
        edtphone.setText(phone);
    }

    private void findviewById() {
        edtname = (EditText)findViewById(R.id.edtname);
        edtphone = (EditText)findViewById(R.id.edtphone);
        btnupdate = (Button)findViewById(R.id.btnupdate);
        btnupdate.setOnClickListener(btnlistener);
        btndelete = (Button)findViewById(R.id.btndelete);
        btndelete.setOnClickListener(btnlistener);

    }
    private View.OnClickListener btnlistener = new View.OnClickListener() {


        @Override
        public void onClick(View v) {

            if (v.getId()==R.id.btnupdate) {
                //where的條件敘述,name=? AND 資料格式=?
                String wherename = ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?";
                //條件敘述中的資料值,對應到上面的兩個問號位置
                String[] paramsname = new String[]{name, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE};

                String wherephone = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?";
                String[] paramsphone = new String[]{edtname.getText().toString().trim(), ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE};

                ArrayList alList = new ArrayList();

                alList.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                        .withSelection(wherename, paramsname)
                        .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, edtname.getText().toString().trim())
                        .build());

                alList.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
                        .withSelection(wherephone, paramsphone)
                        .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, edtphone.getText().toString().trim())
                        .build());


                try {
                    getContentResolver().applyBatch(ContactsContract.AUTHORITY, alList);
                    new AlertDialog.Builder(updateContacts.this)
                            .setMessage("更新成功")
                            .setPositiveButton("確定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    finish();
                                }
                            })
                            .show();
                } catch (RemoteException e) {
                    e.printStackTrace();
                } catch (OperationApplicationException e) {
                    e.printStackTrace();
                }
            }
            else {
                String where = ContactsContract.Data.DISPLAY_NAME + "= ? ";
                String[] params = new String[]{name};
                ArrayList alist = new ArrayList();
                alist.add(ContentProviderOperation.newDelete(ContactsContract.RawContacts.CONTENT_URI)
                .withSelection(where,params)
                .build());

                try {
                    getContentResolver().applyBatch(ContactsContract.AUTHORITY,alist);
                    new AlertDialog.Builder(updateContacts.this)
                            .setMessage("刪除成功")
                            .setPositiveButton("確定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    finish();
                                }
                            })
                            .show();

                } catch (RemoteException e) {
                    e.printStackTrace();
                } catch (OperationApplicationException e) {
                    e.printStackTrace();
                }
            }
        }
    };

}

listItem.java:

public class listItem {

    private String name;
    private String phone;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

listAdapter.java:

public class listAdapter extends BaseAdapter {
    private ArrayList<listItem> listData;
    private LayoutInflater layoutInflater;
    public listAdapter(Context context, ArrayList<listItem> listData) {
        this.listData = listData;
        layoutInflater = LayoutInflater.from(context);
    }
    @Override
    public int getCount() {
        return listData.size();
    }
    @Override
    public Object getItem(int position) {
        return listData.get(position);
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            convertView = layoutInflater.inflate(R.layout.listlayout, null);
            holder = new ViewHolder();
            holder.nameView = (TextView) convertView.findViewById(R.id.txtname);
            holder.phoneView = (TextView) convertView.findViewById(R.id.txtphone);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        listItem newsItem = listData.get(position);
        holder.nameView.setText(newsItem.getName());
        holder.phoneView.setText(newsItem.getPhone());
        return convertView;
    }
    static class ViewHolder {
        TextView nameView;
        TextView phoneView;

    }
}

listlayout.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txtname"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/txtphone"/>

</LinearLayout>

2 則留言:

  1. 您好 不好意思請問一下
    這篇文章是不是少了一個listlayout
    因為程式有報錯 並且在listAdapter.java裡面
    還報錯了txtname和txtphone這兩項
    請問是不是也是在listlayout
    謝謝

    回覆刪除
    回覆
    1. 抱歉,前陣子沒空看blog,所以沒回答你
      沒錯少了一個listlayout.xml
      請開一個listlayout.xml在裡面加上兩個TextView
      一個id=txtname、另一個=txtphone

      刪除