黑马52期学后总结笔记(七)

本文详细介绍了如何在Android设备上管理手机应用,包括短信备份、获取存储空间信息、安装和卸载应用、查看系统应用与用户应用的区别,以及如何在应用管理器中展示和操作这些应用。此外,还讨论了如何利用PopupWindow实现弹出式菜单,以增强用户体验。通过这些技术,用户能够更有效地管理手机资源,提高设备性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

61_ 短信备份的原理_30

1、查看金山手机卫士的短信备份功能。

 短信备份的原理,是用内容提供者读取短信,然后保存。

 

2、在高级工具AtoolsActivity布局文件里添加短信备份,并处理点击事件smsBackup

 

3、在com.itheima.mobilesafe.utils工具包目录创建工具类SmsTools用于写短信备份代码

 

  A:短信备份方法backup(Contextcontext,String path)

 

  B:导出短信数据库保存的路径

data/data/com.android.provider.telephony/databases/mmssms.db

address 短信收件人发件人地址

date 短信接收的时间

type 1 发进来短信 2 发出去短信

read 1已读短信 0 未读短信

 

  C:参照源代码Uri路径怎么写

//备份所有的短信,未读的、已读的等待

   Uri uri = Uri.parse("content://sms/");

   读取短信代码:

Cursor cursor =resolver.query(uri, new String[]{"address","date","type","body"}, null, null, null);

        while(cursor.moveToNext()){

            String address = cursor.getString(0);

            String date = cursor.getString(1);

            String type = cursor.getString(2);

            String body = cursor.getString(3);

           

        }

 

把短信生成XML文件,得到xml的序列化器,设置参数

       XmlSerializer serializer = Xml.newSerializer();

        Filefile = new File(path);

        FileOutputStreamos = new FileOutputStream(file);

        //设置序列化器的参数

        serializer.setOutput(os, "utf-8");

 

 

设置文档的开头和结束

 serializer.startDocument("utf-8", true);

 serializer.endDocument();

 

设置文档根节点smss开始和结束

serializer.startTag(null, "smss");

serializer.endTag("", "smss");

 

设置sms里面具体内容,在while循环里面做

      serializer.startTag(null, "sms");

        

         serializer.startTag(null, "address");

         String address =cursor.getString(0);

         serializer.text(address);

         serializer.endTag(null, "address");

 

      serializer.endTag(null, "sms");

 

 

 

4、使用写好的短信备份工具

 判断sdcard是否存在

 

   if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){

            File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath(),"smsbackup.xml");

            try {

                SmsTools.backup(this, file.toString());

                Toast.makeText(this, "短信备份成功", 0).show();

            } catch (Exception e) {

                // TODO Auto-generatedcatch block

                e.printStackTrace();

                Toast.makeText(this, "短信备份失败", 0).show();

            }

        }else{

            Toast.makeText(this, "sdcard不可用", 0).show();

            return;

        }

       

 

   5、添加读短信的权限

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

 

知识拓展 生成excel表 poc

http://blog.csdn.net/zhy_cheng/article/details/10286563

 

 

62_接口和回调_26

1、当前备份短信代码,是写在主线程,如果短信很多的话会出现ANR异常。

 

2、把短信备份代码移植到子线程;

 

new Thread(){

 public void run() {

        try {

    SmsTools.backup(AtoolsActivity.this,file.toString());

        } catch (Exception e) {

            e.printStackTrace();

        }

 };

}.start();

 

3、模拟短信备份耗时,在没一个While循环里休眠1000毫秒

 

4、创建一个对话框ProgressDialog用户等待备份时间,和消掉对话框

     显示对话框

    final ProgressDialog dialog = new ProgressDialog(this);

    dialog.setMessage("请稍等,正在备份钟...");

    dialog.show();

  备份完后在子线程消掉对话框?

  dialog.dismiss();

运行演示,看效果;

 

5、做成是有加载进度的对话框

dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);

但是我们需要知道总条数和当前备份了多少条;

 

运行演示看效果

 

在短信备份方法增加参数ProgressDialogdialog参数

在备份方法里设置短信总条数

//设置总条数

dialog.setMax(cursor.getCount()); 

 

定义进度

//当前进度

int progress = 0;

 

在while循环里跟新进度

progress ++;

dialog.setProgress(progress);

 

 

考虑在工作中真实的情况:

备份短信界面UI  是由A程序员写的;

备份短信的功能工具类  是用B程序员写的;

 

A程序员被老板叫去需要改成进度条,在布局文件修改

    <ProgressBar

        android:id="@+id/progressBar1"

        style="?android:attr/progressBarStyleHorizontal"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"/>

 

 

  在代码里初始化

(ProgressBar)findViewById(R.id.progressBar1);

并找程序员B帮忙吧参数修改成ProgressBar

 

 

这时候程序员A又被老板叫去说,还没有原来的好看,改成原来的吧;如果有版本控制工具,可以还原,但同时也还原了B程序员的代码;

 

 

这时候老板又突发奇想,说想要对话框同时显示进度条

A程序员就需要把注释的地方打开,然后需要B程序员再增加一个参数ProgressDialog ,B程序员还需要做如下代码:

progressDialog.setMax(cursor.getCount());

在while循环里还得progressDialog.setProgress(progress);

 

 

给我暴露一个接口吧

给我提供一个回调

 

6、接口的定义

 

B工程师最关心的是备份的过程,并不关心如何更新UI;

但B工程师知道在相应时间更新需要跟新对应UI;

 

B工程师定义一个接口。暴露一些回调;

// B 工程师就定义一个接口,暴露一些回调方法

 

   public interface SmsBackupCallBack {

      /**

       * 当短信备份前调用的方法

       * @param total 短信的总条数

       */

      public void beforeSmsBackup(int total);

 

      /**

       * 当短信备份过程中调用

       * @param progress 备份的进度

       */

      public void onSmsBackup(intprogress);

   }

 

 

 

备份方法参数和里面的变化

 backup(Context context, String path, SmsBackupCallBackbackupCallBack)

 

当短信备份前调用的方法

backupCallBack.beforeSmsBackup(cursor.getCount());

 

While循环里面的代码

backupCallBack.onSmsBackup(progress);

 

 

7、回调的使用

 

new SmsBackupCallBack() {

                    

      @Override

      public void onSmsBackup(int progress) {

         dialog.setProgress(progress);

                         progressBar1.setProgress(progress);

                     }

                    

                     @Override

                     public void beforeSmsBackup(int total) {

                        dialog.setMax(total);

                        progressBar1.setMax(total);

                     }

                  }

 

 

 

 

 

 

A程序员有接到任务了,把进度掉去掉就行了,这样就很方便了;

 

 

 

63_获取手机存储空间信息_22

1、要开发软件管理这个功能了,启动2.3模拟题,参照金山手机卫士看一下;

2、创建AppManagerActivity并在功能清单文件注册,验证完成跳转逻辑;

3、参照金山手机卫士,写相对布局,用于保存

 <RelativeLayout

        android:layout_width="fill_parent"

        android:layout_height="wrap_content" >

        <TextView

            android:id="@+id/tv_avail_rom"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_marginLeft="3dip"

            android:text="内存可用:"

            android:textColor="#000000"

            android:textSize="16sp" />

        <TextView

            android:id="@+id/tv_avail_sd"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:layout_alignParentRight="true"

            android:layout_marginRight="3dip"

            android:text="sd卡可用:"

            android:textColor="#000000"

            android:textSize="16sp" />

    </RelativeLayout>

这里说的内存和电脑说的内存是有区别的,这里的内存指的是手机内部存储空间,相当于手机内置了一块硬盘;

 

4、获取某个路径可用的空间的大小

public long getTotalSpace(String path){

      StatFs statfs = new StatFs(path);

      //得到有多少个可以使用

      int count=statfs.getAvailableBlocks();

      //得到每一个的容量

      int size =statfs.getBlockSize();

      return count*size;

   }

 

解释为什么要相乘

在左面上创建一个空文件连续写4个a一边写一遍看

 

画图进一步分析

5、修改getTotalSpace()方法直接返回计算好的结构

/**

    * 获取某一个路径的可用空间的总大小

    * @param path

    * @return

    */

   public String getTotalSpace(Stringpath){

      StatFs statfs = new StatFs(path);

      //得到一个可以用的区域的大小

      int count=statfs.getAvailableBlocks();

      //得到一个可以用的区域的个数

      int size =statfs.getBlockSize();

      return Formatter.formatFileSize(this, count*size);

   }

Formatter的包是: android.text.format

 

 

高端手机内存比较大,int类型无法容纳,需要改成long类型

 

原理:int 最大值2147483647

             2147483647/1024 =2097151.999023438 KB

 2097151.999023438/1024 = 2047.999999046326 MB;

 2047.999999046326/1024 = 1.999999999068677 GB

 支持2G左右的大小数据,多余的就溢出了

 

 

public StringgetTotalSpace(String path){

        StatFsstatfs = new StatFs(path);

       

        long count =statfs.getAvailableBlocks();

        long size = statfs.getBlockSize();

        return Formatter.formatFileSize(this, count*size);

    }

 

 

64_获取手机里面应用程序信息_20

1、Android的应用程序安装在哪里呀?

  pc电脑默认安装在C:\Program Files

 Android 的应用安装在哪里呢,如果是用户程序,安装在data/app/目录下

 

  安装Android软件 做两件事

    A:把APK拷贝到data/app/目录下

    B:把安装包信息写到data/system/目录下两个文件packages.list 和 packages

 

 

2、安装包信息在data/system/

 Packages.list 里面的0 表示系统应用 1 表示用户应用

 Packages.xml是存放应用的一些权限信息的;

 

系统带应用安装在system/app/目录下

 

 

 

3、用PackageManger得到应用的信息;

 

 A、创建新包com.itheima.mobilesafe.engine 里面创建新类AppInfoProvider

 B、在AppInfoProvider里面创建方法public List<AppInfo>getAppInfos()

 C、创建实体类AppInfo,并实现set和get方法

   private Drawable icon;

   private String name;

   private String packageName;

   private boolean isRom;

 

 

 

4、部分代码的实现

      PackageManager pm = context.getPackageManager();

        List<PackageInfo>infos = pm.getInstalledPackages(0);

        for(PackageInfo info: infos){

            AppInfo appinfo = new AppInfo();

            String packageName = info.packageName;

            Drawable icon = info.applicationInfo.loadIcon(pm);

            String name = info.applicationInfo.loadLabel(pm).toString();

           

            appinfo.setIcon(icon);

            appinfo.setName(name);

            appinfo.setPackageName(packageName);

            appinfos.add(appinfo);

        }

     

 

5、写测试代码测试com.ithiema.mobilesafe.test

public class TestAppInfoProvider extends AndroidTestCase {

   

    public voidtestgetAppInfos(){

         List<AppInfo> appinfos =AppInfoProvider.getAppInfos(getContext());

         for(int i = 0; i <appinfos.size();i++){

            AppInfo info =  appinfos.get(i);

            System.out.println(info.toString());

         }

    }

 

}

 

6、为看方便打印,重新toString()方法

 

 

  

 

65_程序管理器的UI显示_43

 

1、获取应用程序类型,是用户应用还是系统应用

  在AppInfo 实体类增加 booleanisUuserApp 并创建set和get方法

 

 info.applicationInfo.flags;

 //flags是应用程序的特征标志。可以是任意标志的组合   。

 

一个int在内存中占4个字节,一个字节占8个二进制位,所以一个int在内存中表示32位。

 

画图分析理解flags

最多可以移位31位,因为总共有32位;这样设计的目的是什么呢?

 

 

看看生活中的案例--机读卡看图片

答题卡 英语答题卡 参照机读卡思路和原理我们开发一个机读系统

 

 

举例生活中的例子,老师手工改试卷

 

如何知道是系统应用还是用户应用的,画图理解

 

 

 

 

写具体代码了---判断是系统应用还是用户应用

if((flas & ApplicationInfo.FLAG_SYSTEM)==0){

                //用户应用

}else{

                //系统应用

}

  

判断是按照在内存里还是外部存储里面    

if((flas &ApplicationInfo.FLAG_EXTERNAL_STORAGE)==0){

        //手机内存

}else{

        //存储

与运算比if else 判断效率高一些

赋值测试运行;

 

 

 

 

2、布局文件写上ListView ,并加上加载效果

 <FrameLayout

        android:layout_width="fill_parent"

        android:layout_height="fill_parent" >

        <ListView

            android:id="@+id/ll_app_manager"

            android:layout_width="fill_parent"

            android:layout_height="fill_parent" >

        </ListView>

        <LinearLayout

            android:layout_width="fill_parent"

            android:layout_height="fill_parent"

            android:gravity="center"

            android:orientation="vertical" >

            <ProgressBar

                android:layout_width="wrap_content"

                android:layout_height="wrap_content" />

            <TextView

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:text="正在加载应用程序..." />

        </LinearLayout>

</FrameLayout>

 

3.初始化ListView和加载效果线性布局并加载数据

 

 

     A:在onCreate()方法里,子线程加载数据

      new Thread(){

       public void run() {

                infos =  AppInfoProvider.getAppInfos(AppManagerActivity.this);

         handler.sendEmptyMessage(0);

            };

        }.start();

 

   刷新界面用handler

  private Handler handler = new Handler(){

        public voidhandleMessage(android.os.Message msg) {

            adapter = new MyAppAdapter();

            ll_app_manager.setAdapter(adapter);

        };

   };

     B:自定义Adapter,并把数据传进数据,自定义每条的布局list_app_item.xml;布局文件模仿金山手机卫士部分功能

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

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

    android:layout_width="match_parent"

    android:layout_height="60dip" >

    <ImageView

        android:id="@+id/iv_icon"

        android:layout_width="50dip"

        android:layout_height="50dip"

        android:layout_marginLeft="5dip"

        android:layout_marginTop="5dip"

        android:src="@drawable/app" />

 

    <TextView

        android:id="@+id/tv_name"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_marginTop="6dip"

        android:layout_toRightOf="@id/iv_icon"

        android:text="程序名称"

        android:textColor="#000000"

        android:textSize="20sp" />

   

     <TextView

        android:id="@+id/tv_location"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_marginTop="3dip"

        android:layout_toRightOf="@id/iv_icon"

        android:layout_below="@id/tv_name"

        android:text="安装位置"

        android:textColor="#88000000"

        android:textSize="14sp" />

</RelativeLayout>

 

 

代码实现getView()里:

      View view = null;

            ViewHolder holder;

            if(convertView != null){

                view= convertView ;

                holder =(ViewHolder) view.getTag();

            }else{

                view=View.inflate(AppManagerActivity.this, R.layout.list_app_item, null);

                holder= new ViewHolder();

                holder.iv_icon = (ImageView)view.findViewById(R.id.iv_icon);

                holder.tv_name = (TextView)view.findViewById(R.id.tv_name);

                holder.tv_location = (TextView)view.findViewById(R.id.tv_location);

                view.setTag(holder);

            }

            AppInfo info = infos.get(position);

            holder.iv_icon.setImageDrawable(info.getIcon());

            holder.tv_name.setText(info.getName());

            if(info.isRom()){

                holder.tv_location.setText("手机内存");

            }else{

                holder.tv_location.setText("存储");

       }

     

 

 

4、设置指定应用安装在手机内存中还是外部存储卡中

    在功能清单根节点处添加

    android:installLocation="auto"

   auto:自动安装,优先安装在手机内存里面 ,可以切换;

   internalOnly:只安装在手机内存里面,不可以切换;

   preferExternal:安装在外包存储,可以选切换;

  

 

66_复杂的ListView的显示_29

1、把系统应用和用户应用区分开来

 定义两个集合

 List<AppInfo> userInfos; List<AppInfos>systemInfos;

 

 初始化数据,用for区分开来

            userInfos = newArrayList<AppInfo>();

                systemInfos = newArrayList<AppInfo>();

                for(AppInfo info : infos){

                    if(info.isUserApp()){

                        //用户应用

                        userInfos.add(info);

                    }else{

                        //系统应用

                        systemInfos.add(info);

                    }

            }

 

 

2、 在适配器 getCount()方法里重写成如下;

     public int getCount() {

            return userInfos.size()+systemInfos.size();

      }

 

 

在适配器的getView()方法如何修改呢?

画图分析

3、代码实现

       AppInfo info = null;

         if(position < userInfos.size()){

            //加载用户程序

            info = userInfos.get(position);

         }else{

            //加载系统程序

            //系统的0

            int newposition = position -userInfos.size() ;

            info = systemInfos.get(newposition);

           

         }

 

 

  系统应用和用户应用的区别,系统的没法卸载,用户程序可以卸载

 

4、修改适配器增加 用户程序系统程序 条目

  A:在适配器getCount()方法里修改

     public int getCount() {

         //多了两个TextView的item 所以 +1 +1

         return userInfos.size()+1+systemInfos.size()+1;

      }

 

  B:在getView()方法里修改

 getView的作用:是控制每个位置显示的内容

 

 添加用户程序的TextView

if(position == 0){//创建一个TextView显示多少个用户程序

    TextView view = new TextView(AppManagerActivity.this);

    view.setText("用户程序("+userInfos.size()+")");

    view.setTextColor(Color.WHITE);

    view.setBackgroundColor(Color.GRAY);

 

    return view;

}

 

 

添加系统程序的TextView

else if(position== userInfos.size() +1 ){

    TextView view = new TextView(AppManagerActivity.this);

    view.setText("系统程序("+systemInfos.size()+")");

    view.setTextColor(Color.WHITE);

    view.setBackgroundColor(Color.GRAY);

                return view;

    }

 

特殊情况处理了,需要处理一般情况了,画图分析

 

用户程序显示

else if(position <=userInfos.size()){

                //用户程序

                int newposition = position -1;

                info= userInfos.get(newposition);

}

 

系统程序显示

else{

    //系统程序

    int newposition =position -1- userInfos.size()  - 1;

    info = systemInfos.get(newposition);

               

}

 

运行拖动演示报错,讲解报错的原因

 

删除应用 ,进入应用管理 ,删除应用 进入应用管理

 

contverView

重用旧的视图,如果可能的话。注意:您应该检查,这个观点是在使用非空和适当的类型。如果它是不可能将这个视图来显示正确的数据,这种方法可以创建一个新的视图。异构列表可以指定数量的视图类型,以便这一观点总是正确的类型(getViewTypeCount()getItemViewType(int))

 

 

5、解决报错问题

if(convertView!=null&&convertViewinstanceof RelativeLayout){

                //.................

    }else{

                //.............

    }

 

 

6、回顾处理ListView 中的getCount()和getView()这个过程

 

67_ListView的状态栏_14

 知识拓展,增加快速滚动条

 在ListView布局文件加上:

 android:fastScrollEnabled="true"

 

1、在布局文件添加TextView长得和getView里面创建的一样

  <TextView

            android:textColor="#ffffff"

            android:background="#ff888888"

            android:text="用户程序(7)"

            android:layout_width="fill_parent"

            android:layout_height="wrap_content"/>

 

2.给ListView设置滚动监听

 

ll_app_manager.setOnScrollListener(newOnScrollListener() {

            @Override

            public voidonScrollStateChanged(AbsListView view, int scrollState) {

            }

           

            @Override

            public voidonScroll(AbsListView view, int firstVisibleItem,

                    int visibleItemCount,int totalItemCount) {

               

if(systemInfos != null&&userInfos != null){

                   

    if(firstVisibleItem> userInfos.size()){

            //显示系统应用

    tv_status.setText("系统程序("+systemInfos.size()+")");

    }else{

            //显示用户应用

    tv_status.setText("用户程序("+userInfos.size()+")");

                    }

                }

            }

        });

 

68_popupwindow的使用_44

1、打开2.3模拟器演示联系人效果

2、创建一个新工程专门学习popupwindow

一个弹出窗口,可以用来显示一个任意视图。弹出窗口是一个浮动的容器,出现在当前活动的顶端。

  在按钮中添加点击事件

初识popupWindow

TextViewcontentView = new TextView(this);

contentView.setText("我是PopupWindow");

contentView.setTextColor(Color.RED);

View parent =findViewById(R.id.rl_root);

PopupWindow window= newPopupWindow(contentView, 200, 100);

window.showAtLocation(parent, Gravity.LEFT + Gravity.TOP, 200, 100);

 

左上角对齐

 

通过设置PopupWindow 的背景,了解它有多大

PopupWindow window= newPopupWindow(contentView, 200, 100);

window.setBackgroundDrawable(new ColorDrawable(Color.GREEN));

window.showAtLocation(parent, Gravity.LEFT + Gravity.TOP, 200, 100);

 

 

 

点击返回直接退出Activity

 对话框点击退出是消掉,那么PopupWindow是否也可以呢?

PopupWindowwindow = new PopupWindow(contentView,200, 100,true);

 

 

3、把学习好的PopupWindow 移植到工程中

 A:监听每点一条的事件,并打印日志;

 Object obj = ll_app_manager.getItemAtPosition(position);

 System.out.println("obj=="+obj);

 getItemAtPosition(position)获取数据列表中指定的位置。

 

 

 B:在适配器中修改如下,运行点击,看日志

public Object getItem(int position) {

         return "asbllldkk";

}

 

 

解决该问题:

@Override

        public Object getItem(int position) {

            AppInfo info = null;

            if(position == 0){//创建一个TextView显示多少个用户程序

                return null;

            }else if(position == userInfos.size() +1 ){

                return null;

            }else if(position <= userInfos.size()){

                //用户程序

                int newposition =position -1;

                info= userInfos.get(newposition);

            }else{

                //系统程序

                int newposition =position -1- userInfos.size()  - 1;

                info= systemInfos.get(newposition);

            }

            return info;

        }

 

 

 

 

 

 

 点击事件做处理,运行看日志

Object obj = ll_app_manager.getItemAtPosition(position);

if(obj != null){

    AppInfo info = (AppInfo) obj;

                    System.out.println("info=="+info.getPackageName());

}

 

 

4、在点击事件中添加PopuWindow,运行演示,并点击看效果

TextViewcontentView = newTextView(AppManagerActivity.this);

contentView.setText(info.getPackageName());

contentView.setTextColor(Color.RED);

PopupWindowpopupWindow = newPopupWindow(contentView, LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);

int [] location = new int[2];

view.getLocationInWindow(location);

                   

popupWindow.showAtLocation(parent, Gravity.LEFT+Gravity.TOP, 0, location[1]);

 

5、希望同一时间只能显示一个PopupWindow

  把PopWindow定义成类的成员变量

 

  每次点击,隐藏上次创建的,便于重新创建

 if(popupWindow != null&&popupWindow.isShowing()){

                  popupWindow.dismiss();

                  popupWindow = null;

   }

 

 

6、滚动时隐藏PopupWindow

  把隐藏PopupWindow代码重构成一个方法dimissPopupWindow()

  在监听滚动处onScroll()和点击前调用即可;

 

7、自定义布局文件加载到PopupWindow里;

我们希望,弹出的PopupWindow有三个功能,启动软件 卸载软件 分享软件

 

 

自定义线性布局文件popup_item.xml

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

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

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:background="@drawable/local_popup_bg"

    android:orientation="horizontal" >

    <LinearLayout

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:orientation="vertical" >

        <ImageView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:src="@drawable/img1" />

        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="卸载"

            android:textColor="#000000" />

    </LinearLayout>

    <LinearLayout

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_marginLeft="5dip"

        android:orientation="vertical" >

        <ImageView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:src="@drawable/img2" />

        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="启动"

            android:textColor="#000000" />

    </LinearLayout>

    <LinearLayout

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_marginLeft="5dip"

        android:orientation="vertical" >

        <ImageView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:src="@drawable/img3" />

        <TextView

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="分享"

            android:textColor="#000000" />

    </LinearLayout>

 

</LinearLayout>

 

把布局文件加载到PopupWindow里面

把TextView注释掉,加载如下代码

ViewcontentView = View.inflate(getApplicationContext(),R.layout.popup_item, null)

 

运行演示看效果,修改距离左边 60个像数;

 

解决图片竖直方法不协调文,把图片local_popup_bg移动到drawable-hdpi目录,运行,并解释现象;

 

当前模拟器屏幕是480*800,当前引用的图片drawable-hdpi目录下图片,最适合他,如果找不到就会到drawbale目录下去找,drawbale是所有屏幕默认使用的图片,它没有对图片做缩放处理;图片是多大就显示多大;drawable-xxhdpi目录下图片是给超大手机屏幕使用的,如果在其他目录没有找到图片,它就到drawable-xxhdpi去找,本身图片就很大,显示的时候做缩小显示。当热缩小也是不会很小。

 

 

开发过程中,一般会有两套以上图片

 

 

 

8、给PopupWindow加上两个动画效果

AlphaAnimation aa = new AlphaAnimation(0.5f,1.0f);

aa.setDuration(500);

 

ScaleAnimation sa = new ScaleAnimation(0.5f, 1.0f, 0.5f,

                     1.0f, Animation.RELATIVE_TO_SELF, 0,

                     Animation.RELATIVE_TO_SELF, 0.5f);

sa.setDuration(500);

AnimationSet set = new AnimationSet(false);

set.addAnimation(sa);

set.addAnimation(aa);

   //播放动画

contentView.startAnimation(set);

 

 

演示当时间设置5秒也没用效果,原因是PopupWindow没有加背景;

 

播放动画是要前提:就是窗体必须有背景;为什么呢?

如果没有背景的话,就不知道以怎么样的方式画出来,没有办法去合成背景颜色。

 

 

 

 

 

 

 

 

 

9、要想有动画效果就需要设置背景,透明背景也行

popupWindow = new PopupWindow(contentView,

                     LayoutParams.WRAP_CONTENT,

                     LayoutParams.WRAP_CONTENT);

               //必须要设置背景

               popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

 

 

 

 

 

注意:需要在构造方法后面这张背景,在

popupWindow.showAtLocation(parent,Gravity.LEFT

                     +Gravity.TOP, 60, location[1]);

后面才设置背景同样也是没有效果的。

 

 

 

 

69_软件管理器的完成_39

 

1、定义ID处理点击事件ll_uninstall、ll_start、ll_share

  在线性布局加上ID,初始化成类的成员变量。

   private LinearLayout ll_uninstall;

   private LinearLayout ll_start;

   private LinearLayout ll_share;

 

  在Activity设置点击事件

  ll_uninstall.setOnClickListener(AppManagerActivity.this);

ll_start.setOnClickListener(AppManagerActivity.this);

ll_share.setOnClickListener(AppManagerActivity.this);

 

 AppInfo也定义成类的成员变量,并写注释;

   private AppInfo info ;

 

  处理点击事件,打日志,点击并把PopupWindow消掉

@Override

   public void onClick(View v) {

      dimissPopupWindow();

      switch (v.getId()) {

      case R.id.ll_uninstall:

         Log.i(TAG, "卸载:"+info.getName());

         break;

      case R.id.ll_share:

         Log.i(TAG, "分享:"+info.getName());

         break;

      case R.id.ll_start:

         Log.i(TAG, "启动:"+info.getName());

         break;

      }

   }

 

 

2、卸载程序

Intent intent = new Intent();

intent.setAction("android.intent.action.VIEW");

intent.addCategory("android.intent.category.DEFAULT");

intent.setData(Uri.parse("package:"+info.getPackageName()));startActivity(intent);

 

 

 

卸载后刷新界面

启动Intent 改成

startActivityForResult(intent,0);

 

把刷得到数据,并刷新界面的代码重构到fillData()方法里面

 

 

在onActivityResult();调用fillData方法,代码如下:

@Override

protected void onActivityResult(int requestCode, int resultCode,Intent data) {

       

super.onActivityResult(requestCode,resultCode, data);

        fillData();

       

    }

 

 

卸载系统应用加上判断

if(info.isUserApp()){

        }else{

            Toast.makeText(this, "系统应用需要root权限后才能卸载", 0).show();

        }

 

 

 

 

3、软件的分享

进入金山软件主页,按菜单键。点击推荐

金山的包名:com.ijinshan.mguard

QQ的包名:com.tencent.mobileqq

 

写代码是参照短信应用去写Action

/**

    * 分享应用

    */

private void shareApp() {

    Intent intent = new Intent();

//  <actionandroid:name="android.intent.action.SEND" />

//<categoryandroid:name="android.intent.category.DEFAULT" />

//  <dataandroid:mimeType="text/plain" />

intent.setAction("android.intent.action.SEND");

     intent.addCategory("android.intent.category.DEFAULT");

intent.setType("text/plain");

intent.putExtra(Intent.EXTRA_TEXT, "推荐一款软件名叫:"+info.getName()+",下载地址:ccc"+info.getPackageName());

     startActivity(intent)  ;

}

 

https://play.google.com/store/apps/details?id=com.tencent.mobileqq

 

 

 

知识拓展,当前的代码已经支持分享到QQ空间里面了;

 

 

 

 

 

4、软件的启动,打开应用程序的Activity

 

启动原理,开启Activity,第一个Activity是通常是启动类;

 

private void startApp() {

    Intent intent = new Intent();

    PackageManager pm = getPackageManager();

    try {

    PackageInfo packInfo = pm.getPackageInfo(info.getPackageName(),0);

            ActivityInfo [] acivityInfos = packInfo.activities;

            if(acivityInfos != null&&acivityInfos.length>0){

                ActivityInfoactivityInfo = acivityInfos[0];

                intent.setClassName(info.getPackageName(),activityInfo.name);

                startActivity(intent);

            }else{

                Toast.makeText(this, "这个程序没有界面", 0).show();

            }

        } catch(NameNotFoundException e) {

            // TODO Auto-generatedcatch block

            e.printStackTrace();

            Toast.makeText(this, "这个应用无法启动", 0).show();

        }

       

    }

 

 

解决弹出没有界面的问题,分析问题的原因

PackageInfo packInfo = pm.getPackageInfo(info.getPackageName(),PackageManager.GET_ACTIVITIES);

 

 

演示启动各个软件,启动联系人Pico TTS启动报错 ,金山屏蔽了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值