当前位置:首页 » 安卓系统 » labelforandroid

labelforandroid

发布时间: 2023-07-20 13:33:26

① android开发怎么让个推服务不被手机系统杀掉

服务是一个应用程序组件,可以在后台执行长时间运行的操作,不提供用户界面。一个应用程序组件可以启动一个服务,它将继续在后台运行,即使用户切换到另一个应用程序。此外,一个组件可以绑定到一个服务与它交互,甚至执行进程间通信(IPC)。例如,一个服务可能处理网络通信,播放音乐,执行文件I/O,或与一个内容提供者交互,都在后台执行。
一个服务本质上讲有两种形式:
Started 启动的
started 形式的服务是指当一个应用组件(比如 activity )通过startService()方法开启的服务。一旦开启,该服务就可以 无限期 地在后台运行,哪怕开启它的组件被销毁掉。
通常,开启的服务执行一个单独的操作且并不向调用者返回一个结果。
比如,可能从网络进行下载或者上传一个文件。当任务完成,服务就该自我停止。
Bound 绑定的
bound 形式的服务是指一个应用组件通过调用 bindService() 方法与服务绑定。一个绑定的服务提供一个客户-服务端接口,以允许组件与服务交互,发送请求,获得结果,甚至执行进程间通信。一个绑定的服务只和与其绑定的组件同时运行。多个组件可以同时绑定到一个服务,但当全部接触绑定后,服务就被销毁。
虽然分这两类,但是一个服务可以同时使用这两种方式——可以用 started 无限期的运行,同时允许绑定。只需要在服务中实现两个回调方法: onStartCommand() 允许组件开启服务, onBind() 允许绑定。
不论应用程序是怎么起服务的, 任何 应用程序都可以用这个服务。同样的,任何组件可以使用一个 Activity 通过传递 Intent 开启服务。你也可以在配置文件设置服务为私有来防止其他应用访问该服务。
注意: 一个服务在进程中的主线程运行——一个服务 不会 创建自己的线程,也 不会 在另外的进程运行(除非另外指定)。这意味着,如果服务需要做一些频繁占用CPU的工作或者会发生阻塞的操作,你需要在服务中另开线程执行任务。这可以降低产生ANR的风险,提高用户体验。
基础
创建一个服务需要建立一个 Service 相关的子类,然后需要实现一些回调方法,好在不同的生命周期内做对应处理和绑定服务,比较重要的方法如下:
onStartCommand()
当其他组件,如 activity 请求服务启动时,系统会调用这个方法。一旦这个方法执行,服务就开始并且无限期的执行。如果实现这个方法,当这个服务完成任务后,需要你来调用 stopSelf() 或者 stopService() 停掉服务。如果只想提供绑定,不需要自己实现这个方法。
onBind()
当有其他组件想通过 bindService() 方法绑定这个服务时系统就会调用此方法。在实现的方法里面,必须添加一个供客户端使用的接口通过返回一个 IBinder 来与服务通信,这个方法必须实现。当然不想允许绑定的话,返回 null 即可。
onCreate()
服务第一次建立的时候会调用这个方法,执行一次性设置程序,在上面2个方法执行前调用。如果服务已存在,则不执行该方法。
onDestroy()
服务不再使用则使用该方法。服务应该实现这个方法来清理诸如线程,注册的监听器等资源。这是最后调用的方法。
安卓系统只会在内存占用很高,必须恢复系统资源供当前运行程序的情况下强制停掉一个运行中的服务。如果服务绑定在当前运行的程序中,就几乎不会被杀掉,如果服务声明了在前台运行(其实在后台,只是给系统一个错的信息来提高优先级),就几乎不会被杀掉。另外,如果一个服务正在运行,且运行了很久,系统就会根据运行时间把其排在后台任务列表的后面,则这个服务很容易被杀掉。根据onStartCommand() 的返回值设置,服务被杀掉后仍可以在资源充足的条件下立即重启。
是用一个服务好还是开一个线程好
一个服务就是一个可以忽略交互,在后台独立运行的组件,如果你需要这样就用服务
如果你需要在用户与程序交互时在主线程外执行任务,那就开个线程吧。
比如想播放音乐,但只在程序运行时播放,你可能在 onCreate() 开一个线程,在 onStart() 中开启它,在 onStop() 停止它。也可以考虑使用 AsyncTask 或者HandlerThread 取代一般的线程。
记住,如果使用一个服务,它还是默认在主线程中运行,如果会发生阻塞,还是要在服务中另开线程的。
在 manifest 文件声明服务
要使用服务就必须在 manifest 文件声明要用的所有服务,只用在<application> 标签内添加子标签 <service> 即可。
<manifest ...>
...
<application ...>
<service android:name=".ExampleService"
android:enabled=["true" | "false"]
android:exported=["true" | "false"]
android:isolatedProcess=["true" | "false"]
android:label="string resource"
android:icon="drawable resource"
android:permission="string"
android:process="string" >
...
</service>
</application>
</manifest>

下面对 service 标签属性做说明
android:name
你所编写的服务类的类名,可填写完整名称,包名+类名,如com.example.test.ServiceA ,也可以忽略包名,用 . 开头,如 .ServiceA,因为在 manifest 文件开头会定义包名,它会自己引用。
一旦你发布应用,你就不能改这个名字(除非设置 android:exported="false"),另外 name 没有默认值,必须定义。
android:enabled
是否可以被系统实例化,默认为 true
因为父标签 <application> 也有 enable 属性,所以必须两个都为默认值true 的情况下服务才会被激活,否则不会激活。
android:exported
其他应用能否访问该服务,如果不能,则只有本应用或有相同用户ID的应用能访问。当然除了该属性也可以在下面 permission 中限制其他应用访问本服务。
这个默认值与服务是否包含意图过滤器 intent filters 有关。如果一个也没有则为 false
android:isolatedProcess
设置 true 意味着,服务会在一个特殊的进程下运行,这个进程与系统其他进程分开且没有自己的权限。与其通信的唯一途径是通过服务的API(binding and starting)。
android:label
可以显示给用户的服务名称。如果没设置,就用 <application> 的 lable 。不管怎样,这个值是所有服务的意图过滤器的默认 lable 。定义尽量用对字符串资源的引用。
android:icon
类似 label ,是图标,尽量用 drawable 资源的引用定义。
android:permission
是一个实体必须要运行或绑定一个服务的权限。如果没有权限,startService() , bindService() 或 stopService() 方法将不执行,Intent 也不会传递到服务。
如果属性未设置,会由 <application> 权限设置情况应用到服务。如果两者都未设置,服务就不受权限保护。
android:process
服务运行所在的进程名。通常为默认为应用程序所在的进程,与包名同名。<application> 元素的属性 process 可以设置不同的进程名,当然组件也可设置自己的进程覆盖应用的设置。
如果名称设置为冒号 : 开头,一个对应用程序私有的新进程会在需要时和运行到这个进程时建立。如果名称为小写字母开头,服务会在一个相同名字的全局进程运行,如果有权限这样的话。这允许不同应用程序的组件可以分享一个进程,减少了资源的使用。
创建“启动的”服务
启动的(started)服务由 startService(Intent) 方法启动,在服务中的onStartCommand() 方法里获得 Intent 信息。关闭则由服务自己的方法 stopSelf() 或者由启动服务的地方调用 stopService(Intent) 方法来关闭。并不会因为启动服务的应用程序销毁而关闭。
示例,一个应用需要保存数据到远程数据库,这时启动一个服务,通过创建启动的服务给服务传递数据,由服务执行保存行为,行为结束再自我销毁。因为服务跟启动它的应用在一个进程的主线程中,所以对于耗时的操作要起一个新的线程去做。
//activity中
Intent intent = new Intent(MainActivity.this, ServiceA.class);
intent.putExtra("name", strName);
startService(intent);
//service中
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
// 获取数据
String strName = intent.getStringExtra("name");
// ... 数据库操作
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
耗时的操作
}
}).run();
return Service.START_STICKY;
}

写服务有2种,继承 service 或者 IntentService 。后者是前者的子类。前者包含上面介绍的各种方法,用于普通的服务。后者可以自己开一个工作线程一个接一个处理多个请求。
继承IntentService
大多数服务不需要同时处理多个请求,继承 IntentService 是最好的选择
IntentService处理流程
创建默认的一个 worker 线程处理传递给 onStartCommand() 的所有 intent ,不占据应用的主线程
创建一个工作队列一次传递一个 intent 到你实现的 onHandleIntent() 方法,避免了多线程
在所以启动请求被处理后自动关闭服务,不需要调用 stopSelf()
默认提供 onBind() 的实现,并返回 null
默认提供 onStartCommand() 的实现,实现发送 intent 到工作队列再到你的onHandleIntent() 方法实现。
这些都加入到 IntentService 中了,你需要做的就是实现构造方法和onHandleIntent() ,如下:
public class HelloIntentService extends IntentService {
/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public HelloIntentService() {
super("HelloIntentService");
}
/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
@Override
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
}
}

如果需要重写其他回调方法,如 onCreate() , onStartCommand() 等,一定要调用super() 方法,保证 IntentService 正确处理 worker 线程,只有 onHandleIntent()和 onBind() 不需要这样。如:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent,flags,startId);
}

继承Service
继承 Service 就可以实现对请求多线程的处理,前面介绍了 service 的生命周期,可以按照生命周期实现方法。就不放示例了。
onStartCommand() 的返回值
返回一个整型值,用来描述系统在杀掉服务后是否要继续启动服务,返回值有三种:
START_NOT_STICKY
系统不重新创建服务,除非有将要传递来的 intent 。这是最安全的选项,可以避免在不必要的时候运行服务。
START_STICKY
系统重新创建服务并且调用 onStartCommand() 方法,但并不会传递最后一次传递的 intent ,只是传递一个空的 intent 。除非存在将要传递来的 intent ,那么就会传递这些 intent 。这个适合播放器一类的服务,不需要执行命令,只需要独自运行,等待任务。
START_REDELIVER_INTENT
系统重新创建服务并且调用 onStartCommand() 方法,传递最后一次传递的intent 。其余存在的需要传递的intent会按顺序传递进来。这适合像下载一样的服务,立即恢复,积极执行。
如果想从服务获得结果,可以用广播来处理
创建“绑定的”服务
用 bindService() 方法将应用组件绑定到服务,建立一个长时间保持的联系。
如果需要在 activity 或其他组件和服务交互或者通过进程间通信给其他应用程序提供本应用的功能,就需要绑定的服务。
建立一个绑定的服务需要实现 onBind() 方法返回一个定义了与服务通信接口的IBinder 对象。其他应用程序组件可以调用 bindService() 方法获取接口并且调用服务上的方法。
创建一个绑定的服务,第一件事就是定义一个说明客户端与服务通信方式的接口。这个接口必须是 IBinder 的实现,并且必须要从 onBind() 方法返回。一旦客户端接收到了 IBinder ,就可以通过这个接口进行交互。
多个客户端可以绑定到一个服务,可以用 unbindService() 方法解除绑定,当没有组件绑定在服务上,这个服务就会被销毁。
//activity中
private ServiceConnection connB = new ServiceConnection() {

@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
Log.v(tag, "Service B disconnected");
}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
Log.v(tag, "Service B connected");
MyBinderB binder = (MyBinderB) service;
ServiceB SB = binder.getService();
SB.showLog();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent a = new Intent(MainActivity.this, ServiceB.class);
bindService(a, connB, BIND_AUTO_CREATE);
}
}

//ServiceB
public class ServiceB extends Service {
public void showLog() {
Log.i(tag, "serviceB-->showLog()");
}

public class MyBinderB extends Binder {

public ServiceB getService() {
return ServiceB.this;
}
}

private MyBinderB myBinderB = new MyBinderB();

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return myBinderB;
}
}

启动前台服务
前台服务是被认为是用户已知的正在运行的服务,当系统需要释放内存时不会优先杀掉该进程。前台进程必须发一个 notification 在状态栏中显示,直到进程被杀死。因为前台服务会一直消耗一部分资源,但不像一般服务那样会在需要的时候被杀掉,所以为了能节约资源,保护电池寿命,一定要在建前台服务的时候发notification ,提示用户。当然,系统提供的方法就是必须有 notification 参数的,所以不要想着怎么把 notification 隐藏掉。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification noti = new Notification.Builder(this)
.setContentTitle("Title")
.setContentText("Message")
.setSmallIcon(R.drawable.ic_launcher)
.setContentIntent(pendingIntent)
.build();
startForeground(12346, noti);
return Service.START_STICKY;
}

startForeground() 方法就是将服务设为前台服务。参数12346就是这个通知唯一的id,只要不为0即可。

② 如何用代码更改android中的radio控件设为选中

Radio 对象代表 HTML 表单中的单选按钮。在 HTML 表单中 <input type="radio"> 每出现一次,一个 Radio 对象就会被创建。

单选按钮是表示一组互斥选项按钮中的一个。当一个按钮被选中,之前选中的按钮就变为非选中的。当单选按钮被选中或不选中时,该按钮就会触发 onclick 事件句柄。您可通过遍历表单的 elements[] 数组来访问 Radio 对象,或者通过使用 document.getElementById()。

一、单选按钮控件语法

1 <input name="Fruit" type="radio" value="" />

使用html input标签,name为自定义,type类型为“radio”的表单.

二、radio单选按钮代码举例

1、html代码片段:

12345678 <form action="" method="get">
您最喜欢水果?<br /><br />
<label><input name="Fruit" type="radio" value="" />苹果 </label>
<label><input name="Fruit" type="radio" value="" />桃子 </label>
<label><input name="Fruit" type="radio" value="" />香蕉 </label>
<label><input name="Fruit" type="radio" value="" />梨 </label>
<label><input name="Fruit" type="radio" value="" />其它 </label>
</form>

2.举例代码片段二(默认选中设置举例):

123 <input type="radio" name="identity" value="学生" checked="checked" />学生
<input type="radio" name="identity" value="教师" />教师
<input type="radio" name="identity" value="管理员" />管理员

在代码举例二种, checked="checked" 表示默认选中项设置。

3.代码举例三(js操作radio):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gbk">
<script>
<!--
//选中2返回的也是1,找到第一个ID为该值的DOM,弹出 1
function getVById(){alert(document.getElementById('test11').value);}
function getVByName(){
var tt = document.getElementsByName('test11');
for (var iIndex = 0; iIndex < tt.length ; iIndex++ )
{
if(tt[iIndex].checked)
{
alert(tt[iIndex].value);
break;
}
}
};
-->
</script>
<title>http://www.169it.com</title>
</head>
<body>
<input type="radio" id="test11" name="test11" value="1" />测试1
<input type="radio" id="test11" name="test11" value="2" />测试2
<input type="button" value="BTN_ByID" onclick="getVById()" />
<input type="button" value="BTN_ByName" onclick="getVByName()" />
</body>
<html>

③ android 怎么批量插入联系人,高效率的方法

参考下面方法:
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ArrayList<VCardEntry> list = params[0];
Iterator<VCardEntry> it = null;
if (list != null) {
it = list.iterator();
}
Logger.v(TAG,"--->doInBackground it:"+it);
int rawContactInsertIndex = 0;
while(it!= null && it.hasNext()) {
VCardEntry mv = it.next();
rawContactInsertIndex = ops.size(); // 有了它才能给真正的实现批量添加
Logger.v(TAG,"--->>>>>>>name:"+mv.getDisplayName());
Logger.v(TAG,"--->>>>>>>getPhoneList:"+mv.getPhoneList());
if (mv.getPhoneList() != null) {
ops.add(ContentProviderOperation
.newInsert(RawContacts.CONTENT_URI)
.withValue(RawContacts.ACCOUNT_TYPE, ACCOUNT_NAME)
.withValue(RawContacts.ACCOUNT_NAME, ACCOUNT_TYPE)
.withYieldAllowed(true).build());
// add name
ops.add(ContentProviderOperation
.newInsert(Data.CONTENT_URI)
.withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
.withValue(StructuredName.DISPLAY_NAME, mv.getDisplayName())
.withYieldAllowed(true).build());
// add number
for(VCardEntry.PhoneData phone : mv.getPhoneList()) {
Logger.v(TAG,"--->>>>>>>number:"+phone.getNumber());
ops.add(ContentProviderOperation
.newInsert(Data.CONTENT_URI)
.withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
.withValue(Phone.NUMBER, phone.getNumber())
.withValue(Phone.TYPE, Phone.TYPE_MOBILE)
.withValue(Phone.LABEL, "")
.withYieldAllowed(true).build());
}
}
}
ContentProviderResult[] results = null;
if (ops != null) {
try {
results = mContext.getContentResolver()
.applyBatch(ContactsContract.AUTHORITY, ops);
} catch (RemoteException e) {
Logger.e(TAG,String.format("%s: %s", e.toString(), e.getMessage()));
} catch (OperationApplicationException e) {
Logger.e(TAG,String.format("%s: %s", e.toString(), e.getMessage()));
}
}

④ Android应用如何支持不同尺寸的屏幕

想要Android应用适应不同尺寸的屏幕,思路如下:
一:不同的layout
Android手机屏幕大小不一,有480x320, 640x360, 800x480,让app适应不同屏幕,需要在res目录下创建不同的layout文件夹,比如layout-640x360,layout-800x480,所有的layout文件在编译之后都会写入R.java里,而系统会根据屏幕的大小自己选择合适的layout进行使用。
二:hdpi、mdpi、ldpi
在之前的版本中,只有一个drawable,而2.1版本中有drawable-mdpi、drawable-ldpi、drawable-hdpi三个,这三个主要是为了支持多分辨率。
drawable- hdpi、drawable- mdpi、drawable-ldpi的区别:
(1)drawable-hdpi里面存放高分辨率的图片,如WVGA (480x800),FWVGA (480x854)
(2)drawable-mdpi里面存放中等分辨率的图片,如HVGA (320x480)
(3)drawable-ldpi里面存放低分辨率的图片,如QVGA (240x320)
系统会根据机器的分辨率来分别到这几个文件夹里面去找对应的图片。
更正:应该是对应不同density 的图片
在开发程序时为了兼容不同平台不同屏幕,建议各自文件夹根据需求均存放不同版本图片。
屏幕方向:
横屏竖屏自动切换:
可以在res目录下建立layout-port-800x600和layout-land两个目录,里面分别放置竖屏和横屏两种布局文件,这样在手机屏幕方向变化的时候系统会自动调用相应的布局文件,避免一种布局文件无法满足两种屏幕显示的问题。
不同分辨率横屏竖屏自动切换:
以800x600为例 :
可以在res目录下建立layout-port-800x600和layout-land-800x600两个目录
不切换:
以下步骤是网上流传的,不过我自己之前是通过图形化界面实现这个配置,算是殊途同归,有空我会把图片贴上来。
还要说明一点:每个activity都有这个属性screenOrientation,每个activity都需要设置,可以设置为竖屏(portrait),也可以设置为无重力感应(nosensor)。
要让程序界面保持一个方向,不随手机方向转动而变化的处理办法:
在AndroidManifest.xml里面配置一下就可以了。加入这一行android:screenOrientation="landscape"。
例如(landscape是横向,portrait是纵向):
Java代码:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ray.linkit"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Main"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".GamePlay"
android:screenOrientation="portrait"></activity>
<activity android:name=".OptionView"
android:screenOrientation="portrait"></activity>
</application>
<uses-sdk android:minSdkVersion="3" />
</manifest>
另外,android中每次屏幕的切换动会重启Activity,所以应该在Activity销毁前保存当前活动的状态,在Activity再次Create的时候载入配置,那样,进行中的游戏就不会自动重启了!
有的程序适合从竖屏切换到横屏,或者反过来,这个时候怎么办呢?可以在配置Activity的地方进行如下的配置android:screenOrientation="portrait"。这样就可以保证是竖屏总是竖屏了,或者landscape横向。
而有的程序是适合横竖屏切换的。如何处理呢?首先要在配置Activity的时候进行如下的配置:android:configChanges="keyboardHidden|orientation",另外需要重写Activity的 onConfigurationChanged方法。实现方式如下,不需要做太多的内容:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
// land do nothing is ok
} else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
// port do nothing is ok
}
}
写一个支持多分辨的程序,基于1.6开发的,建立了三个资源文件夹drawable-hdpi drawable-mdpi drawable-ldpi,里面分别存放72*72 48*48 36*36的icon图标文件。当我在G1(1.5的系统)上测试时,图标应该自适应为48*48才对啊,但实际显示的是36*36。怎么才能让其自适应 48*48的icon图标呢
解决办法 drawable-hdpi drawable-mdpi drawable-ldpi改成drawable-480X320 drawable-800X480的多分辨支持的文件夹

⑤ Android创建桌面快捷方式(兼容Android 8.0)

在Android O原生桌面上,按照传统创建快捷方式的形式,是不会产生快捷方式的。

传统方式如下:

从Android 7.1(API 25)开始,新增了ShortcutManager,可以对桌面久按应用图标弹出的快捷方式进行管理。

但是,Android 7.1上直接往桌面上添加快捷方式依然是使用上面说到的这种旧方式,但是Android O上,Google应该是想通过比较统一的接口来管理桌面快捷方式了,所以摒弃了这种形式,转而使用ShortcutManager进行管理。所以API 26上,ShortcutManager进行管理。所以API 26上,ShortcutManager新增了对Pinned Shortcuts(固定快捷方式)的管理。

官文:
Apps can pin an existing shortcut (either static or dynamic) or an entirely new shortcut to a supported launcher programatically using requestPinShortcut(ShortcutInfo, IntentSender). You pass two arguments into this method:

A ShortcutInfo object – If the shortcut already exists, this object should contain only the shortcut’s ID. Otherwise, the new ShortcutInfo object must contain an ID, an intent, and a short label for the new shortcut.
A PendingIntent object – This intent represents the callback that your app receives if the shortcut is successfully pinned to the device’s launcher.

Note: If the user doesn’t allow the shortcut to be pinned to the launcher, the pinning process fails, and the Intent object that is passed into this PendingIntent object isn’t executed.

Note: Due to background execution limits introced in Android O, it’s best to use a manifest-declared receiver to receive a callback.
Also, to prevent other apps from invoking the receiver, add the attribute assignment android:exported=”false” to the receiver’s manifest entry.

Note: As you add logic in your app to make requests to pin shortcuts, keep in mind that not all launchers support pinning of shortcuts. To determine whether your app can complete this process on a particular device, check the return value of isRequestPinShortcutSupported(). Based on this return value, you might decide to hide the option in your app that allows users to pin a shortcut.

Note: See also the support library APIs isRequestPinShortcutSupported(Context) and requestPinShortcut(Context, ShortcutInfoCompat, IntentSender), which works on Android versions lower than O by falling back to the deprecated private intent com.android.launcher.action.INSTALL_SHORTCUT.

译:
应用程序可以使用requestPinShortcut(ShortcutInfo,IntentSender)将现有的快捷方式(静态或动态)或全新的快捷方式固定到支持的启动器。你通过这个方法的两个参数:

ShortcutInfo对象 - 如果快捷方式已存在,则该对象应仅包含快捷方式的ID。否则,新的ShortcutInfo对象必须包含新快捷方式的ID,意图和短标签。
PendingIntent对象 - 此意图表示如果快捷方式成功固定到设备的启动器,您的应用程序将收到回调。

注意:如果用户不允许将快捷方式固定在启动器上,则固定进程将失败,并且未执行传入此PendingIntent对象的Intent对象。

注意:由于Android O中引入的后台执行限制,最好使用清单声明的接收器来接收回调。
另外,为了防止其他应用程序调用接收器,将属性赋值android:exported =“false”添加到接收者的清单条目中。

注意:当您在应用程序中添加逻辑以引导快捷方式时,请记住,并非所有启动器都支持固定快捷方式。 要确定您的应用程序是否可以在特定设备上完成此过程,请检查isRequestPinShortcutSupported()的返回值。 根据此返回值,您可以决定隐藏您应用程序中允许用户固定快捷方式的选项。

注意:另请参见支持库API isRequestPinShortcutSupported(Context)和requestPinShortcut(Context,ShortcutInfoCompat,IntentSender),它可以在低于O的Android版本上运行,因为它们回落到不推荐使用的私有意图com.android.launcher.action.INSTALL_SHORTCUT。

ShortcutManager类在API level 26上,增加了对isRequestPinShortcutSupported、requestPinShortcut、createShortcutResultIntent三个方法。说明如下:

1.isRequestPinShortcutSupported

官文:
Return TRUE if the app is running on a device whose default launcher supports requestPinShortcut(ShortcutInfo, IntentSender).

The return value may change in subsequent calls if the user changes the default launcher app.

Note: See also the support library counterpart isRequestPinShortcutSupported(Context), which supports Android versions lower than O using the legacy private intent com.android.launcher.action.INSTALL_SHORTCUT.

译:
如果默认桌面支持requestPinShortcut(ShortcutInfo,IntentSender)方法,则返回TRUE。

如果用户更改默认启动程序应用程序,返回值可能会在后续调用中更改。

注意:另请参见支持库对应的isRequestPinShortcutSupported(Context),在低于O的Android版本,它支持使用旧的私有意图com.android.launcher.action.INSTALL_SHORTCUT。

2.requestPinShortcut

官文:
Request to create a pinned shortcut. The default launcher will receive this request and ask the user for approval. If the user approves it, the shortcut will be created, and resultIntent will be sent. If a request is denied by the user, however, no response will be sent to the caller.

Only apps with a foreground activity or a foreground service can call this method. Otherwise, it’ll throw IllegalStateException.

It’s up to the launcher to decide how to handle previous pending requests when the same package calls this API multiple times in a row. One possible strategy is to ignore any previous requests.

Note: See also the support library counterpart requestPinShortcut(Context, ShortcutInfoCompat, IntentSender), which supports Android versions lower than O using the legacy private intent com.android.launcher.action.INSTALL_SHORTCUT.

译:
请求创建固定的快捷方式。默认启动器将收到该请求,并要求用户批准。如果用户批准,将创建快捷方式,并且将发送resultIntent。但是,如果请求被用户拒绝,则不会向呼叫者发送任何响应。

只有具有前台活动或前台服务的应用程序才能调用此方法。否则,它将抛出IllegalStateException。

当同一个软件包连续多次调用该API时,由开发人员决定如何处理以前的待处理请求。一个可能的策略是忽略任何先前的请求。

注意:另请参见支持库对应件requestPinShortcut(Context,ShortcutInfoCompat,IntentSender),在低于O的Android版本,它支持使用旧的私有意图com.android.launcher.action.INSTALL_SHORTCUT。

3.createShortcutResultIntent

官文:
Returns an Intent which can be used by the default launcher to pin a shortcut containing the given ShortcutInfo. This method should be used by an Activity to set a result in response to ACTION_CREATE_SHORTCUT.

译:
返回默认启动器可以使用的Intent来固定包含给定的ShortcutInfo的快捷方式。 Activity应该使用此方法来设置响应ACTION_CREATE_SHORTCUT的结果。

根据弹窗提示可以看出,可以通过拖动这个图标往桌面上添加快捷方式,可以通过点击自动添加按键,系统给你在桌面的默认位置上添加。

添加后,桌面上会出现如图所示的图标:

回调用到的Receiver:

打印log发现,onReceive如图官方文档所说,点击弹框自动添加按键后,会得到回调。但实践发现,如果桌面上已经添加了图标,当再次调用requestPinShortcut进行添加时,onReceive会在调用requestPinShortcut的时候,直接被回调,而且弹框也会弹出来。

在以上三个方法官方介绍中,官方提示我们,可以使用Android support库的ShortcutManagerCompat进行快捷方式的版本适配。于是,在build.gradle中添加依赖进行尝试:

⑥ 如何解决Android7.0及以上的权限崩溃问题

话说自从google出来Android 7.0系统之后,我们公司的测试小伙伴就向我提出了7.0的bug,接下来就着手查阅了下问题是出在哪里的,该如何来解决呢。
bug日志是长这样子的:
android.os.FileUriExposedException: file:///storage/emulated/0/ys_toutiao.apk exposed beyond app through Intent.getData()
at android.os.StrictMode.onFileUriExposed(StrictMode.java:1816)
at android.net.Uri.checkFileUriExposed(Uri.java:2350)
at android.content.Intent.prepareToLeaveProcess(Intent.java:9076)
at android.content.Intent.prepareToLeaveProcess(Intent.java:9037)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1530)
at android.app.Activity.startActivityForResult(Activity.java:4391)
at android.support.v4.app.BaseFragmentActivityJB.startActivityForResult(BaseFragmentActivityJB.java)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java)
at android.app.Activity.startActivityForResult(Activity.java:4335)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java)
at android.app.Activity.startActivity(Activity.java:4697)
at android.app.Activity.startActivity(Activity.java:4665)
at com.ijuyin.prints.news.utils.VersionUtils$1.handleMessage(VersionUtils.java)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:156)
at android.app.ActivityThread.main(ActivityThread.java:6524)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:941)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:831)

也就是说是在什么情况下会出现呢?
1、是在调用系统相机的时候;
2、是在写入文件的时候, 在我这里是强制升级后下载完成安装Apk时;
关于FileUriExposedException 异常的描述是这样子的:
针对于权限部分,Android7.0是google推出的对权限做了一个更新即不允许出现以file://的形式调用隐式APP系统,也就是说以前呢,Uri的获取方式是以file://xxx的样式来,那么我们也就是通过Uri.fromFile()来获取如今放在7.0及以上系统呢,这样子就不行啦;
如今的解决关键在哪里呢,需要在应用间共享文件,也就是需要发送一项content://URI,并授予 URI 临时访问权限。进行此授权的最简单方式是使用FileProvider类。
嗯的,FileProvider
1、首先我们需要在AndroidManifest中的application下添加provider:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.ijuyin.prints.news">

<application
android:name="com.ijuyin.prints.news.base.BaseApplication"
android:allowBackup="true"
android:hardwareAccelerated="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/text_app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:replace="android:label"
android:fullBackupContent="false">

<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.ijuyin.prints.news.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"/>
</provider>

</application>

</manifest>

在这里我们需要注意一下其中设置的各种属性的含义:
authorities:是该项目的包名+provider
grantUriPermissions:必须是true,表示授予 URI 临时访问权限
exported:必须是false
resource:中的@xml/file_paths是我们接下来要在资源文件目录下添加的文件
2、在res目录下新建一个xml文件夹,并且新建一个file_paths的xml文件
设置file_path路径.png
3、打开file_paths.xml文件添加如下内容
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path
name="camera_photos"
path="."/>
<external-path
name="files_root"
path="Android/data/com.ijuyin.prints.news/"/>
<external-path
name="external_storage_root"
path="."/>
</paths>
</resources>

需要注意的是:
path:需要临时授权访问的路径(.代表在相机调用时候访问的是所有路径,而文件写入时访问的路径是Android/data/com.ijuyin.prints.news/)
name: 是你为设置的这个访问路径起的名字
4、接下来便是修改适配Android 7.0及以上系统的代码
第一部分是对于相机模块的修改
/**
* Open camera
*/
private void showCameraAction() {
if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission
.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,
getString(R.string.mis_permission_rationale_write_storage),
REQUEST_STORAGE_WRITE_ACCESS_PERMISSION);
} else {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getActivity().getPackageManager()) != null) {
try {
mTmpFile = FileUtils.createTmpFile(getActivity());
} catch (IOException e) {
e.printStackTrace();
}
Uri imageUri;
if (mTmpFile != null && mTmpFile.exists()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
String authority = getActivity().getPackageName() + ".provider";
imageUri = FileProvider.getUriForFile(getActivity(), authority, mTmpFile);
} else {
imageUri = Uri.fromFile(mTmpFile);
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, REQUEST_CAMERA);
} else {
Toast.makeText(getActivity(), R.string.mis_error_image_not_exist, Toast
.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getActivity(), R.string.mis_msg_no_camera, Toast.LENGTH_SHORT)
.show();
}
}
}

第二部分是对文件写入模块的代码修改
private static Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == DOWN_UPDATE) {
mProgress.setProgress(progress);
} else if (msg.what == DOWN_OVER) {
if (null != downloadDialog && downloadDialog.isShowing()) {
try {
downloadDialog.dismiss();
} catch (Exception e) {
e.printStackTrace();
}
}
File apkfile = new File(apkPath);
if (!apkfile.exists()) {
return;
}
Intent intent = new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
String authority = mContext.getPackageName() + ".provider";
Uri contentUri = FileProvider.getUriForFile(mContext, authority, apkfile);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.fromFile(apkfile), "application/vnd.android" +
".package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
mContext.startActivity(intent);
}
}
};

其中最核心的部分是

配置provider.png

需要注意的地方是:
首先我们对Android系统的型号做出判断
添加flags,表明我们要被授予什么样的临时权限
以前我们直接 Uri.fromFile(apkFile)构建出一个Uri,现在我们使用FileProvider.getUriForFile(getActivity(), getActivity().getPackageName() + ".provider", mTmpFile);
其中getActivity().getPackageName()指的是该项目的应用包名(此处调用的是在fragment,所以使用的是getActivity())
通过以上4步的设置操作,就可以完全解决android 7.0及以上权限问题导致的崩溃问题。

⑦ android中怎么创建一个表格

效果图:


5、 单击该项目,执行。便得到以上效果!

热点内容
手机配置内存颜色怎么看 发布:2025-02-05 12:47:36 浏览:198
电脑服务器盘口顺序 发布:2025-02-05 12:40:20 浏览:663
mcpe服务器怎么开 发布:2025-02-05 12:40:13 浏览:835
linux文件记录 发布:2025-02-05 12:39:31 浏览:775
编程奖金计算 发布:2025-02-05 12:27:01 浏览:185
软件怎么去掉付费配置 发布:2025-02-05 12:26:17 浏览:504
安卓手机怎么下载谷歌商店apk 发布:2025-02-05 12:21:09 浏览:367
腾讯视频的缓存在哪里 发布:2025-02-05 12:21:03 浏览:710
安卓聊天记录未备份怎么恢复 发布:2025-02-05 12:05:02 浏览:953
海外搭建服务器可以连外网吗 发布:2025-02-05 11:49:21 浏览:64