Launcher(发射器),就是你经常看到主屏幕吧,其实它也是一个App,它加载着其它app的图标和名字,并通过意图打开i它们。
从本博客你可以从认识Launcher并且开发一个简单的Launcher,在你的模拟器上使用。
注意:
- 下面代码需要自己强烈建议手打,否则你只是复制了一个Demo。
- 如果你需要的只是看一下效果的话,请点击下载,转到GitHub上下载Demo,并查看。
- GitHub代码 需要把清单列表的注释解开
一、Launcher
1.什么是Launcher
安卓系统中的桌面启动器,安卓系统的桌面UI统称为Launcher
2. 定制Launcher
在许多国内手机都定制了自己的Launcher,并不予许用户使用其它Launcher。
尤其是在智能电视和车载上,都有自己的Launcher。
3.不同Launcher
Launcher也有许多不同版本,这章就不展开讲了,只是让你认识一下Launcher。
具体你可以看这里
二、开发一个简单Launcher
开发一个Launcher很简单,你只需要跟着我写下面的代码就可以得到一个自己的Launcher。
1.清单列表
在自己开发的APP的AndroidManifest中添加两句代码到自己的Activity里。
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT"/>

启动模拟器,可以使用夜神或者AS中的模拟器,我使用过夜神5.0和AS中模拟器(5.0),都可以。一般国内真机都不行。
运行起来,就是一个Hellowrod,但是一旦返回到主界面,就会弹出询问使用什么Launcher。
这里是因为系统中有多个Launcher,所以询问,点击仅一次。你会发现效果是打开了这个只有HelloWrod的App,其实它已经是你的主屏幕了,接下来我们把它改造的像一点。
2.通过PackageManager获取应用
private void getApps() {
PackageManager packageManager = getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
mMApps = packageManager.queryIntentActivities(intent, 0);
}
3.建立视图预览
简单点,先创建一个RecycleView,把图标显示到上面,并添加点击事件,跳到个个应用。
在onBindViewHolder中写获取App图标和名字的代码,和点击事件的接口回调。
@Override
public void onBindViewHolder(@NonNull MyAppsAdapter.ViewHolder viewHolder, int i) {
ResolveInfo resolveInfo = mMApps.get(i);
Drawable drawable = resolveInfo.activityInfo.loadIcon(mContext.getPackageManager());
CharSequence charSequence = resolveInfo.loadLabel(mContext.getPackageManager());
viewHolder.mAppimg.setImageDrawable(drawable);
viewHolder.mAppname.setText(charSequence);
viewHolder.mAppimg.setOnClickListener(v -> {
mMyAppsAdapterSetOnClickListener.OnClickListener(i);
});
}
大概效果就这样了
此时这个Launcher基本可以使用了,如果你嫌弃它不好看,我们可以加一个简单的背景。
在Styet里面添加一个背景
<style name="MyLauncher" parent="android:Theme.Wallpaper">
<item name="android:windowNoTitle">true</item>
</style>
在清单里配置
<activity
android:name=".MainActivity"
android:theme="@style/MyLauncher"
>
运行一下,效果如下:
如果崩溃了,请更改Activity继承关系
public class MainActivity extends Activity implements MyAppsAdapter.MyAppsAdapterSetOnClickListener {
三、附代码:
为了方便大家查看代码,在这我附出应用代码,免去下载代码的麻烦。
1.manifest
<?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.example.mylauncher"
>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
tools:ignore="GoogleAppIndexingWarning"
>
<activity
android:name=".MainActivity"
android:theme="@style/MyLauncher"
>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
2.MainActivty
1.MainActivty的代码
public class MainActivity extends Activity implements MyAppsAdapter.MyAppsAdapterSetOnClickListener {
private String TAG = "MainActivity";
private RecyclerView rl;
private MyAppsAdapter mMyAppsAdapter;
private List<ResolveInfo> mMApps;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
getApps();
setData();
}
private void setData() {
if (mMyAppsAdapter == null) {
mMyAppsAdapter = new MyAppsAdapter(this, mMApps);
}
rl.setLayoutManager(new GridLayoutManager(this, 4));
rl.setAdapter(mMyAppsAdapter);
mMyAppsAdapter.setMyAppsAdapterSetOnClickListener(this);
}
private void getApps() {
PackageManager packageManager = getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
mMApps = packageManager.queryIntentActivities(intent, 0);
}
private void initView() {
rl = findViewById(R.id.rl);
}
@Override
public void OnClickListener(int i) {
ResolveInfo resolveInfo = mMApps.get(i);
String packageName = resolveInfo.activityInfo.packageName;
String appName = resolveInfo.activityInfo.name;
ComponentName componentName = new ComponentName(packageName, appName);
Intent intent = new Intent();
intent.setComponent(componentName);
startActivity(intent);
}
}
2.MainActivty的布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/rl"
/>
</android.support.constraint.ConstraintLayout>
3.MyAppsAdapter
1.MyAppsAdapter代码
package com.example.mylauncher;
import java.util.List;
import android.content.Context;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
class MyAppsAdapter extends RecyclerView.Adapter<MyAppsAdapter.ViewHolder> {
private final Context mContext;
private final List<ResolveInfo> mMApps;
public MyAppsAdapter(MainActivity context, List<ResolveInfo> mApps) {
mContext = context;
mMApps = mApps;
}
@NonNull
@Override
public MyAppsAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(mContext).inflate(R.layout.recycler_view_item, null);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull MyAppsAdapter.ViewHolder viewHolder, int i) {
ResolveInfo resolveInfo = mMApps.get(i);
Drawable drawable = resolveInfo.activityInfo.loadIcon(mContext.getPackageManager());
CharSequence charSequence = resolveInfo.loadLabel(mContext.getPackageManager());
viewHolder.mAppimg.setImageDrawable(drawable);
viewHolder.mAppname.setText(charSequence);
viewHolder.mAppimg.setOnClickListener(v -> {
mMyAppsAdapterSetOnClickListener.OnClickListener(i);
});
}
@Override
public int getItemCount() {
return mMApps.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private final TextView mAppname;
private final ImageView mAppimg;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mAppimg = itemView.findViewById(R.id.appimg);
mAppname = itemView.findViewById(R.id.appname);
}
}
public MyAppsAdapterSetOnClickListener mMyAppsAdapterSetOnClickListener;
public void setMyAppsAdapterSetOnClickListener(
MyAppsAdapterSetOnClickListener myAppsAdapterSetOnClickListener) {
mMyAppsAdapterSetOnClickListener = myAppsAdapterSetOnClickListener;
}
interface MyAppsAdapterSetOnClickListener {
void OnClickListener(int i);
}
}
xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<ImageView
android:id="@+id/appimg"
android:layout_width="50dp"
android:layout_height="50dp"
tools:src="@tools:sample/avatars"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/appname"
android:layout_width="50dp"
android:layout_height="wrap_content"
android:text="appname"
app:layout_constraintTop_toBottomOf="@+id/appimg"
app:layout_constraintStart_toStartOf="@+id/appimg"
app:layout_constraintEnd_toEndOf="@+id/appimg"
/>
</android.support.constraint.ConstraintLayout>
3其它
1.style
<style name="MyLauncher" parent="android:Theme.Wallpaper">
<item name="android:windowNoTitle">true</item>
</style>
2.依赖
implementation 'com.android.support:recyclerview-v7:28.0.0'