Android之MediaProjectionManager实现手机截屏总结

比较好的文章:

Android中使用代码截图的各种方法总结

http://blog.csdn.net/woshinia/article/details/11520403


手机截屏:

http://www.cnblogs.com/tgyf/p/4655507.html

转载的地方:

http://www.cnblogs.com/tgyf/p/4851092.html

分享一种截屏方法

在任何时候点击手机上的浮动小球(红色圈内)就能完成整个屏幕信息的截取功能,而且最终保存的图像还不会包含该小球,这就是本文将要介绍的 方法。手机整体屏幕获取项目下载链接:http://files.cnblogs.com/files/tgyf/CaptureScreen.rar

  以新的视角实现手机屏幕的截取(快照)功能,文章可能比较长,感兴趣的朋友一定得看完,会有收获的哦!若发现有哪些地方存在问题或某些功能有更好的实现方式,欢迎指点,先谢过(我可以尽快改正或完善,以免继续误导别人)。

  关于手机(或平板,以下描述均以手机表示这两类设备)整体屏幕的截取,有的机型默认设置的方式是同时按下电源键和一个音量键(如华硕、诺基亚等,向下音量键+电源键),有的机型是同时按下电源键和Home键(如苹果)。另外,借助一些辅助工具经过特定的设置也是可以完成屏幕快照的获取。

  从打算开发一个与传统截屏方法不同的截屏应用开始,针对Android手机截屏的基本原理、相关知识及Google最新案例,已经在学习与摸索的途中写过两篇文章了,感兴趣的朋友可以通过下面给出的链接去瞧一瞧(这方面知识掌握较好的可以直接忽略)。

  在Win7+Android Studio环境尝试了网络上晒出的很多方式均失败后,带着受打击的心态写了第一篇文章:

  “Android手机截屏”——http://www.cnblogs.com/tgyf/p/4655507.html

  当时的目的是希望实现过的大神能给点有用的建议或意见。当然,一般来说Android应用在Android Studio和Eclipse下都是可以实现的,虽不能将项目代码在两者之间直接进行转换,但如若工作量不是特别大,移植起来也不麻烦,尝试过的朋友应该懂得。

  可能对于截屏应用进行学习或者实现的人不太多,笔者并没有得到什么宝贵性的建议。后面不甘心又进行了一番Google,还是没有直截了当的答案,最后决定静下心来老老实实地分析案例源码(案例没有屏幕数据获取与图片保存的实现)。于是就有了第二篇文章:

  “Google最新截屏案例详解”——http://www.cnblogs.com/tgyf/p/4675082.html

  简单回顾一下:如果只是想得到正在运行的应用程序自身的界面,那相当简单,真正获取界面信息的代码只有两三句,在第一篇文章给出的例子中有提及。由于在旧版本的API中,Google是将手机截屏相关的方法与接口隐藏的,开发者要想自主实现手机完整屏幕的快照,有很多局限性(必须采用System级别的应用开发,或者在Linux下进行Root、源码编译等操作),这部分内容的总结在第二篇文章中。

  大家都知道一些手机厂商会在自家手机发售前定制、预装一些应用,而这些应用APK有些就是System级的(需要通过源码Build)。也就是说不是没有办法利用隐藏的方法或借口实现手机截屏,而是本文将要寻找一种谁都能自己进行实现的方式,包括初学者。

  俗话说事不过三,今天这篇文章就来说说怎么实现轻松自在地、以一种全新的方式进行手机截屏,希望能给人眼前一亮的感觉。

  本文截屏应用的实现思路大致是这样:

  1、抛弃组合快捷键,采用浮动小图标作为截屏按键(类似于360浮动小球,对其思想和详细的实现方式感兴趣的小伙伴可以见另一篇文章:“Android浮动小球与开机自启动”——http://www.cnblogs.com/tgyf/p/4665401.html)。浮动小图标的实现类Service1继承自Service类,这样可以方便地创建只有一个浮动图标按键的布局,在Activity等地方利用startService(Intent intent)方法开启服务。

  2、由于浮动按键本身不是希望截取的屏幕信息,故在开始截屏后将其隐藏,图像保存后面再使其浮现。

  3、图像保存为PNG格式,路径为手机sdcard的Pictures文件目录下,而系统截屏默认的目录是Screenshots。

  4、浮动小球的优先级为一般应用的最顶层,即除了状态栏下拉列表外,小球总是可见的,这要得益于Service类的性质了。虽然在看电视等环境下会比较不适合,但该设计能让用户随时、方便地截取到想要的屏幕图像。

  5、开机自启动功能虽然保留了,但是因为截屏应用需要得到用户的同意,所以在手机重启后由广播机制自动打开的小球并不能完成截屏,还是需要点击应用图标打开应用以进行截取环境的请求。

  文章开头已经给出整个工程的代码(Android Studio版本),所以在介绍过程中就只给出实现截屏的关键代码,感兴趣的可以下载并自己进行实践。这里再给出链接为:http://files.cnblogs.com/files/tgyf/CaptureScreen.rar。一切准备就绪,开始吧。

 

一、截屏请求结果数据共享类ShotApplication

  上面已经提到,屏幕获取需要用户同意,初次运行时会有请求对话框,同意之后才能继续,否则程序会终止。既然需要用户选择后的信息,那在发出截屏请求时就不能用简单的startActivity(Intent intent)方法,而是要用startActivityForResult(Intent intent, intresquestCode)方法。而可恨的是Service类中startActivityForResult(Intent intent, int resquestCode)方法不可用,确切的说是不存在可供子类重载的onActivityResult(int resquestCode, int resultCode, Intent data) 方法。但现实是Service1类在实现截屏过程中又要用到后面两个返回值(resultCode与data)来构建MediaProjection类的对象。

  可能有人会有疑问,那截屏过程直接在Activity中进行不就可以了吗?没错,是可以。但是问题在于我们需要在任何想截取屏幕的时候就能快速、方便地进行,即需要借助利用Service实现并浮动在一般性应用窗口之上的小球。而在Activity中实现的话就达不到这种效果了,往往能获取的只能是应用本身界面,或者是将其隐藏后的下一层界面,总之做不到想要即可得的效果。

  所以,首要问题是让类Service1的对象能得到这两个数据。另外得注意,Bundle可以完成一般数据的加载并赋给Intent类对象,然后一起发送给目标类,但参数data本身就是Intent类型的。虽然Intent类存在putExtras(Intent src)方法,但为了体现面向对象数据封装的思想,这里采取的是数据共享的思路,利用继承自Application类的子类ShotApplication,然后定义需要共享的成员变量(有些是其他类的对象)。类代码很简单(不包括import *):

public class ShotApplication extends Application {private int result;private Intent intent;private MediaProjectionManager mMediaProjectionManager;public int getResult(){return result;}public Intent getIntent(){return intent;}public MediaProjectionManager getMediaProjectionManager(){return mMediaProjectionManager;}public void setResult(int result1){this.result = result1;}public void setIntent(Intent intent1){this.intent = intent1;}public void setMediaProjectionManager(MediaProjectionManager mMediaProjectionManager){this.mMediaProjectionManager = mMediaProjectionManager;}
}

其中MediaProjectionManager类对象在发送截屏请求和构建MediaProjection类对象时均会用到,至于成员值的设置及获取很直观,就不解释了。那么数据的传递就明朗了:先从主程序类MainActivity中存入共享类ShotApplication,然后服务类Service1从共享类ShotApplication中提取出来。

 

二、主程序类MainActivity所做4件事

  先给出代码(不包括import *),然后分析到底是哪4件事:

public class MainActivity extends ActionBarActivity {private int result = 0;private Intent intent = null;private int REQUEST_MEDIA_PROJECTION = 1;private MediaProjectionManager mMediaProjectionManager;@TargetApi(Build.VERSION_CODES.LOLLIPOP)@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mMediaProjectionManager = (MediaProjectionManager)getApplication().getSystemService(Context.MEDIA_PROJECTION_SERVICE);startIntent();}@TargetApi(Build.VERSION_CODES.LOLLIPOP)private void startIntent(){if(intent != null && result != 0){((ShotApplication)getApplication()).setResult(result);((ShotApplication)getApplication()).setIntent(intent);Intent intent = new Intent(getApplicationContext(), Service1.class);startService(intent);}else{startActivityForResult(mMediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION);((ShotApplication)getApplication()).setMediaProjectionManager(mMediaProjectionManager);}}@TargetApi(Build.VERSION_CODES.LOLLIPOP)@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {if (requestCode == REQUEST_MEDIA_PROJECTION) {if (resultCode != Activity.RESULT_OK) {return;}else if(data != null && resultCode != 0){result = resultCode;intent = data;((ShotApplication)getApplication()).setResult(resultCode);((ShotApplication)getApplication()).setIntent(data);Intent intent = new Intent(getApplicationContext(), Service1.class);startService(intent);finish();}}}
}

向用户提出截屏请求的代码就是下面这句:

startActivityForResult(mMediaProjectionManager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION);

这正是类MainActivity做的第1件事。当然,在这之前需要获取类MediaProjectionManager实例,代码为:
mMediaProjectionManager = (MediaProjectionManager)getApplication().getSystemService(Context.MEDIA_PROJECTION_SERVICE);

由于onCreate()方法是应用开启后自动调用的(startIntent随即被调用),所以这一行截屏请求代码也会自动执行。如果是应用安装后第一次开启,那么就会弹出截屏权限允许对话框,需要用户授权。如图:

说到这,既可以解释上面提到思路的第5条了,开机自启动后能够开启服务,但不能执行截屏请求操作。原因很简单:一开机就莫名其妙弹出截屏请求对话框不符合用户使用习惯,再者无论是在广播还是服务中调用sratActivityForResult()方法都是不太现实的。

  类MainActivity做的第2件事就是将用户操作所返回的值和初始获取的类MediaProjectionManager实例写入数据共享类ShotApplication中了,代码如下:

1 //截屏请求对话框用户操作返回数据result和intent
2 ((ShotApplication)getApplication()).setResult(result);
3 ((ShotApplication)getApplication()).setIntent(intent);
4 //类MediaProjectionManager对象mMediaProjectionManager
5 ((ShotApplication)getApplication()).setMediaProjectionManager(mMediaProjectionManager);

类MainActivity做的第3件事就是肯定是开启截屏服务了,代码如下:
 Intent intent = new Intent(getApplicationContext(), Service1.class);
2 startService(intent);
<span style="font-size: 16px;"> 注意自定义方法startIntent()时在onCreate()方法被调用,其在不同时期作用不同。如果在此次被调用之前用户已经允许过截屏操作,那么直接开启截屏服务;而如果没有允许过,则向用户请求,即做上述第1件事。</span><p><span style="font-size: 16px;">  类MainActivity做的第4件事是将自身销毁,之后的控制权就交给服务类Service1的浮动小球(这即是该类整个界面)了。</span></p><pre name="code" class="html">1 finish();

三、服务类Service1完成整体屏幕截取

  终于到了关键的类Service1了,同样先给出代码(不包括import *):

public class Service1 extends Service
{private LinearLayout mFloatLayout = null;private WindowManager.LayoutParams wmParams = null;private WindowManager mWindowManager = null;private LayoutInflater inflater = null;private ImageButton mFloatView = null;private static final String TAG = "MainActivity";private SimpleDateFormat dateFormat = null;private String strDate = null;private String pathImage = null;private String nameImage = null;private MediaProjection mMediaProjection = null;private VirtualDisplay mVirtualDisplay = null;public static int mResultCode = 0;public static Intent mResultData = null;public static MediaProjectionManager mMediaProjectionManager1 = null;private WindowManager mWindowManager1 = null;private int windowWidth = 0;private int windowHeight = 0;private ImageReader mImageReader = null;private DisplayMetrics metrics = null;private int mScreenDensity = 0;@Overridepublic void onCreate(){// TODO Auto-generated method stubsuper.onCreate();createFloatView();createVirtualEnvironment();}@Overridepublic IBinder onBind(Intent intent){// TODO Auto-generated method stubreturn null;}private void createFloatView(){wmParams = new WindowManager.LayoutParams();mWindowManager = (WindowManager)getApplication().getSystemService(getApplication().WINDOW_SERVICE);wmParams.type = LayoutParams.TYPE_PHONE;wmParams.format = PixelFormat.RGBA_8888;wmParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE;wmParams.gravity = Gravity.LEFT | Gravity.TOP;wmParams.x = 0;wmParams.y = 0;wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;inflater = LayoutInflater.from(getApplication());mFloatLayout = (LinearLayout) inflater.inflate(R.layout.float_layout, null);mWindowManager.addView(mFloatLayout, wmParams);mFloatView = (ImageButton)mFloatLayout.findViewById(R.id.float_id);mFloatLayout.measure(View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));mFloatView.setOnTouchListener(new OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {// TODO Auto-generated method stubwmParams.x = (int) event.getRawX() - mFloatView.getMeasuredWidth() / 2;wmParams.y = (int) event.getRawY() - mFloatView.getMeasuredHeight() / 2 - 25;mWindowManager.updateViewLayout(mFloatLayout, wmParams);return false;}});mFloatView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// hide the buttonmFloatView.setVisibility(View.INVISIBLE);Handler handler1 = new Handler();handler1.postDelayed(new Runnable() {public void run() {//start virtualstartVirtual();}}, 500);Handler handler2 = new Handler();handler2.postDelayed(new Runnable() {public void run() {//capture the screenstartCapture();}}, 1500);Handler handler3 = new Handler();handler3.postDelayed(new Runnable() {public void run() {mFloatView.setVisibility(View.VISIBLE);//stopVirtual();}}, 1000);}});Log.i(TAG, "created the float sphere view");}private void createVirtualEnvironment(){dateFormat = new SimpleDateFormat("yyyy_MM_dd_hh_mm_ss");strDate = dateFormat.format(new java.util.Date());pathImage = Environment.getExternalStorageDirectory().getPath()+"/Pictures/";nameImage = pathImage+strDate+".png";mMediaProjectionManager1 = (MediaProjectionManager)getApplication().getSystemService(Context.MEDIA_PROJECTION_SERVICE);mWindowManager1 = (WindowManager)getApplication().getSystemService(Context.WINDOW_SERVICE);windowWidth = mWindowManager1.getDefaultDisplay().getWidth();windowHeight = mWindowManager1.getDefaultDisplay().getHeight();metrics = new DisplayMetrics();mWindowManager1.getDefaultDisplay().getMetrics(metrics);mScreenDensity = metrics.densityDpi;mImageReader = ImageReader.newInstance(windowWidth, windowHeight, 0x1, 2); //ImageFormat.RGB_565Log.i(TAG, "prepared the virtual environment");}@TargetApi(Build.VERSION_CODES.LOLLIPOP)public void startVirtual(){if (mMediaProjection != null) {Log.i(TAG, "want to display virtual");virtualDisplay();} else {Log.i(TAG, "start screen capture intent");Log.i(TAG, "want to build mediaprojection and display virtual");setUpMediaProjection();virtualDisplay();}}@TargetApi(Build.VERSION_CODES.LOLLIPOP)public void setUpMediaProjection(){mResultData = ((ShotApplication)getApplication()).getIntent();mResultCode = ((ShotApplication)getApplication()).getResult();mMediaProjectionManager1 = ((ShotApplication)getApplication()).getMediaProjectionManager();mMediaProjection = mMediaProjectionManager1.getMediaProjection(mResultCode, mResultData);Log.i(TAG, "mMediaProjection defined");}@TargetApi(Build.VERSION_CODES.LOLLIPOP)private void virtualDisplay(){mVirtualDisplay = mMediaProjection.createVirtualDisplay("screen-mirror",windowWidth, windowHeight, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,mImageReader.getSurface(), null, null);Log.i(TAG, "virtual displayed");}@TargetApi(Build.VERSION_CODES.LOLLIPOP)private void startCapture(){strDate = dateFormat.format(new java.util.Date());nameImage = pathImage+strDate+".png";Image image = mImageReader.acquireLatestImage();int width = image.getWidth();int height = image.getHeight();final Image.Plane[] planes = image.getPlanes();final ByteBuffer buffer = planes[0].getBuffer();int pixelStride = planes[0].getPixelStride();int rowStride = planes[0].getRowStride();int rowPadding = rowStride - pixelStride * width;Bitmap bitmap = Bitmap.createBitmap(width+rowPadding/pixelStride, height, Bitmap.Config.ARGB_8888);bitmap.copyPixelsFromBuffer(buffer);bitmap = Bitmap.createBitmap(bitmap, 0, 0,width, height);image.close();Log.i(TAG, "image data captured");if(bitmap != null) {try{File fileImage = new File(nameImage);if(!fileImage.exists()){fileImage.createNewFile();Log.i(TAG, "image file created");}FileOutputStream out = new FileOutputStream(fileImage);if(out != null){bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);out.flush();out.close();Intent media = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);Uri contentUri = Uri.fromFile(fileImage);media.setData(contentUri);this.sendBroadcast(media);Log.i(TAG, "screen image saved");}}catch(FileNotFoundException e) {e.printStackTrace();}catch (IOException e){e.printStackTrace();}}}@TargetApi(Build.VERSION_CODES.LOLLIPOP)private void tearDownMediaProjection() {if (mMediaProjection != null) {mMediaProjection.stop();mMediaProjection = null;}Log.i(TAG,"mMediaProjection undefined");}private void stopVirtual() {if (mVirtualDisplay == null) {return;}mVirtualDisplay.release();mVirtualDisplay = null;Log.i(TAG,"virtual display stopped");}@Overridepublic void onDestroy(){// to remove mFloatLayout from windowManagersuper.onDestroy();if(mFloatLayout != null){mWindowManager.removeView(mFloatLayout);}tearDownMediaProjection();Log.i(TAG, "application destroy");}
}
 由于类Service1中大部分代码和之前文章中给出的相差不大,接下来会先将类中各方法简单罗列一遍,然后更加着重介绍改进的地方。

  从onCreate()方法开始,其调用了两个方法:createFloatView()和createVirtualEnvironment();createFloatView()方法负责浮动小球的生成、拖动及其点击事件的响应;createVirtualEnvironment()方法定义截屏所需的变量(包括屏幕信息、图像格式、保存格式等等)。另外,各个方法利用Log日志类输出了运行过程中的状态信息,便于观察代码执行过程。

  关键之处就在于对浮动小球点击事件的响应实现,而拖动只是附带的一个辅助功能而已。浮动小球点击事件的响应代码也完成了4件事情,下面一一进行分析。

  1、隐藏小球

1 mFloatView.setVisibility(View.INVISIBLE);

 2、初始化截屏环境
public void startVirtual(){if (mMediaProjection != null) {Log.i(TAG, "want to display virtual");virtualDisplay();} else {Log.i(TAG, "start screen capture intent");Log.i(TAG, "want to build mediaprojection and display virtual");setUpMediaProjection();virtualDisplay();}
}

可以看出,这个过程先是对MediaProjection类实例mMediaProjection的值进行了判断,若之前没有初始化(即值为null),则调用setUpMediaProjection()方法获取共享数据并对其进行赋值;若已初始化,则直接调用virtualDisplay()方法利用之前定义的变量对截屏环境进行初始化,而真正执行最终操作的方法为createVirtualDisplay()。

  3、屏幕截取

      截屏环境初始化完成之后,便可以开始获取屏幕信息了,所以接下来调用的是startCapture()方法。该方法的实现和之前不同,也是容易出错的地方在于以下两句代码:

int rowPadding = rowStride - pixelStride * width;
2 Bitmap bitmap = Bitmap.createBitmap(width+rowPadding/pixelStride, height, Bitmap.Config.ARGB_8888);

值得注意的是调用方法createBitmap()创建Bitmap对象时所用的第1、3个参数,分别对应于图像的宽度、格式。实现过程中发现,只有将格式设置为ARGB_8888才能获取想要的图像质量;而对于宽度,后面会解释为什么要为其设置偏移值。

  4、显示小球

mFloatView.setVisibility(View.VISIBLE);

四、总结

  至于服务类Service1类中的其他代码,以及用于开机自启动服务的广播子类BootBroadcastReceiver这里就不打算介绍了。

  下面来看看不同情况下的效果图,这里指的不同情况跟上述创建位图的两个参数有关。

  1、图像格式

  如果创建位图时用的格式不是ARGB_8888,比如RGB_565,虽然屏幕信息的获取没有问题,但是在将信息转化为图像并保存的过程中出现了严重的偏差。如下图:

2、宽度值

  之前介绍过调用createBitmap()方法设置其宽度参数时添加了偏移信息,如果不这么做,获取的屏幕截图会出现左边部分缺失的情况(右边会以黑色补全)。如下图:

而图像的宽度和格式参数设置正确后的截屏结果图如下:




  

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/293981.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络游戏同步法则

转自&#xff1a;http://www.cppblog.com/keigoliye/archive/2009/09/12/95986.html网络游戏同步法则网路的硬件也有限&#xff0c;而人的创造也无限&#xff0c;在公网平均130ms的Latency下&#xff0c;是不存在“完全的”的同步情况。如何通过消除/隐藏延时&#xff0c;将用户…

【JavaScript】关于eval( )

为什么80%的码农都做不了架构师&#xff1f;>>> 一、eval() 动态执行时使用当前函数的闭包。 var i 100; function myFunc(ctx) {var i test;eval(var test "hello."); //test执行后为局部变量 } myFunc(); // 输出值100 alert(i); 二、eva l() 访问…

在ASP.Net Core和JAVA中,使用Azure配置密钥——Key Vault

思路浅析 在软件开发中&#xff0c;项目安全是重中之重&#xff0c;特别是在多部门或者开源项目中&#xff0c;如何保存我们的密钥&#xff0c;但又不影响本地的开发&#xff0c;更需要我们开发者需要考虑的问题&#xff0c;这里简单的列举了下平时开发中我们做的…

我怀疑对象做了什么对不起我的事......

1 狗狗已经这么明显提醒你了▼2 传销老总都怕的传销......▼3 和一只狗撞衫了▼4 你信吗&#xff1f;我跳水不会湿头发&#xff01;▼5 东北雪糕行业繁荣的原因还挺在理▼6 打了个平手&#xff1f;▼7 缅甸网红苏娜英腰围35公分她还想减▼8 哈哈哈哈▼你点的每个赞&…

jQuery 事件和动画

jQuery 事件和动画 上回说到jQuery的选择器&#xff0c;大家都应该知道了&#xff0c;jQuery的使用可以让我们少写很多的代码&#xff0c;达到一个轻量级的效果&#xff0c;那么既然都有选择器等等方便&#xff0c;那么事件的使用肯定也是不可能缺少的&#xff0c;另外还加入一…

Android之用SingleTask和TaskAffinity解决手机截取的项目启动页面问题

今天做的远程截屏功能,服务端发一个命令下来,然后客户端截屏,截屏的代码已经写好,因为是跨进程通信的,我最后采取的办法是启动activity来实现的,但是问题来了,如果用户没有登录的情况下,可以截屏到任何页面,但是登录了之后,不在本应用里面切换的话,会回到应用的页面…

html怎么用excel打开乱码,我的Excel表格打开就乱码了,请问该如何修复?

回答&#xff1a; 第一种方法&#xff1a;采取直接修复最新版本的Excel具有直接修复受损文件的功能&#xff0c;大家可以利用Excel新增的“打开并修复”命令&#xff0c;来直接检查并修复Excel文件中的错误&#xff0c;只要单击该命令&#xff0c;Excel就会打开一个修复对话框&…

汽车模型身上出现反射效果

博客列表: www.1111kp.info, www.163123.info, www.360111.info, www.360123.info, www.6699ysk.info, www.aaafaipiao.com, www.bbbkp123.info, www.fp1111.info, www.fp1234.info, www.fpfuzhou.com, 3dsmax导出的模型&#xff0c;默认材质是漫反射&#xff08;diffuse&…

记一次 .NET 某市附属医院 Web程序 偶发性CPU爆高分析

一&#xff1a;背景 1. 讲故事这个月初&#xff0c;一位朋友加微信求助他的程序出现了 CPU 偶发性爆高&#xff0c;希望能有偿解决一下。从描述看&#xff0c;这个问题应该困扰了很久&#xff0c;还是医院的朋友给力&#xff0c;开门就是 100块 红包 &#x1f923;&#x1f923…

执行CMD命令

可以执行多条命令&#xff0c;用“\r\n”分割 1 using System;2 using System.Diagnostics;3 4 namespace Tool5 {6 7 public class CMDHelper8 {9 public static string[] ExeCommand(string commandText) 10 { 11 12 Process p new Pr…

[iOS]应用内支付(内购)的个人开发过程及坑!

本文基于XcodeVersion 7.3 (7D175)版本&#xff0c;手机是iPhone 6&#xff0c;9.3系统。 一. 创建测试App 首先你需要登录 App的ItunesConnection&#xff0c;你会看到如下界面 简单的介绍一下这几个选项 1.我的App主要用于管理自己的App应用&#xff0c;例如编辑资料&…

Android之Intent 序列化反序列化

我们做截屏功能的时候&#xff0c;因为有2个进程&#xff0c;本来是把intent和MediaProjection放到Application里面&#xff0c;但是由于跨进程了&#xff0c;所以数据拿不到&#xff0c;就采用了Parcel 序列化出错,未找到出错的原因,找其它的解决方法: 查看Intent 的源代码, 发…

农商银行招聘计算机人员考什么,农商银行招聘考试题都考什么?

整理了农商农商一、行政职业能力测试类农商银行行测考试题型主要以选择题形式出现。主要包括言语理解、数量关系、判断推理、资料分析、常识五大部分。二、英语类农商银行考试英语部分&#xff1a;一般银行英语考试内容包括英语词汇与语法、英汉互译、改错、完型填空和阅读理解…

一步步学习微软InfoPath2010和SP2010--第八章节--使用InfoPath表单Web部件

本章中&#xff0c;你将学习到&#xff1a; 1. 配置Web部件设置 2. 创建Web部件连接 3. 创建表单参数 4. 使用其他浏览器表单参数 你可以使用InfoPath表单Web部件&#xff08;Microsoft SharePoint2010新引入的&#xff09;在SharePoint企业版或Microsoft…

讲一讲应用服务的新鲜事儿

微软中国MSDN 点击上方蓝字关注我们为了新功能的发布&#xff0c;以及 Linux 和 Windows 的改进&#xff0c;Azure App Service 团队付出了非常多的努力。很开心的是&#xff0c;我们看到了 Windows Containers 的正式版本&#xff0c;并可应用于 App Service 环境 v3 上。此外…

运维自动化之基于python语言的文字界面的运维管理软件

之前开发了phpmysqlshell运维监控系统&#xff0c;监控起来很方便&#xff0c;但在运维管理方便还是不能实现&#xff0c;所以最近打算使用python语言编写一套的运维管理系统&#xff0c;可以使用单台或多台机器同时管理与部署等功能&#xff0c;实现类似func、triaquae等管理软…

Android之4.0新特性

Android 4.0 平台 API等级:14 Android 4.0 是一次重要的平台发布版,为用户和应用程序开发者增加了大量的新特性。在下面我们将讨论的所有新特性和API中,因为它将 Android 3.x 版本中广泛使用的API和全息图像主题带给了小屏幕设备,因此我们说 Android 4.0 是一次重要的平…

iOS中的动画

2019独角兽企业重金招聘Python工程师标准>>> iOS中的动画 Core Animation Core Animation是一组非常强大的动画处理API,使用它能做出非常绚丽的动画效果,而且往往是事半功倍,使用它需要添加QuartzCore .framework和引入对应的框架<QuartzCore/QuartzCore.h>…