首页 > 代码库 > Android5.0开发范例大全 读书笔记(六)

Android5.0开发范例大全 读书笔记(六)

(六)与系统交互

6.1后台通知

1.关于后台通知,下面展示6种样式。值得一提的是,笔者的小米5只能显示基本样式,雷军真是良心厂商啊。

2.首先上布局xml

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

    <RadioGroup
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:id="@+id/options_group">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Rich Styles"/>
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_basic"
            android:text="Basic Notification"
            android:checked="true"/>
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_bigtext"
            android:text="BigText Style"
            />
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_bigpicture"
            android:text="BigPicture Style"
            />
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_inbox"
            android:text="Inbox Style"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:text="Secured Styles"/>
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_private"
            android:text="Public Version LockScreen" />
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_secret"
            android:text="Secret LockScreen" />
        <RadioButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/option_headsup"
            android:text="Heads-Up Notification" />
    </RadioGroup>

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Post a Notification"
        android:onClick="onPostClick"/>
</LinearLayout>

3.接着是完整代码

ublic class NotificationActivity extends AppCompatActivity {
    private RadioGroup mOptionsGroup;
    private static Handler mHandle = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_notification);
        mOptionsGroup = (RadioGroup) findViewById(R.id.options_group);

    }

    public void onPostClick(View view) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        final int noteId = mOptionsGroup.getCheckedRadioButtonId();
        Notification note = null;
        switch (noteId) {
            case R.id.option_basic:
            case R.id.option_bigtext:
            case R.id.option_bigpicture:
            case R.id.option_inbox:
                note = buildStyledNotification(noteId);
                break;
            case R.id.option_private:
            case R.id.option_secret:
            case R.id.option_headsup:

                note = buildSecuredNotification(noteId);
                break;
        }
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        manager.notify(noteId, note);
    }

    private Notification buildStyledNotification(int type) {
        Intent launchIntent = new Intent(this, NotificationActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, launchIntent, 0);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(NotificationActivity.this);
        builder.setSmallIcon(R.mipmap.ic_launcher)
                .setTicker("something happen")
                .setWhen(System.currentTimeMillis())
                .setAutoCancel(true)
                .setDefaults(Notification.DEFAULT_SOUND)
                .setContentTitle("we are finished")
                .setContentText("click here")
                .setContentIntent(contentIntent);

        switch (type) {
            case R.id.option_basic:
                return builder.build();
            case R.id.option_bigtext:
                builder.addAction(android.R.drawable.ic_menu_call, "Call", contentIntent);
                builder.addAction(android.R.drawable.ic_menu_recent_history, "History", contentIntent);

                NotificationCompat.BigTextStyle textStyle = new NotificationCompat.BigTextStyle(builder);
                textStyle.bigText("BigText Mode");
                return textStyle.build();
            case R.id.option_bigpicture:
                builder.addAction(android.R.drawable.ic_menu_compass, "View Location", contentIntent);

                NotificationCompat.BigPictureStyle pictureStyle = new NotificationCompat.BigPictureStyle(builder);
                pictureStyle.bigPicture(BitmapFactory.decodeResource(getResources(), R.mipmap.cat));
                return pictureStyle.build();
            case R.id.option_inbox:
                NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(builder);
                inboxStyle.setSummaryText("4 new tasks")
                        .addLine("make dinner")
                        .addLine("call mom")
                        .addLine("call handsome")
                        .addLine("call father");
                return inboxStyle.build();
            default:
                throw new IllegalArgumentException("Unknown Type");
        }
    }

    private Notification buildSecuredNotification(int type) {
        Intent launchIntent = new Intent(this, NotificationActivity.class);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, launchIntent, 0);

        NotificationCompat.Builder builder = new NotificationCompat.Builder(NotificationActivity.this);
        builder.setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("account balance update")
                .setContentText("your account balance is -250")
                .setStyle(new NotificationCompat.BigTextStyle().bigText("Your account balance is-250 please pay"))
                .setContentIntent(contentIntent);


        switch (type) {
            case R.id.option_private:
                Notification publicNote = new Notification.Builder(this)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setContentTitle("Account Notification")
                        .setContentText("an important message")
                        .setContentIntent(contentIntent)
                        .build();
                return builder.setPublicVersion(publicNote).build();

            case R.id.option_secret:
                return builder.setVisibility(Notification.VISIBILITY_SECRET).build();
            case R.id.option_headsup:
                return builder.setDefaults(Notification.DEFAULT_SOUND)
                        .setPriority(Notification.PRIORITY_HIGH)
                        .build();
            default:
                throw new IllegalArgumentException("Unknown Type");
        }
    }
}

 6.3定时执行周期任务

1.AlarmManager用来管理和执行任务,可以在程序没有运行的时候执行。并且有多种启动和计算时间的方式

  定义一个广播接收者,在其中附加需要执行的操作

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Calendar now=Calendar.getInstance();
        DateFormat format= SimpleDateFormat.getTimeInstance();
        Toast.makeText(context,format.format(now.getTime()),Toast.LENGTH_SHORT).show();
    }

}

  通过AlarmManager设置时间任务

public void start(View view) {
        Toast.makeText(this,"Scheduled",Toast.LENGTH_SHORT).show();
        manager.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime()+ interval, interval,mAlarmIntent);

    }

  为了方便,下面写出全部代码

  其中start是间隔一段时间执行任务

  clock是在指定时间执行任务

public class AlarmActivity extends AppCompatActivity {
private PendingIntent mAlarmIntent;
    private AlarmManager manager;
    private long interval;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timing);
        Intent launchIntent=new Intent(this,AlarmReceiver.class);
        mAlarmIntent=PendingIntent.getBroadcast(this,0,launchIntent,0);
        manager = (AlarmManager) getSystemService(ALARM_SERVICE);
        interval = 5*1000;
    }

    public void start(View view) {
        Toast.makeText(this,"Scheduled",Toast.LENGTH_SHORT).show();
        manager.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime()+ interval, interval,mAlarmIntent);

    }

    public void stop(View view) {
        Toast.makeText(this,"Canceled",Toast.LENGTH_SHORT).show();
        manager.cancel(mAlarmIntent);
    }

    public void clock(View view) {
        long oneDay=24*3600*1000;
        long firstTime;
        Calendar startTime=Calendar.getInstance();
        startTime.set(Calendar.HOUR_OF_DAY,17);
        startTime.set(Calendar.MINUTE,18);
        startTime.set(Calendar.SECOND,0);
        Calendar now=Calendar.getInstance();
        if(now.before(startTime)){
            firstTime=startTime.getTimeInMillis();
            System.out.println(firstTime);
        }else {
            startTime.add(Calendar.DATE,1);
            firstTime=startTime.getTimeInMillis();
        }
        manager.setRepeating(AlarmManager.RTC_WAKEUP,firstTime,oneDay,mAlarmIntent);

    }
}

2.JobScheduler也可以实现类似的功能

   1.首先自定义一个service继承自JobService

public class WorkService extends JobService

  在内部放一个handler来进行简单的队列处理

   private Handler mJobProcessor=new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            JobParameters parameters= (JobParameters) msg.obj;
            System.out.println(parameters.getJobId());
            doWork();
            jobFinished(parameters,false);
        return true;
        }
    });

  实现onStartJob()方法,

 @Override
    public boolean onStartJob(JobParameters params) {
        mJobProcessor.sendMessageDelayed(Message.obtain(mJobProcessor,MSG_JOB,params),7500);
        return true;
    }

  实现onStopJob()方法

 @Override
    public boolean onStopJob(JobParameters params) {
        mJobProcessor.removeMessages(MSG_JOB);
        return false;
    }

  实现具体处理任务的doWork()方法

 private void doWork() {
        Calendar now=Calendar.getInstance();
        DateFormat formatter= SimpleDateFormat.getTimeInstance();
        Toast.makeText(this,formatter.format(now.getTime()),Toast.LENGTH_SHORT).show();
    }

  2.在主函数中调用JobScheduler

public class JobSchedulerActivity extends AppCompatActivity {
    private static final int JOB_ID = 1;
    private JobScheduler scheduler;
    private JobInfo info;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_job_scheduler);
        scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
        long interval =  5 * 1000;
        info = new JobInfo.Builder(JOB_ID, new ComponentName(getPackageName(), WorkService.class.getName()))
                .setPeriodic(interval)
                .build();
    }

    public void start(View view) {

        int result = scheduler.schedule(info);
        if (result <= 0) {
            Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
        }
    }

    public void stop(View view) {
        scheduler.cancel(JOB_ID);
    }
}

6.4创建粘性操作

1.粘性操作是指当应用程序被用户终止时也可以执行的一个或多个操作.

2.IntentService会将要执行的任务放到队列中,然后逐个请求,全部处理完后终结自己

   以下是自定义IntentService的完整代码

public class OperationsManager extends IntentService {
    public static final String ACTION_EVENT = "ACTION_EVENT";
    public static final String ACTION_WARNING = "ACTION_WARNING";
    public static final String ACTION_ERROR = "ACTION_ERROR";
    public static final String EXTRA_NAME = "eventName";

    private static final String LOGTAG = "com.joshua.log";
    private IntentFilter matcher;

    public OperationsManager() {
        super("OperationsManager");
        matcher = new IntentFilter();
        matcher.addAction(ACTION_EVENT);
        matcher.addAction(ACTION_WARNING);
        matcher.addAction(ACTION_ERROR);
    }


    @Override
    protected void onHandleIntent(Intent intent) {
        if (!matcher.matchAction(intent.getAction())) {
            Toast.makeText(this, "Invalid Request", Toast.LENGTH_SHORT).show();
        }
        switch (intent.getAction()) {
            case ACTION_EVENT:
                logEvent(intent.getStringExtra(EXTRA_NAME));
                break;
            case ACTION_WARNING:
                logWarning(intent.getStringExtra(EXTRA_NAME));
                break;
            case ACTION_ERROR:
                logError(intent.getStringExtra(EXTRA_NAME));
                break;
        }

    }

    private void logError(String name) {
        try {
            Thread.sleep(5000);
            Log.i(LOGTAG,name);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    private void logWarning(String name) {
        try {
            Thread.sleep(5000);
            Log.w(LOGTAG,name);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void logEvent(String name) {
        try {
            Thread.sleep(5000);
            Log.e(LOGTAG,name);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

2.在activity中通过Intent调用IntentService

public class ReportActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_report);
        logEvent("CREATE");
    }

    @Override
    protected void onStart() {
        super.onStart();
        logEvent("START");
    }

    @Override
    protected void onResume() {
        super.onResume();
        logEvent("RESUME");
    }

    @Override
    protected void onPause() {
        super.onPause();
        logEvent("PAUSE");
    }

    @Override
    protected void onStop() {
        super.onStop();
        logEvent("STOP");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        logEvent("DESTROY");
    }

    private void logEvent(String event){
        Intent intent=new Intent(this,OperationsManager.class);
        intent.setAction(OperationsManager.ACTION_EVENT);
        intent.putExtra(OperationsManager.EXTRA_NAME,event);
        startService(intent);
    }

    private void logWarning(String event){
        Intent intent=new Intent(this,OperationsManager.class);
        intent.setAction(OperationsManager.ACTION_WARNING);
        intent.putExtra(OperationsManager.EXTRA_NAME,event);
        startService(intent);
    }
}

6.6分享内容

1.通过Intent启动系统的其他相关程序

 public void share(View view) {
        Intent intent=new Intent(Intent.ACTION_SEND);
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_TEXT,"分享");
        startActivity(Intent.createChooser(intent,"Share..."));
    }

6.10读取设备媒体和文档

1.通过Intent获取感兴趣的设备内容,比如image/video/audio

  不过笔者的小米5不管你调用的是什么,它都给你弹出文件管理器的首页……

intent = new Intent();
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.KITKAT){
            intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
        }else {
            intent.setAction(Intent.ACTION_GET_CONTENT);
        }
        intent.addCategory(Intent.CATEGORY_OPENABLE);

    }
    public void image(View view) {
       intent.setType("image/*");
        startActivityForResult(intent,REQUEST_IMAGE);
    }

    public void video(View view) {
        intent.setType("video/*");
        startActivityForResult(intent,REQUEST_VIDEO);
    }

    public void audio(View view) {
        intent.setType("audio/*");
        startActivityForResult(intent,REQUEST_AUDIO);
    }

6.16自定义任务栈

1.当程序A的A3界面被程序B的B3界面启动后,按返回是返回B3还是A2呢?当然是B3啦,因为属于程序A的任务栈并没有被创建。

  因此如果想要返回A2,则必须启动A的任务栈。

2.首先,创建一个根界面

public class RootActivity extends AppCompatActivity {

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

    public void next(View view) {
        Intent intent=new Intent(this,ItemsListActivity.class);
        startActivity(intent);
    }
}

3.接着,创建一个二级界面,其中重点是NavUtils的应用,可以创建任务栈

public class ItemsListActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
    private static final String[] ITEMS = {"Mon", "Dad", "Sister", "Brother", "Cousin"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_items_list);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        ListView list = new ListView(this);
        ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, ITEMS);
        list.setAdapter(adapter);
        list.setOnItemClickListener(this);
        setContentView(list);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                Intent upIntent = NavUtils.getParentActivityIntent(this);
                if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                    TaskStackBuilder.create(this)
                            .addParentStack(this)
                            .startActivities();
                } else {
                    NavUtils.navigateUpFromSameTask(this);
                }
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Intent intent = new Intent(this, DetailsActivity.class);
        intent.putExtra(Intent.EXTRA_TEXT, ITEMS[position]);
        startActivity(intent);

    }
}

4.创建三级界面

public class DetailsActivity extends AppCompatActivity {
private static final String ACTION_NEW_ARRIVAL="com.examples.taskstack.ACTION_NEW_ARRIVAL";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        TextView textView=new TextView(this);
        textView.setGravity(Gravity.CENTER);
        String item=getIntent().getStringExtra(Intent.EXTRA_TEXT);
        textView.setText(item);
        setContentView(textView);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                Intent upIntent = NavUtils.getParentActivityIntent(this);
                if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
                    TaskStackBuilder.create(this)
                            .addParentStack(this)
                            .startActivities();
                } else {
                    NavUtils.navigateUpFromSameTask(this);
                }
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }
}

5.AndroidManifest中配置如下,为各级设置parent,其中4.1以后不需要使用meta-data

 <activity android:name=".day20161019.RootActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".day20161019.ItemsListActivity"
            android:parentActivityName=".day20161019.RootActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".day20161019.RootActivity" />
        </activity>
        <activity
            android:name=".day20161019.DetailsActivity"
            android:parentActivityName=".day20161019.ItemsListActivity">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".day20161019.ItemsListActivity" />

            <intent-filter>
                <action android:name="com.examples.taskstack.ACTION_NEW_ARRIVAL" />

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

(七)总结

看过一个大神的博客,他说自己不觉得有多么聪明,但别人总爱称他是大神,可能只是因为自己在半年内看了50多本书吧,至于书该怎么看,很简单,敲一遍。

强,无敌。

于是阅读《Android5.0开发范例大全》的时候,我也把部分代码敲了一遍,很多时候怎么看都看不懂的代码,运行一下大多就能理解了。

不过因为个人水平太差,这文章写出来估计没几个人能读明白,实在汗颜。

接下来,我会开很多新书,继续写读书笔记这个系列。

希望能多多进步吧。

Android5.0开发范例大全 读书笔记(六)