Android第一行代码阅读笔记-2

七、运行时权限

低于6.0系统只需要在AndroidManifest.xml加入需要的权限,用户同意安装时会统一授予。6.0之后加入运行时权限,即在使用过程中授予权限,可以随时回收权限。

普通权限:申请时系统自动进行授权。

危险权限:设计隐私和设备安全需要手动授权。9组24个。

权限列表:http://developer.android.google.cn/reference/android/Manifest.permission.html

权限组 权限
CALENDAR
CAMERA
CONTACTS
LOCATION
MICROPHONE
PHONE
SENSORS
SMS
STORAGE

1、在AndroidManifest.xml中声明

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.runtimepermissiontest">

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

    <application>
        ......
    </application>
</manifest>

2、在代码中申请

处理授予和不授予的执行代码

public class MainActivity extends AppCompatActivity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

       ......

        makeCall.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {

                if(ContextCompat.checkSelfPermission(ManiActivity.this, Manifest.permission.CALL_PHONE) 
					!= PackageManager.PERMISSION_GRANTED){
					ActivityCompat.requestPermissions(ManiActivity.this, new String[] {Manifest.permission.CALL_PHONE}, 1)
                }
        });

    }

    private void call() {

        try {

            Intent intent = new Intent(Intent.ACTION_CALL);

            intent.setData(Uri.parse("tel:10086"));

            startActivity(intent);

        } catch (SecurityException e) {

            e.printStackTrace();

        }

    }


    @Override

    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

        switch (requestCode) {

            case 1:

                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    call();

                } else {

                    Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show();

                }

                break;

            default:

        }

    }

} 

八、ContentProvider

APP通过ContentProvider对其数据向外提供访问接口。想要对该数据执行CRUD操作首先要通过Context中的getContentResolver()得到ContentResolver类。通过该类调用insert()等方法。这些方法都要接收一个Uri参数指定内容。

content://author+path

Uri mUri = Uri.parse("content://com.example.app.provider/table1");

1、AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.databasetest">

    <application

        .......>

        .......

        </activity>

        <provider

            android:name=".DatabaseProvider"

            android:authorities="com.example.databasetest.provider"

            android:enabled="true"

            android:exported="true" />

    </application>

</manifest>

2、MyDatabaseHelper

创建数据库

public class MyDatabaseHelper extends SQLiteOpenHelper {

    public static final String CREATE_BOOK = "create table Book ("

            + "id integer primary key autoincrement, "

            + "author text, "

            + "price real, "

            + "pages integer, "

            + "name text)";

    public static final String CREATE_CATEGORY = "create table Category ("

            + "id integer primary key autoincrement, "

            + "category_name text, "

            + "category_code integer)";

    private Context mContext;

    public MyDatabaseHelper(Context context, String name,
                            SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);

        mContext = context;

    }

    @Override
    public void onCreate(SQLiteDatabase db) {

        db.execSQL(CREATE_BOOK);

        db.execSQL(CREATE_CATEGORY);

       // Toast.makeText(mContext, "Create succeeded", Toast.LENGTH_SHORT).show();

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        db.execSQL("drop table if exists Book");

        db.execSQL("drop table if exists Category");

        onCreate(db);

    }

}

3、DataBaseProvider.java

创建ContentProvider,需要重写各种操作方法, getType返回Uri对象的MIME类型。

目录:vnd.android.cursor.dir/vnd.com.example.databasetest. provider.category

文件:vnd.android.cursor.item/vnd.com.example.databasetest. provider.category

public class DatabaseProvider extends ContentProvider {

    public static final int BOOK_DIR = 0;

    public static final int BOOK_ITEM = 1;

    public static final int CATEGORY_DIR = 2;

    public static final int CATEGORY_ITEM = 3;

    public static final String AUTHORITY = "com.example.databasetest.provider";

    private static UriMatcher uriMatcher;

    private MyDatabaseHelper dbHelper;

    static {

        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

        uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);

        uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);/#匹配任意长度数字

        uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);

        uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);

    }
    @Override
    public boolean onCreate() {

        dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2);

        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        // 查询数据
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        Cursor cursor = null;
        switch (uriMatcher.match(uri)) {
            case BOOK_DIR:
                cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case BOOK_ITEM:
                String bookId = uri.getPathSegments().get(1);
                cursor = db.query("Book", projection, "id = ?", new String[] { bookId }, null, null, sortOrder);
                break;
            case CATEGORY_DIR:
                cursor = db.query("Category", projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case CATEGORY_ITEM:
                String categoryId = uri.getPathSegments().get(1);
                cursor = db.query("Category", projection, "id = ?", new String[] { categoryId }, null, null, sortOrder);
                break;
            default:
                break;
        }
        return cursor;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // 添加数据
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        Uri uriReturn = null;
        switch (uriMatcher.match(uri)) {
            case BOOK_DIR:
            case BOOK_ITEM:
                long newBookId = db.insert("Book", null, values);
                uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
                break;
            case CATEGORY_DIR:
            case CATEGORY_ITEM:
                long newCategoryId = db.insert("Category", null, values);
                uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);
                break;
            default:
                break;
        }
        return uriReturn;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        // 更新数据
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int updatedRows = 0;
        switch (uriMatcher.match(uri)) {
            case BOOK_DIR:
                updatedRows = db.update("Book", values, selection, selectionArgs);
                break;
            case BOOK_ITEM:
                String bookId = uri.getPathSegments().get(1);
                updatedRows = db.update("Book", values, "id = ?", new String[] { bookId });
                break;
            case CATEGORY_DIR:
                updatedRows = db.update("Category", values, selection, selectionArgs);
                break;
            case CATEGORY_ITEM:
                String categoryId = uri.getPathSegments().get(1);
                updatedRows = db.update("Category", values, "id = ?", new String[] { categoryId });
                break;
            default:
                break;
        }
        return updatedRows;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // 删除数据
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int deletedRows = 0;
        switch (uriMatcher.match(uri)) {
            case BOOK_DIR:
                deletedRows = db.delete("Book", selection, selectionArgs);
                break;
            case BOOK_ITEM:
                String bookId = uri.getPathSegments().get(1);
                deletedRows = db.delete("Book", "id = ?", new String[] { bookId });
                break;
            case CATEGORY_DIR:
                deletedRows = db.delete("Category", selection, selectionArgs);
                break;
            case CATEGORY_ITEM:
                String categoryId = uri.getPathSegments().get(1);
                deletedRows = db.delete("Category", "id = ?", new String[] { categoryId });
                break;
            default:
                break;
        }
        return deletedRows;
    }

    @Override
    public String getType(Uri uri) {
        switch (uriMatcher.match(uri)) {
            case BOOK_DIR:
               return "vnd.android.cursor.dir/vnd.com.example.databasetest. provider.book";
            case BOOK_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.databasetest. provider.book";
            case CATEGORY_DIR:
                return "vnd.android.cursor.dir/vnd.com.example.databasetest. provider.category";
            case CATEGORY_ITEM:
                return "vnd.android.cursor.item/vnd.com.example.databasetest. provider.category";
        }
        return null;
    }
}

4、ManiActivity操作ContentProvider

public class MainActivity extends AppCompatActivity {
    private MyDatabaseHelper dbHelper;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
      dbHelper = new MyDatabaseHelper(this, "BookStore.db", null, 2);
        Button createDatabase = (Button) findViewById(R.id.create_database);
        createDatabase.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                dbHelper.getWritableDatabase();
            }
        });

        Button addData = (Button) findViewById(R.id.add_data);
        addData.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                // 开始组装第一条数据
                values.put("name", "The Da Vinci Code");
                values.put("author", "Dan Brown");
                values.put("pages", 454);
                values.put("price", 16.96);
                db.insert("Book", null, values); // 插入第一条数据
                values.clear();
                // 开始组装第二条数据
                values.put("name", "The Lost Symbol");
                values.put("author", "Dan Brown");
                values.put("pages", 510);
                values.put("price", 19.95);
                db.insert("Book", null, values); // 插入第二条数据
            }
        });

        Button updateData = (Button) findViewById(R.id.update_data);
        updateData.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                ContentValues values = new ContentValues();
                values.put("price", 10.99);
               db.update("Book", values, "name = ?", new String[] { "The Da Vinci Code" });
            }
        });

        Button deleteButton = (Button) findViewById(R.id.delete_data);

        deleteButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                db.delete("Book", "pages > ?", new String[] { "500" });
            }
        });
        Button queryButton = (Button) findViewById(R.id.query_data);
        queryButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase db = dbHelper.getWritableDatabase();
                // 查询Book表中所有的数据
                Cursor cursor = db.query("Book", null, null, null, null, null, null);
                if (cursor.moveToFirst()) {
                    do {
                        String name = cursor.getString(cursor.getColumnIndex("name"));
                        String author = cursor.getString(cursor.getColumnIndex("author"));
                        int pages = cursor.getInt(cursor.getColumnIndex("pages"));
                        double price = cursor.getDouble(cursor.getColumnIndex("price"));
                    } while (cursor.moveToNext());
                }
                cursor.close();
            }
        });
    }
}

九、Service

Service实现APP后台运行,适合不与用户交互但需长期运行的任务。服务不运行在单独的进程,依赖于创建服务时所在应用程序进程。服务默认不开启线程,即它默认运行在主线程需要手动在内部创建线程。

1、多线程操作

#继承方式
class MyThread extend Thread {
	public void run() {
		
	}
}
//启动
new MyThread().start();

#接口方式
class MyThread implements Runnable {
	public void run() {
		
	}
}
//启动
MyThread mThread = new MyThread();
new Thread(mThread).start();

#匿名类
new Thread(new Runnable() {
	public void run() {
	
	}
}).start();

2、UI操作

    Android中的异步消息主要由4部分组成:Message, Handler, MessageQueue和Looper。MessageQueue用于存放通过Handler发送的消息,这部分消息已知存在于消息队列等待被处理。每个线程只有一个MessageQueue对象。Looper是每个线程MessageQueue的管家,调用Looper的loop()方法后,就会将它取出并传递到Handler的handlerMessage()方法中。每个线程也只有一个Looper对象。

    一般首先在主线程中创建一个Handler对象,并重写HandlerMessage()方法。当子线程需要进程UI操作时,创建一个Message对象并通过Handler发出这条消息。之后这条消息会被添加到MessageQueue中等待被处理。而Looper则一直尝试从MessageQueue中取出待处理消息,分发到handler中的handleMessage()方法中。

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    public static final int UPDATE_TEXT = 1;
    private TextView text;
    private Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case UPDATE_TEXT:
                    // 在这里可以进行UI操作
                    text.setText("Nice to meet you");
                    break;
                default:
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text = (TextView) findViewById(R.id.text);
        Button changeText = (Button) findViewById(R.id.change_text);
        changeText.setOnClickListener(this);
    }

   @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.change_text:
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Message message = new Message();
                        message.what = UPDATE_TEXT;
                       handler.sendMessage(message); // 将Message对象发送出去
                    }
                }).start();
                break;
            default:
                break;
        }
   }
}

3、Service基本用法

onCreate()方法是在服务第一次创建时候调用,而onStartCommand()方法则是每次启动服务都会调用。onBind()方法在Activity绑定服务时回调。

MainService.java

public class MyService extends Service {

    public MyService() {
    }

    private DownloadBinder mBinder = new DownloadBinder();

    class DownloadBinder extends Binder {

        public void startDownload() {
            Log.d("MyService", "startDownload executed");
        }

        public int getProgress() {
            Log.d("MyService", "getProgress executed");
            return 0;
        }

    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("MyService", "onCreate executed");
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
        Notification notification = new NotificationCompat.Builder(this)
                .setContentTitle("This is content title")
                .setContentText("This is content text")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.mipmap.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
                .setContentIntent(pi)
                .build();
        startForeground(1, notification);//启动前台服务
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("MyService", "onStartCommand executed");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyService", "onDestroy executed");
    }

}

MainActivity

    重写ServiceConnection的onServiceConnection()和onServiceDisconnected(),他们在活动和服务绑定和解绑时调用。

每调用一个startService(),onStartCommand()就会执行一次,但实际上每个服务只存在一个实例。所以不管调用了多少次startService(), 只需要调用一次stopService()或stopSelf()。调用bindService()来获得一个和服务的持久连接。这时会回调onBind()方法。如果该服务还未创建则先调用onCreate()。

    如果对一个服务既调用了startService()又调用了bindService(),则必须同时调用stopService()和unbindService()方法,onDestroy()方法才会执行。

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private MyService.DownloadBinder downloadBinder;

    private ServiceConnection connection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            downloadBinder = (MyService.DownloadBinder) service;
            downloadBinder.startDownload();
            downloadBinder.getProgress();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startService = (Button) findViewById(R.id.start_service);
        Button stopService = (Button) findViewById(R.id.stop_service);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
        Button bindService = (Button) findViewById(R.id.bind_service);
        Button unbindService = (Button) findViewById(R.id.unbind_service);
        bindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
        Button startIntentService = (Button) findViewById(R.id.start_intent_service);
        startIntentService.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.start_service:
                Intent startIntent = new Intent(this, MyService.class);
                startService(startIntent); // 启动服务
                break;
            case R.id.stop_service:
                Intent stopIntent = new Intent(this, MyService.class);
                stopService(stopIntent); // 停止服务
                break;
            case R.id.bind_service:
                Intent bindIntent = new Intent(this, MyService.class);
                bindService(bindIntent, connection, BIND_AUTO_CREATE); // 绑定服务
                break;
            case R.id.unbind_service:
                unbindService(connection); // 解绑服务
                break;
            case R.id.start_intent_service:
                // 打印主线程的id
                Log.d("MainActivity", "Thread id is " + Thread.currentThread(). getId());
                Intent intentService = new Intent(this, MyIntentService.class);
                startService(intentService);
                break;
            default:
                break;
        }
    }

}

IntentService

服务默认执行在主线程中,如果需要处理耗时操作需要在Service中手动开启和关闭子线程。Android设计了IntentService类,启动后自动执行其中的onHandleIntent()方法,执行完执行onDestroy()方法。

public class MyIntentService extends IntentService {

    public MyIntentService() {
        super("MyIntentService"); // 调用父类的有参构造函数
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // 打印当前线程的id
        Log.d("MyIntentService", "Thread id is " + Thread.currentThread(). getId());
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d("MyIntentService", "onDestroy executed");
    }

}

10、Application

    Android提供一个Application类,每当程序启动时,系统自动初始化这个类。我们可以自己定制这个类,以便获取全局信息,如Context。 程序运行时自动执行onCreate(), 在Activity中只需要执行 MyApplication.getContext()

public class MyApplication extends Application {
	private static Context context;
	
	@override
	public void onCreate() {
		context = getApplicationCcontext();
	}
	
	public static Context getContext() {
		return context;
	}
} 

    还需要在AndroidManifest.xml中声明这个Application

<application
	android:name="com.example.howie.MyApplication"
	...>
</application>

猜你喜欢

转载自blog.csdn.net/qq_23084801/article/details/80573029