Apache一些常用名命令:

# 安装服务
httpd -k install -n apache

# 启动服务
net start apache
httpd -k start -n apache

# 关闭服务
net stop apache
httpd -k stop -n apache

# 重启服务
httpd -k restart -n apache

# 卸载服务
## 卸载服务时先停止
httpd -k stop -n apache
## 再卸载服务
httpd -k uninstall -n apache

下载zip文件知识点:

(1)使用HttpURLConnection进行http下载

(2)使用AsyncTask创建异步任务

(3)申请权限

将zip文件写到sdcard知识点

(1)创建保存目录

(2)写文件

(3)下载完成返回标志

解压zip文件到指定目录知识点

(1)将zip包内文件解压到指定目录

(2)将zip文件删除

注意:Android高版本不能使用http协议

解决方法:清单文件里面添加(application中)

android:usesCleartextTraffic="true"

注意:还需要在清单里面申请使用网络的权限(application外)、读sd卡权限、写sd卡权限、管理sd卡权限

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>

MainActivity.java

package a.b.c.testdwonloadzip;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;

});
TextView tv = findViewById(R.id.tv_downResult);
findViewById(R.id.btn_startDownload).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
DownloadZip downloadZip = new DownloadZip(tv);
downloadZip.execute("http://192.168.31.197/down/test.zip");//由于没有下载资源,就不实操了
}
});
findViewById(R.id.btn_startzip).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
UnzipFile unzipFile = new UnzipFile(tv);
unzipFile.execute("");
}
});
}
}

DownloadZip.java

package a.b.c.testdwonloadzip;


import android.os.AsyncTask;
import android.os.Environment;
import android.util.Log;
import android.widget.TextView;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

public class DownloadZip extends AsyncTask<String,String,String>
{
private TextView tv;
private String ret = "";
public DownloadZip(TextView ptv)
{
tv = ptv;
}



@Override
protected String doInBackground(String... strings)
{
HttpURLConnection httpURLConnection = null;
InputStream inputStream = null;
OutputStream outputStream;
FileOutputStream outputStreamToFle;

try {
URL url = new URL(strings[0]);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.connect();
if (httpURLConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
Log.d("DownloadZip", "nor error code" + httpURLConnection.getResponseCode());
return "code error";
}
inputStream = httpURLConnection.getInputStream();
outputStream = httpURLConnection.getOutputStream();

File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS + "/" + "zipSaveDir/");
if (dir.exists()) {
dir.mkdir();
}
String fullFile = dir + "/" + "2058.zip";
File file = new File(fullFile);
if (file.exists()) {
file.delete();
}
file.createNewFile();
outputStreamToFle = new FileOutputStream(file.getAbsoluteFile());

byte[] buffer = new byte[1024];
int count;
while (true)
{

count = inputStream.read(buffer);
if (count == -1) {
break;
}
outputStreamToFle.write(buffer, 0, count);
}
outputStreamToFle.close();
ret = "success";
}catch (Exception ee)
{
ee.printStackTrace();
ret = "fail";
}finally
{
try
{
if(inputStream !=null)
{
inputStream.close();
}
if(httpURLConnection!=null)
{
httpURLConnection.disconnect();
}
}catch (Exception ee)
{
ee.printStackTrace();
}
}
return ret;
}
@Override
protected void onPostExecute(String s)
{
super.onPostExecute(s);
if(ret.equals("success"))
{
tv.setText("下载success");
}
else
{
tv.setText("下载fail");
}
}
}

UnzipFile.java

package a.b.c.testdwonloadzip;
import android.os.AsyncTask;
import android.os.Environment;
import android.widget.TextView;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class UnzipFile extends AsyncTask
{
private String ret = "";
InputStream inputStream = null;
ZipInputStream zipInputStream = null;
OutputStream outputStream = null;
TextView tv;
public UnzipFile(TextView ptv)
{
tv = ptv;
}
@Override
protected Object doInBackground(Object[] objects)
{
try
{
File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS + "/" + "zipSaveDir/");
String fullFilePath = dir + "/" + "2058.zip";
File file = new File(fullFilePath);
if(file.exists())
{
String jieyaDir = dir.getAbsolutePath();
inputStream = new FileInputStream(file);
zipInputStream = new ZipInputStream(new BufferedInputStream(inputStream));
byte[] buffer = new byte[1024];
ZipEntry zipEntry;
while((zipEntry = zipInputStream.getNextEntry())!= null )
{
String fileName = zipEntry.getName();
if(zipEntry.isDirectory())
{
File subDir = new File(jieyaDir + "/"+fileName);
subDir.mkdirs();
continue;
}
int rCount;

FileOutputStream fout = new FileOutputStream(jieyaDir + "/"+fileName);
while((rCount = zipInputStream.read(buffer))!=-1)
{
fout.write(buffer,0,rCount);
}
fout.close();
zipInputStream.closeEntry();
}

zipInputStream.close();
ret = "unzip success";
}
else
{
ret = "file not exits";
}
}catch (Exception ee)
{
ee.printStackTrace();
}
return ret;
}

@Override
protected void onPostExecute(Object o)
{
super.onPostExecute(o);
if(ret.equals("unzip success"))
{
tv.setText("解压成功");
}
else
{
tv.setText("解压失败");
}
}
}

认识Handler

简介:Handler是一套Android消息传递机制,主要用于线程间通信,异步消息处理。

场景:主线程负责更新UI,子线程干活并反馈给主线程结果

使用例子:

1、sendMessage、post区别?

看一看Handler类源码post函数

2、主线程handler、子线程handler区别?

3、Message是个容器,卡车,装箱

4、先写代码,然后画个图?

和SDK的消息队列一样

底层原理:线程同步

线程同步回顾:

synchronized、wait()、notify()

模型:

生产者消费者

底层原理:线程同步-缓冲区:

具备条件:

使用synchronized

有入队操作

有出队操作

生产者:Handler

生产消息:sendMessage post

目标:Msg.target = this

消费者:Looper

如何消费:

1、死循环获取消息loop()

2、队列获取消息 next()

3、派发消息 对应Handle的处理函数handleMessage()

MainActivity

package a.b.c.testhandler;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.TextView;

import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class MainActivity extends AppCompatActivity {

private MyHandler myHandler;
private TextView tv;

public void updateUI01()
{
tv.setText("01");
}
public void updateUI02()
{
tv.setText("02");
}
public void updateUI03()
{
tv.setText("03");
}
public void updataUI04()
{
tv.setText("04");
}


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_main);
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
return insets;
});
myHandler = new MyHandler(this);
SubThreadCreateHander subThread = new SubThreadCreateHander();
subThread.start();

//主线程
tv =findViewById(R.id.tv_view);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view)
{
if(false)
{
//子线程使用sendMessage给主线程发消息
MyThread myThread = new MyThread(myHandler);
myThread.start();
//子线程使用post给主线程发消息(这里不是很理解)
myHandler.post(new Runnable() {
@Override
public void run()
{
for(int i=0;i<5;i++)
{
try {
Thread.sleep(2000);
updateUI01();
updateUI02();
tv.setText("i:"+i);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
});

}
//子线程使用sendMessage给主线程发消息
//MyThread myThread = new MyThread(myHandler);
//myThread.start();
//子线程使用post给主线程发消息(这里不是很理解)
//myHandler.post(new Runnable() {
// @Override
// public void run()
// {
// for(int i=0;i<5;i++)
// {
// try {
// Thread.sleep(2000);
// updateUI01();
// updateUI02();
// tv.setText("i:"+i);
// } catch (InterruptedException e) {
// throw new RuntimeException(e);
// }
// }
// }
// });
//主线程做完事情后,把结果通过子线程的handler发送给子线程用
Message message = Message.obtain();
message.what = 99;
Bundle bundle = new Bundle();
bundle.putString("key1","这条内容是先放入Bundle,然后通过Message传递");
message.setData(bundle);
subThread.subHandler.sendMessage(message);
}
});
}
}

MyHandler

package a.b.c.testhandler;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import androidx.annotation.NonNull;
public class MyHandler extends Handler
{
private MainActivity mainActivity;
public MyHandler(MainActivity pmainActivity)
{
mainActivity = pmainActivity;
}
@Override
public void handleMessage(@NonNull Message msg)
{
super.handleMessage(msg);
Log.i("MyHandler","in handleMessage");
switch (msg.what)
{
case 1:
{
mainActivity.updateUI01();
break;
}
case 2:
{
mainActivity.updateUI02();
break;
}
case 3:
{
mainActivity.updateUI03();
break;
}
case 4:
{
mainActivity.updataUI04();
break;
}

}
}
}

MyThread

package a.b.c.testhandler;
import android.os.Message;
public class MyThread extends Thread
{
private MyHandler mh;
public MyThread(MyHandler mh)
{
this.mh = mh;
}
@Override
public void run()
{
super.run();
for(int i=0;i<5;i++)
{
try {
Thread.sleep(2000);
} catch (InterruptedException e)
{
throw new RuntimeException(e);
}
Message message = Message.obtain();
message.what =i;
mh.sendMessage(message);
}
}
}

SubThreadCreateHander

package a.b.c.testhandler;
import android.os.Message;
public class MyThread extends Thread
{
private MyHandler mh;
public MyThread(MyHandler mh)
{
this.mh = mh;
}
@Override
public void run()
{
super.run();
for(int i=0;i<5;i++)
{
try {
Thread.sleep(2000);
} catch (InterruptedException e)
{
throw new RuntimeException(e);
}
Message message = Message.obtain();
message.what =i;
mh.sendMessage(message);
}
}
}

Handler总结

在Android开发中,Handler是一种用于与线程间通信的机制,它允许你发送和处理消息和Runnable对象,从而在不同的线程之间执行代码。主要用途是在后台线程执行耗时操作后,将结果传递给主线程更新UI,或者实现定时任务等功能。

主要用途和特点:

  1. 线程间通信

    • 在Android中,UI更新必须在主线程(UI线程)中执行,而耗时操作(如网络请求、文件读写等)需要在后台线程执行,为了在这两者之间进行通信,可以使用Handler机制。
  2. 消息处理和处理机制

    • Handler可以用来发送消息(Message)或者投递任务(Runnable)到特定的线程消息队列中,这些消息或任务会按照一定的顺序执行。
  3. 主要组件

    • Looper:一个线程本地的消息循环机制,用来不断地从消息队列中取出消息或任务,并将其分发给对应的Handler处理。
    • MessageQueue:用来存放所有待处理的消息或任务。
    • HandlerThread:一种带有Looper的线程类,通常用于后台线程的创建和消息处理。
  4. 主要方法和用法

    • **sendMessage(Message)**:将Message对象发送到Handler关联的消息队列中。
    • **post(Runnable)**:将Runnable对象发送到Handler关联的消息队列中,用于执行一些任务。
    • **handleMessage(Message)**:处理从消息队列中取出的Message对象,通常在Handler的子类中重写这个方法来处理消息。
  5. 主线程操作:发送消息到主线程,在主线程中使用Handler,可以将消息或任务发送到主线程的消息队列中,以便在主线程上处理UI更新和其他操作。

    示例:

    假设在一个后台线程中执行了一个耗时操作(例如网络请求),操作完成后需要更新UI显示结果。

    // 在主线程中创建Handler,用于处理后台线程发送的消息
    Handler handler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
    super.handleMessage(msg);
    // 处理消息,更新UI
    switch (msg.what) {
    case MESSAGE_NETWORK_RESPONSE:
    String response = (String) msg.obj;
    textView.setText(response); // 更新UI显示网络请求的结果
    break;
    // 可以处理更多的消息类型
    }
    }
    };

    // 在后台线程中执行耗时操作,操作完成后发送消息到主线程更新UI
    new Thread(new Runnable() {
    @Override
    public void run() {
    // 模拟网络请求耗时操作
    try {
    Thread.sleep(3000); // 模拟耗时3秒的网络请求
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    // 网络请求完成后,发送消息给主线程更新UI
    Message message = handler.obtainMessage();
    message.what = MESSAGE_NETWORK_RESPONSE;
    message.obj = "Response from server"; // 假设这是网络请求返回的数据
    handler.sendMessage(message);
    }
    }).start();

在这个示例中:

  • 主线程中创建了一个Handler对象,并重写了handleMessage方法来处理接收到的消息。
  • 在后台线程中执行了一个模拟的网络请求耗时操作(通过Thread.sleep来模拟),操作完成后通过Handler发送了一个包含网络请求结果的消息到主线程。
  • 主线程接收到消息后,根据消息的类型(MESSAGE_NETWORK_RESPONSE),更新了TextView的显示内容。

这样,通过Handler可以实现在后台线程执行耗时操作后,将结果发送到主线程更新UI的功能。

2. 后台线程操作:发送消息到后台线程

尽管主要用途是在主线程和后台线程之间进行通信,但是也可以使用Handler在后台线程之间发送消息。这种情况比较少见,但在特定场景下可能会有用,例如在一个长时间运行的后台线程中执行任务,然后将任务结果或状态消息发送给另一个后台线程

示例:

假设有两个后台线程,一个线程负责执行某种计算任务,另一个线程监听并处理计算结果。

// 创建两个Handler,分别用于两个后台线程之间通信
Handler backgroundHandler1 = new Handler(Looper.getMainLooper()); // 用于处理后台任务1
Handler backgroundHandler2 = new Handler(Looper.getMainLooper()); // 用于处理后台任务2

// 后台线程1执行计算任务,并将结果发送给后台线程2
new Thread(new Runnable() {
@Override
public void run() {
// 模拟计算任务
int result = performCalculation();

// 将计算结果发送给后台线程2
Message message = backgroundHandler2.obtainMessage();
message.what = MESSAGE_CALCULATION_RESULT;
message.arg1 = result;
backgroundHandler2.sendMessage(message);
}
}).start();

// 后台线程2监听并处理计算结果
new Thread(new Runnable() {
@Override
public void run() {
// 监听后台线程1发送的消息
backgroundHandler2.post(new Runnable() {
@Override
public void run() {
// 处理收到的消息
switch (msg.what) {
case MESSAGE_CALCULATION_RESULT:
int result = msg.arg1;
// 处理计算结果
break;
// 可以处理更多的消息类型
}
}
});
}
}).start();