Android 中自定义ContentProvider与ContentObserver的使用简单实例

Android 中自定义ContentProvider与ContentObserver的使用简单实例

示例说明:

该示例中一共包含两个工程。其中一个工程完成了自定义ContentProvider,另外一个工程用于测试该自定义ContentProvider且在该工程中使用了ContentObserver监听自定义ContentProvider的数据变化

以下代码为工程TestContentProvider

ContentProviderTest如下:

package cn.testcontentprovider;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
/**
 * Demo描述:
 * 自定义ContentProvider的实现
 * ContentProvider主要用于在不同的应用程序之间共享数据,这也是官方推荐的方式.
 *
 * 注意事项:
 * 1 在AndroidManifest.xml中注册ContentProvider时的属性
 *  android:exported="true"表示允许其他应用访问.
 * 2 注意*和#这两个符号在Uri中的作用
 *  其中*表示匹配任意长度的字符
 *  其中#表示匹配任意长度的数据
 *  所以:
 *  一个能匹配所有表的Uri可以写成:
 *  content://cn.bs.testcontentprovider/*
 *  一个能匹配person表中任意一行的Uri可以写成:
 *  content://cn.bs.testcontentprovider/person/#
 *
 */
public class ContentProviderTest extends ContentProvider {
  private SQLiteDatabaseOpenHelper mSQLiteDatabaseOpenHelper;
  private final static String AUTHORITY="cn.bs.testcontentprovider";
  private static UriMatcher mUriMatcher;
  private static final int PERSON_DIR = 0;
  private static final int PERSON = 1; 

  /**
   * 利用静态代码块初始化UriMatcher
   * 在UriMatcher中包含了多个Uri,每个Uri代表一种操作
   * 当调用UriMatcher.match(Uri uri)方法时就会返回该uri对应的code;
   * 比如此处的PERSONS和PERSON
   */
  static {
    mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    // 该URI表示返回所有的person,其中PERSONS为该特定Uri的标识码
    mUriMatcher.addURI(AUTHORITY, "person", PERSON_DIR);
    // 该URI表示返回某一个person,其中PERSON为该特定Uri的标识码
    mUriMatcher.addURI(AUTHORITY, "person/#", PERSON);
  } 

  /**
   * 在自定义ContentProvider中必须覆写getType(Uri uri)方法.
   * 该方法用于获取Uri对象所对应的MIME类型.
   *
   * 一个Uri对应的MIME字符串遵守以下三点:
   * 1 必须以vnd开头
   * 2 如果该Uri对应的数据可能包含多条记录,那么返回字符串应该以"vnd.android.cursor.dir/"开头
   * 3 如果该Uri对应的数据只包含一条记录,那么返回字符串应该以"vnd.android.cursor.item/"开头
   */
  @Override
  public String getType(Uri uri) {
    switch (mUriMatcher.match(uri)) {
    case PERSON_DIR:
      return "vnd.android.cursor.dir/"+AUTHORITY+".persons";
    case PERSON:
      return "vnd.android.cursor.item/"+AUTHORITY+".person";
    default:
      throw new IllegalArgumentException("unknown uri"+uri.toString());
    }
  }   

  @Override
  public boolean onCreate() {
    mSQLiteDatabaseOpenHelper=new SQLiteDatabaseOpenHelper(getContext());
    return true;
  } 

  /**
   * 插入操作:
   * 插入操作只有一种可能:向一张表中插入
   * 返回结果为新增记录对应的Uri
   * 方法db.insert()返回结果为新增记录对应的主键值
   */
  @Override
  public Uri insert(Uri uri, ContentValues values) {
    SQLiteDatabase db = mSQLiteDatabaseOpenHelper.getWritableDatabase();
    switch (mUriMatcher.match(uri)) {
    case PERSON_DIR:
      long newId = db.insert("person", "name,phone,salary", values);
      //向外界通知该ContentProvider里的数据发生了变化 ,以便ContentObserver作出相应
      getContext().getContentResolver().notifyChange(uri, null);
      return ContentUris.withAppendedId(uri, newId);
    default:
      throw new IllegalArgumentException("unknown uri" + uri.toString());
    }
  } 

  /**
   * 更新操作:
   * 更新操作有两种可能:更新一张表或者更新某条数据
   * 在更新某条数据时原理类似于查询某条数据,见下.
   */
  @Override
  public int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {
    SQLiteDatabase db = mSQLiteDatabaseOpenHelper.getWritableDatabase();
    int updatedNum = 0;
    switch (mUriMatcher.match(uri)) {
    // 更新表
    case PERSON_DIR:
      updatedNum = db.update("person", values, selection, selectionArgs);
      break;
    // 按照id更新某条数据
    case PERSON:
      long id = ContentUris.parseId(uri);
      String where = "personid=" + id;
      if (selection != null && !"".equals(selection.trim())) {
        where = selection + " and " + where;
      }
      updatedNum = db.update("person", values, where, selectionArgs);
      break;
    default:
      throw new IllegalArgumentException("unknown uri" + uri.toString());
    }
    //向外界通知该ContentProvider里的数据发生了变化 ,以便ContentObserver作出相应
    getContext().getContentResolver().notifyChange(uri, null);
    return updatedNum;
  } 

  /**
   * 删除操作:
   * 删除操作有两种可能:删除一张表或者删除某条数据
   * 在删除某条数据时原理类似于查询某条数据,见下.
   */
  @Override
  public int delete(Uri uri, String selection, String[] selectionArgs) {
    SQLiteDatabase db = mSQLiteDatabaseOpenHelper.getWritableDatabase();
    int deletedNum = 0;
    switch (mUriMatcher.match(uri)) {
    // 删除表
    case PERSON_DIR:
      deletedNum = db.delete("person", selection, selectionArgs);
      break;
    // 按照id删除某条数据
    case PERSON:
      long id = ContentUris.parseId(uri);
      String where = "personid=" + id;
      if (selection != null && !"".equals(selection.trim())) {
        where = selection + " and " + where;
      }
      deletedNum = db.delete("person", where, selectionArgs);
      break;
    default:
      throw new IllegalArgumentException("unknown uri" + uri.toString());
    }
    //向外界通知该ContentProvider里的数据发生了变化 ,以便ContentObserver作出相应
    getContext().getContentResolver().notifyChange(uri, null);
    return deletedNum;
  } 

  /**
   * 查询操作:
   * 查询操作有两种可能:查询一张表或者查询某条数据
   *
   * 注意事项:
   * 在查询某条数据时要注意--因为此处是按照personid来查询
   * 某条数据,但是同时可能还有其他限制.例如:
   * 要求personid为2且name为xiaoming1
   * 所以在查询时分为两步:
   * 第一步:
   * 解析出personid放入where查询条件
   * 第二步:
   * 判断是否有其他限制(如name),若有则将其组拼到where查询条件.
   *
   * 详细代码见下.
   */
  @Override
  public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {
    SQLiteDatabase db = mSQLiteDatabaseOpenHelper.getWritableDatabase();
    Cursor cursor =null;
    switch (mUriMatcher.match(uri)) {
    // 查询表
    case PERSON_DIR:
      cursor = db.query("person", projection, selection, selectionArgs,null, null, sortOrder);
      break;
    // 按照id查询某条数据
    case PERSON:
      // 第一步:
      long id = ContentUris.parseId(uri);
      String where = "personid=" + id;
      // 第二步:
      if (selection != null && !"".equals(selection.trim())) {
        where = selection + " and " + where;
      }
      cursor = db.query("person", projection, where, selectionArgs, null, null, sortOrder);
      break;
    default:
      throw new IllegalArgumentException("unknown uri" + uri.toString());
    }
    return cursor;
  } 

}

SQLiteDatabaseOpenHelper如下:

package cn.testcontentprovider;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class SQLiteDatabaseOpenHelper extends SQLiteOpenHelper {
  public SQLiteDatabaseOpenHelper(Context context) {
    super(context, "contentprovidertest.db", null, 1);
  } 

  @Override
  public void onCreate(SQLiteDatabase db) {
    db.execSQL("create table person(personid integer primary key autoincrement,name varchar(20),phone varchar(12),salary Integer(12))");
  } 

  //当数据库版本号发生变化时调用该方法
  @Override
  public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
    //db.execSQL("ALTER TABLE person ADD phone varchar(12) NULL");
    //db.execSQL("ALTER TABLE person ADD salary Integer NULL");
  } 

} 

MainActivity如下:
[java] view plain copy
package cn.testcontentprovider;
import android.app.Activity;
import android.os.Bundle;
public class MainActivity extends Activity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
  } 

}

AndroidManifest.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="cn.testcontentprovider"
  android:versionCode="1"
  android:versionName="1.0" > 

  <uses-sdk
    android:minSdkVersion="8"
    android:targetSdkVersion="8" /> 

  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> 

  <application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
      android:name="cn.testcontentprovider.MainActivity"
      android:label="@string/app_name" >
      <intent-filter>
        <action android:name="android.intent.action.MAIN" /> 

        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity> 

     <provider
      android:name="cn.testcontentprovider.ContentProviderTest"
      android:authorities="cn.bs.testcontentprovider"
      android:exported="true"
     />
  </application> 

</manifest>

main.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"
  > 

   <Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="该应用包含一个自定义的ContentProvider"
    android:textSize="15sp"
   android:layout_centerInParent="true"
  /> 

</RelativeLayout>

以下代码为工程TestBaidu

MainActivity如下:

package cn.testbaidu;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.ContentObserver;
import android.database.Cursor;
/**
 * Demo描述:
 * 应用A(TestBaidu)调用另外一个应用(TestContentProvider)中的自定义ContentProvider,即:
 * 1 自定义ContentProvider的使用
 * 2 其它应用调用该ContentProvider
 * 3 ContentObserver的使用
 *
 * 备注说明:
 * 1 该例子在以前版本的基础上整理了代码
 * 2 该例子在以前版本的基础上融合了ContentObserver的使用
 *  利用ContentObserver随时监听ContentProvider的数据变化.
 *  为实现该功能需要在自定义的ContentProvider的insert(),update(),delete()
 *  方法中调用getContext().getContentResolver().notifyChange(uri, null);
 *  向外界通知该ContentProvider里的数据发生了变化 ,以便ContentObserver作出相应
 *
 * 测试方法:
 * 1 依次测试ContentProvider的增查删改(注意该顺序)!!
 * 2 其它应用查询该ContentProvider的数据
 *
 */
public class MainActivity extends Activity {
  private Button mAddButton;
  private Button mDeleteButton;
  private Button mUpdateButton;
  private Button mQueryButton;
  private Button mTypeButton;
  private long lastTime=0;
  private ContentResolver mContentResolver;
  private ContentObserverSubClass mContentObserverSubClass;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    init();
    initContentObserver();
  } 

  private void init() {
    mContentResolver=this.getContentResolver(); 

    mAddButton=(Button) findViewById(R.id.addButton);
    mAddButton.setOnClickListener(new ClickListenerImpl()); 

    mDeleteButton=(Button) findViewById(R.id.deleteButton);
    mDeleteButton.setOnClickListener(new ClickListenerImpl()); 

    mUpdateButton=(Button) findViewById(R.id.updateButton);
    mUpdateButton.setOnClickListener(new ClickListenerImpl()); 

    mQueryButton=(Button) findViewById(R.id.queryButton);
    mQueryButton.setOnClickListener(new ClickListenerImpl()); 

    mTypeButton=(Button) findViewById(R.id.typeButton);
    mTypeButton.setOnClickListener(new ClickListenerImpl()); 

  } 

  // 注册一个针对ContentProvider的ContentObserver用来观察内容提供者的数据变化
  private void initContentObserver() {
    Uri uri = Uri.parse("content://cn.bs.testcontentprovider/person");
    mContentObserverSubClass=new ContentObserverSubClass(new Handler());
    this.getContentResolver().registerContentObserver(uri, true,mContentObserverSubClass);
  } 

  @Override
  protected void onDestroy() {
    super.onDestroy();
    if (mContentObserverSubClass!=null) {
      this.getContentResolver().unregisterContentObserver(mContentObserverSubClass);
    }
  } 

  // 自定义一个内容观察者ContentObserver
  private class ContentObserverSubClass extends ContentObserver { 

    public ContentObserverSubClass(Handler handler) {
      super(handler);
    } 

    //采用时间戳避免多次调用onChange( )
    @Override
    public void onChange(boolean selfChange) {
      super.onChange(selfChange);
      System.out.println("ContentObserver onChange() selfChange="+ selfChange);
      if (System.currentTimeMillis()-lastTime>2000) {
        ContentResolver resolver = getContentResolver();
        Uri uri = Uri.parse("content://cn.bs.testcontentprovider/person");
        // 获取最新的一条数据
        Cursor cursor = resolver.query(uri, null, null, null,"personid desc limit 1");
        while (cursor.moveToNext()) {
          int personid = cursor.getInt(cursor.getColumnIndex("personid"));
          System.out.println("内容提供者中的数据发生变化,现数据中第一条数据的personid="+ personid);
        }
        cursor.close();
        lastTime=System.currentTimeMillis();
      }else{
        System.out.println("时间间隔过短,忽略此次更新");
      } 

    } 

    @Override
    public boolean deliverSelfNotifications() {
      return true;
    } 

  } 

  private class ClickListenerImpl implements OnClickListener {
    @Override
    public void onClick(View v) {
      switch (v.getId()) {
      case R.id.addButton:
        Person person = null;
        for (int i = 0; i < 5; i++) {
          person = new Person("xiaoming" + i, "9527" + i, (8888 + i));
          testInsert(person);
        }
        break;
      case R.id.deleteButton:
        testDelete(1);
        break;
      case R.id.updateButton:
        testUpdate(3);
        break;
      case R.id.queryButton:
        // 查询表
        // queryFromContentProvider(-1); 

        // 查询personid=2的数据
        testQuery(2);
        break;
      case R.id.typeButton:
        testType();
        break;
      default:
        break;
      } 

    } 

  }
  private void testInsert(Person person) {
    ContentValues contentValues=new ContentValues();
    contentValues.put("name", person.getName());
    contentValues.put("phone", person.getPhone());
    contentValues.put("salary",person.getSalary());
    Uri insertUri=Uri.parse("content://cn.bs.testcontentprovider/person");
    Uri returnUri=mContentResolver.insert(insertUri, contentValues);
    System.out.println("新增数据:returnUri="+returnUri);
  } 

  private void testDelete(int index){
    Uri uri=Uri.parse("content://cn.bs.testcontentprovider/person/"+String.valueOf(index));
    mContentResolver.delete(uri, null, null);
  } 

  private void testUpdate(int index){
    Uri uri=Uri.parse("content://cn.bs.testcontentprovider/person/"+String.valueOf(index));
    ContentValues values=new ContentValues();
    values.put("name", "hanmeimei");
    values.put("phone", "1234");
    values.put("salary", 333);
    mContentResolver.update(uri, values, null, null);
  } 

  private void testQuery(int index) {
    Uri uri=null;
    if (index<=0) {
      //查询表
      uri=Uri.parse("content://cn.bs.testcontentprovider/person");
    } else {
       //按照id查询某条数据
      uri=Uri.parse("content://cn.bs.testcontentprovider/person/"+String.valueOf(index));
    } 

    //对应上面的:查询表
    //Cursor cursor= mContentResolver.query(uri, null, null, null, null); 

    //对应上面的:查询personid=2的数据
    //注意:因为name是varchar字段的,所以应该写作"name='xiaoming1'"
    //   若写成"name=xiaoming1"查询时会报错
    Cursor cursor= mContentResolver.query(uri, null, "name='xiaoming1'", null, null); 

    while(cursor.moveToNext()){
      int personid=cursor.getInt(cursor.getColumnIndex("personid"));
      String name=cursor.getString(cursor.getColumnIndex("name"));
      String phone=cursor.getString(cursor.getColumnIndex("phone"));
      int salary=cursor.getInt(cursor.getColumnIndex("salary"));
      System.out.println("查询得到:personid=" + personid+",name="+name+",phone="+phone+",salary="+salary);
    }
    cursor.close();
  } 

  private void testType(){
    Uri dirUri=Uri.parse("content://cn.bs.testcontentprovider/person");
    String dirType=mContentResolver.getType(dirUri);
    System.out.println("dirType:"+dirType); 

    Uri itemUri=Uri.parse("content://cn.bs.testcontentprovider/person/3");
    String itemType=mContentResolver.getType(itemUri);
    System.out.println("itemType:"+itemType);
  } 

}

Person如下:

package cn.testbaidu; 

public class Person {
  private Integer id;
  private String name;
  private String phone;
  private Integer salary;
  public Person(String name, String phone,Integer salary) {
    this.name = name;
    this.phone = phone;
    this.salary=salary;
  }
  public Person(Integer id, String name, String phone,Integer salary) {
    this.id = id;
    this.name = name;
    this.phone = phone;
    this.salary=salary;
  }
  public Integer getId() {
    return id;
  }
  public void setId(Integer id) {
    this.id = id;
  }
  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;
  }
  public Integer getSalary() {
    return salary;
  }
  public void setSalary(Integer salary) {
    this.salary = salary;
  }
  @Override
  public String toString() {
    return "Person [id=" + id + ", name=" + name + ", phone=" + phone+ ", salary=" + salary + "]";
  } 

}

main.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" > 

  <Button
    android:id="@+id/addButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="30dip"
    android:text="增加"
    android:textSize="20sp" /> 

   <Button
    android:id="@+id/queryButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="30dip"
     android:layout_below="@id/addButton"
    android:text="查询"
    android:textSize="20sp" /> 

  <Button
    android:id="@+id/deleteButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="30dip"
    android:layout_below="@id/queryButton"
    android:text="删除"
    android:textSize="20sp" /> 

  <Button
    android:id="@+id/updateButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="30dip"
     android:layout_below="@id/deleteButton"
    android:text="修改"
    android:textSize="20sp" /> 

   <Button
    android:id="@+id/typeButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="30dip"
     android:layout_below="@id/updateButton"
    android:text="类型"
    android:textSize="20sp" /> 

</RelativeLayout>

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • Android中okhttp3使用详解

    一.引入包 在项目module下的build.gradle添加okhttp3依赖 compile 'com.squareup.okhttp3:okhttp:3.3.1' 二.基本使用 1.okhttp3 Get 方法 1.1 .okhttp3 同步 Get方法 /** * 同步Get方法 */ private void okHttp_synchronousGet() { new Thread(new Runnable() { @Override public void run() { try {

  • Android SQLite数据库版本升级的管理实现

    Android SQLite数据库版本升级的管理实现 我们知道在SQLiteOpenHelper的构造方法: super(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) 中最后一个参数表示数据库的版本号.当新的版本号大于当前的version时会调用方法: onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 所以我们

  • 微信Android热更新Tinker使用详解(星空武哥)

    Tinker是什么 Tinker是微信官方的Android热补丁解决方案,它支持动态下发代码.So库以及资源,让应用能够在不需要重新安装的情况下实现更新.当然,你也可以使用Tinker来更新你的插件. 它主要包括以下几个部分: gradle编译插件: tinker-patch-gradle-plugin 核心sdk库: tinker-android-lib 非gradle编译用户的命令行版本: tinker-patch-cli.jar 为什么使用Tinker 当前市面的热补丁方案有很多,其中比较

  • Android ListView之setEmptyView正确使用方法

    Android ListView之setEmptyView正确使用方法 我们知道ListView组件提供了一个空数据是的视图设置方法setEmptyView,该方法存在一个诟病,就是空视图和listview组件要在一个Parent中,这个就不在此细说,下面说另一个问题,原因其实和前面那个问题同出一辙. 假如emptyView和listview在布局中,已经属于同一个parent,设置EmptyView的代码如下 private void setEmptyView(){ emptyTv.setTe

  • Android 优化Handler防止内存泄露

    Android 优化Handler防止内存泄露 Demo描述: Handler可能导致的内存泄露及其优化 1 关于常见的Handler的用法但是可能导致内存泄露 2 优化方式请参考BetterHandler和BetterRunnable的实现 package cc.cc; import java.lang.ref.WeakReference; import android.os.Bundle; import android.os.Handler; import android.os.Messag

  • Android LocationManager获取经度与纬度等地理信息

    Android LocationManager获取经度与纬度等地理信息 利用LocationManager实现定位功能 1 实时更新经度,纬度 2 根据经度和纬度获取地理信息(比如:国家,街道等)(略过) MainActivity如下: package cc.bb; import java.util.Iterator; import java.util.List; import android.location.Location; import android.location.Location

  • Android 中自定义ContentProvider与ContentObserver的使用简单实例

    Android 中自定义ContentProvider与ContentObserver的使用简单实例 示例说明: 该示例中一共包含两个工程.其中一个工程完成了自定义ContentProvider,另外一个工程用于测试该自定义ContentProvider且在该工程中使用了ContentObserver监听自定义ContentProvider的数据变化 以下代码为工程TestContentProvider ContentProviderTest如下: package cn.testcontentp

  • Android中自定义ContentProvider实例

    //以下为TestBaidu MainActivity如下: 复制代码 代码如下: package cn.testbaidu; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.app.Activity; import an

  • Android中自定义水平进度条样式之黑色虚线

    以下内容给大家介绍Android中自定义水平进度条样式之黑色虚线,对代码实现方法感兴趣的朋友一起学习吧. 布局layout中使用: <ProgressBar android:id="@+id/progress_bar" style="?android:attr/progressBarStyleHorizontal" <!--必须设置为水平--> android:progressDrawable="@drawable/myprogress&

  • Android中自定义PopupWindow实现弹出框并带有动画效果

    使用PopupWindow来实现弹出框,并且带有动画效果 首先自定义PopupWindow public class LostPopupWindow extends PopupWindow { public Lost lost; public void onLost(Lost lost){ this.lost = lost; } private View conentView; public View getConentView() { return conentView; } public L

  • Android中自定义的dialog中的EditText无法弹出输入法解决方案

    1.解决无法弹出输入法: 在show()方法调用之前,用dialog.setView(new EditText(context))添加一个空的EditText,由于是自定义的AlertDialog,有我们指定的布局,所以设置这个不会影响我们的功能,这样就可以弹出输入法了-- 2.可以弹出输入法了,但了为了增强用户体验性,当dialog中含有editText时应该,在显示dialog的同时自动弹出键盘: (1) 可以在自定义的dialog中增加如下方法: public void showKeybo

  • Android中自定义view实现侧滑效果

    效果图: 看网上的都是两个view拼接,默认右侧的不显示,水平移动的时候把右侧的view显示出来.但是看最新版QQ上的效果不是这样的,但给人的感觉却很好,所以献丑来一发比较高仿的. 知识点: 1.ViewDragHelper 的用法: 2.滑动冲突的解决: 3.自定义viewgroup. ViewDragHelper 出来已经比较久了 相信大家都比较熟悉,不熟悉的话google一大把这里主要简单用一下它的几个方法 1.tryCaptureView(View child, int pointerI

  • Android中自定义一个View的方法详解

    本文实例讲述了Android中自定义一个View的方法.分享给大家供大家参考,具体如下: Android中自定义View的实现比较简单,无非就是继承父类,然后重载方法,即便如此,在实际编码中难免会遇到一些坑,我把自己遇到的一些问题和解决方法总结一下,希望对广大码友们有所帮助. 注意点① 用xml定义Layout时,Root element 最好使用merge 当我们需要继承一个布局比较复杂的ViewGroup(比较多的是LinearLayout.RelativeLayout)时,通常会用xml来

  • Android 中自定义Dialog样式的Activity点击空白处隐藏软键盘功能(dialog不消失)

    一.需求触发场景: 项目中需要开发带有EditText的Dialog显示,要求在编辑完EditText时,点击Dilog的空白处隐藏软键盘.但是Dialog不会消失.示例如下: 二.实现方法: 发布需求时,我个人曾想过直接通过new的方式直接创建Dialog,经过多次尝试,无法实现要求,所以采用将Activity设置为Dialog样式进行展示,调用方法实现需求.具体实现如下: 本次演示示例的工程结构: 2.1AndroidMainfest.xml配置文件 需要在配置文件中将需要显示为dialog

  • 解决Android中自定义DialogFragment解决宽度和高度问题

    关于详解Android应用中DialogFragment的基本用法,大家可以参考下. 1. 概述 DialogFragment在android 3.0时被引入.是一种特殊的Fragment,用于在Activity的内容之上展示一个模态的对话框.典型的用于:展示警告框,输入框,确认框等等. 在DialogFragment产生之前,我们创建对话框:一般采用AlertDialog和Dialog.注:官方不推荐直接使用Dialog创建对话框. 2. 好处与用法 使用DialogFragment来管理对话

  • Android中ActionBar和ToolBar添加返回箭头的实例代码

     1.ActionBar添加返回箭头 //onCreate方法中 ActionBar actionBar = this.getSupportActionBar(); actionBar.setTitle("搜索功能"); actionBar.setDisplayHomeAsUpEnabled(true); //activity类中的方法 @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.get

随机推荐