(六)與系統交互 6.1後臺通知 1.關於後臺通知,下麵展示6種樣式。值得一提的是,筆者的小米5只能顯示基本樣式,雷軍真是良心廠商啊。 2.首先上佈局xml 3.接著是完整代碼 6.3定時執行周期任務 1.AlarmManager用來管理和執行任務,可以在程式沒有運行的時候執行。並且有多種啟動和計算 ...
(六)與系統交互
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開發範例大全》的時候,我也把部分代碼敲了一遍,很多時候怎麼看都看不懂的代碼,運行一下大多就能理解了。
不過因為個人水平太差,這文章寫出來估計沒幾個人能讀明白,實在汗顏。
接下來,我會開很多新書,繼續寫讀書筆記這個系列。
希望能多多進步吧。